diff --git a/ci-scripts/conf_files/gnb-cu.sa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb-cu.sa.f1.conf
similarity index 87%
rename from ci-scripts/conf_files/gnb-cu.sa.band78.106prb.usrpb200.conf
rename to ci-scripts/conf_files/gnb-cu.sa.f1.conf
index 3d716c81efeb41af9933f725d64009fa5019ca56..c419979a96b7cf2ad4821bd93235d8a0f90a2f79 100644
--- a/ci-scripts/conf_files/gnb-cu.sa.band78.106prb.usrpb200.conf
+++ b/ci-scripts/conf_files/gnb-cu.sa.f1.conf
@@ -78,12 +78,8 @@ security = {
      log_config :
      {
        global_log_level                      ="info";
-       hw_log_level                          ="info";
-       phy_log_level                         ="info";
-       mac_log_level                         ="info";
-       rlc_log_level                         ="debug";
        pdcp_log_level                        ="info";
        rrc_log_level                         ="info";
-       f1ap_log_level                         ="debug";
-       ngap_log_level                         ="debug";
+       f1ap_log_level                         ="info";
+       ngap_log_level                         ="info";
     };
diff --git a/ci-scripts/conf_files/gnb-du.sa.band1.52prb.usrpb210.conf b/ci-scripts/conf_files/gnb-du.sa.band1.52prb.usrpb210.conf
new file mode 100644
index 0000000000000000000000000000000000000000..ed4a1da547fcf128ead7d355099f03bcc7966900
--- /dev/null
+++ b/ci-scripts/conf_files/gnb-du.sa.band1.52prb.usrpb210.conf
@@ -0,0 +1,218 @@
+Active_gNBs = ( "gNB-Eurecom-DU");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+gNBs =
+(
+ {
+    ////////// Identification parameters:
+    gNB_ID = 0xe00;
+    gNB_DU_ID = 0xe00;
+
+#     cell_type =  "CELL_MACRO_GNB";
+
+    gNB_name  =  "gNB-Eurecom-DU";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code  =  1;
+    plmn_list = ({ mcc = 222; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) });
+
+
+    nr_cellid = 12345678L;
+
+    ////////// Physical parameters:
+
+    min_rxtxtime                                              = 6;
+
+
+    servingCellConfigCommon = (
+    {
+ #spCellConfigCommon
+
+      physCellId                                                    = 0;
+
+#  downlinkConfigCommon
+    #frequencyInfoDL
+      # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
+      absoluteFrequencySSB                                             = 423130;
+      dl_frequencyBand                                                 = 1;
+      # this is 3600 MHz
+      dl_absoluteFrequencyPointA                                       = 422194;
+      #scs-SpecificCarrierList
+        dl_offstToCarrier                                              = 0;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
+        dl_subcarrierSpacing                                           = 0;
+        dl_carrierBandwidth                                            = 52;
+     #initialDownlinkBWP
+      #genericParameters
+        # this is RBstart=27,L=48 (275*(L-1))+RBstart
+        initialDLBWPlocationAndBandwidth                               = 14025; # 6366 12925 12956 28875 12952
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
+        initialDLBWPsubcarrierSpacing                                  = 0;
+      #pdcch-ConfigCommon
+        initialDLBWPcontrolResourceSetZero                             = 7;
+        initialDLBWPsearchSpaceZero                                    = 0;
+
+  #uplinkConfigCommon
+     #frequencyInfoUL
+      ul_frequencyBand                                                 = 1;
+      ul_absoluteFrequencyPointA                                       = 384194;
+      #scs-SpecificCarrierList
+      ul_offstToCarrier                                                = 0;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
+      ul_subcarrierSpacing                                             = 0;
+      ul_carrierBandwidth                                              = 52;
+      pMax                                                             = 20;
+     #initialUplinkBWP
+      #genericParameters
+        initialULBWPlocationAndBandwidth                               = 14025;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
+        initialULBWPsubcarrierSpacing                                  = 0;
+      #rach-ConfigCommon
+        #rach-ConfigGeneric
+          prach_ConfigurationIndex                                     = 98;
+#prach_msg1_FDM
+#0 = one, 1=two, 2=four, 3=eight
+          prach_msg1_FDM                                               = 0;
+          prach_msg1_FrequencyStart                                    = 0;
+          zeroCorrelationZoneConfig                                    = 12;
+          preambleReceivedTargetPower                                  = -90;
+#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
+          preambleTransMax                                             = 6;
+#powerRampingStep
+# 0=dB0,1=dB2,2=dB4,3=dB6
+        powerRampingStep                                               = 1;
+#ra_ReponseWindow
+#1,2,4,8,10,20,40,80
+        ra_ResponseWindow                                              = 4;
+#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
+#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR                   = 3;
+#oneHalf (0..15) 4,8,12,16,...60,64
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB                      = 15;
+#ra_ContentionResolutionTimer
+#(0..7) 8,16,24,32,40,48,56,64
+        ra_ContentionResolutionTimer                                   = 7;
+        rsrp_ThresholdSSB                                              = 19;
+#prach-RootSequenceIndex_PR
+#1 = 839, 2 = 139
+        prach_RootSequenceIndex_PR                                     = 2;
+        prach_RootSequenceIndex                                        = 1;
+        # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
+        #
+        msg1_SubcarrierSpacing                                         = 0,
+# restrictedSetConfig
+# 0=unrestricted, 1=restricted type A, 2=restricted type B
+        restrictedSetConfig                                            = 0,
+
+        msg3_DeltaPreamble                                             = 1;
+        p0_NominalWithGrant                                            =-90;
+
+# pucch-ConfigCommon setup :
+# pucchGroupHopping
+# 0 = neither, 1= group hopping, 2=sequence hopping
+        pucchGroupHopping                                              = 0;
+        hoppingId                                                      = 40;
+        p0_nominal                                                     = -70;
+        n_TimingAdvanceOffset                                          = 0;
+# ssb_PositionsInBurs_BitmapPR
+# 1=short, 2=medium, 3=long
+      ssb_PositionsInBurst_PR                                          = 2;
+      ssb_PositionsInBurst_Bitmap                                      = 1;
+
+# ssb_periodicityServingCell
+# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
+      ssb_periodicityServingCell                                       = 2;
+
+# dmrs_TypeA_position
+# 0 = pos2, 1 = pos3
+      dmrs_TypeA_Position                                              = 0;
+
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
+      subcarrierSpacing                                                = 0;
+
+
+  #tdd-UL-DL-ConfigurationCommon
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
+      referenceSubcarrierSpacing                                       = 0;
+      ssPBCH_BlockPower                                             = -25;
+     }
+
+  );
+
+
+    # ------- SCTP definitions
+    SCTP :
+    {
+        # Number of streams to use in input/output
+        SCTP_INSTREAMS  = 2;
+        SCTP_OUTSTREAMS = 2;
+    };
+  }
+);
+
+MACRLCs = (
+  {
+    num_cc           = 1;
+    tr_s_preference  = "local_L1";
+    tr_n_preference  = "f1";
+    local_n_if_name = "eth0";
+    local_n_address = "192.168.68.195";
+    remote_n_address = "192.168.68.194";
+    local_n_portc   = 500;
+    local_n_portd   = 2153;
+    remote_n_portc  = 501;
+    remote_n_portd  = 2153;
+    pusch_TargetSNRx10          = 200;
+    pucch_TargetSNRx10          = 200;
+    ulsch_max_frame_inactivity = 1;
+  }
+);
+
+L1s = (
+{
+  num_cc = 1;
+  tr_n_preference = "local_mac";
+  prach_dtx_threshold = 200;
+  pucch0_dtx_threshold = 150;
+  ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
+}
+);
+
+RUs = (
+    {
+       local_rf       = "yes"
+         nb_tx          = 1
+         nb_rx          = 1
+         # The higher att for TX than RX is because we use a circulator (as for TDD),
+         # while we should use a duplexer in the FDD case. However, it uses the same setup.
+         att_tx         = 18
+         att_rx         = 0;
+         bands          = [1];
+         max_pdschReferenceSignalPower = -27;
+         max_rxgain                    = 108;
+         eNB_instances  = [0];
+         #beamforming 1x4 matrix:
+         bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000];
+         clock_src = "internal";
+    }
+);
+
+THREAD_STRUCT = (
+  {
+    #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
+    parallel_config    = "PARALLEL_SINGLE_THREAD";
+    #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
+    worker_config      = "WORKER_ENABLE";
+  }
+);
+
+log_config : {
+  global_log_level = "info";
+};
diff --git a/ci-scripts/xml_files/container_sa_f1_b200_quectel.xml b/ci-scripts/xml_files/container_sa_f1_b200_quectel.xml
index 1f28fce309018f22fe91eacd0053b9fd22b08bf3..e473fdea10a51381003dfe19b3b13157fbb2d427 100644
--- a/ci-scripts/xml_files/container_sa_f1_b200_quectel.xml
+++ b/ci-scripts/xml_files/container_sa_f1_b200_quectel.xml
@@ -22,7 +22,7 @@
 -->
 <testCaseList>
   <htmlTabRef>TEST-SA-FR1-F1-B200</htmlTabRef>
-  <htmlTabName>40 MHz TDD F1 SA</htmlTabName>
+  <htmlTabName>10 MHz FDD F1 SA</htmlTabName>
   <htmlTabIcon>tasks</htmlTabIcon>
   <repeatCount>1</repeatCount>
   <TestCaseRequestedList>
@@ -89,11 +89,11 @@
 
   <testCase id="130102">
     <class>Deploy_Object</class>
-    <desc>Deploy gNB-DU (TDD/Band78/40MHz/B200) in a container</desc>
+    <desc>Deploy gNB-DU (FDD/Band1/10MHz/B200) in a container</desc>
     <yaml_path>ci-scripts/yaml_files/sa_f1_b200_gnb</yaml_path>
     <eNB_instance>0</eNB_instance>
     <eNB_serverId>0</eNB_serverId>
-    <services>gnb_du_tdd</services>
+    <services>gnb_du_fdd</services>
   </testCase>
 
   <testCase id="100000">
@@ -159,8 +159,8 @@
 
   <testCase id="170000">
     <class>Iperf</class>
-    <desc>iperf (DL/80Mbps/UDP)(30 sec)</desc>
-    <iperf_args>-u -b 80M -t 30 -i 1 -fm</iperf_args>
+    <desc>iperf (DL/50Mbps/UDP)(30 sec)</desc>
+    <iperf_args>-u -b 50M -t 30 -i 1 -fm</iperf_args>
     <direction>DL</direction>
     <id>idefix</id>
     <iperf_packetloss_threshold>10</iperf_packetloss_threshold>
@@ -170,8 +170,8 @@
 
   <testCase id="170001">
     <class>Iperf</class>
-    <desc>iperf (UL/8Mbps/UDP)(30 sec)</desc>
-    <iperf_args>-u -b 8M -t 30 -i 1 -fm</iperf_args>
+    <desc>iperf (UL/25Mbps/UDP)(30 sec)</desc>
+    <iperf_args>-u -b 25M -t 30 -i 1 -fm</iperf_args>
     <direction>UL</direction>
     <id>idefix</id>
     <iperf_packetloss_threshold>1</iperf_packetloss_threshold>
@@ -181,8 +181,8 @@
 
   <testCase id="170002">
     <class>Iperf</class>
-    <desc>iperf (BIDIR TCP)(20 sec)(single-ue profile)</desc>
-    <iperf_args>-t 20 --bidir</iperf_args>
+    <desc>iperf (BIDIR TCP)(60 sec)(single-ue profile)</desc>
+    <iperf_args>-t 60 --bidir</iperf_args>
     <direction>BIDIR</direction>
     <id>idefix</id>
     <iperf_profile>single-ue</iperf_profile>
diff --git a/ci-scripts/yaml_files/sa_f1_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_f1_b200_gnb/docker-compose.yml
index 2ad0818a4777a0f1071a591fa63163c68d5d6378..072461af5cd1aee294cd846e81f6a25ef0ff7a20 100644
--- a/ci-scripts/yaml_files/sa_f1_b200_gnb/docker-compose.yml
+++ b/ci-scripts/yaml_files/sa_f1_b200_gnb/docker-compose.yml
@@ -8,7 +8,7 @@ services:
         environment:
             USE_ADDITIONAL_OPTIONS: --sa --telnetsrv --telnetsrv.shrmod ci --log_config.global_log_options level,nocolor,time,line_num,function
         volumes:
-            - ../../conf_files/gnb-cu.sa.band78.106prb.usrpb200.conf:/opt/oai-gnb/etc/gnb.conf
+            - ../../conf_files/gnb-cu.sa.f1.conf:/opt/oai-gnb/etc/gnb.conf
         networks:
             public_net:
                 ipv4_address: 192.168.68.194
@@ -20,15 +20,15 @@ services:
             timeout: 5s
             retries: 5
 
-    gnb_du_tdd:
+    gnb_du_fdd:
         image: oai-gnb:latest
         privileged: true
         container_name: sa-du-b200-gnb
         environment:
             USE_B2XX: 'yes'
-            USE_ADDITIONAL_OPTIONS: --sa --RUs.[0].sdr_addrs serial=30C51D4 --continuous-tx -E --telnetsrv --telnetsrv.shrmod ci --log_config.global_log_options level,nocolor,time,line_num,function --gNBs.[0].min_rxtxtime 2 --gNBs.[0].do_CSIRS 1 --gNBs.[0].do_SRS 1 --RUs.[0].att_rx 18 --RUs.[0].att_tx 18
+            USE_ADDITIONAL_OPTIONS: --sa --RUs.[0].sdr_addrs serial=30C51D4 --telnetsrv --telnetsrv.shrmod ci --log_config.global_log_options level,nocolor,time,line_num,function --gNBs.[0].min_rxtxtime 2 --gNBs.[0].do_CSIRS 1 --gNBs.[0].do_SRS 0 --MACRLCs.[0].ul_max_mcs 28 --L1s.[0].max_ldpc_iterations 20
         volumes:
-            - ../../conf_files/gnb-du.sa.band78.106prb.usrpb200.conf:/opt/oai-gnb/etc/gnb.conf
+            - ../../conf_files/gnb-du.sa.band1.52prb.usrpb210.conf:/opt/oai-gnb/etc/gnb.conf
             - /dev:/dev
         networks:
             public_net:
diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h
index ea879e93b40f810f56a695eb83ed88766ccaf429..ea6c8b860e3937031394f693da45a30e73a513c4 100644
--- a/common/utils/nr/nr_common.h
+++ b/common/utils/nr/nr_common.h
@@ -43,6 +43,7 @@
 #define NR_NB_REG_PER_CCE 6
 #define NR_NB_SC_PER_RB 12
 #define NR_MAX_NUM_LCID 32
+#define NR_MAX_NUM_QFI 64
 
 typedef enum {
   nr_FR1 = 0,
diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_crc_byte.c b/openair1/PHY/CODING/nrPolar_tools/nr_crc_byte.c
index 4c2e82dc643c0287224c92c4b919e492b4466c23..d04dde62e72372151a98dc2e8ef049065f1666c5 100644
--- a/openair1/PHY/CODING/nrPolar_tools/nr_crc_byte.c
+++ b/openair1/PHY/CODING/nrPolar_tools/nr_crc_byte.c
@@ -30,27 +30,27 @@ const uint8_t **crc24c_generator_matrix(uint16_t payloadSizeBits)
   uint8_t temp1[crcPolynomialSize], temp2[crcPolynomialSize];
 
 	uint8_t **crc_generator_matrix = malloc(payloadSizeBits*sizeof(uint8_t *) + payloadSizeBits*crcPolynomialSize*sizeof(uint8_t));
-	if (crc_generator_matrix)
-	  for (int i = 0; i < payloadSizeBits; i++)
-	    crc_generator_matrix[i] = ((uint8_t*)&crc_generator_matrix[payloadSizeBits])+i*crcPolynomialSize;
+  if (crc_generator_matrix)
+    for (int i = 0; i < payloadSizeBits; i++)
+      crc_generator_matrix[i] = ((uint8_t *)&crc_generator_matrix[payloadSizeBits]) + i * crcPolynomialSize;
 
-	for (int i = 0; i < crcPolynomialSize; i++)
-	  crc_generator_matrix[payloadSizeBits-1][i]=crcPolynomialPattern[i+1];
+  for (int i = 0; i < crcPolynomialSize; i++)
+    crc_generator_matrix[payloadSizeBits - 1][i] = crcPolynomialPattern[i + 1];
 
-	for (int i = payloadSizeBits-2; i >= 0; i--){
+  for (int i = payloadSizeBits - 2; i >= 0; i--) {
 		for (int j = 0; j < crcPolynomialSize-1; j++) temp1[j]=crc_generator_matrix[i+1][j+1];
 
-		temp1[crcPolynomialSize-1]=0;
+    temp1[crcPolynomialSize - 1] = 0;
 
-		for (int j = 0; j < crcPolynomialSize; j++)
-			temp2[j]=crc_generator_matrix[i+1][0]*crcPolynomialPattern[j+1];
+    for (int j = 0; j < crcPolynomialSize; j++)
+      temp2[j] = crc_generator_matrix[i + 1][0] * crcPolynomialPattern[j + 1];
 
-		for (int j = 0; j < crcPolynomialSize; j++){
+    for (int j = 0; j < crcPolynomialSize; j++) {
 			if(temp1[j]+temp2[j] == 1)
 				crc_generator_matrix[i][j]=1;
 			else
 				crc_generator_matrix[i][j]=0;
-		}
-	}
+    }
+  }
   return (const uint8_t **)crc_generator_matrix;
 }
diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_decoder.c b/openair1/PHY/CODING/nrPolar_tools/nr_polar_decoder.c
index 18de88db79f01d222c860e2a984457a0507abcff..06c852a7dd936beb0f9509a9d31e3dea569e37f4 100644
--- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_decoder.c
+++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_decoder.c
@@ -28,7 +28,7 @@
  * \email raymond.knopp@eurecom.fr, turker.yilmaz@eurecom.fr
  * \note
  * \warning
