diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md
index 5a8f3f6539248af49fd6959c4da24563f4d767c0..17d3f3b80124b8cd5e46e00f228c4d4889c1c47d 100644
--- a/doc/FEATURE_SET.md
+++ b/doc/FEATURE_SET.md
@@ -205,6 +205,7 @@ These modes of operation are supported:
   - F1 UE Context modification required
   - F1 UE Context release req/cmd/complete
   - F1 gNB CU configuration update
+  - F1 Reset (handled at DU only, full reset only)
 - Interface with RRC
 - Interface with GTP-u (tunnel creation/handling for F1-U interface)
 - One CU(-CP) can handle multiple DUs
diff --git a/openair2/COMMON/f1ap_messages_def.h b/openair2/COMMON/f1ap_messages_def.h
index 9177ed9001267befec4e2a6c416d90da34c4d613..405ecae3d5d07f698b6182d3fe77edbd4848b917 100644
--- a/openair2/COMMON/f1ap_messages_def.h
+++ b/openair2/COMMON/f1ap_messages_def.h
@@ -23,6 +23,10 @@
 /* To setup F1 at DU */
 MESSAGE_DEF(F1AP_DU_REGISTER_REQ, MESSAGE_PRIORITY_MED, f1ap_du_register_req_t, f1ap_du_register_req)
 
+/* RESET */
+MESSAGE_DEF(F1AP_RESET, MESSAGE_PRIORITY_MED, f1ap_reset_t, f1ap_reset)
+MESSAGE_DEF(F1AP_RESET_ACK, MESSAGE_PRIORITY_MED, f1ap_reset_ack_t, f1ap_reset_ack)
+
 /* eNB_DU application layer -> F1AP messages or CU F1AP -> RRC*/
 MESSAGE_DEF(F1AP_SETUP_REQ          , MESSAGE_PRIORITY_MED, f1ap_setup_req_t          , f1ap_setup_req)
 MESSAGE_DEF(F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE         , MESSAGE_PRIORITY_MED, f1ap_gnb_cu_configuration_update_acknowledge_t          , f1ap_gnb_cu_configuration_update_acknowledge)
diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h
index 8ec4613327ef17dfd21fe0663f0fd5095986f5bb..3b6082e2210ee6cf600923103c9205ecf610239f 100644
--- a/openair2/COMMON/f1ap_messages_types.h
+++ b/openair2/COMMON/f1ap_messages_types.h
@@ -34,6 +34,9 @@
 
 #define F1AP_DU_REGISTER_REQ(mSGpTR)               (mSGpTR)->ittiMsg.f1ap_du_register_req
 
+#define F1AP_RESET(mSGpTR)                         (mSGpTR)->ittiMsg.f1ap_reset
+#define F1AP_RESET_ACK(mSGpTR)                         (mSGpTR)->ittiMsg.f1ap_reset_ack
+
 #define F1AP_SETUP_REQ(mSGpTR)                     (mSGpTR)->ittiMsg.f1ap_setup_req
 #define F1AP_SETUP_RESP(mSGpTR)                    (mSGpTR)->ittiMsg.f1ap_setup_resp
 #define F1AP_GNB_CU_CONFIGURATION_UPDATE(mSGpTR)   (mSGpTR)->ittiMsg.f1ap_gnb_cu_configuration_update
@@ -78,6 +81,8 @@
 #define F1AP_MAX_NO_OF_TNL_ASSOCIATIONS 32
 #define F1AP_MAX_NO_UE_ID 1024
 
+#define F1AP_MAX_NO_OF_INDIVIDUAL_CONNECTIONS_TO_RESET 65536
+
 typedef net_ip_address_t f1ap_net_ip_address_t;
 
 typedef struct f1ap_net_config_t {
@@ -534,4 +539,29 @@ typedef struct f1ap_lost_connection_t {
   int dummy;
 } f1ap_lost_connection_t;
 
+typedef enum F1AP_ResetType_e {
+  F1AP_RESET_ALL,
+  F1AP_RESET_PART_OF_F1_INTERFACE
+} f1ap_ResetType_t;
+
+typedef struct f1ap_reset_t {
+  uint64_t          transaction_id;
+  f1ap_Cause_t      cause;
+  long              cause_value;
+  f1ap_ResetType_t  reset_type;
+  struct {
+    uint32_t gNB_CU_ue_id;
+    uint32_t gNB_DU_ue_id;
+  } ue_to_reset[F1AP_MAX_NO_OF_INDIVIDUAL_CONNECTIONS_TO_RESET];
+} f1ap_reset_t;
+
+typedef struct f1ap_reset_ack_t {
+  uint64_t          transaction_id;
+  struct {
+    uint32_t gNB_CU_ue_id;
+    uint32_t gNB_DU_ue_id;
+  } ue_to_reset[F1AP_MAX_NO_OF_INDIVIDUAL_CONNECTIONS_TO_RESET];
+  uint16_t criticality_diagnostics;
+} f1ap_reset_ack_t;
+
 #endif /* F1AP_MESSAGES_TYPES_H_ */
diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c
index 360a2323aab658220ec6413e27be429de601e47e..2e73172e2b1f98a1234fad086f344208038a2bb1 100644
--- a/openair2/F1AP/f1ap_cu_interface_management.c
+++ b/openair2/F1AP/f1ap_cu_interface_management.c
@@ -35,12 +35,12 @@
 #include "f1ap_itti_messaging.h"
 #include "f1ap_cu_interface_management.h"
 
-int CU_send_RESET(sctp_assoc_t assoc_id, F1AP_Reset_t *Reset)
+int CU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset)
 {
   AssertFatal(1==0,"Not implemented yet\n");
 }
 
