diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index c08d9378b848933a619cdbaf65eb98175713b4a2..84a98a300efab0c0ed5dd005faea3fd8ec4673ca 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1926,6 +1926,7 @@ set (MAC_SRC_UE
 
 set (MAC_NR_SRC_UE
   ${NR_UE_PHY_INTERFACE_DIR}/NR_IF_Module.c
+  ${NR_UE_PHY_INTERFACE_DIR}/NR_Packet_Drop.c
   ${NR_UE_MAC_DIR}/config_ue.c
   ${NR_UE_MAC_DIR}/mac_vars.c
   ${NR_UE_MAC_DIR}/main_ue_nr.c
diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h
index d13fe260deba559e3b0dcbf3077192289cfa16a5..47e17cc935325af423652d6e9db849239c6857c2 100644
--- a/openair1/PHY/defs_common.h
+++ b/openair1/PHY/defs_common.h
@@ -907,7 +907,7 @@ typedef enum {no_relay=1,unicast_relay_type1,unicast_relay_type2, multicast_rela
 
 
 
-#define MCS_COUNT 28
+#define MCS_COUNT 29
 #define MCS_TABLE_LENGTH_MAX 64
 
 
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
index b8b79f8399f10a5908f5b558aeea52e300a0c7ac..b6f760a86a65cd7c1423c3452d322fb0b42b86ad 100644
--- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
@@ -66,17 +66,6 @@ queue_t nr_tx_req_queue;
 queue_t nr_ul_dci_req_queue;
 queue_t nr_ul_tti_req_queue;
 
-static slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT];
-
-//static int get_mcs_from_sinr(float sinr);
-//static int get_cqi_from_mcs(void);
-static void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int sf, int index);
-//static bool did_drop_transport_block(int slot, uint16_t rnti);
-static float get_bler_val(uint8_t mcs, int sinr);
-static bool should_drop_transport_block(int slot, uint16_t rnti);
-static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request);
-static inline bool is_channel_modeling(void);
-
 void nrue_init_standalone_socket(int tx_port, int rx_port)
 {
   {
@@ -939,7 +928,7 @@ static void enqueue_nr_nfapi_msg(void *buffer, ssize_t len, nfapi_p7_message_hea
     return;
 }
 
-static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request)
+void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request)
 {
   int count_sent = 0;
   NR_UE_MAC_INST_t *mac = get_mac_inst(0);
@@ -1343,245 +1332,3 @@ void RCconfig_nr_ue_L1(void) {
     }
   }
 }