-*/
+ */
 
 /*
  * Return values:
@@ -68,13 +68,13 @@ int8_t polar_decoder(double *input,
 {
   t_nrPolar_params *polarParams=nr_polar_params(messageType, messageLength, aggregation_level, true);
   //Assumes no a priori knowledge.
-  uint8_t bit[polarParams->N][polarParams->n+1][2*listSize];
-  memset(bit,0,sizeof bit);
+  uint8_t bit[polarParams->N][polarParams->n + 1][2 * listSize];
+  memset(bit, 0, sizeof bit);
   uint8_t bitUpdated[polarParams->N][polarParams->n+1]; //0=False, 1=True
   memset(bitUpdated,0,sizeof bitUpdated);
   uint8_t llrUpdated[polarParams->N][polarParams->n+1]; //0=False, 1=True
   memset(llrUpdated,0,sizeof llrUpdated);
-  double  llr[polarParams->N][polarParams->n+1][2*listSize];
+  double llr[polarParams->N][polarParams->n + 1][2 * listSize];
   uint8_t crcChecksum[polarParams->crcParityBits][2*listSize];
   memset(crcChecksum,0,sizeof crcChecksum);
   double  pathMetric[2*listSize];
@@ -127,7 +127,8 @@ int8_t polar_decoder(double *input,
   double d_tilde[polarParams->N];
   nr_polar_rate_matching(input, d_tilde, polarParams->rate_matching_pattern, polarParams->K, polarParams->N, polarParams->encoderLength);
 
-  for (int j = 0; j < polarParams->N; j++) llr[j][polarParams->n][0]=d_tilde[j];
+  for (int j = 0; j < polarParams->N; j++)
+    llr[j][polarParams->n][0] = d_tilde[j];
 
   /*
    * SCL polar decoder.
@@ -139,48 +140,56 @@ int8_t polar_decoder(double *input,
   uint8_t listIndex[2*listSize], copyIndex;
 
   for (uint16_t currentBit=0; currentBit<polarParams->N; currentBit++) {
-    updateLLR(currentListSize, currentBit, 0, polarParams->N, polarParams->n+1, 2*listSize, llr, llrUpdated, bit, bitUpdated);
+    updateLLR(currentListSize, currentBit, 0, polarParams->N, polarParams->n + 1, 2 * listSize, llr, llrUpdated, bit, bitUpdated);
 
     if (polarParams->information_bit_pattern[currentBit]==0) { //Frozen bit.
-      updatePathMetric(pathMetric, currentListSize, 0, currentBit, polarParams->N, polarParams->n+1, 2*listSize, llr);
+      updatePathMetric(pathMetric, currentListSize, 0, currentBit, polarParams->N, polarParams->n + 1, 2 * listSize, llr);
     } else { //Information or CRC bit.
-      updatePathMetric2(pathMetric, currentListSize, currentBit, polarParams->N, polarParams->n+1, 2*listSize, llr);
+      updatePathMetric2(pathMetric, currentListSize, currentBit, polarParams->N, polarParams->n + 1, 2 * listSize, llr);
 
       for (int i = 0; i < currentListSize; i++) {
-      for (int j = 0; j < polarParams->N; j++) {
-	for (int k = 0; k < (polarParams->n+1); k++) {
-            bit[j][k][i+currentListSize]=bit[j][k][i];
-            llr[j][k][i+currentListSize]=llr[j][k][i];
+        for (int j = 0; j < polarParams->N; j++) {
+          for (int k = 0; k < (polarParams->n + 1); k++) {
+            bit[j][k][i + currentListSize] = bit[j][k][i];
+            llr[j][k][i + currentListSize] = llr[j][k][i];
           }
-	}
+        }
       }
 
-	for (int i = 0; i < currentListSize; i++) {
-	  bit[currentBit][0][i]=0;
-	  crcState[i+currentListSize]=crcState[i];
-	}
-
-      for (int i = currentListSize; i < 2*currentListSize; i++) bit[currentBit][0][i]=1;
-
-      bitUpdated[currentBit][0]=1;
-      updateCrcChecksum2(polarParams->crcParityBits, 2*listSize, crcChecksum,
-			 polarParams->K, polarParams->crcParityBits, extended_crc_generator_matrix, 
-                         currentListSize, nonFrozenBit, polarParams->crcParityBits);
-      currentListSize*=2;
+      for (int i = 0; i < currentListSize; i++) {
+        bit[currentBit][0][i] = 0;
+        crcState[i + currentListSize] = crcState[i];
+      }
 
-      //Keep only the best "listSize" number of entries.
+      for (int i = currentListSize; i < 2 * currentListSize; i++)
+        bit[currentBit][0][i] = 1;
+
+      bitUpdated[currentBit][0] = 1;
+      updateCrcChecksum2(polarParams->crcParityBits,
+                         2 * listSize,
+                         crcChecksum,
+                         polarParams->K,
+                         polarParams->crcParityBits,
+                         extended_crc_generator_matrix,
+                         currentListSize,
+                         nonFrozenBit,
+                         polarParams->crcParityBits);
+      currentListSize *= 2;
+
+      // Keep only the best "listSize" number of entries.
       if (currentListSize > listSize) {
-        for (uint8_t i = 0; i < 2*listSize; i++) listIndex[i]=i;
+        for (uint8_t i = 0; i < 2 * listSize; i++)
+          listIndex[i] = i;
 
         nr_sort_asc_double_1D_array_ind(pathMetric, listIndex, currentListSize);
-        //sort listIndex[listSize, ..., 2*listSize-1] in descending order.
+        // sort listIndex[listSize, ..., 2*listSize-1] in descending order.
         uint8_t swaps, tempInd;
 
         for (uint8_t i = 0; i < listSize; i++) {
           swaps = 0;
 
-          for (uint8_t j = listSize; j < (2*listSize - i) - 1; j++) {
-            if (listIndex[j+1] > listIndex[j]) {
+          for (uint8_t j = listSize; j < (2 * listSize - i) - 1; j++) {
+            if (listIndex[j + 1] > listIndex[j]) {
               tempInd = listIndex[j];
               listIndex[j] = listIndex[j + 1];
               listIndex[j + 1] = tempInd;
@@ -196,8 +205,8 @@ int8_t polar_decoder(double *input,
         for (int k=(listSize-1); k>0; k--) {
           for (int i=0; i<polarParams->N; i++) {
             for (int j=0; j<(polarParams->n+1); j++) {
-              bit[i][j][listIndex[(2*listSize-1)-k]]=bit[i][j][listIndex[k]];
-              llr[i][j][listIndex[(2*listSize-1)-k]]=llr[i][j][listIndex[k]];
+              bit[i][j][listIndex[(2 * listSize - 1) - k]] = bit[i][j][listIndex[k]];
+              llr[i][j][listIndex[(2 * listSize - 1) - k]] = llr[i][j][listIndex[k]];
             }
           }
         }
@@ -285,7 +294,8 @@ int8_t polar_decoder(double *input,
 
   for (uint8_t i = 0; i < fmin(listSize, (pow(2,polarParams->crcCorrectionBits)) ); i++) {
     if ( crcState[listIndex[i]] == 1 ) {
-      for (int j = 0; j < polarParams->N; j++) polarParams->nr_polar_U[j]=bit[j][0][listIndex[i]];
+      for (int j = 0; j < polarParams->N; j++)
+        polarParams->nr_polar_U[j] = bit[j][0][listIndex[i]];
 
       //Extract the information bits (û to ĉ)
       nr_polar_info_bit_extraction(polarParams->nr_polar_U, polarParams->nr_polar_CPrime, polarParams->information_bit_pattern, polarParams->N);
@@ -626,7 +636,7 @@ uint32_t polar_decoder_int16(int16_t *input,
   printf("\n");
 #endif
 
-  int16_t d_tilde[polarParams->N];// = malloc(sizeof(double) * polarParams->N);
+  int16_t d_tilde[polarParams->N];
   nr_polar_rate_matching_int16(input, d_tilde, polarParams->rate_matching_pattern, polarParams->K, polarParams->N, polarParams->encoderLength, polarParams->i_bil);
 
   for (int i=0; i<polarParams->N; i++) {
@@ -687,14 +697,9 @@ uint32_t polar_decoder_int16(int16_t *input,
   uint64_t B[4] = {0};
 
   if (polarParams->K<65) {
-    B[0] = polarParams->B_tab0[0][Cprimebyte[0]] |
-           polarParams->B_tab0[1][Cprimebyte[1]] |
-           polarParams->B_tab0[2][Cprimebyte[2]] |
-           polarParams->B_tab0[3][Cprimebyte[3]] |
-           polarParams->B_tab0[4][Cprimebyte[4]] |
-           polarParams->B_tab0[5][Cprimebyte[5]] |
-           polarParams->B_tab0[6][Cprimebyte[6]] |
-           polarParams->B_tab0[7][Cprimebyte[7]];
+    B[0] = polarParams->B_tab0[0][Cprimebyte[0]] | polarParams->B_tab0[1][Cprimebyte[1]] | polarParams->B_tab0[2][Cprimebyte[2]]
+           | polarParams->B_tab0[3][Cprimebyte[3]] | polarParams->B_tab0[4][Cprimebyte[4]] | polarParams->B_tab0[5][Cprimebyte[5]]
+           | polarParams->B_tab0[6][Cprimebyte[6]] | polarParams->B_tab0[7][Cprimebyte[7]];
   } else if (polarParams->K<129) {
     int len = polarParams->K/8;
 
diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_decoding_tools.c b/openair1/PHY/CODING/nrPolar_tools/nr_polar_decoding_tools.c
index 6ae6c46498cd197122799e9bcb6c3df502912d2d..5a4374351a6ffc2b8908ed30c9f9fd2aacd80959 100644
--- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_decoding_tools.c
+++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_decoding_tools.c
@@ -45,20 +45,23 @@ static inline void updateBit(uint8_t listSize,
 			     uint8_t bit[xlen][ylen][zlen],
 			     uint8_t bitU[xlen][ylen])
 {
-	uint16_t offset = ( xlen/(pow(2,(ylen-col))) );
-
-	for (uint8_t i=0; i<listSize; i++) {
-		if (( (row) % (2*offset) ) >= offset ) {
-		  if (bitU[row][col-1]==0) updateBit(listSize, row, (col-1), xlen, ylen, zlen, bit, bitU);
-			bit[row][col][i] = bit[row][col-1][i];
-		} else {
-		  if (bitU[row][col-1]==0) updateBit(listSize, row, (col-1), xlen, ylen, zlen, bit, bitU);
-		  if (bitU[row+offset][col-1]==0) updateBit(listSize, (row+offset), (col-1), xlen, ylen, zlen, bit, bitU);
-			bit[row][col][i] = ( (bit[row][col-1][i]+bit[row+offset][col-1][i]) % 2);
-		}
-	}
+  uint16_t offset = (xlen / (pow(2, (ylen - col))));
+
+  for (uint8_t i = 0; i < listSize; i++) {
+    if (((row) % (2 * offset)) >= offset) {
+      if (bitU[row][col - 1] == 0)
+        updateBit(listSize, row, (col - 1), xlen, ylen, zlen, bit, bitU);
+      bit[row][col][i] = bit[row][col - 1][i];
+    } else {
+      if (bitU[row][col - 1] == 0)
+        updateBit(listSize, row, (col - 1), xlen, ylen, zlen, bit, bitU);
+      if (bitU[row + offset][col - 1] == 0)
+        updateBit(listSize, (row + offset), (col - 1), xlen, ylen, zlen, bit, bitU);
+      bit[row][col][i] = ((bit[row][col - 1][i] + bit[row + offset][col - 1][i]) % 2);
+    }
+  }
 
-	bitU[row][col]=1;
+  bitU[row][col] = 1;
 }
 
 static inline void computeLLR(uint16_t row,
@@ -75,35 +78,38 @@ static inline void computeLLR(uint16_t row,
   llr[row][col][i] = log((exp(a + b) + 1) / (exp(a) + exp(b))); //eq. (8a)
 }
 
-
 void updateLLR(uint8_t listSize,
-	       uint16_t row,
-	       uint16_t col,
-	        uint16_t xlen,
-	       uint8_t ylen,
-	       int zlen,
-	       double  llr[xlen][ylen][zlen],
-	       uint8_t llrU[xlen][ylen],
-	       uint8_t bit[xlen][ylen][zlen],
-	       uint8_t bitU[xlen][ylen]
-	       )
+               uint16_t row,
+               uint16_t col,
+               uint16_t xlen,
+               uint8_t ylen,
+               int zlen,
+               double llr[xlen][ylen][zlen],
+               uint8_t llrU[xlen][ylen],
+               uint8_t bit[xlen][ylen][zlen],
+               uint8_t bitU[xlen][ylen])
 {
-	uint16_t offset = (xlen/(pow(2,(ylen-col-1))));
-	for (uint8_t i=0; i<listSize; i++) {
-		if (( (row) % (2*offset) ) >= offset ) {
-		  if(bitU[row-offset][col]==0) updateBit(listSize, (row-offset), col, xlen, ylen, zlen, bit, bitU);
-		  if(llrU[row-offset][col+1]==0) updateLLR(listSize, (row-offset), (col+1), xlen, ylen, zlen, llr, llrU, bit, bitU );
-		  if(llrU[row][col+1]==0) updateLLR(listSize, row, (col+1), xlen, ylen, zlen, llr, llrU, bit, bitU);
-			llr[row][col][i] = (pow((-1),bit[row-offset][col][i])*llr[row-offset][col+1][i]) + llr[row][col+1][i];
-		} else {
-		  if(llrU[row][col+1]==0) updateLLR(listSize, row, (col+1), xlen, ylen, zlen, llr, llrU, bit, bitU );
-		  if(llrU[row+offset][col+1]==0) updateLLR(listSize, (row+offset), (col+1), xlen, ylen, zlen, llr, llrU, bit, bitU );
-		  computeLLR(row, col, i, offset, xlen, ylen, zlen, llr);
-		}
-	}
-	llrU[row][col]=1;
+  uint16_t offset = (xlen / (pow(2, (ylen - col - 1))));
+  for (uint8_t i = 0; i < listSize; i++) {
+    if ((row % (2 * offset)) >= offset) {
+      if (bitU[row - offset][col] == 0)
+        updateBit(listSize, (row - offset), col, xlen, ylen, zlen, bit, bitU);
+      if (llrU[row - offset][col + 1] == 0)
+        updateLLR(listSize, (row - offset), (col + 1), xlen, ylen, zlen, llr, llrU, bit, bitU);
+      if (llrU[row][col + 1] == 0)
+        updateLLR(listSize, row, (col + 1), xlen, ylen, zlen, llr, llrU, bit, bitU);
+      llr[row][col][i] = (pow((-1), bit[row - offset][col][i]) * llr[row - offset][col + 1][i]) + llr[row][col + 1][i];
+    } else {
+      if (llrU[row][col + 1] == 0)
+        updateLLR(listSize, row, (col + 1), xlen, ylen, zlen, llr, llrU, bit, bitU);
+      if (llrU[row + offset][col + 1] == 0)
+        updateLLR(listSize, (row + offset), (col + 1), xlen, ylen, zlen, llr, llrU, bit, bitU);
+      computeLLR(row, col, i, offset, xlen, ylen, zlen, llr);
+    }
+  }
+  llrU[row][col] = 1;
 
-	//	printf("LLR (a %f, b %f): llr[%d][%d] %f\n",32*a,32*b,col,row,32*llr[col][row]);
+  //	printf("LLR (a %f, b %f): llr[%d][%d] %f\n",32*a,32*b,col,row,32*llr[col][row]);
 }
 
 void updatePathMetric(double *pathMetric,
diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h b/openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h
index e48a2058895de0e3c44fe6b65ef8a56526b7c0f7..490b24860db709f2147fe10786613937a0caf3b3 100644
--- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h
+++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h
@@ -112,7 +112,7 @@ struct nrPolar_params {
 
   const uint8_t **crc_generator_matrix; // G_P
   const uint8_t **G_N;
-  uint64_t **G_N_tab;
+  fourDimArray_t *G_N_tab;
   int groupsize;
   int *rm_tab;
   uint64_t cprime_tab0[32][256];
@@ -219,9 +219,7 @@ uint32_t nr_polar_output_length(uint16_t K,
                                 uint16_t E,
                                 uint8_t n_max);
 
-void nr_polar_channel_interleaver_pattern(uint16_t *cip,
-    uint8_t I_BIL,
-    uint16_t E);
+void nr_polar_channel_interleaver_pattern(uint16_t *cip, const uint8_t I_BIL, const uint16_t E);
 
 void nr_polar_rate_matching_pattern(uint16_t *rmp,
                                     uint16_t *J,
@@ -258,7 +256,7 @@ void nr_polar_info_bit_pattern(uint8_t *ibp,
                                const uint16_t *Q_0_Nminus1,
                                uint16_t K,
                                uint16_t N,
-                               uint16_t E,
+                               const uint16_t E,
                                uint8_t n_PC,
                                uint8_t n_pc_wm);
 
@@ -284,7 +282,7 @@ void nr_polar_generate_u(uint64_t *u,
                          uint16_t N,
                          uint8_t n_pc);
 
-void nr_polar_uxG(uint64_t *D, const uint64_t *u, const uint64_t **G_N_tab, uint16_t N);
+void nr_polar_uxG(uint64_t *D, const uint64_t *u, const fourDimArray_t *G_N_tab, uint16_t N);
 
 void nr_polar_info_extraction_from_u(uint64_t *Cprime,
                                      const uint8_t *u,
diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c b/openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c
index ea476c0d3871c646f75126a3356a8e8d6f203852..0a5982049b802ba68b321cd0a606e8ae3f76a5d7 100644
--- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c
+++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c
@@ -359,15 +359,11 @@ void build_polar_tables(t_nrPolar_params *polarParams) {
   AssertFatal(polarParams->K > 17, "K = %d < 18, is not possible\n",polarParams->K);
   AssertFatal(polarParams->K < 129, "K = %d > 128, is not supported yet\n",polarParams->K);
   int bit_i,ip;
-  int numbytes = polarParams->K>>3;
-  int residue = polarParams->K&7;
-  int numbits;
-
-  if (residue>0) numbytes++;
+  const int numbytes = (polarParams->K+7)/8;
+  const int residue = polarParams->K&7;
 
   for (int byte=0; byte<numbytes; byte++) {
-    if (byte<(polarParams->K>>3)) numbits=8;
-    else numbits=residue;
+    int numbits = byte<(polarParams->K>>3) ? 8 : residue;
 
     for (int val=0; val<256; val++) {
       polarParams->cprime_tab0[byte][val] = 0;
@@ -388,16 +384,20 @@ void build_polar_tables(t_nrPolar_params *polarParams) {
   AssertFatal(polarParams->N == 512 || polarParams->N == 256 || polarParams->N == 128 || polarParams->N == 64, "N = %d, not done yet\n", polarParams->N);
 
   // build G bit vectors for information bit positions and convert the bit as bytes tables in nr_polar_kronecker_power_matrices.c to
-  // 64 bit packed vectors.
-  polarParams->G_N_tab = (uint64_t **)calloc(polarParams->N, sizeof(int64_t *));
-
+  // 64 bit packed vectors. 
+  // Truncates id N%64 != 0
+  allocCast2D(pp, uint64_t, polarParams->G_N_tab, polarParams->N, polarParams->N / 64, false);
+  simde__m256i zeros = simde_mm256_setzero_si256();
+  // this code packs the one bit per byte of G_N into a packed bits G_N_tab
   for (int i = 0; i < polarParams->N; i++) {
-    polarParams->G_N_tab[i] = (uint64_t *)memalign(32, (polarParams->N / 64) * sizeof(uint64_t));
-    memset((void *)polarParams->G_N_tab[i], 0, (polarParams->N / 64) * sizeof(uint64_t));
-
-    for (int j = 0; j < polarParams->N; j++)
-      polarParams->G_N_tab[i][j / 64] |= ((uint64_t)polarParams->G_N[i][j]) << (j & 63);
-
+    for (int j = 0; j < polarParams->N; j += 64) {
+      const simde__m256i tmp1 = simde_mm256_cmpgt_epi8(*(simde__m256i *)&polarParams->G_N[i][j], zeros);
+      const simde__m256i tmp2 = simde_mm256_cmpgt_epi8(*(simde__m256i *)&polarParams->G_N[i][j + 32], zeros);
+      // cast directly to uint64_t from int32_t propagates the sign bit (in gcc)
+      const uint32_t part1 = simde_mm256_movemask_epi8(tmp1);
+      const uint32_t part2 = simde_mm256_movemask_epi8(tmp2);
+      pp[i][j / 64] = ((uint64_t)part2 << 32) | part1;
+    }
 #ifdef DEBUG_POLAR_ENCODER
     printf("Bit %d Selecting row %d of G : ", i, i);
 
@@ -519,17 +519,13 @@ void polar_encoder_fast(uint64_t *A,
   //int bitlen0=bitlen;
 
 #ifdef POLAR_CODING_DEBUG
-  int A_array = (bitlen + 63) >> 6;
   printf("\nTX\n");
   printf("a: ");
-  for (int n = 0; n < bitlen; n++) {
-    if (n % 4 == 0) {
-      printf(" ");
-    }
-    int n1 = n >> 6;
-    int n2 = n - (n1 << 6);
-    int alen = n1 == 0 ? bitlen - (A_array << 6) : 64;
-    printf("%lu", (A[A_array - 1 - n1] >> (alen - 1 - n2)) & 1);
+  for (int n = (bitlen + 63)/64 ; n >=0; n--) {
+    if (n % 4 == 0) 
+      printf(" "); 
+    if (n < bitlen) 
+      printf("%lu", (A[n/64] >> (n%64)) & 1);
   }
   printf("\n");
 #endif
@@ -692,7 +688,7 @@ void polar_encoder_fast(uint64_t *A,
 #endif
 
   uint64_t D[8] = {0};
-  nr_polar_uxG(D, u, (const uint64_t **)polarParams->G_N_tab, polarParams->N);
+  nr_polar_uxG(D, u, polarParams->G_N_tab, polarParams->N);
 
 #ifdef POLAR_CODING_DEBUG
   printf("d: ");
diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_procedures.c b/openair1/PHY/CODING/nrPolar_tools/nr_polar_procedures.c
index 1e065dd3a77061271c023aad7ad8f342f314401e..31eff0318580c134dd9cdb8600ac0b57f327cebf 100644
--- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_procedures.c
+++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_procedures.c
@@ -119,22 +119,19 @@ void nr_polar_info_extraction_from_u(uint64_t *Cprime,
   }
 }
 
-void nr_polar_uxG(uint64_t *D, const uint64_t *u, const uint64_t **G_N_tab, uint16_t N)
+void nr_polar_uxG(uint64_t *D, const uint64_t *u, const fourDimArray_t *G_N_tab, uint16_t N)
 {
-  int N_array = N >> 6;
-
+  const int N64 = N / 64;
+  cast2Darray(g_n, uint64_t, G_N_tab);
   for (int n = 0; n < N; n++) {
-    const uint64_t *Gn = G_N_tab[N - 1 - n];
+    const uint64_t *Gn = g_n[N - 1 - n];
 
     int n_ones = 0;
-    for (int a = 0; a < N_array; a++) {
-      uint64_t uxG = u[a] & Gn[a];
-      if (uxG != 0)
-        n_ones += count_bits_set(uxG);
-    }
+    for (int a = 0; a < N64; a++)
+      n_ones += count_bits_set(u[a] & Gn[a]);
 
-    int n1 = n >> 6;
-    int n2 = n - (n1 << 6);
+    int n1 = n / 64;
+    int n2 = n - (n1 * 64);
     D[n1] |= ((uint64_t)n_ones & 1) << n2;
   }
 }
@@ -147,8 +144,7 @@ void nr_polar_bit_insertion(uint8_t *input,
 			    int16_t *Q_PC_N,
 			    uint8_t n_PC)
 {
-  uint16_t k=0;
-  uint8_t flag;
+  int k = 0;
 
   if (n_PC>0) {
     /*
@@ -156,22 +152,16 @@ void nr_polar_bit_insertion(uint8_t *input,
      */
   } else {
     for (int n=0; n<=N-1; n++) {
-      flag=0;
+      output[n] = 0;
       for (int m=0; m<=(K+n_PC)-1; m++) {
 	if ( n == Q_I_N[m]) {
-	  flag=1;
-	  break;
-	}
-      }
-      if (flag) { // n ϵ Q_I_N
-	output[n]=input[k];
-	k++;
-      } else {
-	output[n] = 0;
+          output[n] = input[k];
+          k++;
+          break;
+  }
       }
     }
   }
-
 }
 
 