-int CU_handle_RESET_ACKKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu)
+int CU_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu)
 {
   AssertFatal(1==0,"Not implemented yet\n");
 }
@@ -50,7 +50,7 @@ int CU_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream,
   AssertFatal(1==0,"Not implemented yet\n");
 }
 
-int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, F1AP_ResetAcknowledge_t *ResetAcknowledge)
+int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack)
 {
   AssertFatal(1==0,"Not implemented yet\n");
 }
diff --git a/openair2/F1AP/f1ap_cu_interface_management.h b/openair2/F1AP/f1ap_cu_interface_management.h
index f506b8315244133b968a38cfe5d44cd788f8a2b0..11a45868e1662e972c9c78248d00ff2edcf4479a 100644
--- a/openair2/F1AP/f1ap_cu_interface_management.h
+++ b/openair2/F1AP/f1ap_cu_interface_management.h
@@ -36,10 +36,10 @@
 /*
  * Reset
  */
-int CU_send_RESET(sctp_assoc_t assoc_id, F1AP_Reset_t *Reset);
-int CU_handle_RESET_ACKKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
+int CU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset);
+int CU_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
 int CU_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
-int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, F1AP_ResetAcknowledge_t *ResetAcknowledge);
+int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack);
 
 /*
  * Error Indication
diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c
index 3d8061b96138454801f28469266ec18d707693a3..a320b92935cb6c8182ca694996e67c5f688f7cc8 100644
--- a/openair2/F1AP/f1ap_cu_task.c
+++ b/openair2/F1AP/f1ap_cu_task.c
@@ -160,6 +160,10 @@ void *F1AP_CU_task(void *arg) {
                                      &received_msg->ittiMsg.sctp_data_ind);
         break;
 
+      case F1AP_RESET_ACK:
+        CU_send_RESET_ACKNOWLEDGE(assoc_id, &F1AP_RESET_ACK(received_msg));
+        break;
+
       case F1AP_SETUP_RESP: // from rrc
         CU_send_F1_SETUP_RESPONSE(assoc_id,
                                   &F1AP_SETUP_RESP(received_msg));
diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c
index 7ea710a0b4a23b4bbc748b7764605c84c6a49cde..f560754bf3ee1f27c71a7161ae04dfc6746863cb 100644
--- a/openair2/F1AP/f1ap_du_interface_management.c
+++ b/openair2/F1AP/f1ap_du_interface_management.c
@@ -52,14 +52,115 @@ int to_NRNRB(int nrb) {
 
 int DU_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu)
 {
-  AssertFatal(1==0,"Not implemented yet\n");
+  LOG_D(F1AP, "DU_handle_RESET\n");\
+  F1AP_Reset_t  *container;
+  F1AP_ResetIEs_t *ie;
+  DevAssert(pdu != NULL);
+  container = &pdu->choice.initiatingMessage->value.choice.Reset;
+
+  /* Reset == Non UE-related procedure -> stream 0 */
+  if (stream != 0) {
+    LOG_W(F1AP, "[SCTP %d] Received Reset on stream != 0 (%d)\n",
+        assoc_id, stream);
+  }
+
+  MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_RESET);
+  msg_p->ittiMsgHeader.originInstance = assoc_id;
+  f1ap_reset_t *f1ap_reset = &F1AP_RESET(msg_p);
+
+  /* Transaction ID */
+  F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_ResetIEs_t, ie, container, F1AP_ProtocolIE_ID_id_TransactionID, true);
+  f1ap_reset->transaction_id = ie->value.choice.TransactionID;
+  LOG_D(F1AP, "req->transaction_id %lu \n", f1ap_reset->transaction_id);
+  
+  /* Cause */
+  F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_ResetIEs_t, ie, container, F1AP_ProtocolIE_ID_id_Cause, true);
+  switch(ie->value.choice.Cause.present) 
+  {
+    case F1AP_Cause_PR_radioNetwork:
+      LOG_D(F1AP, "Cause: Radio Network\n");
+      f1ap_reset->cause = F1AP_CAUSE_RADIO_NETWORK;
+      f1ap_reset->cause_value = ie->value.choice.Cause.choice.radioNetwork;
+      break;
+    case F1AP_Cause_PR_transport:
+      LOG_D(F1AP, "Cause: Transport\n");
+      f1ap_reset->cause = F1AP_CAUSE_TRANSPORT;
+      f1ap_reset->cause_value = ie->value.choice.Cause.choice.transport;
+      break;
+    case F1AP_Cause_PR_protocol:
+      LOG_D(F1AP, "Cause: Protocol\n");
+      f1ap_reset->cause = F1AP_CAUSE_PROTOCOL;
+      f1ap_reset->cause_value = ie->value.choice.Cause.choice.protocol;
+      break;
+    case F1AP_Cause_PR_misc:
+      LOG_D(F1AP, "Cause: Misc\n");
+      f1ap_reset->cause = F1AP_CAUSE_MISC;
+      f1ap_reset->cause_value = ie->value.choice.Cause.choice.misc;
+      break;
+    default:
+      AssertFatal(1==0,"Unknown cause\n");
+  }
+
+  /* ResetType */
+  F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_ResetIEs_t, ie, container, F1AP_ProtocolIE_ID_id_ResetType, true);
+  switch(ie->value.choice.ResetType.present) {
+    case F1AP_ResetType_PR_f1_Interface:
+      LOG_D(F1AP, "ResetType: F1 Interface\n");
+      f1ap_reset->reset_type = F1AP_RESET_ALL;
+      break;
+    case F1AP_ResetType_PR_partOfF1_Interface:
+      LOG_D(F1AP, "ResetType: Part of F1 Interface\n");
+      f1ap_reset->reset_type = F1AP_RESET_PART_OF_F1_INTERFACE;
+      break;
+    default:
+      AssertFatal(1==0,"Unknown reset type\n");
+  }
+
+  /* Part of F1 Interface */
+  if (f1ap_reset->reset_type == F1AP_RESET_PART_OF_F1_INTERFACE) {
+    AssertFatal(1==0, "Not implemented yet\n");
+  }
+  
+  f1_reset_cu_initiated(f1ap_reset);
+  return 0;
 }
 
