From f75cdbcad75eb5e30d93a9ab5dacccde17f2ede3 Mon Sep 17 00:00:00 2001
From: Robert Schmidt <robert.schmidt@openairinterface.org>
Date: Fri, 25 Mar 2022 11:47:23 +0100
Subject: [PATCH] Use F1 DL RRC message transfer internally for RRCSetup

---
 cmake_targets/CMakeLists.txt                  |   3 +
 openair2/COMMON/f1ap_messages_types.h         |   1 +
 openair2/F1AP/dummy_enb.c                     |   4 +
 openair2/F1AP/f1ap_cu_task.c                  |   1 +
 openair2/F1AP/f1ap_du_rrc_message_transfer.c  |  11 ++
 .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c    | 131 +++++++++++++
 .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h    |  30 +++
 openair2/RRC/NR/mac_rrc_dl.h                  |  34 ++++
 openair2/RRC/NR/mac_rrc_dl_direct.c           |  52 +++++
 openair2/RRC/NR/mac_rrc_dl_f1ap.c             |  44 +++++
 openair2/RRC/NR/nr_rrc_defs.h                 |   8 +
 openair2/RRC/NR/rrc_gNB.c                     | 181 ++++--------------
 12 files changed, 357 insertions(+), 143 deletions(-)
 create mode 100644 openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
 create mode 100644 openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h
 create mode 100644 openair2/RRC/NR/mac_rrc_dl.h
 create mode 100644 openair2/RRC/NR/mac_rrc_dl_direct.c
 create mode 100644 openair2/RRC/NR/mac_rrc_dl_f1ap.c

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 157ac1f6b3..b215e6ca4c 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1872,6 +1872,8 @@ set(L2_NR_SRC
   ${NR_RRC_DIR}/rrc_gNB.c
   ${NR_RRC_DIR}/nr_rrc_common.c
   ${NR_RRC_DIR}/L2_nr_interface.c
+  ${NR_RRC_DIR}/mac_rrc_dl_direct.c
+  ${NR_RRC_DIR}/mac_rrc_dl_f1ap.c
   ${NR_RRC_DIR}/nr_rrc_config.c
   ${NR_RRC_DIR}/rrc_gNB_nsa.c
   ${NR_RRC_DIR}/rrc_gNB_internode.c
@@ -1950,6 +1952,7 @@ set (MAC_NR_SRC
   ${NR_GNB_MAC_DIR}/gNB_scheduler_uci.c
   ${NR_GNB_MAC_DIR}/gNB_scheduler_srs.c
   ${NR_GNB_MAC_DIR}/gNB_scheduler_RA.c
+  ${NR_GNB_MAC_DIR}/mac_rrc_dl_handler.c
  )
 
 
diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h
index ae050e2bc2..c19bdff9a2 100644
--- a/openair2/COMMON/f1ap_messages_types.h
+++ b/openair2/COMMON/f1ap_messages_types.h
@@ -23,6 +23,7 @@
 #define F1AP_MESSAGES_TYPES_H_
 
 #include "rlc.h"
+#include "s1ap_messages_types.h"
 
 //-------------------------------------------------------------------------------------------//
 // Defines to access message fields.
diff --git a/openair2/F1AP/dummy_enb.c b/openair2/F1AP/dummy_enb.c
index 8e185c951d..22627c8d92 100644
--- a/openair2/F1AP/dummy_enb.c
+++ b/openair2/F1AP/dummy_enb.c
@@ -47,3 +47,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
                    const int pdusession_id) {
 abort();
 }