@@ -179,7 +169,7 @@ uint32_t nr_polar_output_length(uint16_t K,
 				uint16_t E,
 				uint8_t n_max)
 {
-  uint8_t n_1, n_2, n_min=5, n;
+  int n_1, n_2, n_min = 5;
   double R_min=1.0/8;
   
   if ( (E <= (9.0/8)*pow(2,ceil(log2(E))-1)) && (K/E < 9.0/16) ) {
@@ -189,8 +179,8 @@ uint32_t nr_polar_output_length(uint16_t K,
   }
   
   n_2 = ceil(log2(K/R_min));
-  
-  n=n_max;
+
+  int n = n_max;
   if (n>n_1) n=n_1;
   if (n>n_2) n=n_2;
   if (n<n_min) n=n_min;
@@ -201,19 +191,14 @@ uint32_t nr_polar_output_length(uint16_t K,
   return ((uint32_t) pow(2.0,n)); //=polar_code_output_length
 }
 
-
-void nr_polar_channel_interleaver_pattern(uint16_t *cip,
-					  uint8_t I_BIL,
-					  uint16_t E)
+void nr_polar_channel_interleaver_pattern(uint16_t *cip, const uint8_t I_BIL, const uint16_t E)
 {
   if (I_BIL == 1) {
-    uint16_t T=0, k;
+    int T = E;
     while( ((T/2)*(T+1)) < E ) T++;
-    
-    int16_t **v = malloc(T * sizeof(*v));
-    for (int i = 0; i <= T-1; i++) v[i] = malloc((T-i) * sizeof(*(v[i])));
-    
-    k=0;
+
+    int16_t v[T][T];
+    int k = 0;
     for (int i = 0; i <= T-1; i++) {
       for (int j = 0; j <= (T-1)-i; j++) {
 	if (k<E) {
@@ -234,16 +219,11 @@ void nr_polar_channel_interleaver_pattern(uint16_t *cip,
 	}
       }
     }
-    
-    for (int i = 0; i <= T-1; i++) free(v[i]);
-    free(v);
-    
   } else {
     for (int i=0; i<=E-1; i++) cip[i]=i;
   }
 }
 
-
 void nr_polar_info_bit_pattern(uint8_t *ibp,
                                uint8_t *pcbp,
                                int16_t *Q_I_N,
@@ -253,47 +233,46 @@ void nr_polar_info_bit_pattern(uint8_t *ibp,
                                const uint16_t *Q_0_Nminus1,
                                uint16_t K,
                                uint16_t N,
-                               uint16_t E,
+                               const uint16_t E,
                                uint8_t n_PC,
                                uint8_t n_pc_wm)
 {
-  int16_t *Q_Ftmp_N = malloc(sizeof(int16_t) * (N + 1)); // Last element shows the final
-  int16_t *Q_Itmp_N = malloc(sizeof(int16_t) * (N + 1)); // array index assigned a value.
+  int Q_Ftmp_N[N + 1]; // Last element shows the final
+  int Q_Itmp_N[N + 1]; // array index assigned a value.
 
   for (int i = 0; i <= N; i++) {
     Q_Ftmp_N[i] = -1; // Empty array.
     Q_Itmp_N[i] = -1;
   }
 
-  uint8_t flag;
-  uint16_t limit, ind;
+  int limit;
 
   if (E < N) {
     if ((K / (double)E) <= (7.0 / 16)) { // puncturing
       for (int n = 0; n <= N - E - 1; n++) {
-        ind = Q_Ftmp_N[N] + 1;
-        Q_Ftmp_N[ind] = J[n];
-        Q_Ftmp_N[N] = Q_Ftmp_N[N] + 1;
+  int ind = Q_Ftmp_N[N] + 1;
+  Q_Ftmp_N[ind] = J[n];
+  Q_Ftmp_N[N] = Q_Ftmp_N[N] + 1;
       }
 
       if ((E / (double)N) >= (3.0 / 4)) {
         limit = ceil((double)(3 * N - 2 * E) / 4);
         for (int n = 0; n <= limit - 1; n++) {
-          ind = Q_Ftmp_N[N] + 1;
-          Q_Ftmp_N[ind] = n;
-          Q_Ftmp_N[N] = Q_Ftmp_N[N] + 1;
+    int ind = Q_Ftmp_N[N] + 1;
+    Q_Ftmp_N[ind] = n;
+    Q_Ftmp_N[N] = Q_Ftmp_N[N] + 1;
         }
       } else {
         limit = ceil((double)(9 * N - 4 * E) / 16);
         for (int n = 0; n <= limit - 1; n++) {
-          ind = Q_Ftmp_N[N] + 1;
-          Q_Ftmp_N[ind] = n;
-          Q_Ftmp_N[N] = Q_Ftmp_N[N] + 1;
+    int ind = Q_Ftmp_N[N] + 1;
+    Q_Ftmp_N[ind] = n;
+    Q_Ftmp_N[N] = Q_Ftmp_N[N] + 1;
         }
       }
     } else { // shortening
       for (int n = E; n <= N - 1; n++) {
-        ind = Q_Ftmp_N[N] + 1;
+        int ind = Q_Ftmp_N[N] + 1;
         Q_Ftmp_N[ind] = J[n];
         Q_Ftmp_N[N] = Q_Ftmp_N[N] + 1;
       }
@@ -302,13 +281,12 @@ void nr_polar_info_bit_pattern(uint8_t *ibp,
 
   // Q_I,tmp_N = Q_0_N-1 \ Q_F,tmp_N
   for (int n = 0; n <= N - 1; n++) {
-    flag = 1;
-    for (int m = 0; m <= Q_Ftmp_N[N]; m++) {
+    bool flag = true;
+    for (int m = 0; m <= Q_Ftmp_N[N]; m++)
       if (Q_0_Nminus1[n] == Q_Ftmp_N[m]) {
-        flag = 0;
+        flag = false;
         break;
       }
-    }
     if (flag) {
       Q_Itmp_N[Q_Itmp_N[N] + 1] = Q_0_Nminus1[n];
       Q_Itmp_N[N]++;
@@ -317,7 +295,7 @@ void nr_polar_info_bit_pattern(uint8_t *ibp,
 
   // Q_I_N comprises (K+n_PC) most reliable bit indices in Q_I,tmp_N
   for (int n = 0; n <= (K + n_PC) - 1; n++) {
-    ind = Q_Itmp_N[N] + n - ((K + n_PC) - 1);
+    int ind = Q_Itmp_N[N] + n - ((K + n_PC) - 1);
     Q_I_N[n] = Q_Itmp_N[ind];
   }
 
@@ -330,13 +308,12 @@ void nr_polar_info_bit_pattern(uint8_t *ibp,
 
   // Q_F_N = Q_0_N-1 \ Q_I_N
   for (int n = 0; n <= N - 1; n++) {
-    flag = 1;
-    for (int m = 0; m <= (K + n_PC) - 1; m++) {
+    bool flag = true;
+    for (int m = 0; m <= (K + n_PC) - 1; m++)
       if (Q_0_Nminus1[n] == Q_I_N[m]) {
-        flag = 0;
+        flag = false;
         break;
       }
-    }
     if (flag) {
       Q_F_N[Q_F_N[N] + 1] = Q_0_Nminus1[n];
       Q_F_N[N]++;
@@ -361,11 +338,7 @@ void nr_polar_info_bit_pattern(uint8_t *ibp,
         break;
       }
     }
-
   }
-
-  free(Q_Ftmp_N);
-  free(Q_Itmp_N);
 }
 
 
@@ -391,22 +364,21 @@ void nr_polar_rate_matching_pattern(uint16_t *rmp,
 				    uint16_t N,
 				    uint16_t E)
 {
-  uint8_t i;
-  uint16_t *d, ind;
-  d = (uint16_t *)malloc(sizeof(uint16_t) * N);
-  uint16_t* y = calloc(N, sizeof(uint16_t));
-
-  for (int m=0; m<=N-1; m++) d[m]=m;
+  uint16_t d[N];
+  for (int m = 0; m < N; m++)
+    d[m] = m;
+  uint16_t y[N];
+  memset(y, 0, sizeof(y));
 
   for (int m=0; m<=N-1; m++){
-    i=floor((32*m)/N);
+    int i = floor((32 * m) / N);
     J[m] = (P_i_[i]*(N/32)) + (m%(N/32));
     y[m] = d[J[m]];
   }
 
   if (E>=N) { //repetition
     for (int k=0; k<=E-1; k++) {
-      ind = (k%N);
+      int ind = (k % N);
       rmp[k]=y[ind];
     }
   } else {
@@ -420,9 +392,6 @@ void nr_polar_rate_matching_pattern(uint16_t *rmp,
       }
     }
   }
-
-  free(d);
-  free(y);
 }
 
 
@@ -459,9 +428,9 @@ void nr_polar_rm_deinterleaving_cb(const int16_t *in, int16_t *out, const uint16
 {
   int T = ceil((sqrt(8 * E + 1) - 1) / 2);
   int v_tab[T][T];
+  memset(v_tab, 0, sizeof(v_tab));
   int k = 0;
   for (int i = 0; i < T; i++) {
-    memset(v_tab[i], 0, T * sizeof(int));
     for (int j = 0; j < T - i; j++) {
       if (k < E) {
         v_tab[i][j] = k + 1;
@@ -484,7 +453,7 @@ void nr_polar_rm_deinterleaving_cb(const int16_t *in, int16_t *out, const uint16
   }
 
   k = 0;
-  memset(out, 0, E * sizeof(int16_t));
+  memset(out, 0, E * sizeof(*out));
   for (int i = 0; i < T; i++) {
     for (int j = 0; j < T - i; j++) {
       if (v[i][j] != INT_MAX) {
@@ -508,12 +477,12 @@ void nr_polar_rate_matching_int16(int16_t *input,
   }
 
   if (E >= N) { // repetition
-    memset((void *)output, 0, N * sizeof(int16_t));
+    memset(output, 0, N * sizeof(*output));
     for (int i = 0; i <= E - 1; i++)
       output[rmp[i]] += input[i];
   } else {
     if ((K / (double)E) <= (7.0 / 16))
-      memset((void *)output, 0, N * sizeof(int16_t)); // puncturing
+      memset(output, 0, N * sizeof(*output)); // puncturing
     else { // shortening
       for (int i = 0; i <= N - 1; i++)
         output[i] = 32767; // instead of INFINITY, to prevent [-Woverflow]
diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_rate_match.c b/openair1/PHY/CODING/nrPolar_tools/nr_polar_rate_match.c
index d23760305936857190d03885ca9efe93b5796aec..013bdc73216bbbcd2008619824ff4128f34cae53 100644
--- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_rate_match.c
+++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_rate_match.c
@@ -23,39 +23,34 @@
 #include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
 
 void nr_polar_rate_matching_pattern(uint16_t *rmp, uint16_t *J, const uint8_t *P_i_, uint16_t K, uint16_t N, uint16_t E){
-	
-	uint8_t i;
-	uint16_t *d, *y, ind;
-	d = (uint16_t *)malloc(sizeof(uint16_t) * N);
-	y = (uint16_t *)malloc(sizeof(uint16_t) * N);
-	
-	for (int m=0; m<=N-1; m++) d[m]=m;
-	
-	for (int m=0; m<=N-1; m++){
-		i=floor((32*m)/N);
-		J[m] = (P_i_[i]*(N/32)) + (m%(N/32));
-		y[m] = d[J[m]];
-	}
-	
-	if (E>=N) { //repetition
-		for (int k=0; k<=E-1; k++) {
-			ind = (k%N);
-			rmp[k]=y[ind];
-		}
-	} else {
-		if ( (K/(double)E) <= (7.0/16) ) { //puncturing
-			for (int k=0; k<=E-1; k++) {
-				rmp[k]=y[k+N-E];
-			}
-		} else { //shortening
-			for (int k=0; k<=E-1; k++) {
-				rmp[k]=y[k];
-			}
-		}	
-	}	
-	
-	free(d);
-	free(y);
+  int d[N];
+  int y[N];
+
+  for (int m = 0; m <= N - 1; m++)
+    d[m] = m;
+
+  for (int m = 0; m <= N - 1; m++) {
+    i = floor((32 * m) / N);
+    J[m] = (P_i_[i] * (N / 32)) + (m % (N / 32));
+    y[m] = d[J[m]];
+  }
+
+  if (E >= N) { // repetition
+    for (int k = 0; k <= E - 1; k++) {
+      ind = (k % N);
+      rmp[k] = y[ind];
+    }
+  } else {
+    if ((K / (double)E) <= (7.0 / 16)) { // puncturing
+      for (int k = 0; k <= E - 1; k++) {
+        rmp[k] = y[k + N - E];
+      }
+    } else { // shortening
+      for (int k = 0; k <= E - 1; k++) {
+        rmp[k] = y[k];
+      }
+    }
+  }
 }
 
 
diff --git a/openair1/PHY/CODING/nr_polar_init.c b/openair1/PHY/CODING/nr_polar_init.c
index 23830cc010111faa9369eb768762215be796364f..3d6d7848da3548ae5752a55465f85cd5a587de21 100644
--- a/openair1/PHY/CODING/nr_polar_init.c
+++ b/openair1/PHY/CODING/nr_polar_init.c
@@ -48,10 +48,7 @@ static void nr_polar_delete_list(t_nrPolar_params * polarParams) {
     nr_polar_delete_list(polarParams->nextPtr);
   
   delete_decoder_tree(polarParams);
-  //From build_polar_tables()
-  for (int n=0; n < polarParams->N; n++)
-    if (polarParams->G_N_tab[n])
-      free(polarParams->G_N_tab[n]);
+  // From build_polar_tables()
   free(polarParams->G_N_tab);
   free(polarParams->rm_tab);
   if (polarParams->crc_generator_matrix)
diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c
index 2b617fc5a0cb2dd0607eb17eb9679ae71ff2ab39..3d338fb114150f509c1993fee81d51777f1a209e 100644
--- a/openair1/PHY/MODULATION/nr_modulation.c
+++ b/openair1/PHY/MODULATION/nr_modulation.c
@@ -241,71 +241,74 @@ void nr_modulation(uint32_t *in,
   AssertFatal(false,"Invalid or unsupported modulation order %d\n",mod_order);
 }
 
-void nr_layer_mapping(int16_t **mod_symbs,
+void nr_layer_mapping(int nbCodes,
+                      int encoded_len,
+                      c16_t mod_symbs[nbCodes][encoded_len],
                       uint8_t n_layers,
+                      int layerSz,
                       uint32_t n_symbs,
-                      int16_t **tx_layers)
+                      c16_t tx_layers[n_layers][layerSz])
 {
   LOG_D(PHY,"Doing layer mapping for %d layers, %d symbols\n",n_layers,n_symbs);
 
   switch (n_layers) {
 
     case 1:
-      memcpy((void*)tx_layers[0], (void*)mod_symbs[0], (n_symbs<<1)*sizeof(int16_t));
-      break;
+    memcpy(tx_layers[0], mod_symbs[0], n_symbs * sizeof(**mod_symbs));
+    break;
 
     case 2:
     case 3:
     case 4:
-      for (int i=0; i<n_symbs/n_layers; i++)
-        for (int l=0; l<n_layers; l++) {
-          tx_layers[l][i<<1] = mod_symbs[0][(n_layers*i+l)<<1];
-          tx_layers[l][(i<<1)+1] = mod_symbs[0][((n_layers*i+l)<<1)+1];
-        }
+    for (int i = 0; i < n_symbs / n_layers; i++) {
+      const c16_t *base = mod_symbs[0] + n_layers * i;
+      for (int l = 0; l < n_layers; l++)
+        tx_layers[l][i] = base[l];
+    }
       break;
 
     case 5:
-      for (int i=0; i<n_symbs>>1; i++)
-        for (int l=0; l<2; l++) {
-          tx_layers[l][i<<1] = mod_symbs[0][((i<<1)+l)<<1];
-          tx_layers[l][(i<<1)+1] = mod_symbs[0][(((i<<1)+l)<<1)+1];
-        }
-      for (int i=0; i<n_symbs/3; i++)
-        for (int l=2; l<5; l++) {
-          tx_layers[l][i<<1] = mod_symbs[1][(3*i+l)<<1];
-          tx_layers[l][(i<<1)+1] = mod_symbs[1][((3*i+l)<<1)+1];
-        }
+      for (int i = 0; i < n_symbs; i += 2) {
+      const int txIdx = i / 2;
+      for (int l = 0; l < 2; l++)
+        tx_layers[l][txIdx] = mod_symbs[0][i + l];
+      }
+      for (int i = 0; i < n_symbs; i += 3) {
+      const int txIdx = i / 3;
+      for (int l = 2; l < 5; l++)
+        tx_layers[l][txIdx] = mod_symbs[1][i + l];
+      }
       break;
 
     case 6:
       for (int q=0; q<2; q++)
-        for (int i=0; i<n_symbs/3; i++)
-          for (int l=0; l<3; l++) {
-            tx_layers[l][i<<1] = mod_symbs[q][(3*i+l)<<1];
-            tx_layers[l][(i<<1)+1] = mod_symbs[q][((3*i+l)<<1)+1];
-          }
+      for (int i = 0; i < n_symbs; i += 3) {
+        const int txIdx = i / 3;
+        for (int l = 0; l < 3; l++)
+          tx_layers[l][txIdx] = mod_symbs[q][i + l];
+      }
       break;
 
     case 7:
-      for (int i=0; i<n_symbs/3; i++)
-        for (int l=0; l<3; l++) {
-          tx_layers[l][i<<1] = mod_symbs[1][(3*i+l)<<1];
-          tx_layers[l][(i<<1)+1] = mod_symbs[1][((3*i+l)<<1)+1];
-        }
-      for (int i=0; i<n_symbs/4; i++)
-        for (int l=3; l<7; l++) {
-          tx_layers[l][i<<1] = mod_symbs[0][((i<<2)+l)<<1];
-          tx_layers[l][(i<<1)+1] = mod_symbs[0][(((i<<2)+l)<<1)+1];
-        }
+      for (int i = 0; i < n_symbs; i += 3) {
+      const int txIdx = i / 3;
+      for (int l = 0; l < 3; l++)
+        tx_layers[l][txIdx] = mod_symbs[1][i + l];
+      }
+      for (int i = 0; i < n_symbs; i += 4) {
+      const int txIdx = i / 4;
+      for (int l = 3; l < 7; l++)
+        tx_layers[l][txIdx] = mod_symbs[0][i + l];
+      }
       break;
 
     case 8:
       for (int q=0; q<2; q++)
-        for (int i=0; i<n_symbs>>2; i++)
-          for (int l=0; l<3; l++) {
-            tx_layers[l][i<<1] = mod_symbs[q][((i<<2)+l)<<1];
-            tx_layers[l][(i<<1)+1] = mod_symbs[q][(((i<<2)+l)<<1)+1];
-          }
+      for (int i = 0; i < n_symbs; i += 4) {
+        const int txIdx = i / 4;
+        for (int l = 0; l < 3; l++)
+          tx_layers[l][txIdx] = mod_symbs[q][i + l];
+      }
       break;
 
     default:
@@ -694,17 +697,17 @@ int nr_layer_precoder(int16_t **datatx_F_precoding, const char *prec_matrix, uin
       ((int16_t *)precodatatx_F)[1] = (int16_t)((((int16_t *)precodatatx_F)[1]*ONE_OVER_SQRT2_Q15)>>15);*/
 }
 
-int nr_layer_precoder_cm(int16_t **datatx_F_precoding, int *prec_matrix, uint8_t n_layers, int32_t re_offset)
+c16_t nr_layer_precoder_cm(int n_layers,
+                           int n_symbols,
+                           int symSz,
+                           c16_t datatx_F_precoding[n_layers][n_symbols][symSz],
+                           c16_t *prec_matrix,
+                           int symbol,
+                           int offset)
 {
-  int32_t precodatatx_F = 0;
-  for (int al = 0; al<n_layers; al++) {
-    int16_t antenna_re = datatx_F_precoding[al][re_offset<<1];
-    int16_t antenna_im = datatx_F_precoding[al][(re_offset<<1) +1];
-    //printf("antenna precoding: %d %d\n",((int16_t *)&prec_matrix[al])[0],((int16_t *)&prec_matrix[al])[1]);
-    ((int16_t *) &precodatatx_F)[0] += (int16_t)(((int32_t)(antenna_re*(((int16_t *)&prec_matrix[al])[0])) - (int32_t)(antenna_im* (((int16_t *)&prec_matrix[al])[1])))>>15);
-    ((int16_t *) &precodatatx_F)[1] += (int16_t)(((int32_t)(antenna_re*(((int16_t *)&prec_matrix[al])[1])) + (int32_t)(antenna_im* (((int16_t *)&prec_matrix[al])[0])))>>15);
-  }
-
+  c16_t precodatatx_F = {0};
+  for (int al = 0; al < n_layers; al++)
+    precodatatx_F = c16maddShift(datatx_F_precoding[al][symbol][offset], prec_matrix[al], precodatatx_F, 15);
   return precodatatx_F;
 }
 
diff --git a/openair1/PHY/MODULATION/nr_modulation.h b/openair1/PHY/MODULATION/nr_modulation.h
index be3cc33afc2f3aa04a56a60544246874b366da95..45cd4858e8eb44da7487a84229f71b409dd00a47 100644
--- a/openair1/PHY/MODULATION/nr_modulation.h
+++ b/openair1/PHY/MODULATION/nr_modulation.h
@@ -54,10 +54,13 @@ void nr_modulation(uint32_t *in,
   @param[out] tx_layers, modulated symbols for each layer
 */
 
-void nr_layer_mapping(int16_t **mod_symbs,
-                         uint8_t n_layers,
-                         uint32_t n_symbs,
-                         int16_t **tx_layers);
+void nr_layer_mapping(int nbCodes,
+                      int encoded_len,
+                      c16_t mod_symbs[nbCodes][encoded_len],
+                      uint8_t n_layers,
+                      int layerSz,
+                      uint32_t n_symbs,
+                      c16_t tx_layers[n_layers][layerSz]);
 
 /*! \brief Perform NR layer mapping. TS 38.211 V15.4.0 subclause 7.3.1.3
   @param[in] ulsch_ue, double Pointer to NR_UE_ULSCH_t struct
@@ -135,9 +138,11 @@ void apply_nr_rotation_RX(NR_DL_FRAME_PARMS *frame_parms,
   @param[in] n_layers, number of DLSCH layers
 */
 int nr_layer_precoder(int16_t **datatx_F_precoding, const char *prec_matrix, uint8_t n_layers, int32_t re_offset);
-
-int nr_layer_precoder_cm(int16_t **datatx_F_precoding,
-                int *prec_matrix,
-                uint8_t n_layers,
-                int32_t re_offset);
+c16_t nr_layer_precoder_cm(int n_layers,
+                           int n_symbols,
+                           int symSz,
+                           c16_t datatx_F_precoding[n_layers][n_symbols][symSz],
+                           c16_t *prec_matrix,
+                           int symbol,
+                           int offset);
 #endif
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c
index 8d81b42fdf425ec9486351b64792efb7ebbbe4fc..b1f9f1a1aa764e8915abf1156753f1683f907c34 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c
@@ -53,15 +53,10 @@ void nr_pdsch_codeword_scrambling(uint8_t *in,
   nr_codeword_scrambling(in, size, q, Nid, n_RNTI, out);
 }
 
-void nr_generate_pdsch(processingData_L1tx_t *msgTx,
-                       int frame,
-                       int slot) {
-
+void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
+{
   PHY_VARS_gNB *gNB = msgTx->gNB;
-  NR_gNB_DLSCH_t *dlsch;
-  c16_t** txdataF = gNB->common_vars.txdataF;
-  int16_t amp = gNB->TX_AMP;
-  int xOverhead = 0;
+  const int16_t amp = gNB->TX_AMP;
   NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
   time_stats_t *dlsch_encoding_stats=&gNB->dlsch_encoding_stats;
   time_stats_t *dlsch_scrambling_stats=&gNB->dlsch_scrambling_stats;
@@ -75,25 +70,17 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
   time_stats_t *dlsch_segmentation_stats=&gNB->dlsch_segmentation_stats;
 
   for (int dlsch_id=0; dlsch_id<msgTx->num_pdsch_slot; dlsch_id++) {
-    dlsch = &msgTx->dlsch[dlsch_id][0];
+    NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id];
 
     NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process;
     nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
-    int16_t **mod_symbs = (int16_t**)dlsch->mod_symbs;
-    int16_t **tx_layers = (int16_t**)dlsch->txdataF;
-    int8_t Wf[2], Wt[2], l0, l_prime, l_overline, delta;
-    uint8_t dmrs_Type = rel15->dmrsConfigType;
-    int nb_re_dmrs;
-    uint16_t n_dmrs;
+    const int layerSz = frame_parms->N_RB_DL * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8;
+    c16_t tx_layers[rel15->nrOfLayers][layerSz] __attribute__((aligned(64)));
+    const int dmrs_Type = rel15->dmrsConfigType;
+    const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4);
     LOG_D(PHY,"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n",
           rel15->BWPStart,rel15->BWPSize,rel15->rbStart,rel15->rbSize);
-    if (rel15->dmrsConfigType==NFAPI_NR_DMRS_TYPE1) {
-      nb_re_dmrs = 6*rel15->numDmrsCdmGrpsNoData;
-    }
-    else {
-      nb_re_dmrs = 4*rel15->numDmrsCdmGrpsNoData;
-    }
-    n_dmrs = (rel15->BWPStart+rel15->rbStart+rel15->rbSize)*nb_re_dmrs;
+    const int n_dmrs = (rel15->BWPStart + rel15->rbStart + rel15->rbSize) * nb_re_dmrs;
 
     if(rel15->dlDmrsScramblingId != gNB->pdsch_gold_init[rel15->SCID])  {
       gNB->pdsch_gold_init[rel15->SCID] = rel15->dlDmrsScramblingId;
@@ -101,16 +88,16 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
     }
 
     uint32_t ***pdsch_dmrs = gNB->nr_gold_pdsch_dmrs[slot];
-    uint16_t dmrs_symbol_map = rel15->dlDmrsSymbPos;//single DMRS: 010000100 Double DMRS 110001100
-    uint8_t dmrs_len = get_num_dmrs(rel15->dlDmrsSymbPos);
-    uint32_t nb_re = ((12*rel15->NrOfSymbols)-nb_re_dmrs*dmrs_len-xOverhead)*rel15->rbSize*rel15->nrOfLayers;
-    uint8_t Qm = rel15->qamModOrder[0];
-    uint32_t encoded_length = nb_re*Qm;
-    int16_t mod_dmrs[n_dmrs<<1] __attribute__ ((aligned(16)));
+    const int dmrs_symbol_map = rel15->dlDmrsSymbPos; // single DMRS: 010000100 Double DMRS 110001100
+    const int xOverhead = 0;
+    const int nb_re =
+        (12 * rel15->NrOfSymbols - nb_re_dmrs * get_num_dmrs(rel15->dlDmrsSymbPos) - xOverhead) * rel15->rbSize * rel15->nrOfLayers;
+    const int Qm = rel15->qamModOrder[0];
+    const int encoded_length = nb_re * Qm;
 
     /* PTRS */
     uint16_t dlPtrsSymPos = 0;
-    uint16_t n_ptrs = 0;
+    int n_ptrs = 0;
     uint32_t ptrsSymbPerSlot = 0;
     if(rel15->pduBitmap & 0x1) {
       set_ptrs_symb_idx(&dlPtrsSymPos,
@@ -125,7 +112,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
 
     /// CRC, coding, interleaving and rate matching
     AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n");
-    unsigned char output[rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers] __attribute__((aligned(32)));
+    unsigned char output[rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers] __attribute__((aligned(64)));
     bzero(output,rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers);
     start_meas(dlsch_encoding_stats);
 
@@ -163,18 +150,14 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
     if (IS_SOFTMODEM_DLSIM)
       memcpy(harq->f, output, encoded_length);
 
-    for (int q=0; q<rel15->NrOfCodewords; q++) {
+    c16_t mod_symbs[rel15->NrOfCodewords][encoded_length];
+    for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) {
       /// scrambling
       start_meas(dlsch_scrambling_stats);
       uint32_t scrambled_output[(encoded_length>>5)+4]; // modulator acces by 4 bytes in some cases
       memset(scrambled_output, 0, sizeof(scrambled_output));
       if ( encoded_length > rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers) abort();
-      nr_pdsch_codeword_scrambling(output,
-                                   encoded_length,
-                                   q,
-                                   rel15->dataScramblingId,
-                                   rel15->rnti,
-                                   scrambled_output);
+      nr_pdsch_codeword_scrambling(output, encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output);
 
 #ifdef DEBUG_DLSCH
       printf("PDSCH scrambling:\n");
@@ -188,36 +171,30 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
       stop_meas(dlsch_scrambling_stats);
       /// Modulation
       start_meas(dlsch_modulation_stats);
-      nr_modulation(scrambled_output,
-                    encoded_length,
-                    Qm,
-                    mod_symbs[q]);
+      nr_modulation(scrambled_output, encoded_length, Qm, (int16_t *)mod_symbs[codeWord]);
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 0);
       stop_meas(dlsch_modulation_stats);
 #ifdef DEBUG_DLSCH
       printf("PDSCH Modulation: Qm %d(%u)\n", Qm, nb_re);
-      for (int i=0; i<nb_re>>3; i++) {
+      for (int i = 0; i < nb_re; i += 8) {
         for (int j=0; j<8; j++) {
-          printf("%d %d\t", mod_symbs[0][((i<<3)+j)<<1], mod_symbs[0][(((i<<3)+j)<<1)+1]);
+          printf("%d %d\t", mod_symbs[codeWord][i + j].r, mod_symbs[codeWord][i + j].i);
         }
         printf("\n");
       }
 #endif
     }
-    
+
     start_meas(&gNB->dlsch_layer_mapping_stats); 
     /// Layer mapping
-    nr_layer_mapping(mod_symbs,
-                     rel15->nrOfLayers,
-                     nb_re,
-                     tx_layers);
+    nr_layer_mapping(rel15->NrOfCodewords, encoded_length, mod_symbs, rel15->nrOfLayers, layerSz, nb_re, tx_layers);
 #ifdef DEBUG_DLSCH
     printf("Layer mapping (%d layers):\n", rel15->nrOfLayers);
     for (int l=0; l<rel15->nrOfLayers; l++)
-      for (int i=0; i<(nb_re/rel15->nrOfLayers)>>3; i++) {
-        printf("layer %d, Re %d..%d : ",l,i<<3,(i<<3)+7);
+      for (int i = 0; i < nb_re / rel15->nrOfLayers; i += 8) {
+        printf("layer %d, Re %d..%d : ", l, i, i + 7);
         for (int j=0; j<8; j++) {
-          printf("l%d %d\t", tx_layers[l][((i<<3)+j)<<1], tx_layers[l][(((i<<3)+j)<<1)+1]);
+          printf("l%d %d\t", tx_layers[l][i + j].r, tx_layers[l][i + j].i);
         }
         printf("\n");
       }
@@ -232,10 +209,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
     if (start_sc >= frame_parms->ofdm_symbol_size)
       start_sc -= frame_parms->ofdm_symbol_size;
 
-    int txdataF_offset = slot*frame_parms->samples_per_slot_wCP;
-    int16_t **txdataF_precoding = (int16_t **)malloc16(rel15->nrOfLayers*sizeof(int16_t *));
-    for (int layer = 0; layer<rel15->nrOfLayers; layer++)
-      txdataF_precoding[layer] = (int16_t *)malloc16(2*14*frame_parms->ofdm_symbol_size*sizeof(int16_t));
+    const uint32_t txdataF_offset = slot*frame_parms->samples_per_slot_wCP;
+    c16_t txdataF_precoding[rel15->nrOfLayers][NR_NUMBER_OF_SYMBOLS_PER_SLOT][frame_parms->ofdm_symbol_size] __attribute__((aligned(64)));;
 
 #ifdef DEBUG_DLSCH_MAPPING
     printf("PDSCH resource mapping started (start SC %d\tstart symbol %d\tN_PRB %d\tnb_re %u,nb_layers %d)\n",
@@ -243,63 +218,66 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
 #endif
 
     start_meas(&gNB->dlsch_resource_mapping_stats);
-    for (int nl=0; nl<rel15->nrOfLayers; nl++) {
-
-      int dmrs_port = get_dmrs_port(nl,rel15->dmrsPorts);
+    for (int layer = 0; layer < rel15->nrOfLayers; layer++) {
+      int dmrs_port = get_dmrs_port(layer, rel15->dmrsPorts);
 
       // DMRS params for this dmrs port
+      int Wt[2], Wf[2];
       get_Wt(Wt, dmrs_port, dmrs_Type);
       get_Wf(Wf, dmrs_port, dmrs_Type);
-      delta = get_delta(dmrs_port, dmrs_Type);
-      l_prime = 0; // single symbol nl 0
-      l0 = get_l0(rel15->dlDmrsSymbPos);
-      l_overline = l0;
+      const int8_t delta = get_delta(dmrs_port, dmrs_Type);
+      int8_t l_prime = 0; // single symbol layer 0
+      int8_t l_overline = get_l0(rel15->dlDmrsSymbPos);
 
 #ifdef DEBUG_DLSCH_MAPPING
-      uint8_t dmrs_symbol = l0+l_prime;
-      printf("DMRS Type %d params for nl %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n",
-	     1+dmrs_Type,nl, Wt[0], Wt[1], Wf[0], Wf[1], delta, l_prime, l0, dmrs_symbol);
+      uint8_t dmrs_symbol = l_overline + l_prime;
+      printf("DMRS Type %d params for layer %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n",
+             1 + dmrs_Type,
+             layer,
+             Wt[0],
+             Wt[1],
+             Wf[0],
+             Wf[1],
+             delta,
+             l_prime,
+             l_overline,
+             dmrs_symbol);
 #endif
 
       uint32_t m=0, dmrs_idx=0;
+      AssertFatal(n_dmrs, "n_dmrs can't be 0\n");
+      c16_t mod_dmrs[n_dmrs] __attribute__((aligned(64)));
 
       // Loop Over OFDM symbols:
-      for (int l=rel15->StartSymbolIndex; l<rel15->StartSymbolIndex+rel15->NrOfSymbols; l++) {
+      for (int l_symbol = rel15->StartSymbolIndex; l_symbol < rel15->StartSymbolIndex + rel15->NrOfSymbols; l_symbol++) {
         /// DMRS QPSK modulation
         uint8_t k_prime=0;
         uint16_t n=0;
-
-        if ((dmrs_symbol_map & (1 << l))){ // DMRS time occasion
+        if ((dmrs_symbol_map & (1 << l_symbol))) { // DMRS time occasion
           // The reference point for is subcarrier 0 of the lowest-numbered resource block in CORESET 0 if the corresponding
           // PDCCH is associated with CORESET 0 and Type0-PDCCH common search space and is addressed to SI-RNTI
           // 3GPP TS 38.211 V15.8.0 Section 7.4.1.1.2 Mapping to physical resources
-          if (rel15->rnti==SI_RNTI) {
-            if (dmrs_Type==NFAPI_NR_DMRS_TYPE1) {
-              dmrs_idx = rel15->rbStart*6;
-            } else {
-              dmrs_idx = rel15->rbStart*4;
-            }
-          } else {
-            if (dmrs_Type == NFAPI_NR_DMRS_TYPE1) {
-              dmrs_idx = (rel15->rbStart+rel15->BWPStart)*6;
-            } else {
-              dmrs_idx = (rel15->rbStart+rel15->BWPStart)*4;
-            }
-          }
-          if (l==(l_overline+1)) //take into account the double DMRS symbols
+          dmrs_idx = rel15->rbStart;
+          if (rel15->rnti != SI_RNTI)
+            dmrs_idx += rel15->BWPStart;
+          dmrs_idx *= dmrs_Type == NFAPI_NR_DMRS_TYPE1 ? 6 : 4;
+          if (l_symbol == (l_overline + 1)) // take into account the double DMRS symbols
             l_prime = 1;
-          else if (l>(l_overline+1)) {//new DMRS pair
-            l_overline = l;
+          else if (l_symbol > (l_overline + 1)) { // new DMRS pair
+            l_overline = l_symbol;
             l_prime = 0;
           }
           /// DMRS QPSK modulation
-          nr_modulation(pdsch_dmrs[l][rel15->SCID], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // Qm = 2 as DMRS is QPSK modulated
+          nr_modulation(pdsch_dmrs[l_symbol][rel15->SCID],
+                        n_dmrs * DMRS_MOD_ORDER,
+                        DMRS_MOD_ORDER,
+                        (int16_t *)mod_dmrs); // Qm = 2 as DMRS is QPSK modulated
 
 #ifdef DEBUG_DLSCH
-          printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l, n_dmrs, dmrs_Type);
-          for (int i=0; i<n_dmrs>>4; i++) {
+          printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l_symbol, n_dmrs, dmrs_Type);
+          for (int i = 0; i < n_dmrs / 2; i += 8) {
             for (int j=0; j<8; j++) {
-              printf("%d %d\t", mod_dmrs[((i<<3)+j)<<1], mod_dmrs[(((i<<3)+j)<<1)+1]);
+              printf("%d %d\t", mod_dmrs[i + j].r, mod_dmrs[i + j].i);
             }
             printf("\n");
           }
@@ -307,22 +285,19 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
         }
 
         /* calculate if current symbol is PTRS symbols */
-        uint16_t ptrs_idx = 0;
-        int16_t *mod_ptrs = NULL;
-        uint8_t ptrs_symbol = 0;
+        int ptrs_idx = 0;
+        int ptrs_symbol = 0;
+        c16_t mod_ptrs[max(n_ptrs, 1)] __attribute__((aligned(64))); //max only to please sanitizer, that kills if 0 even if it is not a error
         if(rel15->pduBitmap & 0x1) {
-          ptrs_symbol = is_ptrs_symbol(l, dlPtrsSymPos);
+          ptrs_symbol = is_ptrs_symbol(l_symbol, dlPtrsSymPos);
           if(ptrs_symbol) {
             /* PTRS QPSK Modulation for each OFDM symbol in a slot */
-            LOG_D(PHY,"Doing ptrs modulation for symbol %d, n_ptrs %d\n", l, n_ptrs);
-            int16_t mod_ptrsBuf[n_ptrs<<1] __attribute__ ((aligned(16)));
-            mod_ptrs = mod_ptrsBuf;
-            nr_modulation(pdsch_dmrs[l][rel15->SCID], (n_ptrs << 1), DMRS_MOD_ORDER, mod_ptrs);
+            LOG_D(PHY, "Doing ptrs modulation for symbol %d, n_ptrs %d\n", l_symbol, n_ptrs);
+            nr_modulation(pdsch_dmrs[l_symbol][rel15->SCID], n_ptrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_ptrs);
           }
         }
         uint16_t k = start_sc;
-        if (ptrs_symbol || dmrs_symbol_map & (1 << l)) {
-
+        if (ptrs_symbol || dmrs_symbol_map & (1 << l_symbol)) {
           // Loop Over SCs:
           for (int i=0; i<rel15->rbSize*NR_NB_SC_PER_RB; i++) {
             /* check if cuurent RE is PTRS RE*/
@@ -338,14 +313,18 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
                                               frame_parms->ofdm_symbol_size);
             }
             /* Map DMRS Symbol */
-            if ( (dmrs_symbol_map & (1 << l)) &&
-                 (k == ((start_sc+get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type))%(frame_parms->ofdm_symbol_size)))) {
-              txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1)     ] = (Wt[l_prime]*Wf[k_prime]*amp*mod_dmrs[dmrs_idx<<1]) >> 15;
-              txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 ] = (Wt[l_prime]*Wf[k_prime]*amp*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15;
+            if ((dmrs_symbol_map & (1 << l_symbol))
+                && (k == ((start_sc + get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type)) % (frame_parms->ofdm_symbol_size)))) {
+              txdataF_precoding[layer][l_symbol][k] = c16mulRealShift(mod_dmrs[dmrs_idx], Wt[l_prime] * Wf[k_prime] * amp, 15);
 #ifdef DEBUG_DLSCH_MAPPING
               printf("dmrs_idx %u\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d\n",
-                     dmrs_idx, l, k, k_prime, n, txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1)],
-                     txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1]);
+                     dmrs_idx,
+                     l_symbol,
+                     k,
+                     k_prime,
+                     n,
+                     txdataF_precoding[layer][l_symbol][k].r,
+                     txdataF_precoding[layer][l_symbol][k].i);
 #endif
               dmrs_idx++;
               k_prime++;
@@ -353,38 +332,49 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
               n+=(k_prime)?0:1;
             }
             /* Map PTRS Symbol */
-            else if(is_ptrs_re){
+            else if (is_ptrs_re) {
               uint16_t beta_ptrs = 1;
-              txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1)    ] = (beta_ptrs*amp*mod_ptrs[ptrs_idx<<1]) >> 15;
-              txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = (beta_ptrs*amp*mod_ptrs[(ptrs_idx<<1) + 1])>> 15;
+              txdataF_precoding[layer][l_symbol][k] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * amp, 15);
 #ifdef DEBUG_DLSCH_MAPPING
               printf("ptrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d, mod_ptrs: %d %d\n",
-                     ptrs_idx, l, k, k_prime, n, ((int16_t*)txdataF_precoding[nl])[((l*frame_parms->ofdm_symbol_size + k)<<1)],
-                     ((int16_t*)txdataF_precoding[nl])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1],mod_ptrs[ptrs_idx<<1],mod_ptrs[(ptrs_idx<<1)+1]);
+                     ptrs_idx,
+                     l_symbol,
+                     k,
+                     k_prime,
+                     n,
+                     txdataF_precoding[layer][l_symbol][k].r,
+                     txdataF_precoding[layer][l_symbol][k].i,
+                     mod_ptrs[ptrs_idx].r,
+                     mod_ptrs[ptrs_idx].i);
 #endif
               ptrs_idx++;
             }
-          /* Map DATA Symbol */
-            else if( ptrs_symbol || allowed_xlsch_re_in_dmrs_symbol(k,start_sc,frame_parms->ofdm_symbol_size,rel15->numDmrsCdmGrpsNoData,dmrs_Type)) {
-              txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1)    ] = (amp * tx_layers[nl][m<<1]) >> 15;
-              txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = (amp * tx_layers[nl][(m<<1) + 1]) >> 15;
+            /* Map DATA Symbol */
+            else if (ptrs_symbol
+                     || allowed_xlsch_re_in_dmrs_symbol(k,
+                                                        start_sc,
+                                                        frame_parms->ofdm_symbol_size,
+                                                        rel15->numDmrsCdmGrpsNoData,
+                                                        dmrs_Type)) {
+              txdataF_precoding[layer][l_symbol][k] = c16mulRealShift(tx_layers[layer][m], amp, 15);
 #ifdef DEBUG_DLSCH_MAPPING
               printf("m %u\t l %d \t k %d \t txdataF: %d %d\n",
-                     m, l, k, txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1)],
-                     txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1]);
+                     m,
+                     l_symbol,
+                     k,
+                     txdataF_precoding[layer][l_symbol][k].r,
+                     txdataF_precoding[layer][l_symbol][k].i);
 #endif
               m++;
             }
             /* mute RE */
             else {
-              txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1)    ] = 0;
-              txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = 0;
+              txdataF_precoding[layer][l_symbol][k] = (c16_t){0};
             }
             if (++k >= frame_parms->ofdm_symbol_size)
               k -= frame_parms->ofdm_symbol_size;
           } //RE loop
-        }
-        else { // no PTRS or DMRS in this symbol
+        } else { // no PTRS or DMRS in this symbol
           // Loop Over SCs:
           int upper_limit=rel15->rbSize*NR_NB_SC_PER_RB;
           int remaining_re = 0;
@@ -393,27 +383,28 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
             upper_limit = frame_parms->ofdm_symbol_size - start_sc;
           }
           // fix the alignment issues later, use 64-bit SIMD below instead of 128.
+          // can be made with loadu/storeu
           if (0/*(frame_parms->N_RB_DL&1)==0*/) {
-            simde__m128i *txF=(simde__m128i*)&txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size+start_sc)<<1)];
+            simde__m128i *txF = (simde__m128i *)&txdataF_precoding[layer][l_symbol][start_sc];
 
-            simde__m128i *txl = (simde__m128i*)&tx_layers[nl][m<<1];
+            simde__m128i *txl = (simde__m128i *)&tx_layers[layer][m];
             simde__m128i amp128=simde_mm_set1_epi16(amp);
             for (int i=0; i<(upper_limit>>2); i++) {
               txF[i] = simde_mm_mulhrs_epi16(amp128,txl[i]);
             } //RE loop, first part
             m+=upper_limit;
             if (remaining_re > 0) {
-               txF = (simde__m128i*)&txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size)<<1)];
-               txl = (simde__m128i*)&tx_layers[nl][m<<1];
-               for (int i=0; i<(remaining_re>>2); i++) {
-                 txF[i] = simde_mm_mulhrs_epi16(amp128,txl[i]);
-               }
+              txF = (simde__m128i *)&txdataF_precoding[layer][l_symbol];
+              txl = (simde__m128i *)&tx_layers[layer][m];
+              for (int i = 0; i < (remaining_re >> 2); i++) {
+                txF[i] = simde_mm_mulhrs_epi16(amp128, txl[i]);
+              }
             }
           }
           else {
-            simde__m128i *txF = (simde__m128i *)&txdataF_precoding[nl][((l * frame_parms->ofdm_symbol_size + start_sc) << 1)];
+            simde__m128i *txF = (simde__m128i *)&txdataF_precoding[layer][l_symbol][start_sc];
 
-            simde__m128i *txl = (simde__m128i *)&tx_layers[nl][m << 1];
+            simde__m128i *txl = (simde__m128i *)&tx_layers[layer][m];
             simde__m128i amp64 = simde_mm_set1_epi16(amp);
             int i;
             for (i = 0; i < (upper_limit >> 2); i++) {
@@ -421,19 +412,22 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
               simde_mm_storeu_si128(txF + i, simde_mm_mulhrs_epi16(amp64, txL));
 #ifdef DEBUG_DLSCH_MAPPING
               if ((i&1) > 0)
-                  printf("m %u\t l %d \t k %d \t txdataF: %d %d\n",
-                         m, l, start_sc+(i>>1), txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + start_sc+(i>>1))<<1)],
-                         txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + start_sc+(i>>1))<<1) + 1]);
+                printf("m %u\t l %d \t k %d \t txdataF: %d %d\n",
+                       m,
+                       l_symbol,
+                       start_sc + (i >> 1),
+                       txdataF_precoding[layer][l_symbol][start_sc].r,
+                       txdataF_precoding[layer][l_symbol][start_sc].i);
 #endif
               /* handle this, mute RE */
               /*else {
-                txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) ] = 0;
-                txdataF_precoding[anl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = 0;
+                txdataF_precoding[layer][((l*frame_parms->ofdm_symbol_size + k)<<1) ] = 0;
+                txdataF_precoding[layer][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = 0;
                 }*/
             }
             if (i * 4 != upper_limit) {
-              c16_t *txFc = (c16_t *)&txdataF_precoding[nl][((l * frame_parms->ofdm_symbol_size + start_sc) << 1)];
-              c16_t *txlc = (c16_t *)&tx_layers[nl][m << 1];
+              c16_t *txFc = &txdataF_precoding[layer][l_symbol][start_sc];
+              c16_t *txlc = &tx_layers[layer][m];
               for (i = (upper_limit >> 2) << 2; i < upper_limit; i++) {
                 txFc[i].r = ((txlc[i].r * amp) >> 14) + 1;
                 txFc[i].i = ((txlc[i].i * amp) >> 14) + 1;
@@ -441,8 +435,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
             }
             m+=upper_limit;
             if (remaining_re > 0) {
-              txF = (simde__m128i *)&txdataF_precoding[nl][((l * frame_parms->ofdm_symbol_size) << 1)];
-              txl = (simde__m128i *)&tx_layers[nl][m << 1];
+              txF = (simde__m128i *)&txdataF_precoding[layer][l_symbol];
+              txl = (simde__m128i *)&tx_layers[layer][m];
               int i;
               for (i = 0; i < (remaining_re >> 2); i++) {
                 const simde__m128i txL = simde_mm_loadu_si128(txl + i);
@@ -451,29 +445,32 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
 #ifdef DEBUG_DLSCH_MAPPING
                  if ((i&1) > 0)
                    printf("m %u\t l %d \t k %d \t txdataF: %d %d\n",
-                          m, l, i>>1, txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + (i>>1))<<1) ],
-                          txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + (i>>1))<<1) + 1]);
+                          m,
+                          l_symbol,
+                          i >> 1,
+                          txdataF_precoding[layer][l_symbol][i >> 1].r,
+                          txdataF_precoding[layer][l_symbol][i >> 1].i);
 #endif
                 /* handle this, mute RE */
-                /*else {
-                  txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1)    ] = 0;
-                  txdataF_precoding[nl][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = 0;
-                  }*/
+                 /*else {
+                   txdataF_precoding[layer][((l*frame_parms->ofdm_symbol_size + k)<<1)    ] = 0;
+                   txdataF_precoding[layer][((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = 0;
+                   }*/
               } // RE loop, second part
               if (i * 4 != remaining_re) {
-                c16_t *txFc = (c16_t *)&txdataF_precoding[nl][((l * frame_parms->ofdm_symbol_size) << 1)];
-                c16_t *txlc = (c16_t *)&tx_layers[nl][m << 1];
+                c16_t *txFc = txdataF_precoding[layer][l_symbol];
+                c16_t *txlc = &tx_layers[layer][m];
                 for (i = (remaining_re >> 2) << 2; i < remaining_re; i++) {
                   txFc[i].r = ((txlc[i].r * amp) >> 14) + 1;
                   txFc[i].i = ((txlc[i].i * amp) >> 14) + 1;
                 }
               }