-int DU_send_RESET_ACKKNOWLEDGE(sctp_assoc_t assoc_id, F1AP_ResetAcknowledge_t *ResetAcknowledge) {
-  AssertFatal(1==0,"Not implemented yet\n");
+int DU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack)
+{
+  F1AP_F1AP_PDU_t       pdu= {0};
+  uint8_t  *buffer;
+  uint32_t  len;
+  /* Create */
+  /* 0. pdu Type */
+  pdu.present = F1AP_F1AP_PDU_PR_successfulOutcome;
+  asn1cCalloc(pdu.choice.successfulOutcome, successMsg);
+  successMsg->procedureCode = F1AP_ProcedureCode_id_Reset;
+  successMsg->criticality   = F1AP_Criticality_reject;
+  successMsg->value.present = F1AP_SuccessfulOutcome__value_PR_ResetAcknowledge;
+  F1AP_ResetAcknowledge_t *f1ResetAcknowledge = &successMsg->value.choice.ResetAcknowledge;
+  /* mandatory */
+  /* c1. Transaction ID (integer value) */
+  asn1cSequenceAdd(f1ResetAcknowledge->protocolIEs.list, F1AP_ResetAcknowledgeIEs_t, ieC1);
+  ieC1->id                        = F1AP_ProtocolIE_ID_id_TransactionID;
+  ieC1->criticality               = F1AP_Criticality_reject;
+  ieC1->value.present             = F1AP_ResetAcknowledgeIEs__value_PR_TransactionID;
+  ieC1->value.choice.TransactionID = ack->transaction_id;
+
+  /* TODO: (Optional) partialF1Interface, criticality diagnostics */
+
+  /* encode */
+  if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) {
+    LOG_E(F1AP, "Failed to encode F1ResetAcknowledge\n");
+    return -1;
+  }
+
+  /* send */
+  ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu);
+  f1ap_itti_send_sctp_data_req(assoc_id, buffer, len);
+  return 0;
 }
 