-
-/*
-static int get_mcs_from_sinr(float sinr)
-{
-  if (sinr < (nr_bler_data[0].bler_table[0][0]))
-  {
-    LOG_D(NR_MAC, "The SINR found is smaller than first MCS table\n");
-    return 0;
-  }
-
-  if (sinr > (nr_bler_data[NR_NUM_MCS-1].bler_table[nr_bler_data[NR_NUM_MCS-1].length - 1][0]))
-  {
-    LOG_D(NR_MAC, "The SINR found is larger than last MCS table\n");
-    return NR_NUM_MCS-1;
-  }
-
-  for (int n = NR_NUM_MCS-1; n >= 0; n--)
-  {
-    CHECK_INDEX(nr_bler_data, n);
-    float largest_sinr = (nr_bler_data[n].bler_table[nr_bler_data[n].length - 1][0]);
-    float smallest_sinr = (nr_bler_data[n].bler_table[0][0]);
-    if (sinr < largest_sinr && sinr > smallest_sinr)
-    {
-      LOG_D(NR_MAC, "The SINR found in MCS %d table\n", n);
-      return n;
-    }
-  }
-  LOG_E(NR_MAC, "Unable to get an MCS value.\n");
-  abort();
-}
-*/
-
-/*
-static int get_cqi_from_mcs(void)
-{
-  static const int mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
-                                   9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15};
-  assert(NUM_ELEMENTS(mcs_to_cqi) == NR_NUM_MCS);
-  int slot = 0;
-  while (slot < NUM_NFAPI_SLOT)
-  {
-    if (slot_rnti_mcs[slot].latest)
-    {
-      int num_pdus = slot_rnti_mcs[slot].num_pdus;
-      if (num_pdus <= 0)
-      {
-        LOG_E(NR_MAC, "%s: slot_rnti_mcs[%d].num_pdus = 0\n", __FUNCTION__, slot);
-        abort();
-      }
-
-      CHECK_INDEX(slot_rnti_mcs[slot].mcs, num_pdus);
-      int mcs = get_mcs_from_sinr(slot_rnti_mcs[slot].sinr);
-      CHECK_INDEX(mcs_to_cqi, mcs);
-      int cqi = mcs_to_cqi[mcs];
-      LOG_D(NR_MAC, "SINR: %f -> MCS: %d -> CQI: %d\n", slot_rnti_mcs[slot].sinr, mcs, cqi);
-      return cqi;
-    }
-    slot++;
-  }
-  LOG_E(NR_MAC, "Unable to get CQI value because no MCS found\n");
-  abort();
-}
-*/
-
-static void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int slot, int index)
-{
-  if (pdu == NULL)
-  {
-    LOG_E(NR_MAC,"PDU NULL\n");
-    abort();
-  }
-
-  /* This function is executed for every pdsch pdu type in a dl_tti_request. We save
-     the assocaited MCS and RNTI value for each. The 'index' passed in is a count of
-     how many times we have called this function for a particular dl_tti_request. It
-     allows us to save MCS/RNTI data in correct indicies when multiple pdsch pdu's are received.*/
-  for (int i = 0; i < NUM_NFAPI_SLOT; i++)
-  {
-    slot_rnti_mcs[i].latest = false;
-  }
-
-  CHECK_INDEX(slot_rnti_mcs[slot].rnti, index);
-  CHECK_INDEX(slot_rnti_mcs[slot].mcs, index);
-  CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, index);
-  slot_rnti_mcs[slot].rnti[index] = pdu->rnti;
-  slot_rnti_mcs[slot].mcs[index] = pdu->mcsIndex[0];
-  slot_rnti_mcs[slot].rvIndex[index] = pdu->rvIndex[0];
-  slot_rnti_mcs[slot].drop_flag[index] = false;
-  slot_rnti_mcs[slot].num_pdus = index+1; //index starts at 0 so we incrament to get num of pdus
-  slot_rnti_mcs[slot].latest = true;
-  LOG_D(NR_MAC, "Adding MCS %d and RNTI %x for slot_rnti_mcs[%d]\n", slot_rnti_mcs[slot].mcs[index], slot_rnti_mcs[slot].rnti[index], slot);
-
-  return;
-}
-
-/*
-static bool did_drop_transport_block(int slot, uint16_t rnti)
-{
-  int num_pdus = slot_rnti_mcs[slot].num_pdus;
-  if (num_pdus <= 0)
-  {
-    LOG_E(MAC, "Problem, the PDU size is <= 0. We dropped this packet\n");
-    return true;
-  }
-  CHECK_INDEX(slot_rnti_mcs[slot].rnti, num_pdus);
-  CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, num_pdus);
-  for (int n = 0; n < num_pdus; n++)
-  {
-    if (slot_rnti_mcs[slot].rnti[n] == rnti && slot_rnti_mcs[slot].drop_flag[n])
-    {
-      return true;
-    }
-  }
-  return false;
-}
-*/
-
-static float get_bler_val(uint8_t mcs, int sinr)
-{
-  // 4th col = dropped packets, 5th col = total packets
-  float bler_val = 0.0;
-  CHECK_INDEX(nr_bler_data, mcs);
-  LOG_D(NR_MAC, "sinr %d min %d max %d\n", sinr,
-                (int)(nr_bler_data[mcs].bler_table[0][0] * 10),
-                (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10)
-  );
-
-  if (sinr < (int)(nr_bler_data[mcs].bler_table[0][0] * 10))
-  {
-    LOG_D(NR_MAC, "MCS %d table. SINR is smaller than lowest SINR, bler_val is set based on lowest SINR in table\n", mcs);
-    bler_val = nr_bler_data[mcs].bler_table[0][4] / nr_bler_data[mcs].bler_table[0][5];
-    return bler_val;
-  }
-  if (sinr > (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10))
-  {
-    LOG_D(NR_MAC, "MCS %d table. SINR is greater than largest SINR. bler_val is set based on largest SINR in table\n", mcs);
-    bler_val = nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][4] / nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][5];
-    return bler_val;
-  }
-  // Loop through bler table to find sinr_index
-  for (int i = 0; i < nr_bler_data[mcs].length; i++)
-  {
-    int temp_sinr = (int)(nr_bler_data[mcs].bler_table[i][0] * 10);
-    if (temp_sinr == sinr)
-    {
-      bler_val = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5];
-      return bler_val;
-    }
-    // Linear interpolation when SINR is between indices
-    if (temp_sinr > sinr)
-    {
-      float bler_val1 = nr_bler_data[mcs].bler_table[i - 1][4] / nr_bler_data[mcs].bler_table[i - 1][5];
-      float bler_val2 = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5];
-      LOG_D(NR_MAC, "sinr %d min %f max %f\n", sinr, bler_val1, bler_val2);
-      return ((bler_val1 + bler_val2) / 2);
-    }
-  }
-  LOG_E(NR_MAC, "NO SINR INDEX FOUND!\n");
-  abort();
-
-}
-
-static inline bool is_channel_modeling(void)
-{
-  /* TODO: For now we enable channel modeling based on the node_number.
-     Replace with a command line option to enable/disable channel modeling.
-     The LTE UE will crash when channel modeling is conducted for NSA
-     mode. It does not crash for LTE mode. We have not implemented channel
-     modeling for NSA mode yet. For now, we ensure only do do channel modeling
-     in LTE/NR mode. */
-  return get_softmodem_params()->node_number == 0 && !get_softmodem_params()->nsa;
-}
-
-static bool should_drop_transport_block(int slot, uint16_t rnti)
-{
-  if (!is_channel_modeling())
-  {
-    return false;
-  }
-
-  /* We want to avoid dropping setup messages because this would be pathological. */
-  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
-  if (mac->ra.ra_state < RA_SUCCEEDED)
-  {
-    LOG_D(NR_MAC, "Not dropping because MAC state: %d", mac->ra.ra_state);
-    return false;
-  }
-
-  /* Get block error rate (bler_val) from table based on every saved
-     MCS and SINR to be used as the cutoff rate for dropping packets.
-     Generate random uniform vairable to compare against bler_val. */
-  int num_pdus = slot_rnti_mcs[slot].num_pdus;
-  assert(slot < 20 && slot >= 0);
-  LOG_D(NR_MAC, "rnti: %x  num_pdus %d state %d slot %u sinr %f\n",
-        rnti, num_pdus, mac->ra.ra_state, slot, slot_rnti_mcs[slot].sinr);
-  assert(num_pdus > 0);
-  CHECK_INDEX(slot_rnti_mcs[slot].rnti, num_pdus);
-  CHECK_INDEX(slot_rnti_mcs[slot].mcs, num_pdus);
-  CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, num_pdus);
-  int n = 0;
-  uint8_t mcs = 99;
-  for (n = 0; n < num_pdus; n++)
-  {
-    if (slot_rnti_mcs[slot].rnti[n] == rnti)
-    {
-      mcs = slot_rnti_mcs[slot].mcs[n];
-    }
-    if (mcs != 99)
-    {
-      /* Use MCS to get the bler value. Since there can be multiple MCS
-         values for a particular slot, we verify that all PDUs are not
-         flagged for drop before returning. If even one is flagged for drop
-         we return immediately because we drop the entire packet. */
-
-      LOG_D(NR_MAC, "rnti: %x mcs %u slot %u sinr %f\n",
-        slot_rnti_mcs[slot].rnti[n], mcs, slot, slot_rnti_mcs[slot].sinr);
-
-      float bler_val;
-      if (slot_rnti_mcs[slot].rvIndex[n] != 0)
-        bler_val = 0;
-      else
-        bler_val = get_bler_val(mcs, ((int)(slot_rnti_mcs[slot].sinr * 10)));
-      double drop_cutoff = ((double) rand() / (RAND_MAX));
-      assert(drop_cutoff <= 1);
-      LOG_D(NR_MAC, "SINR = %f, Bler_val = %f, MCS = %"PRIu8"\n", slot_rnti_mcs[slot].sinr, bler_val, slot_rnti_mcs[slot].mcs[n]);
-      if (drop_cutoff <= bler_val)
-      {
-        slot_rnti_mcs[slot].drop_flag[n] = true;
-        LOG_T(NR_MAC, "We are dropping this packet. Bler_val = %f, MCS = %"PRIu8", slot = %d\n", bler_val, slot_rnti_mcs[slot].mcs[n], slot);
-        return slot_rnti_mcs[slot].drop_flag[n];
-      }
-    }
-
-  }
-
-  if (mcs == 99)
-  {
-    LOG_E(NR_MAC, "NO MCS Found for rnti %x. slot_rnti_mcs[%d].mcs[%d] \n", rnti, slot, n);
-    abort();
-  }
-  return false;
-}
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
index 45d1a071ca96323c353dcf5d0b5754c773fedae2..f663c17d10f310530483b65dfa506811b7cb3037 100755
--- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
@@ -40,45 +40,12 @@
 #include "openair2/PHY_INTERFACE/queue_t.h"
 #include "nfapi_nr_interface_scf.h"
 #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h"