-            } // 
+            } // remaining_re > 0
             m+=remaining_re;
           } // N_RB_DL even
-        } // no DMRS/PTRS in symbol  
+        } // no DMRS/PTRS in symbol
       } // symbol loop
-    }// layer loop
+    } // layer loop
     stop_meas(&gNB->dlsch_resource_mapping_stats);
 
     ///Layer Precoding and Antenna port mapping
@@ -484,13 +481,15 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
     // The Precoding matrix:
     // The Codebook Type I
     start_meas(&gNB->dlsch_precoding_stats);
+    c16_t **txdataF = gNB->common_vars.txdataF;
 
-    for (int ap=0; ap<frame_parms->nb_antennas_tx; ap++) {
-
-      for (int l=rel15->StartSymbolIndex; l<rel15->StartSymbolIndex+rel15->NrOfSymbols; l++) {
-        uint16_t k = start_sc;
+    for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) {
+      for (int l_symbol = rel15->StartSymbolIndex; l_symbol < rel15->StartSymbolIndex + rel15->NrOfSymbols; l_symbol++) {
+        uint16_t subCarrier = start_sc;
 
         for (int rb=0; rb<rel15->rbSize; rb++) {
+          const size_t txdataF_offset_per_symbol = l_symbol * frame_parms->ofdm_symbol_size + txdataF_offset;
+
           //get pmi info
           uint8_t pmi;
           if (0 /*rel15->precodingAndBeamforming.prg_size > 0*/)
@@ -499,76 +498,79 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
             pmi = 0;//no precoding
 
           if (pmi == 0) {//unitary Precoding
-            if (k + NR_NB_SC_PER_RB <= frame_parms->ofdm_symbol_size) { // RB does not cross DC
-              if(ap<rel15->nrOfLayers)
-                memcpy((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + txdataF_offset + k],
-                       (void*)&txdataF_precoding[ap][2*(l*frame_parms->ofdm_symbol_size + k)],
-                       NR_NB_SC_PER_RB*sizeof(int32_t));
+            if (subCarrier + NR_NB_SC_PER_RB <= frame_parms->ofdm_symbol_size) { // RB does not cross DC
+              if (ant < rel15->nrOfLayers)
+                memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
+                       &txdataF_precoding[ant][l_symbol][subCarrier],
+                       NR_NB_SC_PER_RB * sizeof(**txdataF));
               else
-                memset((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + txdataF_offset + k],
-                       0,
-                       NR_NB_SC_PER_RB*sizeof(int32_t));
+                 memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
+                        0,
+                        NR_NB_SC_PER_RB * sizeof(**txdataF));
             } else { // RB does cross DC
-              int neg_length = frame_parms->ofdm_symbol_size - k;
+              int neg_length = frame_parms->ofdm_symbol_size - subCarrier;
               int pos_length = NR_NB_SC_PER_RB - neg_length;
-              if (ap<rel15->nrOfLayers) {
-                memcpy((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + txdataF_offset + k],
-                       (void*)&txdataF_precoding[ap][2*(l*frame_parms->ofdm_symbol_size + k)],
-                       neg_length*sizeof(int32_t));
-                memcpy((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + txdataF_offset],
-                       (void*)&txdataF_precoding[ap][2*(l*frame_parms->ofdm_symbol_size)],
-                       pos_length*sizeof(int32_t));
+              if (ant < rel15->nrOfLayers) {
+                memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
+                       &txdataF_precoding[ant][l_symbol][subCarrier],
+                       neg_length * sizeof(**txdataF));
+                memcpy(&txdataF[ant][txdataF_offset_per_symbol], &txdataF_precoding[ant][l_symbol], pos_length * sizeof(**txdataF));
               } else {
-                memset((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + txdataF_offset + k],
-                       0,
-                       neg_length*sizeof(int32_t));
-                memset((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + txdataF_offset],
-                       0,
-                       pos_length*sizeof(int32_t));
+                 memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
+                        0,
+                        neg_length * sizeof(**txdataF));
+                 memset(&txdataF[ant][txdataF_offset_per_symbol],
+                        0,
+                        pos_length * sizeof(**txdataF));
               }
             }
-            k += NR_NB_SC_PER_RB;
-            if (k >= frame_parms->ofdm_symbol_size) {
-              k -= frame_parms->ofdm_symbol_size;
+            subCarrier += NR_NB_SC_PER_RB;
+            if (subCarrier >= frame_parms->ofdm_symbol_size) {
+              subCarrier -= frame_parms->ofdm_symbol_size;
             }
           }
           else {
             if(frame_parms->nb_antennas_tx==1){//no precoding matrix defined
-              memcpy((void*)&txdataF[ap][l*frame_parms->ofdm_symbol_size + txdataF_offset + k],
-                     (void*)&txdataF_precoding[ap][2*(l*frame_parms->ofdm_symbol_size + k)],
-                     NR_NB_SC_PER_RB*sizeof(int32_t));
-              k += NR_NB_SC_PER_RB;
-              if (k >= frame_parms->ofdm_symbol_size) {
-                k -= frame_parms->ofdm_symbol_size;
+              memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
+                     &txdataF_precoding[ant][l_symbol][subCarrier],
+                     NR_NB_SC_PER_RB * sizeof(**txdataF));
+              subCarrier += NR_NB_SC_PER_RB;
+              if (subCarrier >= frame_parms->ofdm_symbol_size) {
+                 subCarrier -= frame_parms->ofdm_symbol_size;
               }
             }
             else {
               //get the precoding matrix weights:
-              int32_t **mat = gNB->nr_mimo_precoding_matrix[rel15->nrOfLayers-1];
+              c16_t **mat = (c16_t**)gNB->nr_mimo_precoding_matrix[rel15->nrOfLayers - 1];
               //i_row =0,...,dl_antenna_port
               //j_col =0,...,nrOfLayers
               //mat[pmi][i_rows*2+j_col]
-              int *W_prec;
-              W_prec = (int32_t *)&mat[pmi][ap*rel15->nrOfLayers];
+              c16_t *W_prec = &mat[pmi][ant * rel15->nrOfLayers];
               for (int i=0; i<NR_NB_SC_PER_RB; i++) {
-                int32_t re_offset = l*frame_parms->ofdm_symbol_size + k;
-                int32_t precodatatx_F = nr_layer_precoder_cm(txdataF_precoding, W_prec, rel15->nrOfLayers, re_offset);
-                ((int16_t*)txdataF[ap])[(re_offset<<1) + (2*txdataF_offset)] = ((int16_t *) &precodatatx_F)[0];
-                ((int16_t*)txdataF[ap])[(re_offset<<1) + 1 + (2*txdataF_offset)] = ((int16_t *) &precodatatx_F)[1];
-  #ifdef DEBUG_DLSCH_MAPPING
-                printf("antenna %d\t l %d \t k %d \t txdataF: %d %d\n",
-                       ap, l, k, ((int16_t*)txdataF[ap])[(re_offset<<1) + (2*txdataF_offset)],
-                       ((int16_t*)txdataF[ap])[(re_offset<<1) + 1 + (2*txdataF_offset)]);
-  #endif
-                if (++k >= frame_parms->ofdm_symbol_size) {
-                  k -= frame_parms->ofdm_symbol_size;
+                txdataF[ant][txdataF_offset_per_symbol + subCarrier] = nr_layer_precoder_cm(rel15->nrOfLayers,
+                                                                                            NR_SYMBOLS_PER_SLOT,
+                                                                                            frame_parms->ofdm_symbol_size,
+                                                                                            txdataF_precoding,
+                                                                                            W_prec,
+                                                                                            l_symbol,
+                                                                                            subCarrier);
+#ifdef DEBUG_DLSCH_MAPPING
+                printf("antenna %d\t l %d \t subCarrier %d \t txdataF: %d %d\n",
+                       ant,
+                       l_symbol,
+                       subCarrier,
+                       txdataF[ant][l_symbol * frame_parms->ofdm_symbol_size + subCarrier + txdataF_offset].r,
+                       txdataF[ant][l_symbol * frame_parms->ofdm_symbol_size + subCarrier + txdataF_offset].i);
+#endif
+                if (++subCarrier >= frame_parms->ofdm_symbol_size) {
+                  subCarrier -= frame_parms->ofdm_symbol_size;
                 }
               }
             }
           }
         } //RB loop
       } // symbol loop
-    }// port loop
+    } // port loop
 
     stop_meas(&gNB->dlsch_precoding_stats);
 