-int DU_send_RESET(sctp_assoc_t assoc_id, F1AP_Reset_t *Reset)
+int DU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset)
 {
   AssertFatal(1==0,"Not implemented yet\n");
 }
@@ -223,6 +324,8 @@ static F1AP_GNB_DU_System_Information_t *encode_system_info(const f1ap_gnb_du_sy
 // SETUP REQUEST
 int DU_send_F1_SETUP_REQUEST(sctp_assoc_t assoc_id, const f1ap_setup_req_t *setup_req)
 {
+  LOG_D(F1AP, "DU_send_F1_SETUP_REQUEST\n");
+
   F1AP_F1AP_PDU_t       pdu= {0};
   uint8_t  *buffer;
   uint32_t  len;
diff --git a/openair2/F1AP/f1ap_du_interface_management.h b/openair2/F1AP/f1ap_du_interface_management.h
index c48754010fcd1f7fdb983ce402a7b7913c994451..f8d7eafb025d53889ae64749744a6da0b5b41051 100644
--- a/openair2/F1AP/f1ap_du_interface_management.h
+++ b/openair2/F1AP/f1ap_du_interface_management.h
@@ -37,8 +37,8 @@
  * Reset
  */
 int DU_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
-int DU_send_RESET_ACKKNOWLEDGE(sctp_assoc_t assoc_id, F1AP_ResetAcknowledge_t *ResetAcknowledge);
-int DU_send_RESET(sctp_assoc_t assoc_id, F1AP_Reset_t *Reset);
+int DU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack);
+int DU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset);
 int DU_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
 
 /*
diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c
index 7959f734fecc20a9ebfdb05f8194c9ce057a1d77..ff188e52df7ea6b8bed0c06efcbcb5943a744784 100644
--- a/openair2/F1AP/f1ap_du_task.c
+++ b/openair2/F1AP/f1ap_du_task.c
@@ -134,6 +134,10 @@ void *F1AP_DU_task(void *arg) {
         DUuniqInstance = gtpInst;
       } break;
 
+      case F1AP_RESET_ACK:
+        DU_send_RESET_ACKNOWLEDGE(assoc_id, &F1AP_RESET_ACK(msg));
+        break;
+
       case F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE:
         DU_send_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(assoc_id,
             &F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg));
diff --git a/openair2/F1AP/f1ap_handlers.c b/openair2/F1AP/f1ap_handlers.c
index ecdda720009fc682f1cf9e4d848fec06e491272e..bfaa9959dc3ed9639540cf0298ec25b8430ec74e 100644
--- a/openair2/F1AP/f1ap_handlers.c
+++ b/openair2/F1AP/f1ap_handlers.c
@@ -42,7 +42,10 @@
 /* Handlers matrix. Only f1 related procedure present here */
 static const f1ap_message_processing_t f1ap_messages_processing[][3] = {
 
-    {0, 0, 0}, /* Reset */
+    // TODO: How to handle RESET if CU/DU has their respective handlers? 
+    // We need to check node type and call the right handler.
+    {DU_handle_RESET, CU_handle_RESET_ACKNOWLEDGE, 0}, /* Reset */ 
+    // {CU_handle_RESET, DU_handle_RESET_ACKNOWLEDGE, 0}, /* Reset */ 
     {CU_handle_F1_SETUP_REQUEST, DU_handle_F1_SETUP_RESPONSE, DU_handle_F1_SETUP_FAILURE}, /* F1Setup */
     {0, 0, 0}, /* ErrorIndication */
     {CU_handle_gNB_DU_CONFIGURATION_UPDATE, 0, 0}, /* gNBDUConfigurationUpdate */
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
index 200a21258e7ee8f25064afa6a293e437d641c081..495eb30eef73cabb815bc3cf76a4d2f0cd89e3ac 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
@@ -2190,6 +2190,7 @@ void nr_schedule_RA(module_id_t module_idP,
         if (ra->contention_resolution_timer < 0) {
           LOG_W(NR_MAC, "(%d.%d) RA Contention Resolution timer expired for UE 0x%04x, RA procedure failed...\n", frameP, slotP, ra->rnti);
           nr_mac_release_ue(mac, ra->rnti);
+          nr_mac_trigger_release_complete(mac, ra->rnti);
           nr_clear_ra_proc(ra);
           continue;
         }
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index 4c67bfdf354c564530be5072eeb7d2ad0320c581..5728f6bb3f1fb89469e6e54d17182087b15d4fbf 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -3013,32 +3013,36 @@ int nr_mac_enable_ue_rrc_processing_timer(gNB_MAC_INST *mac, NR_UE_info_t *UE, b
   return 0;
 }
 
-void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti)
+void nr_mac_trigger_release_complete(gNB_MAC_INST *mac, int rnti)
 {
-  NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
-
-  nr_rlc_remove_ue(rnti);
-  mac_remove_nr_ue(mac, rnti);
-
   // the CU might not know such UE, e.g., because we never sent a message to
   // it, so there might not be a corresponding entry for such UE in the look up
   // table. This can happen, e.g., on Msg.3 with C-RNTI, where we create a UE
   // MAC context, decode the PDU, find the C-RNTI MAC CE, and then throw the
   // newly created context away. See also in _nr_rx_sdu() and commit 93f59a3c6e56f
-  if (du_exists_f1_ue_data(rnti)) {
-    // unlock the scheduler temporarily to prevent possible deadlocks with
-    // du_remove_f1_ue_data() (and also while sending the message to RRC)
-    NR_SCHED_UNLOCK(&mac->sched_lock);
-    f1_ue_data_t ue_data = du_get_f1_ue_data(rnti);
-    f1ap_ue_context_release_complete_t complete = {
-      .gNB_CU_ue_id = ue_data.secondary_ue,
-      .gNB_DU_ue_id = rnti,
-    };
-    mac->mac_rrc.ue_context_release_complete(&complete);
+  if (!du_exists_f1_ue_data(rnti)) 
+    return;
 
-    du_remove_f1_ue_data(rnti);
-    NR_SCHED_LOCK(&mac->sched_lock);
-  }
+  // unlock the scheduler temporarily to prevent possible deadlocks with
+  // du_remove_f1_ue_data() (and also while sending the message to RRC)
+  NR_SCHED_UNLOCK(&mac->sched_lock);
+  f1_ue_data_t ue_data = du_get_f1_ue_data(rnti);
+  f1ap_ue_context_release_complete_t complete = {
+    .gNB_CU_ue_id = ue_data.secondary_ue,
+    .gNB_DU_ue_id = rnti,
+  };
+  mac->mac_rrc.ue_context_release_complete(&complete);
+
+  du_remove_f1_ue_data(rnti);
+  NR_SCHED_LOCK(&mac->sched_lock);
+}
+
+void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti)
+{
+  NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
+
+  nr_rlc_remove_ue(rnti);
+  mac_remove_nr_ue(mac, rnti);
 }
 
 void nr_mac_update_timers(module_id_t module_id,
@@ -3055,6 +3059,8 @@ void nr_mac_update_timers(module_id_t module_id,
     NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
 
     if (nr_mac_check_release(sched_ctrl, UE->rnti)) {
+      // trigger release first as nr_mac_release_ue() invalidates UE ptr
+      nr_mac_trigger_release_complete(mac, UE->rnti);
       nr_mac_release_ue(mac, UE->rnti);
       // go back to examine the next UE, which is at the position the
       // current UE was
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index 84f06c873c6c2e5041fb00e6f00ba86030096134..938d5cf27b5f64494dbf43f27a3d1d8ddc47e9d8 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -438,6 +438,7 @@ void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid);
 
 void nr_mac_trigger_release_timer(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing);
 bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti);
+void nr_mac_trigger_release_complete(gNB_MAC_INST *mac, int rnti);
 void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti);
 
 void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing);
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 7353e617113edc4c43b502fba286a62323d713df..2435ed629a41b05dee793d05b59024e448682758 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
@@ -29,6 +29,8 @@
 #include "openair3/ocp-gtpu/gtp_itf.h"
 #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
 