+#include "NR_Packet_Drop.h"
 
-#define NR_NUM_MCS 29
-#define NUM_SINR 100
-#define NUM_BLER_COL 13
-#define NUM_NFAPI_SLOT 20
-#define NR_NUM_LAYER 1
+extern slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT];
 
 typedef struct NR_UL_TIME_ALIGNMENT NR_UL_TIME_ALIGNMENT_t;
 
-typedef struct nr_phy_channel_params_t
-{
-    uint16_t sfn_slot;
-    uint16_t message_id;
-    uint16_t nb_of_sinrs;
-    float sinr[NR_NUM_LAYER];
-    // Incomplete, need all channel parameters
-} nr_phy_channel_params_t;
-
-typedef struct
-{
-    uint8_t slot;
-    uint16_t rnti[256];
-    uint8_t mcs[256];
-    uint8_t rvIndex[256];
-    float sinr;
-    uint16_t num_pdus;
-    bool drop_flag[256];
-    bool latest;
-
-} slot_rnti_mcs_s;
-
-typedef struct
-{
-    uint16_t length;
-    float bler_table[NUM_SINR][NUM_BLER_COL];
-} nr_bler_struct;
-
-extern nr_bler_struct nr_bler_data[NR_NUM_MCS];
-
 typedef enum {
   ONLY_PUSCH,
   NOT_PUSCH,
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c
new file mode 100644
index 0000000000000000000000000000000000000000..41d27bda8061482f6c425eb4394ea61b4daca8f2
--- /dev/null
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+#include <stdio.h>
+#include "openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h"
+#include "executables/softmodem-common.h"
+#include "NR_MAC_UE/mac_proto.h"
+
+slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT];
+void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int slot, int index)
+{
+  if (pdu == NULL)
+  {
+    LOG_E(NR_MAC,"PDU NULL\n");
+    abort();
+  }
+
+  /* This function is executed for every pdsch pdu type in a dl_tti_request. We save
+     the assocaited MCS and RNTI value for each. The 'index' passed in is a count of
+     how many times we have called this function for a particular dl_tti_request. It
+     allows us to save MCS/RNTI data in correct indicies when multiple pdsch pdu's are received.*/
+  for (int i = 0; i < NUM_NFAPI_SLOT; i++)
+  {
+    slot_rnti_mcs[i].latest = false;
+  }
+
+  CHECK_INDEX(slot_rnti_mcs[slot].rnti, index);
+  CHECK_INDEX(slot_rnti_mcs[slot].mcs, index);
+  CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, index);
+  slot_rnti_mcs[slot].rnti[index] = pdu->rnti;
+  slot_rnti_mcs[slot].mcs[index] = pdu->mcsIndex[0];
+  slot_rnti_mcs[slot].rvIndex[index] = pdu->rvIndex[0];
+  slot_rnti_mcs[slot].drop_flag[index] = false;
+  slot_rnti_mcs[slot].num_pdus = index+1; //index starts at 0 so we incrament to get num of pdus
+  slot_rnti_mcs[slot].latest = true;
+  LOG_D(NR_MAC, "Adding MCS %d and RNTI %x for slot_rnti_mcs[%d]\n", slot_rnti_mcs[slot].mcs[index], slot_rnti_mcs[slot].rnti[index], slot);
+
+  return;
+}
+
+float get_bler_val(uint8_t mcs, int sinr)
+{
+  // 4th col = dropped packets, 5th col = total packets
+  nr_bler_struct nr_bler_data[NR_NUM_MCS];
+  float bler_val = 0.0;
+  CHECK_INDEX(nr_bler_data, mcs);
+  LOG_D(NR_MAC, "sinr %d min %d max %d\n", sinr,
+                (int)(nr_bler_data[mcs].bler_table[0][0] * 10),
+                (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10)
+  );
+
+  if (sinr < (int)(nr_bler_data[mcs].bler_table[0][0] * 10))
+  {
+    LOG_D(NR_MAC, "MCS %d table. SINR is smaller than lowest SINR, bler_val is set based on lowest SINR in table\n", mcs);
+    bler_val = nr_bler_data[mcs].bler_table[0][4] / nr_bler_data[mcs].bler_table[0][5];
+    return bler_val;
+  }
+  if (sinr > (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10))
+  {
+    LOG_D(NR_MAC, "MCS %d table. SINR is greater than largest SINR. bler_val is set based on largest SINR in table\n", mcs);
+    bler_val = nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][4] / nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][5];
+    return bler_val;
+  }
+  // Loop through bler table to find sinr_index
+  for (int i = 0; i < nr_bler_data[mcs].length; i++)
+  {
+    int temp_sinr = (int)(nr_bler_data[mcs].bler_table[i][0] * 10);
+    if (temp_sinr == sinr)
+    {
+      bler_val = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5];
+      return bler_val;
+    }
+    // Linear interpolation when SINR is between indices
+    if (temp_sinr > sinr)
+    {
+      float bler_val1 = nr_bler_data[mcs].bler_table[i - 1][4] / nr_bler_data[mcs].bler_table[i - 1][5];
+      float bler_val2 = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5];
+      LOG_D(NR_MAC, "sinr %d min %f max %f\n", sinr, bler_val1, bler_val2);
+      return ((bler_val1 + bler_val2) / 2);
+    }
+  }
+  LOG_E(NR_MAC, "NO SINR INDEX FOUND!\n");
+  abort();
+
+}
+
+bool is_channel_modeling(void)
+{
+  /* TODO: For now we enable channel modeling based on the node_number.
+     Replace with a command line option to enable/disable channel modeling.
+     The LTE UE will crash when channel modeling is conducted for NSA
+     mode. It does not crash for LTE mode. We have not implemented channel
+     modeling for NSA mode yet. For now, we ensure only do do channel modeling
+     in LTE/NR mode. */
+  return get_softmodem_params()->node_number == 0 && !get_softmodem_params()->nsa;
+}
+
+bool should_drop_transport_block(int slot, uint16_t rnti)
+{
+  if (!is_channel_modeling())
+  {
+    return false;
+  }
+
+  /* We want to avoid dropping setup messages because this would be pathological. */
+  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
+  if (mac->ra.ra_state < RA_SUCCEEDED)
+  {
+    LOG_D(NR_MAC, "Not dropping because MAC state: %d", mac->ra.ra_state);
+    return false;
+  }
+
+  /* Get block error rate (bler_val) from table based on every saved
+     MCS and SINR to be used as the cutoff rate for dropping packets.
+     Generate random uniform vairable to compare against bler_val. */
+  int num_pdus = slot_rnti_mcs[slot].num_pdus;
+  assert(slot < 20 && slot >= 0);
+  LOG_D(NR_MAC, "rnti: %x  num_pdus %d state %d slot %u sinr %f\n",
+        rnti, num_pdus, mac->ra.ra_state, slot, slot_rnti_mcs[slot].sinr);
+  assert(num_pdus > 0);
+  CHECK_INDEX(slot_rnti_mcs[slot].rnti, num_pdus);
+  CHECK_INDEX(slot_rnti_mcs[slot].mcs, num_pdus);
+  CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, num_pdus);
+  int n = 0;
+  uint8_t mcs = 99;
+  for (n = 0; n < num_pdus; n++)
+  {
+    if (slot_rnti_mcs[slot].rnti[n] == rnti)
+    {
+      mcs = slot_rnti_mcs[slot].mcs[n];
+    }
+    if (mcs != 99)
+    {
+      /* Use MCS to get the bler value. Since there can be multiple MCS
+         values for a particular slot, we verify that all PDUs are not
+         flagged for drop before returning. If even one is flagged for drop
+         we return immediately because we drop the entire packet. */
+
+      LOG_D(NR_MAC, "rnti: %x mcs %u slot %u sinr %f\n",
+        slot_rnti_mcs[slot].rnti[n], mcs, slot, slot_rnti_mcs[slot].sinr);
+
+      float bler_val;
+      if (slot_rnti_mcs[slot].rvIndex[n] != 0)
+        bler_val = 0;
+      else
+        bler_val = get_bler_val(mcs, ((int)(slot_rnti_mcs[slot].sinr * 10)));
+      double drop_cutoff = ((double) rand() / (RAND_MAX));
+      assert(drop_cutoff <= 1);
+      LOG_D(NR_MAC, "SINR = %f, Bler_val = %f, MCS = %"PRIu8"\n", slot_rnti_mcs[slot].sinr, bler_val, slot_rnti_mcs[slot].mcs[n]);
+      if (drop_cutoff <= bler_val)
+      {
+        slot_rnti_mcs[slot].drop_flag[n] = true;
+        LOG_T(NR_MAC, "We are dropping this packet. Bler_val = %f, MCS = %"PRIu8", slot = %d\n", bler_val, slot_rnti_mcs[slot].mcs[n], slot);
+        return slot_rnti_mcs[slot].drop_flag[n];
+      }
+    }
+
+  }
+
+  if (mcs == 99)
+  {
+    LOG_E(NR_MAC, "NO MCS Found for rnti %x. slot_rnti_mcs[%d].mcs[%d] \n", rnti, slot, n);
+    abort();
+  }
+  return false;
+}
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h
new file mode 100644
index 0000000000000000000000000000000000000000..549eb5c2e38288be8f69bc01ddf34c5d31843256
--- /dev/null
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+#ifndef __NR_CHAN_MODEL_H__
+#define __NR_CHAN_MODEL_H__
+
+#include <platform_types.h>
+#include <nfapi_nr_interface_scf.h>
+#include <openair1/PHY/thread_NR_UE.h>
+#include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h"
+
+#define NR_NUM_MCS 29
+#define NUM_SINR 100
+#define NUM_BLER_COL 13
+#define NUM_NFAPI_SLOT 20
+#define NR_NUM_LAYER 1
+#define MAX_CHAN_PARAMS 256
+
+typedef struct nr_phy_channel_params_t
+{
+    uint16_t sfn_slot;
+    uint16_t message_id;
+    uint16_t nb_of_sinrs;
+    float sinr[NR_NUM_LAYER];
+} nr_phy_channel_params_t;
+
+typedef struct
+{
+    uint8_t slot;
+    uint16_t rnti[MAX_CHAN_PARAMS];
+    uint8_t mcs[MAX_CHAN_PARAMS];
+    uint8_t rvIndex[MAX_CHAN_PARAMS];
+    float sinr;
+    uint16_t num_pdus;
+    bool drop_flag[MAX_CHAN_PARAMS];
+    bool latest;
+} slot_rnti_mcs_s;
+
+typedef struct
+{
+    uint16_t length;
+    float bler_table[NUM_SINR][NUM_BLER_COL];
+} nr_bler_struct;
+
+void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int sf, int index);
+void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request);
+float get_bler_val(uint8_t mcs, int sinr);
+bool should_drop_transport_block(int slot, uint16_t rnti);
+bool is_channel_modeling(void);
+
+#endif
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.c b/openair2/PHY_INTERFACE/phy_stub_UE.c
index c4650f18f3a93e8c7e1878bbc5e687b6b0da81b2..cd57ea9ff101ea225e6169408cc5e5fad5d3d255 100644
--- a/openair2/PHY_INTERFACE/phy_stub_UE.c
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.c
@@ -1956,7 +1956,7 @@ static int get_mcs_from_sinr(float sinr)
 
 static int get_cqi_from_mcs(void)
 {
-  static const int mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15};
+  static const int mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15};
   assert(NUM_ELEMENTS(mcs_to_cqi) == NUM_MCS);
   int sf = 0;
   while(sf < NUM_NFAPI_SUBFRAME)
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.h b/openair2/PHY_INTERFACE/phy_stub_UE.h
index d68d1dffdd91a25371c7193521bd2ae68f8a3298..fe0e7be12e171a12c9858bdbf38cd6dfaf94b9f9 100644
--- a/openair2/PHY_INTERFACE/phy_stub_UE.h
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.h
@@ -21,7 +21,7 @@
 //#include "openair1/PHY/LTE_TRANSPORT/defs.h"
 #include "queue_t.h"
 
-#define NUM_MCS 28
+#define NUM_MCS 29
 #define NUM_SINR 100
 #define NUM_BLER_COL 13
 #define LTE_NUM_LAYER 1