@@ -587,9 +589,6 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx,
     else {
       LOG_D(PHY,"beam index for PDSCH allocation already taken\n");
     }
-    for (int layer = 0; layer<rel15->nrOfLayers; layer++)
-      free16(txdataF_precoding[layer],2*14*frame_parms->ofdm_symbol_size);
-    free16(txdataF_precoding,rel15->nrOfLayers);
   }// dlsch loop
 }
 
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
index 0b240ac488c775642e48ef462b3ff05b2c87025e..04a320be248a42fbd4258d042729188708a75e0c 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
@@ -74,18 +74,11 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARM
   free(harq->c);
   free(harq->pdu);
 
-  int nb_codewords = NR_MAX_NB_LAYERS > 4 ? 2 : 1;
-  for (int q=0; q<nb_codewords; q++)
-    free(dlsch->mod_symbs[q]);
-  free(dlsch->mod_symbs);
-
   for (int layer = 0; layer < max_layers; layer++) {
-    free(dlsch->txdataF[layer]);
     for (int aa = 0; aa < 64; aa++)
       free(dlsch->ue_spec_bf_weights[layer][aa]);
     free(dlsch->ue_spec_bf_weights[layer]);
   }
-  free(dlsch->txdataF);
   free(dlsch->ue_spec_bf_weights);
 }
 
@@ -103,10 +96,6 @@ NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB)
   uint32_t dlsch_bytes = a_segments*1056;  // allocated bytes per segment
   NR_gNB_DLSCH_t dlsch;
 
-  int txdataf_size = frame_parms->N_RB_DL*NR_SYMBOLS_PER_SLOT*NR_NB_SC_PER_RB*8; // max pdsch encoded length for each layer
-
-  dlsch.txdataF = (int32_t **)malloc16(max_layers * sizeof(int32_t *));
-
   dlsch.ue_spec_bf_weights = (int32_t ***)malloc16(max_layers * sizeof(int32_t **));
   for (int layer=0; layer<max_layers; layer++) {
     dlsch.ue_spec_bf_weights[layer] = (int32_t **)malloc16(64 * sizeof(int32_t *));
@@ -118,14 +107,8 @@ NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB)
         dlsch.ue_spec_bf_weights[layer][aa][re] = 0x00007fff;
       }
     }
-    dlsch.txdataF[layer] = (int32_t *)malloc16((txdataf_size) * sizeof(int32_t));
   }
 
-  int nb_codewords = NR_MAX_NB_LAYERS > 4 ? 2 : 1;
-  dlsch.mod_symbs = (int32_t **)malloc16(nb_codewords * sizeof(int32_t *));
-  for (int q=0; q<nb_codewords; q++)
-    dlsch.mod_symbs[q] = (int32_t *)malloc16(txdataf_size * max_layers * sizeof(int32_t));
-
   NR_DL_gNB_HARQ_t *harq = &dlsch.harq_process;
   bzero(harq, sizeof(NR_DL_gNB_HARQ_t));
   harq->b = malloc16(dlsch_bytes);
diff --git a/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c b/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c
index 85d3cf3be17ef17bc55cdebd29056a2419acbc64..a88c429d44e7307555f7bc6b5311cc22e1e57fe5 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.c
@@ -65,14 +65,16 @@ void get_antenna_ports(uint8_t *ap, uint8_t n_symbs, uint8_t config) {
       *(ap+i) = i;
 }
 