+
+int dl_rrc_message(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc) {
+  abort();
+}
diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c
index efbc9f2c8b..b521d0c83d 100644
--- a/openair2/F1AP/f1ap_cu_task.c
+++ b/openair2/F1AP/f1ap_cu_task.c
@@ -172,6 +172,7 @@ void *F1AP_CU_task(void *arg) {
         LOG_I(F1AP, "CU Task Received F1AP_DL_RRC_MESSAGE\n");
         CU_send_DL_RRC_MESSAGE_TRANSFER(ITTI_MSG_DESTINATION_INSTANCE(received_msg),
                                         &F1AP_DL_RRC_MESSAGE(received_msg));
+        free(F1AP_DL_RRC_MESSAGE(received_msg).rrc_container);
         break;
 
       case F1AP_UE_CONTEXT_SETUP_REQ: // from rrc
diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.c b/openair2/F1AP/f1ap_du_rrc_message_transfer.c
index e158e9519a..d896a2640b 100644
--- a/openair2/F1AP/f1ap_du_rrc_message_transfer.c
+++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.c
@@ -56,6 +56,7 @@
 #include "intertask_interface.h"
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 
+#include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
 
 int DU_handle_DL_NR_RRC_MESSAGE_TRANSFER(instance_t       instance,
     uint32_t         assoc_id,
@@ -986,6 +987,16 @@ int DU_handle_DL_NR_RRC_MESSAGE_TRANSFER(instance_t       instance,
     }
   }
 
+  f1ap_dl_rrc_message_t dl_rrc = {
+    .rrc_container_length = ie->value.choice.RRCContainer.size,
+    .rrc_container = ie->value.choice.RRCContainer.buf,
+    .rnti = f1ap_get_rnti_by_du_id(DUtype, instance, du_ue_f1ap_id),
+    .srb_id = srb_id
+  };
+  int rc = dl_rrc_message(instance, &dl_rrc);
+  if (rc == 0)
+    return 0; /* has been handled, otherwise continue below */
+
   // decode RRC Container and act on the message type
   AssertFatal(srb_id<3,"illegal srb_id\n");
   MessageDef *msg = itti_alloc_new_message(TASK_DU_F1, 0, NR_DU_RRC_DL_INDICATION);
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
new file mode 100644
index 0000000000..578e4fb453
--- /dev/null
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c
@@ -0,0 +1,131 @@
+/*
+ * 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 "mac_rrc_dl_handler.h"
+
+#include "mac_proto.h"
+#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
+
+#include "NR_RRCSetup.h"
+#include "NR_DL-CCCH-Message.h"
+#include "NR_CellGroupConfig.h"
+
+int dl_rrc_message_rrcSetup(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc, NR_RRCSetup_t *rrcSetup);
+
+int dl_rrc_message(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc)
+{
+  /* dispatch message to dl_rrc_message_rrcSetup() and others, similar to as is
+   * done in the DU (should be the same here) */
+
+  if (dl_rrc->srb_id == 0) {
+
+    NR_DL_CCCH_Message_t *dl_ccch_msg = NULL;
+    asn_dec_rval_t dec_rval = uper_decode(NULL,
+                                          &asn_DEF_NR_DL_CCCH_Message,
+                                          (void **) &dl_ccch_msg,
+                                          dl_rrc->rrc_container,
+                                          dl_rrc->rrc_container_length,
+                                          0,
+                                          0);
+    AssertFatal(dec_rval.code == RC_OK, "could not decode F1AP message\n");
+
+    switch (dl_ccch_msg->message.choice.c1->present) {
+    case NR_DL_CCCH_MessageType__c1_PR_NOTHING:
+      LOG_W(NR_MAC, "Received NOTHING on DL-CCCH-Message\n");
+      break;
+    case NR_DL_CCCH_MessageType__c1_PR_rrcReject:
+      LOG_D(NR_MAC, "DL-CCCH/SRB0, received rrcReject for RNTI %04x\n", dl_rrc->rnti);
+      AssertFatal(0, "rrcReject not implemented yet\n");
+      break;
+    case NR_DL_CCCH_MessageType__c1_PR_rrcSetup:
+      LOG_I(NR_MAC, "DL-CCCH/SRB0, received rrcSetup for RNTI %04x\n", dl_rrc->rnti);
+      return dl_rrc_message_rrcSetup(module_id, dl_rrc, dl_ccch_msg->message.choice.c1->choice.rrcSetup);
+      break;
+    case NR_DL_CCCH_MessageType__c1_PR_spare2:
+      LOG_W(NR_MAC, "DL-CCCH/SRB0, received spare2\n");
+      break;
+    case NR_DL_CCCH_MessageType__c1_PR_spare1:
+      LOG_W(NR_MAC, "DL-CCCH/SRB0, received spare1\n");
+      break;
+    default:
+      AssertFatal(0 == 1, "Unknown DL-CCCH/SRB0 message %d\n", dl_ccch_msg->message.choice.c1->present);
+      break;
+    }
+    return 0;
+  }
+
+  return -1; /* not handled yet */
+}
+
+int dl_rrc_message_rrcSetup(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc, NR_RRCSetup_t *rrcSetup)
+{
+  DevAssert(rrcSetup != NULL);
+
+  NR_RRCSetup_IEs_t *rrcSetup_ies = rrcSetup->criticalExtensions.choice.rrcSetup;
+  AssertFatal(rrcSetup_ies->masterCellGroup.buf != NULL,"masterCellGroup is NULL\n");
+  NR_CellGroupConfig_t *cellGroup = NULL;
+  asn_dec_rval_t dec_rval = uper_decode(NULL,
+                                        &asn_DEF_NR_CellGroupConfig,
+                                        (void **)&cellGroup,
+                                        rrcSetup_ies->masterCellGroup.buf,
+                                        rrcSetup_ies->masterCellGroup.size,
+                                        0,
+                                        0);
+  AssertFatal(dec_rval.code == RC_OK, "could not decode masterCellGroup\n");
+
+  /* there might be a memory leak for the cell group if we call this multiple
+   * times. Also, the first parameters of rrc_mac_config_req_gNB() are only
+   * relevant when setting the scc, which we don't do (and cannot do) here. */
+  rrc_pdsch_AntennaPorts_t pap = {0};
+  rrc_mac_config_req_gNB(module_id,
+                         pap, /* only when scc != NULL */
+                         0, /* only when scc != NULL */
+                         0, /* only when scc != NULL */
+                         0, /* only when scc != NULL */
+                         NULL, /* scc */
+                         NULL, /* mib */
+                         NULL, /* sib1 */
+                         0, /* add_ue */
+                         dl_rrc->rnti,
+                         cellGroup);
+
+  /* TODO: drop the RRC context */
+  gNB_RRC_INST *rrc = RC.nrrrc[module_id];
+  struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, dl_rrc->rnti);
+  gNB_RRC_UE_t *ue_p = &ue_context_p->ue_context;
+  ue_context_p->ue_context.SRB_configList = rrcSetup_ies->radioBearerConfig.srb_ToAddModList;
+  ue_context_p->ue_context.masterCellGroup = cellGroup;
+
+  /* TODO: this should pass through RLC and NOT the RRC with a shared buffer */
+  AssertFatal(ue_p->Srb0.Active == 1,"SRB0 is not active\n");
+  memcpy(ue_p->Srb0.Tx_buffer.Payload, dl_rrc->rrc_container, dl_rrc->rrc_container_length);
+  ue_p->Srb0.Tx_buffer.payload_size = dl_rrc->rrc_container_length;
+
+  protocol_ctxt_t ctxt = { .module_id = module_id, .rnti = dl_rrc->rnti };
+  nr_rrc_rlc_config_asn1_req(&ctxt,
+                             ue_context_p->ue_context.SRB_configList,
+                             NULL,
+                             NULL,
+                             NULL,
+                             cellGroup->rlc_BearerToAddModList);
+
+  return 0;
+}
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h
new file mode 100644
index 0000000000..ecbc95eef0
--- /dev/null
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h
@@ -0,0 +1,30 @@
+/*
+ * 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 MAC_RRC_DL_HANDLER_H
+#define MAC_RRC_DL_HANDLER_H
+
+#include "platform_types.h"
+#include "f1ap_messages_types.h"
+
+int dl_rrc_message(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc);
+
+#endif /* MAC_RRC_DL_HANDLER_H */
diff --git a/openair2/RRC/NR/mac_rrc_dl.h b/openair2/RRC/NR/mac_rrc_dl.h
new file mode 100644
index 0000000000..1943490cd6
--- /dev/null
+++ b/openair2/RRC/NR/mac_rrc_dl.h
@@ -0,0 +1,34 @@
+/*
+ * 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:
+ *      conmnc_digit_lengtht@openairinterface.org
+ */
+
+#ifndef MAC_RRC_DL_H
+#define MAC_RRC_DL_H
+
+#include "platform_types.h"
+#include "f1ap_messages_types.h"
+
+typedef void (*dl_rrc_message_transfer_func_t)(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc);
+
+struct nr_mac_rrc_dl_if_s;
+void mac_rrc_dl_direct_init(struct nr_mac_rrc_dl_if_s *mac_rrc);
+void mac_rrc_dl_f1ap_init(struct nr_mac_rrc_dl_if_s *mac_rrc);
+
+#endif /* MAC_RRC_DL_H */
diff --git a/openair2/RRC/NR/mac_rrc_dl_direct.c b/openair2/RRC/NR/mac_rrc_dl_direct.c
new file mode 100644
index 0000000000..b3ba7b9ee5
--- /dev/null
+++ b/openair2/RRC/NR/mac_rrc_dl_direct.c
@@ -0,0 +1,52 @@
+/*
+ * 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:
+ *      conmnc_digit_lengtht@openairinterface.org
+ */
+
+#include "nr_rrc_defs.h"
+
+#include "mac_rrc_dl.h"
+#include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
+
+static void dl_rrc_message_transfer_direct(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc)
+{
+#ifdef ITTI_SIM
+  const int len = dl_rrc->rrc_container_length;
+  LOG_I(NR_RRC,
+        PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n",
+        PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP),
+        len);
+  uint8_t *message_buffer;
+  message_buffer = itti_malloc(TASK_RRC_GNB, TASK_RRC_UE_SIM, len);
+  memcpy (message_buffer, dl_rrc->rrc_container, len);
+  message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_CCCH_DATA_IND);
+  GNB_RRC_CCCH_DATA_IND (message_p).sdu = message_buffer;
+  GNB_RRC_CCCH_DATA_IND (message_p).size = len;
+  itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p);
+#else
+  /* TODO how to manage inter-thread communication? */
+
+  dl_rrc_message(module_id, dl_rrc);
+#endif
+}
+
+void mac_rrc_dl_direct_init(nr_mac_rrc_dl_if_t *mac_rrc)
+{
+  mac_rrc->dl_rrc_message_transfer = dl_rrc_message_transfer_direct;
+}
diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c
new file mode 100644
index 0000000000..40f3b4b6ea
--- /dev/null
+++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c
@@ -0,0 +1,44 @@
+/*
+ * 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:
+ *      conmnc_digit_lengtht@openairinterface.org
+ */
+
+#include "mac_rrc_dl.h"
+#include "nr_rrc_defs.h"
+
+static void dl_rrc_message_transfer_f1ap(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc)
+{
+  /* TODO call F1AP function directly? no real-time constraint here */
+
+  MessageDef *message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_DL_RRC_MESSAGE);
+  f1ap_dl_rrc_message_t *msg = &F1AP_DL_RRC_MESSAGE(message_p);
+  *msg = *dl_rrc;
+  if (dl_rrc->rrc_container) {
+    msg->rrc_container = malloc(dl_rrc->rrc_container_length);
+    AssertFatal(msg->rrc_container != NULL, "out of memory\n");
+    msg->rrc_container_length = dl_rrc->rrc_container_length;
+    memcpy(msg->rrc_container, dl_rrc->rrc_container, dl_rrc->rrc_container_length);
+  }
+  itti_send_msg_to_task (TASK_CU_F1, module_id, message_p);
+}
+
+void mac_rrc_dl_f1ap_init(nr_mac_rrc_dl_if_t *mac_rrc)
+{
+  mac_rrc->dl_rrc_message_transfer = dl_rrc_message_transfer_f1ap;
+}
diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h
index b6a92db7a8..c709a158da 100644
--- a/openair2/RRC/NR/nr_rrc_defs.h
+++ b/openair2/RRC/NR/nr_rrc_defs.h
@@ -42,6 +42,7 @@
 #include "COMMON/platform_types.h"
 #include "RRC/LTE/rrc_defs.h"
 //#include "LAYER2/RLC/rlc.h"