+#include "executables/softmodem-common.h"
+
 #include "uper_decoder.h"
 #include "uper_encoder.h"
 
@@ -95,6 +97,52 @@ static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t
   return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
 }
 
+static void du_clear_all_ue_states()
+{
+  gNB_MAC_INST *mac = RC.nrmac[0];
+  NR_SCHED_LOCK(&mac->sched_lock);
+
+  NR_UE_info_t *UE = *mac->UE_info.list;
+
+  instance_t f1inst = get_f1_gtp_instance();
+
+  while (UE != NULL) {
+    int rnti = UE->rnti;
+    nr_mac_release_ue(mac, rnti);
+    // free all F1 contexts
+    if (du_exists_f1_ue_data(rnti))
+      du_remove_f1_ue_data(rnti);
+    newGtpuDeleteAllTunnels(f1inst, rnti);
+    UE = *mac->UE_info.list;
+  }
+  NR_SCHED_UNLOCK(&mac->sched_lock);
+}
+
+void f1_reset_cu_initiated(const f1ap_reset_t *reset)
+{
+  LOG_I(MAC, "F1 Reset initiated by CU\n");
+
+  f1ap_reset_ack_t ack = {0};
+  if(reset->reset_type == F1AP_RESET_ALL) {
+    du_clear_all_ue_states();
+    ack = (f1ap_reset_ack_t) {
+      .transaction_id = reset->transaction_id
+    };
+  } else {
+    // reset->reset_type == F1AP_RESET_PART_OF_F1_INTERFACE
+    AssertFatal(1==0, "Not implemented yet\n");
+  }
+
+  gNB_MAC_INST *mac = RC.nrmac[0];
+  mac->mac_rrc.f1_reset_acknowledge(&ack);
+}
+
+void f1_reset_acknowledge_du_initiated(const f1ap_reset_ack_t *ack)
+{
+  (void) ack;
+  AssertFatal(false, "%s() not implemented yet\n", __func__);
+}
+
 void f1_setup_response(const f1ap_setup_resp_t *resp)
 {
   LOG_I(MAC, "received F1 Setup Response from CU %s\n", resp->gNB_CU_name);
@@ -126,6 +174,24 @@ void f1_setup_response(const f1ap_setup_resp_t *resp)
     mac->f1_config.setup_resp->gNB_CU_name = strdup(resp->gNB_CU_name);
 
   NR_SCHED_UNLOCK(&mac->sched_lock);
+
+  // NOTE: Before accepting any UEs, we should initialize the UE states.
+  // This is to handle cases when DU loses the existing SCTP connection,
+  // and reestablishes a new connection to either a new CU or the same CU.
+  // This triggers a new F1 Setup Request from DU to CU as per the specs.
+  // Reinitializing the UE states is necessary to avoid any inconsistent states
+  // between DU and CU.
+  // NOTE2: do not reset in phy_test, because there is a pre-configured UE in
+  // this case. Once NSA/phy-test use F1, this might be lifted, because
+  // creation of a UE will be requested from higher layers.
+
+  // TS38.473 [Sec 8.2.3.1]: "This procedure also re-initialises the F1AP UE-related
+  // contexts (if any) and erases all related signalling connections
+  // in the two nodes like a Reset procedure would do."
+  if (!get_softmodem_params()->phy_test) {
+    LOG_I(MAC, "Clearing the DU's UE states before, if any.\n");
+    du_clear_all_ue_states();
+  }
 }
 
 void f1_setup_failure(const f1ap_setup_failure_t *failure)