-void get_Wt(int8_t *Wt, uint8_t ap, uint8_t config) {
+void get_Wt(int *Wt, const int ap, const nfapi_nr_dmrs_type_e config)
+{
   for (int i=0; i<2; i++)
-    *(Wt+i)=(config==NFAPI_NR_DMRS_TYPE1)?(pdsch_dmrs_1[ap][5+i]):(pdsch_dmrs_2[ap][5+i]);
+    Wt[i] = (config == NFAPI_NR_DMRS_TYPE1) ? (pdsch_dmrs_1[ap][5 + i]) : (pdsch_dmrs_2[ap][5 + i]);
 }
 
-void get_Wf(int8_t *Wf, uint8_t ap, uint8_t config) {
+void get_Wf(int *Wf, const int ap, const nfapi_nr_dmrs_type_e config)
+{
   for (int i=0; i<2; i++)
-    *(Wf+i)=(config==NFAPI_NR_DMRS_TYPE1)?(pdsch_dmrs_1[ap][3+i]):(pdsch_dmrs_2[ap][3+i]);
+    Wf[i] = (config == NFAPI_NR_DMRS_TYPE1) ? (pdsch_dmrs_1[ap][3 + i]) : (pdsch_dmrs_2[ap][3 + i]);
 }
 
 uint8_t get_delta(uint8_t ap, uint8_t config) {
diff --git a/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.h b/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.h
index 491e24658e46b747edfbeac88a73068a3036c932..0754611eed188b287a1dc518fe6ddc4609463c7f 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_sch_dmrs.h
@@ -39,10 +39,8 @@
 #define NR_PDSCH_DMRS_NB_ANTENNA_PORTS 12
 
 void get_antenna_ports(uint8_t *ap, uint8_t n_symbs, uint8_t config);
-
-void get_Wt(int8_t *Wt, uint8_t ap, uint8_t config);
-
-void get_Wf(int8_t *Wf, uint8_t ap, uint8_t config);
+void get_Wt(int *Wt, const int ap, const nfapi_nr_dmrs_type_e config);
+void get_Wf(int *Wf, const int ap, const nfapi_nr_dmrs_type_e config);
 
 uint8_t get_delta(uint8_t ap, uint8_t config);
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
index e0b0313462e4a5a1e62f2c5e488db64279f266d3..9c59535e16a66e0630f39360154d264abeffa1ba 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
@@ -116,7 +116,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
 {
   LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot);
 
-  int8_t Wf[2], Wt[2];
+  int Wf[2], Wt[2];
   int l_prime[2], delta;
   uint8_t nb_dmrs_re_per_rb;
   int i;
diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h
index 31ce89b5e452512f4b20563be82df04d4d644e27..61497871f8eb04fd028625d96de2b928b79e3159 100644
--- a/openair1/PHY/TOOLS/tools_defs.h
+++ b/openair1/PHY/TOOLS/tools_defs.h
@@ -193,6 +193,10 @@ extern "C" {
     };
   }
 
+  __attribute__((always_inline)) inline c16_t c16mulRealShift(const c16_t a, const int32_t b, const int Shift)
+  {
+    return (c16_t){.r = (int16_t)((a.r * b) >> Shift), .i = (int16_t)((a.i * b) >> Shift)};
+  }
   __attribute__((always_inline)) inline c16_t c16divShift(const c16_t a, const c16_t b, const int Shift) {
     return (c16_t) {
       .r = (int16_t)((a.r * b.r + a.i * b.i) >> Shift),
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index 1e62e51c2a73da383188195c897af81f166ac5dd..20985cb08aa25608fab6b1f373c24069e03e33b7 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -142,10 +142,6 @@ typedef struct {
 typedef struct {
   /// Pointers to variables related to DLSCH harq process
   NR_DL_gNB_HARQ_t harq_process;
-  /// TX buffers for UE-spec transmission (antenna layers 1,...,4 after to precoding)
-  int32_t **txdataF;
-  /// Modulated symbols buffer
-  int32_t **mod_symbs;
   /// beamforming weights for UE-spec transmission (antenna ports 5 or 7..14), for each codeword, maximum 4 layers?
   int32_t ***ue_spec_bf_weights;
   /// Active flag for baseband transmitter processing
diff --git a/openair2/COMMON/as_message.h b/openair2/COMMON/as_message.h
index 0848714c2c99cc6c0ef230f295c7adc4b5320305..c4724b545834eee3d7a9cd2563dfad3467c7f937 100644
--- a/openair2/COMMON/as_message.h
+++ b/openair2/COMMON/as_message.h
@@ -464,6 +464,13 @@ typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t;
  */
 typedef ul_info_transfer_ind_t dl_info_transfer_ind_t;
 
+typedef struct nas_pdu_session_req_s {
+  int pdusession_id;
+  int pdusession_type;
+  int sst;
+  int sd;
+} nas_pdu_session_req_t;
+
 /*
  * --------------------------------------------------------------------------
  *          Radio Access Bearer establishment
diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h
index dba73dd8b98908aafc14697e6a1e5e63ec8435e4..212c4009881d4bc34f0f4e4e8f1bfa173025cbf3 100644
--- a/openair2/COMMON/e1ap_messages_types.h
+++ b/openair2/COMMON/e1ap_messages_types.h
@@ -119,17 +119,39 @@ typedef struct drb_to_setup_s {
   cell_group_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS];
 } drb_to_setup_t;
 
-typedef struct qos_flow_to_setup_s {
-  long id;
-  fiveQI_type_t fiveQI_type;
-  long fiveQI;
-  long qoSPriorityLevel;
-  long packetDelayBudget;
-  long packetError_scalar;
-  long packetError_exponent;
-  long priorityLevel;
-  long pre_emptionCapability;
-  long pre_emptionVulnerability;
+typedef struct qos_characteristics_s {
+  union {
+    struct {
+      long fiveqi;
+      long qos_priority_level;
+    } non_dynamic;
+    struct {
+      long fiveqi; // -1 -> optional
+      long qos_priority_level;
+      long packet_delay_budget;
+      struct {
+        long per_scalar;
+        long per_exponent;
+      } packet_error_rate;
+    } dynamic;
+  };
+  fiveQI_type_t qos_type;
+} qos_characteristics_t;
+
+typedef struct ngran_allocation_retention_priority_s {
+  uint16_t priority_level;
+  long preemption_capability;
+  long preemption_vulnerability;
+} ngran_allocation_retention_priority_t;
+
+typedef struct qos_flow_level_qos_parameters_s {
+  qos_characteristics_t qos_characteristics;
+  ngran_allocation_retention_priority_t alloc_reten_priority; // additional members should be added!!
+} qos_flow_level_qos_parameters_t;
+
+typedef struct qos_flow_setup_e {
+  long qfi; // qos flow identifier
+  qos_flow_level_qos_parameters_t qos_params;
 } qos_flow_to_setup_t;
 
 typedef struct DRB_nGRAN_to_setup_s {
@@ -199,7 +221,7 @@ typedef struct e1ap_bearer_release_cplt_s {
 } e1ap_bearer_release_cplt_t;
 
 typedef struct qos_flow_setup_s {
-  long id;
+  long qfi;
 } qos_flow_setup_t;
 
 typedef struct DRB_nGRAN_setup_s {
diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h
index d7d46f3bef91fa012b48797cf65b1169243968f4..c0d5c1b437c8696fb473f5590c4590188acc9a1c 100644
--- a/openair2/COMMON/f1ap_messages_types.h
+++ b/openair2/COMMON/f1ap_messages_types.h
@@ -284,12 +284,64 @@ typedef struct f1ap_up_tnl_s {
   uint16_t port;
 } f1ap_up_tnl_t;
 
+typedef enum preemption_capability_e {
+  SHALL_NOT_TRIGGER_PREEMPTION,
+  MAY_TRIGGER_PREEMPTION,
+} preemption_capability_t;
+
+typedef enum preemption_vulnerability_e {
+  NOT_PREEMPTABLE,
+  PREEMPTABLE,
+} preemption_vulnerability_t;
+
+typedef struct f1ap_qos_characteristics_s {
+  union {
+    struct {
+      long fiveqi;
+      long qos_priority_level;
+    } non_dynamic;
+    struct {
+      long fiveqi; // -1 -> optional
+      long qos_priority_level;
+      long packet_delay_budget;
+      struct {
+        long per_scalar;
+        long per_exponent;
+      } packet_error_rate;
+    } dynamic;
+  };
+  fiveQI_type_t qos_type;
+} f1ap_qos_characteristics_t;
+
+typedef struct f1ap_ngran_allocation_retention_priority_s {
+  uint16_t priority_level;
+  preemption_capability_t preemption_capability;
+  preemption_vulnerability_t preemption_vulnerability;
+} f1ap_ngran_allocation_retention_priority_t;
+
+typedef struct f1ap_qos_flow_level_qos_parameters_s {
+  f1ap_qos_characteristics_t qos_characteristics;
+  f1ap_ngran_allocation_retention_priority_t alloc_reten_priority;
+} f1ap_qos_flow_level_qos_parameters_t;
+
+typedef struct f1ap_flows_mapped_to_drb_s {
+  long qfi; // qos flow identifier
+  f1ap_qos_flow_level_qos_parameters_t qos_params;
+} f1ap_flows_mapped_to_drb_t;
+
+typedef struct f1ap_drb_information_s {
+  f1ap_qos_flow_level_qos_parameters_t drb_qos;
+  f1ap_flows_mapped_to_drb_t *flows_mapped_to_drb;
+  uint8_t flows_to_be_setup_length;
+} f1ap_drb_information_t;
+
 typedef struct f1ap_drb_to_be_setup_s {
   long           drb_id;
   f1ap_up_tnl_t  up_ul_tnl[2];
   uint8_t        up_ul_tnl_length;
   f1ap_up_tnl_t  up_dl_tnl[2];
   uint8_t        up_dl_tnl_length;
+  f1ap_drb_information_t drb_info;
   rlc_mode_t     rlc_mode;
   nssai_t nssai;
 } f1ap_drb_to_be_setup_t;
diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h
index 25889468f2c4b38ffe18fe7111889bdf2ff24007..66b8719cc86e1b5624052fc441e690cc87c9992b 100644
--- a/openair2/COMMON/ngap_messages_types.h
+++ b/openair2/COMMON/ngap_messages_types.h
@@ -150,14 +150,14 @@ typedef enum ngap_priority_level_s {
 } ngap_priority_level_t;
 
 typedef enum ngap_pre_emp_capability_e {
-  NGAP_PRE_EMPTION_CAPABILITY_ENABLED  = 0,
-  NGAP_PRE_EMPTION_CAPABILITY_DISABLED = 1,
+  NGAP_PRE_EMPTION_CAPABILITY_SHALL_NOT_TRIGGER_PREEMPTION = 0,
+  NGAP_PRE_EMPTION_CAPABILITY_MAY_TRIGGER_PREEMPTION = 1,
   NGAP_PRE_EMPTION_CAPABILITY_MAX,
 } ngap_pre_emp_capability_t;
 
 typedef enum ngap_pre_emp_vulnerability_e {
-  NGAP_PRE_EMPTION_VULNERABILITY_ENABLED  = 0,
-  NGAP_PRE_EMPTION_VULNERABILITY_DISABLED = 1,
+  NGAP_PRE_EMPTION_VULNERABILITY_NOT_PREEMPTABLE = 0,
+  NGAP_PRE_EMPTION_VULNERABILITY_PREEMPTABLE = 1,
   NGAP_PRE_EMPTION_VULNERABILITY_MAX,
 } ngap_pre_emp_vulnerability_t;
 
@@ -202,6 +202,7 @@ typedef struct nssai_s {
 typedef struct pdusession_level_qos_parameter_s {
   uint8_t qfi;
   uint64_t fiveQI;
+  uint64_t qos_priority;
   fiveQI_type_t fiveQI_type;
   ngap_allocation_retention_priority_t allocation_retention_priority;
 } pdusession_level_qos_parameter_t;
diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h
index e4881f8d8a5f385c4c57492294a73b75d902d266..e1e9fce355ee890a61a82d027d4328d8eb177cf6 100644
--- a/openair2/COMMON/rrc_messages_def.h
+++ b/openair2/COMMON/rrc_messages_def.h
@@ -82,3 +82,4 @@ MESSAGE_DEF(NRRRC_FRAME_PROCESS,        MESSAGE_PRIORITY_MED,       NRRrcFramePr
 
 // eNB: RLC -> RRC messages
 MESSAGE_DEF(RLC_SDU_INDICATION,         MESSAGE_PRIORITY_MED,       RlcSduIndication,           rlc_sdu_indication)
+MESSAGE_DEF(NAS_PDU_SESSION_REQ, MESSAGE_PRIORITY_MED, nas_pdu_session_req_t, nas_pdu_session_req)
diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h
index 037dfbe86cd3675a27f909f61ada6bf0b17afb2b..2810dcfdd65fca1c907e94a512ff9aa70f304b46 100644
--- a/openair2/COMMON/rrc_messages_types.h
+++ b/openair2/COMMON/rrc_messages_types.h
@@ -92,6 +92,7 @@
 #define NRDuDlReq(mSGpTR)      (mSGpTR)->ittiMsg.nr_du_dl_req
 
 #define NAS_OAI_TUN_NSA(mSGpTR)         (mSGpTR)->ittiMsg.nas_oai_tun_nsa
+#define NAS_PDU_SESSION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_pdu_session_req
 
 //-------------------------------------------------------------------------------------------//
 typedef struct RrcStateInd_s {
diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c
index 2aeb873c7140e6b86aa4349cbd582a7e59dfa4fb..353b8931e19c4443bdb3c0b4c43f8ef3a7c07f5d 100644
--- a/openair2/E1AP/e1ap.c
+++ b/openair2/E1AP/e1ap.c
@@ -655,24 +655,28 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bear
 
       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->id;
+        ieC6_1_1_1->qoS_Flow_Identifier = k->qfi;
 
-        if (k->fiveQI_type == non_dynamic) { // non Dynamic 5QI
+        qos_characteristics_t *qos_char_in = &k->qos_params.qos_characteristics;
+        if (qos_char_in->qos_type == non_dynamic) { // non Dynamic 5QI
           ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
           asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI);
-          non_Dynamic_5QI->fiveQI = k->fiveQI;
+          non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi;
         } else { // dynamic 5QI
           ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI;
           asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI);
-          dynamic_5QI->qoSPriorityLevel = k->qoSPriorityLevel;
-          dynamic_5QI->packetDelayBudget = k->packetDelayBudget;
-          dynamic_5QI->packetErrorRate.pER_Scalar = k->packetError_scalar;
-          dynamic_5QI->packetErrorRate.pER_Exponent = k->packetError_exponent;
+          dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level;
+          dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget;
+          dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar;
+          dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent;
         }
 
-        ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = k->priorityLevel;
-        ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = k->pre_emptionCapability;
-        ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = k->pre_emptionVulnerability;
+        ngran_allocation_retention_priority_t *rent_priority_in = &k->qos_params.alloc_reten_priority;
+        ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = rent_priority_in->priority_level;
+        ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability =
+            rent_priority_in->preemption_capability;
+        ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability =
+            rent_priority_in->preemption_vulnerability;
       }
     }
   }
@@ -775,7 +779,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *r
 
         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->id;
+          ieC3_1_1_1->qoS_Flow_Identifier = k->qfi;
         }
       }
 
@@ -953,27 +957,32 @@ 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++) {
-              qos_flow_to_setup_t *qos = drb->qosFlows + k;
+              qos_flow_to_setup_t *qos_flow = drb->qosFlows + k;
               E1AP_QoS_Flow_QoS_Parameter_Item_t *qos2Setup = qos2SetupList->list.array[k];
 
-              qos->id = qos2Setup->qoS_Flow_Identifier;
+              qos_flow->qfi = qos2Setup->qoS_Flow_Identifier;
 
+              qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics;
               if (qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.present ==
                   E1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
-                qos->fiveQI_type = non_dynamic;
-                qos->fiveQI = qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI->fiveQI;
+                qos_char->qos_type = non_dynamic;
+                qos_char->non_dynamic.fiveqi =
+                    qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI->fiveQI;
               } else {
                 E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI;
-                qos->fiveQI_type = dynamic;
-                qos->qoSPriorityLevel = dynamic5QI->qoSPriorityLevel;
-                qos->packetDelayBudget = dynamic5QI->packetDelayBudget;
-                qos->packetError_scalar = dynamic5QI->packetErrorRate.pER_Scalar;
-                qos->packetError_exponent = dynamic5QI->packetErrorRate.pER_Exponent;
+                qos_char->qos_type = dynamic;
+                qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel;
+                qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget;
+                qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar;
+                qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent;
               }
 
-              qos->priorityLevel = qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel;
-              qos->pre_emptionCapability = qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability;
-              qos->pre_emptionVulnerability = qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability;
+              ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority;
+              rent_priority->priority_level = qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel;
+              rent_priority->preemption_capability =
+                  qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability;
+              rent_priority->preemption_vulnerability =
+                  qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability;
             }
           }
         }
@@ -1076,6 +1085,14 @@ void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu,
                 AssertFatal(false, "gTPTunnel information in required\n");
               }
             }
+
+            // Qos Flow Information
+            drbSetup->numQosFlowSetup = drb->flow_Setup_List.list.count;
+            for (int q = 0; q < drb->flow_Setup_List.list.count; q++) {
+              qos_flow_setup_t *qosflowSetup = &drbSetup->qosFlows[q];
+              E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q];
+              qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier;
+            }
           }
         }
         break;
diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c
index 6e6cd8558d61b658a8dd3f7c20f1f53036247989..3f4ff32f475d7246eae3c833f7b83b6e335ab089 100644
--- a/openair2/F1AP/f1ap_cu_interface_management.c
+++ b/openair2/F1AP/f1ap_cu_interface_management.c
@@ -152,7 +152,7 @@ int CU_handle_F1_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint3
       }
       FDDs->dl_freqinfo.arfcn = fDD_Info->dL_NRFreqInfo.nRARFCN;
       int dlBands=fDD_Info->dL_NRFreqInfo.freqBandListNr.list.count;
-      AssertFatal(dlBands == 0, "cannot handled more than one frequency band\n");
+      AssertFatal(dlBands == 1, "cannot handled more than one frequency band\n");
       for (int dlB=0; dlB < dlBands; dlB++) {
 	F1AP_FreqBandNrItem_t * FreqItem=fDD_Info->dL_NRFreqInfo.freqBandListNr.list.array[dlB];
         FDDs->dl_freqinfo.band = FreqItem->freqBandIndicatorNr;
diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c
index 94cecd6254e7725896934a1dee2b385d780339d0..08090a13955058435837be85006cf03879099b58 100644
--- a/openair2/F1AP/f1ap_cu_ue_context_management.c
+++ b/openair2/F1AP/f1ap_cu_ue_context_management.c
@@ -41,27 +41,28 @@
 #include <openair3/ocp-gtpu/gtp_itf.h>
 #include "LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
 
-static void setQos(F1AP_NonDynamic5QIDescriptor_t *toFill) {
-  asn1cCalloc(toFill, tmp);
+static void setQos(F1AP_NonDynamic5QIDescriptor_t **toFill)
+{
+  asn1cCalloc(*toFill, tmp);
   /* fiveQI */
   tmp->fiveQI = 1L;
 
   /* OPTIONAL */
   /* qoSPriorityLevel */
   if (0) {
-    asn1cCallocOne(toFill->qoSPriorityLevel, 1L);
+    asn1cCallocOne((*toFill)->qoSPriorityLevel, 1L);
   }
 
   /* OPTIONAL */
   /* averagingWindow */
   if (0) {
-    asn1cCallocOne(toFill->averagingWindow, 1L);
+    asn1cCallocOne((*toFill)->averagingWindow, 1L);
   }
 
   /* OPTIONAL */
   /* maxDataBurstVolume */
   if (0) {
-    asn1cCallocOne(toFill->maxDataBurstVolume, 1L);
+    asn1cCallocOne((*toFill)->maxDataBurstVolume, 1L);
   }
 }
 
@@ -271,8 +272,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
     asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie12);
     ie12->id                             = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List;
     ie12->criticality                    = F1AP_Criticality_reject;
-    ie12->value.present                  = F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List;
-    LOG_I(F1AP, "Length of drbs_to_be_setup: %d \n", f1ap_ue_context_setup_req->drbs_to_be_setup_length);
+    ie12->value.present = F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List;
 
     for (int i = 0; i < f1ap_ue_context_setup_req->drbs_to_be_setup_length; i++) {
       //
@@ -329,7 +329,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
 
             if (some_decide_qoS_characteristics) {
               DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
-              setQos(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI);
+              setQos(&DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI);
             } else {
               DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
               asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp);
@@ -429,7 +429,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
 
               if (some_decide_qoS_characteristics) {
                 QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
-                setQos(QosParams->choice.non_Dynamic_5QI);
+                setQos(&QosParams->choice.non_Dynamic_5QI);
               } else {
                 QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
                 asn1cCalloc(QosParams->choice.dynamic_5QI, tmp);
@@ -1227,6 +1227,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
 
       else{
         /* 12.1.2 DRB_Information */
+        f1ap_drb_information_t *drb_info_in = &f1ap_ue_context_modification_req->drbs_to_be_setup->drb_info;
         drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension;
         F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie));
         ie->id                             = F1AP_ProtocolIE_ID_id_DRB_Information;
@@ -1237,48 +1238,56 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
         /* 12.1.2.1 dRB_QoS */
         {
           /* qoS_Characteristics */
+          f1ap_qos_flow_level_qos_parameters_t *drb_qos_in = &drb_info_in->drb_qos;
           {
-            int some_decide_qoS_characteristics = 0; // BK: Need Check
+            int some_decide_qoS_characteristics = drb_qos_in->qos_characteristics.qos_type;
 
-            if (some_decide_qoS_characteristics) {
+            f1ap_qos_characteristics_t *drb_qos_char_in = &drb_qos_in->qos_characteristics;
+            if (some_decide_qoS_characteristics == non_dynamic) {
               DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
-              setQos(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI);
+              asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI, tmp);
+
+              /* 5QI */
+              tmp->fiveQI = drb_qos_char_in->non_dynamic.fiveqi;
             } else {
-                DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
-                asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp);
-                /* qoSPriorityLevel */
-                tmp->qoSPriorityLevel = 1L;
-                /* packetDelayBudget */
-                tmp->packetDelayBudget = 1L;
-                /* packetErrorRate */
-                tmp->packetErrorRate.pER_Scalar = 1L;
-                tmp->packetErrorRate.pER_Exponent = 6L;
+              DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
+              asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp);
+              /* qoSPriorityLevel */
+              tmp->qoSPriorityLevel = drb_qos_char_in->dynamic.qos_priority_level;
+              /* packetDelayBudget */
+              tmp->packetDelayBudget = drb_qos_char_in->dynamic.packet_delay_budget;
+              /* packetErrorRate */
+              tmp->packetErrorRate.pER_Scalar = drb_qos_char_in->dynamic.packet_error_rate.per_scalar;
+              tmp->packetErrorRate.pER_Exponent = drb_qos_char_in->dynamic.packet_error_rate.per_scalar;
 
-                /* OPTIONAL */
-                /* delayCritical */
-                if (0) {
-                  asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L);
-                }
+              /* OPTIONAL */
+              /* delayCritical */
+              if (0) {
+                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L);
+              }
 
-                /* OPTIONAL */
-                /* averagingWindow */
-                if (0) {
-                  asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L);
-                }
+              /* OPTIONAL */
+              /* averagingWindow */
+              if (0) {
+                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L);
+              }
 
-                /* OPTIONAL */
-                /* maxDataBurstVolume */
-                if (0) {
-                  asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L);
-                }
-              } // if some_decide_qoS_characteristics
+              /* OPTIONAL */
+              /* maxDataBurstVolume */
+              if (0) {
+                asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L);
+              }
+            } // if some_decide_qoS_characteristics
 
             } // qoS_Characteristics
             /* nGRANallocationRetentionPriority */
             {
-              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum
-              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum
-              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum
+              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel =
+                  drb_qos_in->alloc_reten_priority.priority_level;
+              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability =
+                  drb_qos_in->alloc_reten_priority.preemption_capability;
+              DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability =
+                  drb_qos_in->alloc_reten_priority.preemption_vulnerability;
             } // nGRANallocationRetentionPriority
 
           /* OPTIONAL */
@@ -1327,33 +1336,40 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
               F1AP_NotificationControl_active); // enum
         }
 