+#include "mac_rrc_dl.h"
 
 //#include "COMMON/mac_rrc_primitives.h"
 
@@ -480,6 +481,11 @@ typedef struct {
   int do_drb_integrity;
 } nr_security_configuration_t;
 
+typedef struct nr_mac_rrc_dl_if_s {
+  /* TODO add other message types as necessary */
+  dl_rrc_message_transfer_func_t dl_rrc_message_transfer;
+} nr_mac_rrc_dl_if_t;
+
 //---NR---(completely change)---------------------
 typedef struct gNB_RRC_INST_s {
 
@@ -529,6 +535,8 @@ typedef struct gNB_RRC_INST_s {
 
   // security configuration (preferred algorithms)
   nr_security_configuration_t security;
+
+  nr_mac_rrc_dl_if_t mac_rrc;
 } gNB_RRC_INST;
 
 #include "nr_rrc_proto.h" //should be put here otherwise compilation error
diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c
index 8c6c583289..4340bfa6bd 100755
--- a/openair2/RRC/NR/rrc_gNB.c
+++ b/openair2/RRC/NR/rrc_gNB.c
@@ -196,6 +196,26 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration
   }
 }
 
+static void rrc_gNB_mac_rrc_init(gNB_RRC_INST *rrc)
+{
+  switch (rrc->node_type) {
+    case ngran_gNB_CU:
+      mac_rrc_dl_f1ap_init(&rrc->mac_rrc);
+      break;
+    case ngran_gNB_DU:
+      /* silently drop this, as we currently still need the RRC at the DU. As
+       * soon as this is not the case anymore, we can add the AssertFatal() */
+      //AssertFatal(1==0,"nothing to do for DU\n");
+      break;
+    case ngran_gNB:
+      mac_rrc_dl_direct_init(&rrc->mac_rrc);
+      break;
+    default:
+      AssertFatal(0 == 1, "Unknown node type %d\n", rrc->node_type);
+      break;
+  }
+}
+
 char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigurationReq *configuration) {
   protocol_ctxt_t      ctxt = { 0 };
   gNB_RRC_INST         *rrc=RC.nrrrc[gnb_mod_idP];
@@ -203,13 +223,13 @@ char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigu
   LOG_I(NR_RRC,
         PROTOCOL_NR_RRC_CTXT_FMT" Init...\n",
         PROTOCOL_NR_RRC_CTXT_ARGS(&ctxt));
-
   AssertFatal(rrc != NULL, "RC.nrrrc not initialized!");
   AssertFatal(NUMBER_OF_UE_MAX < (module_id_t)0xFFFFFFFFFFFFFFFF, " variable overflow");
   AssertFatal(configuration!=NULL,"configuration input is null\n");
   rrc->module_id = gnb_mod_idP;
   rrc->Nb_ue = 0;
   rrc->carrier.Srb0.Active = 0;
+  rrc_gNB_mac_rrc_init(rrc);
   nr_uid_linear_allocator_init(&rrc->uid_allocator);
   RB_INIT(&rrc->rrc_ue_head);
   rrc->initial_id2_s1ap_ids = hashtable_create (NUMBER_OF_UE_MAX * 2, NULL, NULL);
@@ -325,14 +345,14 @@ rrc_gNB_generate_RRCSetup(
 )
 //-----------------------------------------------------------------------------
 {
-  LOG_D(NR_RRC, "rrc_gNB_generate_RRCSetup \n");
-  MessageDef                    *message_p;
+  LOG_I(NR_RRC, "rrc_gNB_generate_RRCSetup for RNTI %04x\n", ctxt_pP->rnti);
 
   // T(T_GNB_RRC_SETUP,
   //   T_INT(ctxt_pP->module_id),
   //   T_INT(ctxt_pP->frame),
   //   T_INT(ctxt_pP->subframe),
   //   T_INT(ctxt_pP->rnti));
+
   gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context;
   gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
   NR_ServingCellConfig_t *servingcellconfigdedicated = rrc->configuration.scd;
@@ -351,87 +371,22 @@ rrc_gNB_generate_RRCSetup(
               ue_p->Srb0.Tx_buffer.payload_size,
               "[MSG] RRC Setup\n");
 
-  switch (rrc->node_type) {
-    case ngran_gNB_CU:
-      // create an ITTI message
-      /* TODO: F1 IDs ar missing in RRC */
-      nr_rrc_pdcp_config_asn1_req(ctxt_pP,
-				  ue_context_pP->ue_context.SRB_configList,
-				  NULL,
-				  NULL,
-				  0,
-				  NULL,
-				  NULL,
-				  NULL,
-				  NULL,
-				  NULL,
-				  NULL,
-				  NULL);
-      message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_DL_RRC_MESSAGE);
-      F1AP_DL_RRC_MESSAGE (message_p).rrc_container        =  (uint8_t *)ue_p->Srb0.Tx_buffer.Payload;
-      F1AP_DL_RRC_MESSAGE (message_p).rrc_container_length = ue_p->Srb0.Tx_buffer.payload_size;
-      F1AP_DL_RRC_MESSAGE (message_p).gNB_CU_ue_id         = 0;
-      F1AP_DL_RRC_MESSAGE (message_p).gNB_DU_ue_id         = 0;
-      F1AP_DL_RRC_MESSAGE (message_p).old_gNB_DU_ue_id     = 0xFFFFFFFF; // unknown
-      F1AP_DL_RRC_MESSAGE (message_p).rnti                 = ue_p->rnti;
-      F1AP_DL_RRC_MESSAGE (message_p).srb_id               = CCCH;
-      F1AP_DL_RRC_MESSAGE (message_p).execute_duplication  = 1;
-      F1AP_DL_RRC_MESSAGE (message_p).RAT_frequency_priority_information.en_dc = 0;
-      itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p);
-      LOG_D(NR_RRC, "Send F1AP_DL_RRC_MESSAGE with ITTI\n");
-
-    break;
-
-    case ngran_gNB_DU:
-      // nothing to do for DU
-      AssertFatal(1==0,"nothing to do for DU\n");
-      break;
-
-    case ngran_gNB:
-    {
-      // rrc_mac_config_req_gNB
+  // activate release timer, if RRCSetupComplete not received after 100 frames, remove UE
+  ue_context_pP->ue_context.ue_release_timer = 1;
+  // remove UE after 10 frames after RRCConnectionRelease is triggered
+  ue_context_pP->ue_context.ue_release_timer_thres = 1000;
 
-#ifdef ITTI_SIM
-      LOG_I(NR_RRC,
-            PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n",
-            PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP),
-            ue_p->Srb0.Tx_buffer.payload_size);
-      uint8_t *message_buffer;
-      message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM,
-                ue_p->Srb0.Tx_buffer.payload_size);
-      memcpy (message_buffer, (uint8_t*)ue_p->Srb0.Tx_buffer.Payload, ue_p->Srb0.Tx_buffer.payload_size);
-      message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_CCCH_DATA_IND);
-      GNB_RRC_CCCH_DATA_IND (message_p).sdu = message_buffer;
-      GNB_RRC_CCCH_DATA_IND (message_p).size  = ue_p->Srb0.Tx_buffer.payload_size;
-      itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p);
-#else
-      LOG_D(NR_RRC,
-	    PROTOCOL_NR_RRC_CTXT_UE_FMT" RRC_gNB --- MAC_CONFIG_REQ  (SRB1) ---> MAC_gNB\n",
-	    PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP));
-      LOG_I(NR_RRC,
-	    PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n",
-	    PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP),
-	    ue_p->Srb0.Tx_buffer.payload_size);
-      // activate release timer, if RRCSetupComplete not received after 100 frames, remove UE
-      ue_context_pP->ue_context.ue_release_timer = 1;
-      // remove UE after 10 frames after RRCConnectionRelease is triggered
-      ue_context_pP->ue_context.ue_release_timer_thres = 1000;
-      /* init timers */
-      //   ue_context_pP->ue_context.ue_rrc_inactivity_timer = 0;
-
-      // configure MAC
-
-      apply_macrlc_config(rrc,ue_context_pP,ctxt_pP);
-
-      apply_pdcp_config(ue_context_pP,ctxt_pP);
-#endif
-    }
-    break;
+  /* TODO: this should go through the E1 interface */
+  apply_pdcp_config(ue_context_pP,ctxt_pP);
 