@@ -615,6 +681,7 @@ void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd)
   if (UE->UE_sched_ctrl.ul_failure || cmd->rrc_container_length == 0) {
     /* The UE is already not connected anymore or we have nothing to forward*/
     nr_mac_release_ue(mac, cmd->gNB_DU_ue_id);
+    nr_mac_trigger_release_complete(mac, cmd->gNB_DU_ue_id);
   } else {
     /* UE is in sync: forward release message and mark to be deleted
      * after UL failure */
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h
index 7a284f2d8b67d65a127b3502ad5f6d4a6f65197a..e9aceb1192c9db11dd2e385f44ce54d325ae8228 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h
@@ -26,6 +26,8 @@
 #include "f1ap_messages_types.h"
 #include "openair2/RRC/NR/MESSAGES/asn1_msg.h"
 
+void f1_reset_cu_initiated(const f1ap_reset_t *reset);
+void f1_reset_acknowledge_du_initiated(const f1ap_reset_ack_t *ack);
 void f1_setup_response(const f1ap_setup_resp_t *resp);
 void f1_setup_failure(const f1ap_setup_failure_t *failure);
 void gnb_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_update_acknowledge_t *ack);
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h
index 0d902a77c6fb5e90464dd97c02a7d3ead0090433..1e416f01f9ecdf36911918df1a576cd7f85a0cc2 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h
@@ -25,6 +25,9 @@
 #include "common/platform_types.h"
 #include "f1ap_messages_types.h"
 
+typedef void (*f1_reset_du_initiated_func_t)(const f1ap_reset_t *reset);
+typedef void (*f1_reset_acknowledge_cu_initiated_func_t)(const f1ap_reset_ack_t *ack);
+
 typedef void (*f1_setup_request_func_t)(const f1ap_setup_req_t* req);
 typedef void (*gnb_du_configuration_update_t)(const f1ap_gnb_du_configuration_update_t *upd);
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c
index acef49ef5bb2708aab086fa23056f0fec2454dc5..29a7bc8621b955f24001894b79442149bd41d40a 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c
@@ -24,6 +24,18 @@
 
 #include "mac_rrc_ul.h"
 