-        /* 12.1.2.4 flows_Mapped_To_DRB_List */  // BK: need verifiy
-
-        for (int k = 0; k < 1; k ++) {
+        /* 12.1.2.4 flows_Mapped_To_DRB_List */
+        for (int k = 0; k < drb_info_in->flows_to_be_setup_length; k++) {
           asn1cSequenceAdd(DRB_Information->flows_Mapped_To_DRB_List.list,
                          F1AP_Flows_Mapped_To_DRB_Item_t, flows_mapped_to_drb_item);
+
+          f1ap_flows_mapped_to_drb_t *qos_flow_in = drb_info_in->flows_mapped_to_drb + k;
+
           /* qoSFlowIndicator */
-          flows_mapped_to_drb_item->qoSFlowIdentifier = 1L;
+          flows_mapped_to_drb_item->qoSFlowIdentifier = qos_flow_in->qfi;
           /* qoSFlowLevelQoSParameters */
           {
+            f1ap_qos_flow_level_qos_parameters_t *flow_qos_params_in = &qos_flow_in->qos_params;
             /* qoS_Characteristics */
             {
-              int some_decide_qoS_characteristics = 0; // BK: Need Check
-              F1AP_QoS_Characteristics_t *QosParams=&flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics;
+              int some_decide_qoS_characteristics = flow_qos_params_in->qos_characteristics.qos_type;
+              F1AP_QoS_Characteristics_t *QosParams = &flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics;
+              f1ap_qos_characteristics_t *flow_qos_char_in = &flow_qos_params_in->qos_characteristics;
 
-              if (some_decide_qoS_characteristics) {
+              if (some_decide_qoS_characteristics == non_dynamic) {
                 QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
-                setQos(QosParams->choice.non_Dynamic_5QI);
+                asn1cCalloc(QosParams->choice.non_Dynamic_5QI, tmp);
+
+                /* 5QI */
+                tmp->fiveQI = flow_qos_char_in->non_dynamic.fiveqi;
               } else {
                 QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
                 asn1cCalloc(QosParams->choice.dynamic_5QI, tmp);
                 /* qoSPriorityLevel */
-                tmp->qoSPriorityLevel = 1L;
+                tmp->qoSPriorityLevel = flow_qos_char_in->dynamic.qos_priority_level;
                 /* packetDelayBudget */
-                tmp->packetDelayBudget = 1L;
+                tmp->packetDelayBudget = flow_qos_char_in->dynamic.packet_delay_budget;
                 /* packetErrorRate */
-                tmp->packetErrorRate.pER_Scalar = 1L;
-                tmp->packetErrorRate.pER_Exponent = 6L;
+                tmp->packetErrorRate.pER_Scalar = flow_qos_char_in->dynamic.packet_error_rate.per_scalar;
+                tmp->packetErrorRate.pER_Exponent = flow_qos_char_in->dynamic.packet_error_rate.per_exponent;
 
                 /* OPTIONAL */
                 /* delayCritical */
@@ -1380,9 +1396,12 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
             } // qoS_Characteristics
             /* nGRANallocationRetentionPriority */
             {
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum
-              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum
+              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel =
+                  flow_qos_params_in->alloc_reten_priority.priority_level;
+              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability =
+                  flow_qos_params_in->alloc_reten_priority.preemption_capability;
+              flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability =
+                  flow_qos_params_in->alloc_reten_priority.preemption_vulnerability;
             } // nGRANallocationRetentionPriority
 
             /* OPTIONAL */
diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c
index fe7b8c78f5669c368d6f356cb6f8c6e47e16f36e..4eee1ba6b155b3ed64c328f696232121168d2f60 100644
--- a/openair2/F1AP/f1ap_du_ue_context_management.c
+++ b/openair2/F1AP/f1ap_du_ue_context_management.c
@@ -893,11 +893,99 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t
               (F1AP_QoSInformation_ExtIEs_t *)drbs_tobesetupmod_item_p->qoSInformation.choice.choice_extension;
           if (ie->id == F1AP_ProtocolIE_ID_id_DRB_Information && ie->criticality == F1AP_Criticality_reject
               && ie->value.present == F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information) {
-            F1AP_DRB_Information_t *DRB_Information = &ie->value.choice.DRB_Information;
+            F1AP_DRB_Information_t *dRB_Info = &ie->value.choice.DRB_Information;
+            f1ap_drb_information_t *drb_info = &f1ap_ue_context_modification_req->drbs_to_be_setup->drb_info;
+
+            /* 12.1.2.1 dRB_QoS */
+            {
+              /* QoS-Flow-Level-QoS-Parameters */
+              f1ap_qos_flow_level_qos_parameters_t *drb_qos = &drb_info->drb_qos;
+              F1AP_QoSFlowLevelQoSParameters_t *dRB_QoS = &dRB_Info->dRB_QoS;
+              {
+                /* QoS Characteristics*/
+                f1ap_qos_characteristics_t *drb_qos_char = &drb_qos->qos_characteristics;
+                F1AP_QoS_Characteristics_t *dRB_QoS_Char = &dRB_QoS->qoS_Characteristics;
+
+                if (dRB_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
+                  drb_qos_char->qos_type = non_dynamic;
+                  drb_qos_char->non_dynamic.fiveqi = dRB_QoS_Char->choice.non_Dynamic_5QI->fiveQI;
+                  drb_qos_char->non_dynamic.qos_priority_level = (dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL)
+                                                                     ? *dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel
+                                                                     : -1;
+                } else {
+                  drb_qos_char->qos_type = dynamic;
+                  drb_qos_char->dynamic.fiveqi =
+                      (dRB_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *dRB_QoS_Char->choice.dynamic_5QI->fiveQI : -1;
+                  drb_qos_char->dynamic.qos_priority_level = dRB_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel;
+                  drb_qos_char->dynamic.packet_delay_budget = dRB_QoS_Char->choice.dynamic_5QI->packetDelayBudget;
+                  drb_qos_char->dynamic.packet_error_rate.per_scalar = dRB_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Scalar;
+                  drb_qos_char->dynamic.packet_error_rate.per_exponent =
+                      dRB_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Exponent;
+                }
+              }
+
+              /* nGRANallocationRetentionPriority */
+              drb_qos->alloc_reten_priority.priority_level = dRB_QoS->nGRANallocationRetentionPriority.priorityLevel;
+              drb_qos->alloc_reten_priority.preemption_vulnerability =
+                  dRB_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
+              drb_qos->alloc_reten_priority.preemption_capability =
+                  dRB_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
+            } // dRB_QoS
+
+            // 12.1.2.4 flows_Mapped_To_DRB_List
+            drb_info->flows_to_be_setup_length = dRB_Info->flows_Mapped_To_DRB_List.list.count;
+            drb_info->flows_mapped_to_drb = calloc(drb_info->flows_to_be_setup_length, sizeof(f1ap_flows_mapped_to_drb_t));
+            AssertFatal(drb_info->flows_mapped_to_drb, "could not allocate memory for drb_p->drb_info.flows_mapped_to_drb\n");
+
+            for (int k = 0; k < drb_p->drb_info.flows_to_be_setup_length; k++) {
+              f1ap_flows_mapped_to_drb_t *flows_mapped_to_drb = drb_info->flows_mapped_to_drb + k;
+              F1AP_Flows_Mapped_To_DRB_Item_t *flows_Mapped_To_Drb = dRB_Info->flows_Mapped_To_DRB_List.list.array[0] + k;
+
+              flows_mapped_to_drb->qfi = flows_Mapped_To_Drb->qoSFlowIdentifier;
+
+              /* QoS-Flow-Level-QoS-Parameters */
+              {
+                f1ap_qos_flow_level_qos_parameters_t *flow_qos = &flows_mapped_to_drb->qos_params;
+                F1AP_QoSFlowLevelQoSParameters_t *Flow_QoS = &flows_Mapped_To_Drb->qoSFlowLevelQoSParameters;
+
+                /* QoS Characteristics*/
+                {
+                  f1ap_qos_characteristics_t *flow_qos_char = &flow_qos->qos_characteristics;
+                  F1AP_QoS_Characteristics_t *Flow_QoS_Char = &Flow_QoS->qoS_Characteristics;
+
+                  if (Flow_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
+                    flow_qos_char->qos_type = non_dynamic;
+                    flow_qos_char->non_dynamic.fiveqi = Flow_QoS_Char->choice.non_Dynamic_5QI->fiveQI;
+                    flow_qos_char->non_dynamic.qos_priority_level =
+                        (Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL)
+                            ? *Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel
+                            : -1;
+                  } else {
+                    flow_qos_char->qos_type = dynamic;
+                    flow_qos_char->dynamic.fiveqi =
+                        (Flow_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *Flow_QoS_Char->choice.dynamic_5QI->fiveQI : -1;
+                    flow_qos_char->dynamic.qos_priority_level = Flow_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel;
+                    flow_qos_char->dynamic.packet_delay_budget = Flow_QoS_Char->choice.dynamic_5QI->packetDelayBudget;
+                    flow_qos_char->dynamic.packet_error_rate.per_scalar =
+                        Flow_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Scalar;
+                    flow_qos_char->dynamic.packet_error_rate.per_exponent =
+                        Flow_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Exponent;
+                  }
+                }
+
+                /* nGRANallocationRetentionPriority */
+                flow_qos->alloc_reten_priority.priority_level = Flow_QoS->nGRANallocationRetentionPriority.priorityLevel;
+                flow_qos->alloc_reten_priority.preemption_vulnerability =
+                    Flow_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
+                flow_qos->alloc_reten_priority.preemption_capability =
+                    Flow_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability;
+              }
+            }
+
             /* S-NSSAI */
-            OCTET_STRING_TO_INT8(&DRB_Information->sNSSAI.sST, drb_p->nssai.sst);
-            if (DRB_Information->sNSSAI.sD != NULL)
-              memcpy((uint8_t *)&drb_p->nssai.sd, DRB_Information->sNSSAI.sD->buf, 3);
+            OCTET_STRING_TO_INT8(&dRB_Info->sNSSAI.sST, drb_p->nssai.sst);
+            if (dRB_Info->sNSSAI.sD != NULL)
+              memcpy((uint8_t *)&drb_p->nssai.sd, dRB_Info->sNSSAI.sD->buf, 3);
             else
               drb_p->nssai.sd = 0xffffff;
           }
diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c
index 537349ac345e238f6dbf4f96d1e7f9ca159c95a6..9ffd98062783856aa23166eecfc820c5db5b9a80 100644
--- a/openair2/LAYER2/NR_MAC_UE/config_ue.c
+++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c
@@ -942,6 +942,59 @@ void configure_physicalcellgroup(NR_UE_MAC_INST_t *mac,
                                         *p_UE_FR1 : *p_NR_FR1);
 }
 
+void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroupConfig_t *mcg)
+{
+  NR_UE_SCHEDULING_INFO *si = &mac->scheduling_info;
+  if (mcg->drx_Config)
+    LOG_E(NR_MAC, "DRX not implemented! Configuration not handled!\n");
+  if (mcg->schedulingRequestConfig) {
+    const NR_SchedulingRequestConfig_t *src = mcg->schedulingRequestConfig;
+    if (src->schedulingRequestToReleaseList) {
+      for (int i = 0; i < src->schedulingRequestToReleaseList->list.count; i++) {
+        if (*src->schedulingRequestToReleaseList->list.array[i] == si->sr_id) {
+          si->SR_COUNTER = 0;
+          si->sr_ProhibitTimer = 0;
+          si->sr_ProhibitTimer_Running = 0;
+          si->sr_id = -1; // invalid init value
+        }
+        else
+          LOG_E(NR_MAC, "Cannot release SchedulingRequestConfig. Not configured.\n");
+      }
+    }
+    if (src->schedulingRequestToAddModList) {
+      for (int i = 0; i < src->schedulingRequestToAddModList->list.count; i++) {
+        NR_SchedulingRequestToAddMod_t *sr = src->schedulingRequestToAddModList->list.array[i];
+        AssertFatal(si->sr_id == -1 ||
+                    si->sr_id == sr->schedulingRequestId,
+                    "Current implementation cannot handle more than 1 SR configuration\n");
+        si->sr_id = sr->schedulingRequestId;
+        si->sr_TransMax = sr->sr_TransMax;
+        if (sr->sr_ProhibitTimer)
+          LOG_E(NR_MAC, "SR prohibit timer not properly implemented\n");
+      }
+    }
+  }
+  if (mcg->bsr_Config) {
+    si->periodicBSR_Timer = mcg->bsr_Config->periodicBSR_Timer;
+    si->retxBSR_Timer = mcg->bsr_Config->retxBSR_Timer;
+    if (mcg->bsr_Config->logicalChannelSR_DelayTimer)
+      LOG_E(NR_MAC, "Handling of logicalChannelSR_DelayTimer not implemented\n");
+  }
+  if (mcg->tag_Config) {
+    // TODO TAG not handled
+    if(mcg->tag_Config->tag_ToAddModList) {
+      for (int i = 0; i < mcg->tag_Config->tag_ToAddModList->list.count; i++) {
+        if (mcg->tag_Config->tag_ToAddModList->list.array[i]->timeAlignmentTimer !=
+            NR_TimeAlignmentTimer_infinity)
+          LOG_E(NR_MAC, "TimeAlignmentTimer not handled\n");
+      }
+    }
+  }
+  if (mcg->phr_Config) {
+    // TODO configuration when PHR is implemented
+  }
+}
+
 void nr_rrc_mac_config_req_cg(module_id_t module_id,
                               int cc_idP,
                               NR_CellGroupConfig_t *cell_group_config)
@@ -950,9 +1003,8 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
   AssertFatal(cell_group_config, "CellGroupConfig should not be NULL\n");
   NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
 
-  if (cell_group_config->mac_CellGroupConfig) {
-    // TODO handle MAC-CellGroupConfig
-  }
+  if (cell_group_config->mac_CellGroupConfig)
+    configure_maccellgroup(mac, cell_group_config->mac_CellGroupConfig);
 
   if (cell_group_config->physicalCellGroupConfig)
     configure_physicalcellgroup(mac, cell_group_config->physicalCellGroupConfig);
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
index c7bbee07802fbb945f9eb6efdf6c5d8c4a2942e9..0e57098d7b9ec0527b61c1d4dc96e5c6ff258248 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
@@ -196,8 +196,6 @@ typedef struct {
   NR_LC_SCHEDULING_INFO lc_sched_info[NR_MAX_NUM_LCID];
   // lcg scheduling info
   NR_LCG_SCHEDULING_INFO lcg_sched_info[NR_MAX_NUM_LCGID];
-  /// sum of all lcid buffer size
-  uint16_t All_lcid_buffer_size_lastTTI;
   /// SR pending as defined in 38.321
   uint8_t  SR_pending;
   /// SR_COUNTER as defined in 38.321
@@ -214,14 +212,9 @@ typedef struct {
   uint16_t sr_ProhibitTimer;
   /// sr ProhibitTime running
   uint8_t sr_ProhibitTimer_Running;
-  ///  default value to n5
-  uint16_t maxHARQ_Tx;
-  /// default value is false
-  uint16_t ttiBundling;
-  /// default value is release
-  struct DRX_Config *drx_config;
-  /// default value is release
-  struct MAC_MainConfig__phr_Config *phr_config;
+  // Maximum number of SR transmissions
+  uint32_t sr_TransMax;
+  int sr_id;
   ///timer before triggering a periodic PHR
   uint16_t periodicPHR_Timer;
   ///timer before triggering a prohibit PHR
@@ -234,7 +227,6 @@ typedef struct {
   int16_t prohibitPHR_SF;
   ///DL Pathloss Change in db
   uint16_t PathlossChange_db;
-
   /// default value is false
   uint16_t extendedBSR_Sizes_r10;
   /// default value is false
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index 2bb1691eae415ca413c5dd906de61f77439c3a72..310aceaf6f3a7844189f8abab3ff063d1c07efef 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -182,6 +182,7 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac)
   mac->scheduling_info.SR_COUNTER = 0;
   mac->scheduling_info.sr_ProhibitTimer = 0;
   mac->scheduling_info.sr_ProhibitTimer_Running = 0;
+  mac->scheduling_info.sr_id = -1; // invalid init value
 
   // set init value 0xFFFF, make sure periodic timer and retx time counters are NOT active, after bsr transmission set the value
   // configured by the NW.
@@ -2424,32 +2425,34 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *p
   return sr_count > 0 ? true : false;
 }
 
-int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slot){
+int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slot)
+{
   // no UL-SCH resources available for this tti && UE has a valid PUCCH resources for SR configuration for this tti
   DevCheck(module_idP < NB_NR_UE_MAC_INST, module_idP, NB_NR_UE_MAC_INST, 0);
   NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP);
-  DSR_TRANSMAX_t dsr_TransMax = sr_n64; // todo
-  LOG_D(NR_MAC, "[UE %d] Frame %d slot %d send SR indication (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d\n",
+  NR_UE_SCHEDULING_INFO *si = &mac->scheduling_info;
+  int max_sr_transmissions = (1 << (2 + si->sr_TransMax));
+  LOG_D(NR_MAC, "[UE %d] Frame %d slot %d send SR indication (SR_COUNTER/sr_TransMax %d/%d), SR_pending %d\n",
         module_idP, frameP, slot,
-        mac->scheduling_info.SR_COUNTER,
-        (1 << (2 + dsr_TransMax)),
-        mac->scheduling_info.SR_pending); // todo
+        si->SR_COUNTER,
+        max_sr_transmissions,
+        si->SR_pending); // todo
 
-  if ((mac->scheduling_info.SR_pending == 1) &&
-      (mac->scheduling_info.SR_COUNTER < (1 << (2 + dsr_TransMax)))) {
-    LOG_D(NR_MAC, "[UE %d] Frame %d slot %d PHY asks for SR (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d, increment SR_COUNTER\n",
+  if ((si->SR_pending == 1) &&
+      (si->SR_COUNTER < max_sr_transmissions)) {
+    LOG_D(NR_MAC, "[UE %d] Frame %d slot %d PHY asks for SR (SR_COUNTER/sr_TransMax %d/%d), SR_pending %d, increment SR_COUNTER\n",
           module_idP, frameP, slot,
-          mac->scheduling_info.SR_COUNTER,
-          (1 << (2 + dsr_TransMax)),
-          mac->scheduling_info.SR_pending); // todo
-    mac->scheduling_info.SR_COUNTER++;
+          si->SR_COUNTER,
+          max_sr_transmissions,
+          si->SR_pending); // todo
+    si->SR_COUNTER++;
 
     // start the sr-prohibittimer : rel 9 and above
-    if (mac->scheduling_info.sr_ProhibitTimer > 0) { // timer configured
-      mac->scheduling_info.sr_ProhibitTimer--;
-      mac->scheduling_info.sr_ProhibitTimer_Running = 1;
+    if (si->sr_ProhibitTimer > 0) { // timer configured
+      si->sr_ProhibitTimer--;
+      si->sr_ProhibitTimer_Running = 1;
     } else {
-      mac->scheduling_info.sr_ProhibitTimer_Running = 0;
+      si->sr_ProhibitTimer_Running = 0;
     }
     //mac->ul_active =1;
     return (1);   //instruct phy to signal SR
@@ -2457,7 +2460,7 @@ int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slot){
     // notify RRC to relase PUCCH/SRS
     // clear any configured dl/ul
     // initiate RA
-    if (mac->scheduling_info.SR_pending) {
+    if (si->SR_pending) {
       // release all pucch resource
       //mac->physicalConfigDedicated = NULL; // todo
       //mac->ul_active = 0; // todo
@@ -2465,9 +2468,8 @@ int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slot){
         NR_BSR_TRIGGER_NONE;
       LOG_I(NR_MAC, "[UE %d] Release all SRs \n", module_idP);
     }
-
-    mac->scheduling_info.SR_pending = 0;
-    mac->scheduling_info.SR_COUNTER = 0;
+    si->SR_pending = 0;
+    si->SR_COUNTER = 0;
     return (0);
   }
 }
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
index 5157ff453f9d9db301ab48efc8e615fb6c18a2e8..c1313a495e47b272fa0870bd96055b3190827ec6 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
@@ -30,6 +30,11 @@
 #include "uper_decoder.h"
 #include "uper_encoder.h"
 
+// Standarized 5QI values and Default Priority levels as mentioned in 3GPP TS 23.501 Table 5.7.4-1
+const uint64_t qos_fiveqi[26] = {1, 2, 3, 4, 65, 66, 67, 71, 72, 73, 74, 76, 5, 6, 7, 8, 9, 69, 70, 79, 80, 82, 83, 84, 85, 86};
+const uint64_t qos_priority[26] = {20, 40, 30, 50, 7, 20, 15, 56, 56, 56, 56, 56, 10,
+                                   60, 70, 80, 90, 5, 55, 65, 68, 19, 22, 24, 21, 18};
+
 static long get_lcid_from_drbid(int drb_id)
 {
   return drb_id + 3; /* LCID is DRB + 3 */
@@ -243,6 +248,49 @@ static void set_nssaiConfig(const int drb_len, const f1ap_drb_to_be_setup_t *req
   }
 }
 
+static void set_QoSConfig(const f1ap_ue_context_modif_req_t *req, NR_UE_sched_ctrl_t *sched_ctrl)
+{
+  AssertFatal(req != NULL, "f1ap_ue_context_modif_req is NULL\n");
+  uint8_t drb_count = req->drbs_to_be_setup_length;
+  uint8_t srb_count = req->srbs_to_be_setup_length;
+  LOG_I(NR_MAC, "Number of DRBs = %d and SRBs = %d\n", drb_count, srb_count);
+
+  /* DRBs*/
+  for (int i = 0; i < drb_count; i++) {
+    f1ap_drb_to_be_setup_t *drb_p = &req->drbs_to_be_setup[i];
+    uint8_t nb_qos_flows = drb_p->drb_info.flows_to_be_setup_length;
+    long drb_id = drb_p->drb_id;
+    LOG_I(NR_MAC, "In %s: number of QOS flows mapped to DRB_id %d: %ld \n", __func__, drb_count, drb_id);
+
+    for (int q = 0; q < nb_qos_flows; q++) {
+      f1ap_flows_mapped_to_drb_t *qos_flow = &drb_p->drb_info.flows_mapped_to_drb[q];
+
+      f1ap_qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics;
+      uint64_t priority = qos_char->non_dynamic.qos_priority_level;
+      int64_t fiveqi = qos_char->non_dynamic.fiveqi;
+      if (qos_char->qos_type == dynamic) {
+        priority = qos_char->dynamic.qos_priority_level;
+        fiveqi = qos_char->dynamic.fiveqi > 0 ? qos_char->dynamic.fiveqi : 0;
+      }
+      if (qos_char->qos_type == non_dynamic) {
+        LOG_D(NR_MAC, "Qos Priority level is considered from the standarsdized 5QI to QoS mapping table\n");
+        for (int id = 0; id < 26; id++) {
+          if (qos_fiveqi[id] == fiveqi)
+            priority = qos_priority[id];
+        }
+      }
+      sched_ctrl->qos_config[drb_id - 1][q].fiveQI = fiveqi;
+      sched_ctrl->qos_config[drb_id - 1][q].priority = priority;
+      LOG_D(NR_MAC,
+            "In %s: drb_id %ld: 5QI %lu priority %lu\n",
+            __func__,
+            drb_id,
+            sched_ctrl->qos_config[drb_id - 1][q].fiveQI,
+            sched_ctrl->qos_config[drb_id - 1][q].priority);
+    }
+  }
+}
+
 void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
 {
   gNB_MAC_INST *mac = RC.nrmac[0];
@@ -309,6 +357,9 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
   /* TODO: need to apply after UE context reconfiguration confirmed? */
   nr_mac_prepare_cellgroup_update(mac, UE, new_CellGroup);
 
+  /* Fill the QoS config in MAC for each active DRB */
+  set_QoSConfig(req, &UE->UE_sched_ctrl);
+
   /* Set NSSAI config in MAC for each active DRB */
   set_nssaiConfig(req->drbs_to_be_setup_length, req->drbs_to_be_setup, &UE->UE_sched_ctrl);
 
@@ -409,6 +460,9 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req)
 
     nr_mac_prepare_cellgroup_update(mac, UE, new_CellGroup);
 
+    /* Fill the QoS config in MAC for each active DRB */
+    set_QoSConfig(req, &UE->UE_sched_ctrl);
+
     /* Set NSSAI config in MAC for each active DRB */
     set_nssaiConfig(req->drbs_to_be_setup_length, req->drbs_to_be_setup, &UE->UE_sched_ctrl);
   } else {
@@ -553,8 +607,9 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
     AssertFatal(*dl_rrc->old_gNB_DU_ue_id != dl_rrc->gNB_DU_ue_id,
                 "logic bug: current and old gNB DU UE ID cannot be the same\n");
     /* 38.401 says: "Find UE context based on old gNB-DU UE F1AP ID, replace
-     * old C-RNTI/PCI with new C-RNTI/PCI". So we delete the new contexts
-     * below, then change the C-RNTI of the old one to the new one */
+     * old C-RNTI/PCI with new C-RNTI/PCI". Below, we do the inverse: we keep
+     * the new UE context (with new C-RNTI), but set up everything to reuse the
+     * old config. */
     NR_UE_info_t *oldUE = find_nr_UE(&mac->UE_info, *dl_rrc->old_gNB_DU_ue_id);
     DevAssert(oldUE);
     pthread_mutex_lock(&mac->sched_lock);
@@ -564,6 +619,9 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
     UE->CellGroup->spCellConfig = NULL;
     NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
     NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
+    uid_t temp_uid = UE->uid;
+    UE->uid = oldUE->uid;
+    oldUE->uid = temp_uid;
     configure_UE_BWP(mac, scc, sched_ctrl, NULL, UE, -1, -1);
 
     nr_mac_prepare_cellgroup_update(mac, UE, oldUE->CellGroup);
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 26a24c203e060d26a7a1c3168c4b0d6a6e2f4c9d..e3437f3c9a72fbf9737e2da8fb4a9a3f98b9b0ba 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -536,6 +536,11 @@ typedef struct NR_UE_ul_harq {
   NR_sched_pusch_t sched_pusch;
 } NR_UE_ul_harq_t;
 
+typedef struct NR_QoS_config_s {
+  uint64_t fiveQI;
+  uint64_t priority;
+} NR_QoS_config_t;
+
 /*! \brief scheduling control information set through an API */
 #define MAX_CSI_REPORTS 48
 typedef struct {
@@ -635,6 +640,9 @@ typedef struct {
   /// sri, ul_ri and tpmi based on SRS
   nr_srs_feedback_t srs_feedback;
   nssai_t dl_lc_nssai[NR_MAX_NUM_LCID];
+
+  // Information about the QoS configuration for each LCID/DRB
+  NR_QoS_config_t qos_config[NR_MAX_NUM_LCID - 4][NR_MAX_NUM_QFI]; // 0 -CCCH and 1- 3 SRBs(0,1,2)
 } NR_UE_sched_ctrl_t;
 
 typedef struct {
diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c
index c9bbc6cd052eecc06fdc1c824281ba4c9eae884c..412a974406fbfd0c44c8f8b40c6e0d9d286f86e8 100644
--- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c
+++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c
@@ -53,8 +53,8 @@ static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, const
 
     asn1cCalloc(sdap_config->mappedQoS_FlowsToAdd, FlowsToAdd);
     for (int j=0; j < drb->numQosFlow2Setup; j++) {
-      asn1cSequenceAdd(FlowsToAdd->list, NR_QFI_t, id);
-      *id = drb->qosFlows[j].id;
+      asn1cSequenceAdd(FlowsToAdd->list, NR_QFI_t, qfi);
+      *qfi = drb->qosFlows[j].qfi;
     }
     sdap_config->mappedQoS_FlowsToRelease = NULL;
 
@@ -164,8 +164,11 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
     DRB_nGRAN_setup_t *resp_drb = &resp_pdu->DRBnGRanList[0];
     resp_drb->id = req_drb->id;
     resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup;
-    for (int k = 0; k < resp_drb->numQosFlowSetup; k++)
-      resp_drb->qosFlows[k].id = req_drb->qosFlows[k].id;
+    for (int k = 0; k < resp_drb->numQosFlowSetup; k++) {
+      const qos_flow_to_setup_t *qosflow2Setup = &req_drb->qosFlows[k];
+      qos_flow_setup_t *qosflowSetup = &resp_drb->qosFlows[k];
+      qosflowSetup->qfi = qosflow2Setup->qfi;
+    }
 
     // GTP tunnel for N3/to core
     gtpv1u_gnb_create_tunnel_resp_t resp_n3 = {0};
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
index db57aa63f0a7b1c5484030f789af53265af03fcc..96444e5b1058e40d2c8101405d757adc2eb64707 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
@@ -1093,12 +1093,11 @@ void nr_pdcp_reconfigure_srb(ue_id_t ue_id, int srb_id, long t_Reordering)
   nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
 }
 
-void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, long t_Reordering)
+void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, NR_PDCP_Config_t *pdcp_config, NR_SDAP_Config_t *sdap_config)
 {
-  /* The enabling/disabling of ciphering or integrity protection
-   * can be changed only by releasing and adding the DRB
-   * (so not by reconfiguring).
-   */
+  // The enabling/disabling of ciphering or integrity protection
+  // can be changed only by releasing and adding the DRB
+  // (so not by reconfiguring).
   nr_pdcp_manager_lock(nr_pdcp_ue_manager);
   nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
   nr_pdcp_entity_t *drb = nr_pdcp_get_rb(ue, drb_id, false);
@@ -1107,8 +1106,33 @@ void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, long t_Reordering)
     nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
     return;
   }
-  int decoded_t_reordering = decode_t_reordering(t_Reordering);
-  drb->t_reordering = decoded_t_reordering;
+  if (pdcp_config) {
+    if (pdcp_config->t_Reordering)
+      drb->t_reordering = decode_t_reordering(*pdcp_config->t_Reordering);
+    else
+      drb->t_reordering = -1;
+    struct NR_PDCP_Config__drb *drb_config = pdcp_config->drb;
+    if (drb_config) {
+      if (drb_config->discardTimer)
+        drb->discard_timer = decode_discard_timer(*drb_config->discardTimer);
+      bool size_set = false;
+      if (drb_config->pdcp_SN_SizeUL) {
+        drb->sn_size = decode_sn_size_ul(*drb_config->pdcp_SN_SizeUL);
+        size_set = true;
+      }
+      if (drb_config->pdcp_SN_SizeDL) {
+        int size = decode_sn_size_dl(*drb_config->pdcp_SN_SizeDL);
+        AssertFatal(!size_set || (size == drb->sn_size),
+                    "SN sizes must be the same. dl=%d, ul=%d",
+                    size, drb->sn_size);
+        drb->sn_size = size;
+      }
+    }
+  }
+  if (sdap_config) {
+    // nr_reconfigure_sdap_entity
+    AssertFatal(false, "Function to reconfigure SDAP entity not implemented yet\n");
+  }
   nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
 }
 
@@ -1131,6 +1155,7 @@ void nr_pdcp_release_drb(ue_id_t ue_id, int drb_id)
   nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
   nr_pdcp_entity_t *drb = ue->drb[drb_id - 1];
   if (drb) {
+    nr_sdap_release_drb(ue_id, drb_id, drb->pdusession_id);
     drb->release_entity(drb);
     drb->delete_entity(drb);
     ue->drb[drb_id - 1] = NULL;
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h
index 05e18c23c237b420dba3f248e9376f955fed0c1e..ea88fbfb1840f78db130ec48d22cbcfa780fb240 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h
@@ -69,10 +69,11 @@ void nr_pdcp_reestablishment(ue_id_t ue_id, int rb_id, bool srb_flag);
 void nr_pdcp_suspend_srb(ue_id_t ue_id, int srb_id);
 void nr_pdcp_suspend_drb(ue_id_t ue_id, int drb_id);
 void nr_pdcp_reconfigure_srb(ue_id_t ue_id, int srb_id, long t_Reordering);
-void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, long t_Reordering);
+void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, NR_PDCP_Config_t *pdcp_config, NR_SDAP_Config_t *sdap_config);
 void nr_pdcp_release_srb(ue_id_t ue_id, int srb_id);
 void nr_pdcp_release_drb(ue_id_t ue_id, int drb_id);
 
+
 void add_srb(int is_gnb,
              ue_id_t rntiMaybeUEid,
              struct NR_SRB_ToAddMod *s,
diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c
index 1d331b6340b5e722fcdd8327c5413620b7eda403..d967d3623f2ed569b15f35549acbcd4094a2ccaf 100644
--- a/openair2/RRC/NR/rrc_gNB.c
+++ b/openair2/RRC/NR/rrc_gNB.c
@@ -2035,6 +2035,17 @@ unsigned int mask_flip(unsigned int x) {
   return((((x>>8) + (x<<8))&0xffff)>>6);
 }
 
+static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession)
+{
+  pdusession_t *pdu = &pduSession->param;
+  for (int i = 0; i < pdu->nb_qos; i++) {
+    if (qfi == pdu->qos[i].qfi)
+      return &pdu->qos[i];
+  }
+  AssertFatal(1 == 0, "The pdu session %d does not contain a qos flow with qfi = %d\n", pdu->pdusession_id, qfi);
+  return NULL;
+}
+
 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];
@@ -2068,12 +2079,34 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
   rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, resp->pduSession[0].id, false);
   DevAssert(RRC_pduSession);
   for (int i = 0; i < nb_drb; i++) {
+    DRB_nGRAN_setup_t *drb_config = &resp->pduSession[0].DRBnGRanList[i];
     drbs[i].drb_id = resp->pduSession[0].DRBnGRanList[i].id;
     drbs[i].rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM;
-    drbs[i].up_ul_tnl[0].tl_address = resp->pduSession[0].DRBnGRanList[i].UpParamList[0].tlAddress;
+    drbs[i].up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress;
     drbs[i].up_ul_tnl[0].port = rrc->eth_params_s.my_portd;
-    drbs[i].up_ul_tnl[0].teid = resp->pduSession[0].DRBnGRanList[i].UpParamList[0].teId;
+    drbs[i].up_ul_tnl[0].teid = drb_config->UpParamList[0].teId;
     drbs[i].up_ul_tnl_length = 1;
+
+    /* pass QoS info to MAC */
+    int nb_qos_flows = drb_config->numQosFlowSetup;
+    drbs[i].drb_info.flows_to_be_setup_length = nb_qos_flows;
+    drbs[i].drb_info.flows_mapped_to_drb = (f1ap_flows_mapped_to_drb_t *)calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t));
+    AssertFatal(drbs[i].drb_info.flows_mapped_to_drb, "could not allocate memory\n");
+    for (int j = 0; j < nb_qos_flows; j++) {
+      drbs[i].drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi;
+
+      pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession);
+      f1ap_qos_characteristics_t *qos_char = &drbs[i].drb_info.flows_mapped_to_drb[j].qos_params.qos_characteristics;
+      if (in_qos_char->fiveQI_type == dynamic) {
+        qos_char->qos_type = dynamic;
+        qos_char->dynamic.fiveqi = in_qos_char->fiveQI;
+        qos_char->dynamic.qos_priority_level = in_qos_char->qos_priority;
+      } else {
+        qos_char->qos_type = non_dynamic;
+        qos_char->non_dynamic.fiveqi = in_qos_char->fiveQI;
+        qos_char->non_dynamic.qos_priority_level = in_qos_char->qos_priority;
+      }
+    }
     /* pass NSSAI info to MAC */
     drbs[i].nssai = RRC_pduSession->param.nssai;
   }