-    default:
-      LOG_W(NR_RRC, "Unknown node type %d\n", rrc->node_type);
-      break;
-  }
+  f1ap_dl_rrc_message_t dl_rrc = {
+    .old_gNB_DU_ue_id = 0xFFFFFF,
+    .rrc_container = (uint8_t *)ue_p->Srb0.Tx_buffer.Payload,
+    .rrc_container_length = ue_p->Srb0.Tx_buffer.payload_size,
+    .rnti = ue_p->rnti,
+    .srb_id = CCCH
+  };
+  rrc->mac_rrc.dl_rrc_message_transfer(ctxt_pP->module_id, &dl_rrc);
 }
 
 //-----------------------------------------------------------------------------
@@ -3041,67 +2996,7 @@ static int  rrc_process_DU_DL(MessageDef *msg_p, const char *msg_name, instance_
     rrc_gNB_get_ue_context(rrc, ctxt.rnti);
 
   if (req->srb_id == 0) {
-    NR_DL_CCCH_Message_t *dl_ccch_msg=NULL;
-    asn_dec_rval_t dec_rval;
-    dec_rval = uper_decode(NULL,
-                           &asn_DEF_NR_DL_CCCH_Message,
-                           (void **)&dl_ccch_msg,
-                           req->buf->data,
-                           req->buf->size,0,0);
-    AssertFatal(dec_rval.code == RC_OK, "could not decode F1AP message\n");
-
-    switch (dl_ccch_msg->message.choice.c1->present) {
-    case NR_DL_CCCH_MessageType__c1_PR_NOTHING:
-      LOG_I(F1AP,"Received PR_NOTHING on DL-CCCH-Message\n");
-      break;
-
-    case NR_DL_CCCH_MessageType__c1_PR_rrcReject:
-      LOG_I(F1AP,"Logical Channel DL-CCCH (SRB0), Received RRCReject\n");
-      break;
-
-    case NR_DL_CCCH_MessageType__c1_PR_rrcSetup: {
-      LOG_I(F1AP, "Logical Channel DL-CCCH (SRB0), Received RRCSetup RNTI %x\n",
-	    req->rnti);
-      // Get configuration
-      NR_RRCSetup_t *rrcSetup = dl_ccch_msg->message.choice.c1->choice.rrcSetup;
-      AssertFatal(rrcSetup!=NULL, "rrcSetup is null\n");
-      NR_RRCSetup_IEs_t *rrcSetup_ies = rrcSetup->criticalExtensions.choice.rrcSetup;
-      ue_context_p->ue_context.SRB_configList = rrcSetup_ies->radioBearerConfig.srb_ToAddModList;
-      AssertFatal(rrcSetup_ies->masterCellGroup.buf!=NULL,"masterCellGroup is null\n");
-      asn_dec_rval_t dec_rval;
-      dec_rval = uper_decode(NULL,
-			     &asn_DEF_NR_CellGroupConfig,
-			     (void **)&ue_context_p->ue_context.masterCellGroup,
-			     rrcSetup_ies->masterCellGroup.buf,
-			     rrcSetup_ies->masterCellGroup.size,0,0);
-      AssertFatal(dec_rval.code == RC_OK, "could not decode masterCellGroup\n");
-      apply_macrlc_config(rrc,ue_context_p,&ctxt);
-      gNB_RRC_UE_t *ue_p = &ue_context_p->ue_context;
-      AssertFatal(ue_p->Srb0.Active == 1,"SRB0 is not active\n");
-      memcpy((void *)ue_p->Srb0.Tx_buffer.Payload,
-	     (void *)req->buf->data,
-	     req->buf->size); // ie->value.choice.RRCContainer.size
-      ue_p->Srb0.Tx_buffer.payload_size = req->buf->size;
-      break;
-    } // case
-      
-    case NR_DL_CCCH_MessageType__c1_PR_spare2:
-      LOG_I(F1AP,
-	    "Logical Channel DL-CCCH (SRB0), Received spare2\n");
-      break;
-      
-    case NR_DL_CCCH_MessageType__c1_PR_spare1:
-      LOG_I(F1AP,
-	    "Logical Channel DL-CCCH (SRB0), Received spare1\n");
-      break;
-      
-    default:
-      AssertFatal(1==0,
-		  "Unknown message\n");
-      break;
-    }// switch case
-    
-    return(0);
+    AssertFatal(0 == 1, "should pass through dl_rrc_message()\n");
   } else if (req->srb_id == 1) {
     NR_DL_DCCH_Message_t *dl_dcch_msg=NULL;
     asn_dec_rval_t dec_rval;
-- 
2.26.2