+static void f1_reset_du_initiated_direct(const f1ap_reset_t *reset)
+{
+  (void) reset;
+  AssertFatal(false, "%s() not implemented yet\n", __func__);
+}
+
+static void f1_reset_acknowledge_cu_initiated_direct(const f1ap_reset_ack_t *ack)
+{
+  (void) ack;
+  AssertFatal(false, "%s() not implemented yet\n", __func__);
+}
+
 static void f1_setup_request_direct(const f1ap_setup_req_t *req)
 {
   MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_SETUP_REQ);
@@ -284,6 +296,8 @@ static void initial_ul_rrc_message_transfer_direct(module_id_t module_id, const
 
 void mac_rrc_ul_direct_init(struct nr_mac_rrc_ul_if_s *mac_rrc)
 {
+  mac_rrc->f1_reset = f1_reset_du_initiated_direct;
+  mac_rrc->f1_reset_acknowledge = f1_reset_acknowledge_cu_initiated_direct;
   mac_rrc->f1_setup_request = f1_setup_request_direct;
   mac_rrc->gnb_du_configuration_update = gnb_du_configuration_update_direct;
   mac_rrc->ue_context_setup_response = ue_context_setup_response_direct;
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c
index 19beddad7a9dcb0965c9a2924691b27ad2b40ee7..742f85c390d2d71318ec4d2133f2a742304697e1 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c
@@ -53,6 +53,19 @@ static f1ap_net_config_t read_DU_IP_config(const eth_params_t* f1_params, const
   return nc;
 }
 
+static void f1_reset_du_initiated_f1ap(const f1ap_reset_t *reset)
+{
+  (void) reset;
+  AssertFatal(false, "%s() not implemented yet\n", __func__);
+}
+
+static void f1_reset_acknowledge_cu_initiated_f1ap(const f1ap_reset_ack_t *ack)
+{
+  MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_RESET_ACK);
+  f1ap_reset_ack_t *f1ap_msg = &F1AP_RESET_ACK(msg);
+  *f1ap_msg = *ack;
+  itti_send_msg_to_task(TASK_DU_F1, 0, msg);
+}
 
 static void f1_setup_request_f1ap(const f1ap_setup_req_t *req)
 {
@@ -275,6 +288,8 @@ static void initial_ul_rrc_message_transfer_f1ap(module_id_t module_id, const f1
 
 void mac_rrc_ul_f1ap_init(struct nr_mac_rrc_ul_if_s *mac_rrc)
 {
+  mac_rrc->f1_reset = f1_reset_du_initiated_f1ap;
+  mac_rrc->f1_reset_acknowledge = f1_reset_acknowledge_cu_initiated_f1ap;
   mac_rrc->f1_setup_request = f1_setup_request_f1ap;
   mac_rrc->gnb_du_configuration_update = gnb_du_configuration_update_f1ap;
   mac_rrc->ue_context_setup_response = ue_context_setup_response_f1ap;
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 350a9090888565e11f1d3278eae7dc393a748203..8362a612055963bed25f1e1b508111a1170c48a4 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -690,6 +690,8 @@ typedef struct NR_bler_options {
 } NR_bler_options_t;
 
 typedef struct nr_mac_rrc_ul_if_s {
+  f1_reset_du_initiated_func_t f1_reset;
+  f1_reset_acknowledge_cu_initiated_func_t f1_reset_acknowledge;
   f1_setup_request_func_t f1_setup_request;
   gnb_du_configuration_update_t gnb_du_configuration_update;
   ue_context_setup_response_func_t ue_context_setup_response;
diff --git a/openair2/RRC/NR/mac_rrc_dl.h b/openair2/RRC/NR/mac_rrc_dl.h
index 49eb03512a155ab381dc756afe9f463f7ce1f50d..d6937591b54e5a15ba970a9b744c790d6af8533a 100644
--- a/openair2/RRC/NR/mac_rrc_dl.h
+++ b/openair2/RRC/NR/mac_rrc_dl.h
@@ -25,6 +25,9 @@
 #include "common/platform_types.h"
 #include "f1ap_messages_types.h"
 
+typedef void (*f1_reset_cu_initiated_func_t)(sctp_assoc_t assoc_id, const f1ap_reset_t *reset);
+typedef void (*f1_reset_acknowledge_du_initiated_func_t)(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack);
+
 typedef void (*f1_setup_response_func_t)(sctp_assoc_t assoc_id, const f1ap_setup_resp_t *resp);
 typedef void (*f1_setup_failure_func_t)(sctp_assoc_t assoc_id, const f1ap_setup_failure_t *fail);
 typedef void (*gnb_du_configuration_update_ack_func_t)(sctp_assoc_t assoc_id,
diff --git a/openair2/RRC/NR/mac_rrc_dl_direct.c b/openair2/RRC/NR/mac_rrc_dl_direct.c
index 4b0afbc0e1f43703775d86cfbd8feb97bd57f3ae..54ec7c8e4c2fadb05fa7fdc6535360286161ab79 100644
--- a/openair2/RRC/NR/mac_rrc_dl_direct.c
+++ b/openair2/RRC/NR/mac_rrc_dl_direct.c
@@ -24,6 +24,18 @@
 #include "mac_rrc_dl.h"
 #include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
 
+static void f1_reset_cu_initiated_direct(sctp_assoc_t assoc_id, const f1ap_reset_t *reset)
+{
+  (void)reset;
+  AssertFatal(false, "%s() not implemented yet\n", __func__);
+}
+
+static void f1_reset_acknowledge_du_initiated_direct(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack)
+{
+  (void)ack;
+  AssertFatal(false, "%s() not implemented yet\n", __func__);
+}
+
 static void f1_setup_response_direct(sctp_assoc_t assoc_id, const f1ap_setup_resp_t *resp)
 {
   AssertFatal(assoc_id == -1, "illegal assoc_id %d\n", assoc_id);
@@ -80,6 +92,8 @@ static void dl_rrc_message_transfer_direct(sctp_assoc_t assoc_id, const f1ap_dl_
 
 void mac_rrc_dl_direct_init(nr_mac_rrc_dl_if_t *mac_rrc)
 {
+  mac_rrc->f1_reset = f1_reset_cu_initiated_direct;
+  mac_rrc->f1_reset_acknowledge = f1_reset_acknowledge_du_initiated_direct;
   mac_rrc->f1_setup_response = f1_setup_response_direct;
   mac_rrc->f1_setup_failure = f1_setup_failure_direct;
   mac_rrc->gnb_du_configuration_update_acknowledge = gnb_du_configuration_update_ack_direct;
diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c
index 9a934cc675b5bbb85a7f81de8229c0a1f352d372..439712ec7eefbb7e458e51512eb6c0754f0a3b15 100644
--- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c
+++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c
@@ -24,6 +24,18 @@
 #include "mac_rrc_dl.h"
 #include "nr_rrc_defs.h"
 
+static void f1_reset_cu_initiated_f1ap(sctp_assoc_t assoc_id, const f1ap_reset_t *reset)
+{
+  (void)reset;
+  AssertFatal(false, "%s() not implemented yet\n", __func__);
+}
+
+static void f1_reset_acknowledge_du_initiated_f1ap(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack)
+{
+  (void)ack;
+  AssertFatal(false, "%s() not implemented yet\n", __func__);
+}
+
 static void f1_setup_response_f1ap(sctp_assoc_t assoc_id, const f1ap_setup_resp_t *resp)
 {
   MessageDef *msg = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_SETUP_RESP);
@@ -215,6 +227,8 @@ static void dl_rrc_message_transfer_f1ap(sctp_assoc_t assoc_id, const f1ap_dl_rr
 
 void mac_rrc_dl_f1ap_init(nr_mac_rrc_dl_if_t *mac_rrc)
 {
+  mac_rrc->f1_reset = f1_reset_cu_initiated_f1ap;
+  mac_rrc->f1_reset_acknowledge = f1_reset_acknowledge_du_initiated_f1ap;
   mac_rrc->f1_setup_response = f1_setup_response_f1ap;
   mac_rrc->f1_setup_failure = f1_setup_failure_f1ap;
   mac_rrc->gnb_du_configuration_update_acknowledge = gnb_du_configuration_update_ack_f1ap;
diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h
index 961406986ac1801dccefd8981e7379e1775f4968..a9234ed5bdb7343eb6358d71cbd5d133b51e8519 100644
--- a/openair2/RRC/NR/nr_rrc_defs.h
+++ b/openair2/RRC/NR/nr_rrc_defs.h
@@ -398,6 +398,8 @@ typedef struct neighbour_cell_configuration_s {
 } neighbour_cell_configuration_t;
 
 typedef struct nr_mac_rrc_dl_if_s {
+  f1_reset_cu_initiated_func_t f1_reset;
+  f1_reset_acknowledge_du_initiated_func_t f1_reset_acknowledge;
   f1_setup_response_func_t f1_setup_response;
   f1_setup_failure_func_t f1_setup_failure;
   gnb_du_configuration_update_ack_func_t gnb_du_configuration_update_acknowledge;