@@ -2269,7 +2302,11 @@ void *rrc_gnb_task(void *args_p) {
     itti_receive_msg(TASK_RRC_GNB, &msg_p);
     const char *msg_name_p = ITTI_MSG_NAME(msg_p);
     instance = ITTI_MSG_DESTINATION_INSTANCE(msg_p);
-    LOG_D(NR_RRC, "Received Msg %s\n", msg_name_p);
+    LOG_D(NR_RRC,
+          "RRC GNB Task Received %s for instance %ld from task %s\n",
+          ITTI_MSG_NAME(msg_p),
+          ITTI_MSG_DESTINATION_INSTANCE(msg_p),
+          ITTI_MSG_ORIGIN_NAME(msg_p));
     switch (ITTI_MSG_ID(msg_p)) {
       case TERMINATE_MESSAGE:
         LOG_W(NR_RRC, " *** Exiting NR_RRC thread\n");
diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c
index f6059a91a9181ec89ddf39af8605092631fb3f8d..b659ccc2f870c85e87112b64108f319656fcee61 100644
--- a/openair2/RRC/NR/rrc_gNB_NGAP.c
+++ b/openair2/RRC/NR/rrc_gNB_NGAP.c
@@ -68,6 +68,7 @@
 #include "NGAP_QosFlowSetupRequestItem.h"
 #include "NGAP_QosFlowAddOrModifyRequestItem.h"
 #include "NGAP_NonDynamic5QIDescriptor.h"
+#include "NGAP_Dynamic5QIDescriptor.h"
 #include "conversions.h"
 #include "RRC/NR/rrc_gNB_radio_bearers.h"
 
@@ -263,10 +264,15 @@ static void fill_qos(NGAP_QosFlowSetupRequestList_t *qos, pdusession_t *session)
     // Set the QOS informations
     session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier;
     NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics;
+    AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx);
     if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) {
-      if (qosChar->choice.nonDynamic5QI != NULL) {
-        session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI;
-      }
+      AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n");
+      session->qos[qosIdx].fiveQI_type = non_dynamic;
+      session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI;
+    } else {
+      AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n");
+      session->qos[qosIdx].fiveQI_type = dynamic;
+      session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI);
     }
 
     ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority;
@@ -820,15 +826,25 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
 
       drb->numQosFlow2Setup = session->nb_qos;
       for (int k=0; k < drb->numQosFlow2Setup; k++) {
-        qos_flow_to_setup_t *qos = drb->qosFlows + k;
-
-        qos->id = session->qos[k].qfi;
-        qos->fiveQI = session->qos[k].fiveQI;
-        qos->fiveQI_type = session->qos[k].fiveQI_type;
+        qos_flow_to_setup_t *qos_flow = drb->qosFlows + k;
+        pdusession_level_qos_parameter_t *qos_session = session->qos + k;
+
+        qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics;
+        qos_flow->qfi = qos_session->qfi;
+        qos_char->qos_type = qos_session->fiveQI_type;
+        if (qos_char->qos_type == dynamic) {
+          qos_char->dynamic.fiveqi = qos_session->fiveQI;
+          qos_char->dynamic.qos_priority_level = qos_session->qos_priority;
+        } else {
+          qos_char->non_dynamic.fiveqi = qos_session->fiveQI;
+          qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority;
+        }
 
-        qos->qoSPriorityLevel = session->qos[k].allocation_retention_priority.priority_level;
-        qos->pre_emptionCapability = session->qos[k].allocation_retention_priority.pre_emp_capability;
-        qos->pre_emptionVulnerability = session->qos[k].allocation_retention_priority.pre_emp_vulnerability;
+        ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority;
+        ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority;
+        rent_priority->priority_level = rent_priority_in->priority_level;
+        rent_priority->preemption_capability = rent_priority_in->pre_emp_capability;
+        rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability;
       }
     }
   }
@@ -854,12 +870,15 @@ static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *s
     // Set the QOS informations
     session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier;
     NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters->qosCharacteristics;
+    AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx);
     if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) {
-      if (qosChar->choice.nonDynamic5QI != NULL) {
-        session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI;
-      }
-    } else if (qosChar->present == NGAP_QosCharacteristics_PR_dynamic5QI) {
-      // TODO
+      AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n");
+      session->qos[qosIdx].fiveQI_type = non_dynamic;
+      session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI;
+    } else {
+      AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n");
+      session->qos[qosIdx].fiveQI_type = dynamic;
+      session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI);
     }
 
     ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority;
diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c
index 0617f79a836ccecdff5dca118124fc2b3f436172..389f849b2049a2a0938fb99e2c15159b8bb67cd3 100644
--- a/openair2/RRC/NR_UE/rrc_UE.c
+++ b/openair2/RRC/NR_UE/rrc_UE.c
@@ -1256,8 +1256,9 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc,
       if (rrcNB->status_DRBs[DRB_id] == RB_ESTABLISHED) {
         AssertFatal(drb->reestablishPDCP == NULL, "reestablishPDCP not yet implemented\n");
         AssertFatal(drb->recoverPDCP == NULL, "recoverPDCP not yet implemented\n");
-        if (drb->pdcp_Config && drb->pdcp_Config->t_Reordering)
-          nr_pdcp_reconfigure_drb(rnti, DRB_id, *drb->pdcp_Config->t_Reordering);
+        NR_SDAP_Config_t *sdap_Config = drb->cnAssociation ? drb->cnAssociation->choice.sdap_Config : NULL;
+        if (drb->pdcp_Config || sdap_Config)
+          nr_pdcp_reconfigure_drb(rnti, DRB_id, drb->pdcp_Config, sdap_Config);
         if (drb->cnAssociation)
           AssertFatal(drb->cnAssociation->choice.sdap_Config == NULL, "SDAP reconfiguration not yet implemented\n");
       } else {
diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c
index 6fdd8eb54ad987b7df0b8ed98ea1e5baec2c06cf..f3f83158394da9d1fc6cbf8b6a66316291928a4f 100644
--- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c
+++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c
@@ -468,6 +468,21 @@ nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id)
   return NULL;
 }
 
+void nr_sdap_release_drb(ue_id_t ue_id, int drb_id, int pdusession_id)
+{
+  // remove all QoS flow to DRB mappings associated with the released DRB
+  nr_sdap_entity_t *sdap = nr_sdap_get_entity(ue_id, pdusession_id);
+  if (sdap) {
+    for (int i = 0; i < SDAP_MAX_QFI; i++) {
+      if (sdap->qfi2drb_table[i].drb_id == drb_id)
+        sdap->qfi2drb_table[i].drb_id = SDAP_NO_MAPPING_RULE;
+    }
+  }
+  else
+    LOG_E(SDAP, "Couldn't find a SDAP entity associated with PDU session ID %d\n",
+          pdusession_id);
+}
+
 bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
 {
   nr_sdap_entity_t *entityPtr = sdap_info.sdap_entity_llist;
diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h
index 41a52c083b65da1099bbda921ac885dfecdbea77..07d62a4746b80bc8c52410d7982a466d42c736ac 100644
--- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h
+++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h
@@ -169,6 +169,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, bool has_sdap_rx, bool has_sdap
 /* Entity Handling Related Functions */
 nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id);
 
+void nr_sdap_release_drb(ue_id_t ue_id, int drb_id, int pdusession_id);
+
 /**
  * @brief Function to delete a single SDAP Entity based on the ue_id and pdusession_id.
  * @note  1. SDAP entities may have the same ue_id.
diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c
index 015b2a8f9e5dfa3fd115826b906e49226ba23434..f83f1138b6058ba073e1a124a8725fab158b0daa 100644
--- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c
+++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c
@@ -52,12 +52,14 @@
 #include <openair1/SIMULATION/ETH_TRANSPORT/proto.h>
 #include "openair2/SDAP/nr_sdap/nr_sdap.h"
 #include "openair3/SECU/nas_stream_eia2.h"
+#include "openair3/UTILS/conversions.h"
 
 uint8_t  *registration_request_buf;
 uint32_t  registration_request_len;
 extern char *baseNetAddress;
 extern uint16_t NB_UE_INST;
 static nr_ue_nas_t nr_ue_nas = {0};
+static nr_nas_msg_snssai_t nas_allowed_nssai[8];
 
 static int nas_protected_security_header_encode(
   char                                       *buffer,
@@ -778,7 +780,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi
     initialNasMsg->data[2 + i] = mac[i];
 }
 
-static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg)
+static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, nas_pdu_session_req_t *pdu_req)
 {
   //wait send RegistrationComplete
   usleep(100*150);
@@ -790,11 +792,11 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
   uint8_t *req_buffer = malloc(req_length);
   pdu_session_establishment_request_msg pdu_session_establish;
   pdu_session_establish.protocoldiscriminator = FGS_SESSION_MANAGEMENT_MESSAGE;
-  pdu_session_establish.pdusessionid = 10;
+  pdu_session_establish.pdusessionid = pdu_req->pdusession_id;
   pdu_session_establish.pti = 1;
   pdu_session_establish.pdusessionestblishmsgtype = FGS_PDU_SESSION_ESTABLISHMENT_REQ;
   pdu_session_establish.maxdatarate = 0xffff;
-  pdu_session_establish.pdusessiontype = 0x91;
+  pdu_session_establish.pdusessiontype = pdu_req->pdusession_type;
   encode_pdu_session_establishment_request(&pdu_session_establish, req_buffer);
 
 
@@ -827,22 +829,19 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
   mm_msg->uplink_nas_transport.fgspayloadcontainer.payloadcontainercontents.length = req_length;
   mm_msg->uplink_nas_transport.fgspayloadcontainer.payloadcontainercontents.value = req_buffer;
   size += (2+req_length);
-  mm_msg->uplink_nas_transport.pdusessionid = 10;
+  mm_msg->uplink_nas_transport.pdusessionid = pdu_req->pdusession_id;
   mm_msg->uplink_nas_transport.requesttype = 1;
   size += 3;
-  const bool has_nssai_sd = nas->uicc->nssai_sd != 0xffffff; // 0xffffff means "no SD", TS 23.003
+  const bool has_nssai_sd = pdu_req->sd != 0xffffff; // 0xffffff means "no SD", TS 23.003
   const size_t nssai_len = has_nssai_sd ? 4 : 1;
   mm_msg->uplink_nas_transport.snssai.length = nssai_len;
   //Fixme: it seems there are a lot of memory errors in this: this value was on the stack, 
   // but pushed  in a itti message to another thread
   // this kind of error seems in many places in 5G NAS
   mm_msg->uplink_nas_transport.snssai.value = calloc(1, nssai_len);
-  mm_msg->uplink_nas_transport.snssai.value[0] = nas->uicc->nssai_sst;
-  if (has_nssai_sd) {
-    mm_msg->uplink_nas_transport.snssai.value[1] = (nas->uicc->nssai_sd >> 16) & 0xFF;
-    mm_msg->uplink_nas_transport.snssai.value[2] = (nas->uicc->nssai_sd >> 8)  & 0xFF;
-    mm_msg->uplink_nas_transport.snssai.value[3] = (nas->uicc->nssai_sd)       & 0xFF;
-  }
+  mm_msg->uplink_nas_transport.snssai.value[0] = pdu_req->sst;
+  if (has_nssai_sd)
+    INT24_TO_BUFFER(pdu_req->sd, &mm_msg->uplink_nas_transport.snssai.value[1]);
   size += 1 + 1 + nssai_len;
   int dnnSize=strlen(nas->uicc->dnnStr);
   mm_msg->uplink_nas_transport.dnn.value=calloc(1,dnnSize+1);
@@ -912,6 +911,120 @@ static void send_nas_uplink_data_req(instance_t instance, const as_nas_info_t *i
   itti_send_msg_to_task(TASK_RRC_NRUE, instance, msg);
 }
 
+static void parse_allowed_nssai(nr_nas_msg_snssai_t nssaiList[8], const uint8_t *buf, const uint32_t len)
+{
+  int nssai_cnt = 0;
+  const uint8_t *end = buf + len;
+  while (buf < end) {
+    const int length = *buf++;
+    nr_nas_msg_snssai_t *nssai = nssaiList + nssai_cnt;
+    nssai->sd = 0xffffff;
+
+    switch (length) {
+      case 1:
+        nssai->sst = *buf++;
+        nssai_cnt++;
+        break;
+
+      case 2:
+        nssai->sst = *buf++;
+        nssai->hplmn_sst = *buf++;
+        nssai_cnt++;
+        break;
+
+      case 4:
+        nssai->sst = *buf++;
+        nssai->sd = 0xffffff & ntoh_int24_buf(buf);
+        buf += 3;
+        nssai_cnt++;
+        break;
+
+      case 5:
+        nssai->sst = *buf++;
+        nssai->sd = 0xffffff & ntoh_int24_buf(buf);
+        buf += 3;
+        nssai->hplmn_sst = *buf++;
+        nssai_cnt++;
+        break;
+
+      case 8:
+        nssai->sst = *buf++;
+        nssai->sd = 0xffffff & ntoh_int24_buf(buf);
+        buf += 3;
+        nssai->hplmn_sst = *buf++;
+        nssai->hplmn_sd = 0xffffff & ntoh_int24_buf(buf);
+        buf += 3;
+        nssai_cnt++;
+        break;
+
+      default:
+        LOG_E(NAS, "UE received unknown length in an allowed S-NSSAI\n");
+        break;
+    }
+  }
+}
+
+/* Extract Allowed NSSAI from Regestration Accept according to
+   3GPP TS 24.501 Table 8.2.7.1.1
+*/
+static void get_allowed_nssai(nr_nas_msg_snssai_t nssai[8], const uint8_t *pdu_buffer, const uint32_t pdu_length)
+{
+  if ((pdu_buffer == NULL) || (pdu_length <= 0))
+    return;
+
+  const uint8_t *end = pdu_buffer + pdu_length;
+  if (((nas_msg_header_t *)(pdu_buffer))->choice.security_protected_nas_msg_header_t.security_header_type > 0) {
+    pdu_buffer += SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH;
+  }
+
+  pdu_buffer += 1 + 1 + 1 + 2; // Mandatory fields offset
+  /* optional fields */
+  while (pdu_buffer < end) {
+    const int type = *pdu_buffer++;
+    int length = 0;
+    switch (type) {
+      case 0x77: // 5GS mobile identity
+        pdu_buffer += ntoh_int16_buf(pdu_buffer) + sizeof(uint16_t);
+        break;
+
+      case 0x4A: // PLMN list
+      case 0x54: // 5GS tracking area identity
+        pdu_buffer += *pdu_buffer + 1; // offset length + 1 byte which contains the length
+        break;
+
+      case 0x15: // allowed NSSAI
+        length = *pdu_buffer++;
+        parse_allowed_nssai(nssai, pdu_buffer, length);
+        break;
+
+      default:
+        LOG_W(NAS, "This NAS IEI is not handled when extracting list of allowed NSSAI\n");
+        pdu_buffer = end;
+        break;
+    }
+  }
+}
+
+static void request_default_pdusession(int instance, int nssai_idx)
+{
+  MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_PDU_SESSION_REQ);
+  NAS_PDU_SESSION_REQ(message_p).pdusession_id = 10; /* first or default pdu session */
+  NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91;
+  NAS_PDU_SESSION_REQ(message_p).sst = nas_allowed_nssai[nssai_idx].sst;
+  NAS_PDU_SESSION_REQ(message_p).sd = nas_allowed_nssai[nssai_idx].sd;
+  itti_send_msg_to_task(TASK_NAS_NRUE, instance, message_p);
+}
+
+static int get_user_nssai_idx(const nr_nas_msg_snssai_t allowed_nssai[8], const nr_ue_nas_t *nas)
+{
+  for (int i = 0; i < 8; i++) {
+    const nr_nas_msg_snssai_t *nssai = allowed_nssai + i;
+    if ((nas->uicc->nssai_sst == nssai->sst) && (nas->uicc->nssai_sd == nssai->sd))
+      return i;
+  }
+  return -1;
+}
+
 void *nas_nrue_task(void *args_p)
 {
   nr_ue_nas.uicc = checkUicc(0);
@@ -975,6 +1088,18 @@ void *nas_nrue(void *args_p)
         /* TODO not processed by NAS currently */
         break;
 
+      case NAS_PDU_SESSION_REQ: {
+        as_nas_info_t pduEstablishMsg = {0};
+        nas_pdu_session_req_t *pduReq = &NAS_PDU_SESSION_REQ(msg_p);
+        nr_ue_nas_t *nas = get_ue_nas_info(0);
+        generatePduSessionEstablishRequest(nas, &pduEstablishMsg, pduReq);
+        if (pduEstablishMsg.length > 0) {
+          send_nas_uplink_data_req(instance, &pduEstablishMsg);
+          LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(PduSessionEstablishRequest)\n");
+        }
+        break;
+      }
+
       case NAS_CONN_ESTABLI_CNF: {
         LOG_I(NAS,
               "[UE %ld] Received %s: errCode %u, length %u\n",
@@ -990,6 +1115,7 @@ void *nas_nrue(void *args_p)
           LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n");
           nr_ue_nas_t *nas = get_ue_nas_info(0);
           decodeRegistrationAccept(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length, nas);
+          get_allowed_nssai(nas_allowed_nssai, pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
 
           as_nas_info_t initialNasMsg = {0};
           generateRegistrationComplete(nas, &initialNasMsg, NULL);
@@ -998,11 +1124,11 @@ void *nas_nrue(void *args_p)
             LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n");
           }
 
-          as_nas_info_t pduEstablishMsg = {0};
-          generatePduSessionEstablishRequest(nas, &pduEstablishMsg);
-          if (pduEstablishMsg.length > 0) {
-            send_nas_uplink_data_req(instance, &pduEstablishMsg);
-            LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(PduSessionEstablishRequest)\n");
+          const int nssai_idx = get_user_nssai_idx(nas_allowed_nssai, nas);
+          if (nssai_idx < 0) {
+            LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n");
+          } else {
+            request_default_pdusession(instance, nssai_idx);
           }
         } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
           capture_pdu_session_establishment_accept_msg(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
@@ -1081,12 +1207,11 @@ void *nas_nrue(void *args_p)
               send_nas_uplink_data_req(instance, &initialNasMsg);
               LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n");
             }
-
-            as_nas_info_t pduEstablishMsg = {0};
-            generatePduSessionEstablishRequest(nas, &pduEstablishMsg);
-            if (pduEstablishMsg.length > 0) {
-              send_nas_uplink_data_req(instance, &pduEstablishMsg);
-              LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(PduSessionEstablishRequest)\n");
+            const int nssai_idx = get_user_nssai_idx(nas_allowed_nssai, nas);
+            if (nssai_idx < 0) {
+              LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n");
+            } else {
+              request_default_pdusession(instance, nssai_idx);
             }
             break;
           case FGS_DEREGISTRATION_ACCEPT:
diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.h b/openair3/NAS/NR_UE/nr_nas_msg_sim.h
index fa4911c738238ae4f1597c5c16770ae49490277e..b1a1d25d1e2a6a58d5923854c4d71d6712db4516 100644
--- a/openair3/NAS/NR_UE/nr_nas_msg_sim.h
+++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.h
@@ -73,6 +73,14 @@
 #define PAYLOAD_CONTAINER_LENGTH_MIN                       3
 #define PAYLOAD_CONTAINER_LENGTH_MAX                       65537
 
+/* List of allowed NSSAI from NAS messaging. */
+typedef struct {
+  int sst;
+  int hplmn_sst;
+  int sd;
+  int hplmn_sd;
+} nr_nas_msg_snssai_t;
+
 /* Security Key for SA UE */
 typedef struct {
   uint8_t kausf[32];
diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h
index ad84ecf0e05d230649f69df5b5a6d64d0504249b..2620d106a05e6f6f7a7f8fd946f570bae7795291 100644
--- a/openair3/UTILS/conversions.h
+++ b/openair3/UTILS/conversions.h
@@ -34,13 +34,19 @@
     (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)
 
 # define ntoh_int32_buf(bUF)        \
-    ((*(bUF)) << 24) | ((*((bUF) + 1)) << 16) | ((*((bUF) + 2)) << 8)   \
-  | (*((bUF) + 3))
+    ((*((uint8_t*)bUF)) << 24) | ((*((uint8_t*)bUF + 1)) << 16) | ((*((uint8_t*)bUF + 2)) << 8)   \
+  | (*((uint8_t*)bUF + 3))
 #else
 # define hton_int32(x) (x)
 # define hton_int16(x) (x)
 #endif
 
+#define ntoh_int24_buf(bUF) \
+  ((*(uint8_t*)bUF << 16) | ((*((uint8_t*)bUF + 1)) << 8) | (*((uint8_t*)bUF + 2)))
+
+#define ntoh_int16_buf(bUF) \
+  ((*((uint8_t*)bUF) << 8) | (*((uint8_t*)bUF + 1)))
+
 #define IN_ADDR_TO_BUFFER(X,bUFF) INT32_TO_BUFFER((X).s_addr,(char*)bUFF)
 
 #define IN6_ADDR_TO_BUFFER(X,bUFF)                     \