diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index f5c5425737bae21285201b38aef781c91e46bdf7..7ad42079de4b723622bfc9d411548f4629103857 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -2062,6 +2062,34 @@ target_link_libraries (lte-softmodem
   NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
   -Wl,--end-group z dl)
 
+add_executable(cu_test
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/cu_test.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_handler.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_common.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_net_comm.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_async.c
+  ${T_SOURCE}
+)
+target_link_libraries(cu_test
+  ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FSPT_MSG_LIB} ${PROTOBUF_LIB}
+  ${PROTO_AGENT_LIB} pthread UTIL ${T_LIB} dl
+)
+
+add_executable(du_test
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/du_test.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_handler.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_common.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_net_comm.c
+  ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_async.c
+  ${T_SOURCE}
+)
+target_link_libraries(du_test
+  ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FSPT_MSG_LIB} ${PROTOBUF_LIB}
+  ${PROTO_AGENT_LIB} pthread UTIL ${T_LIB} dl
+)
+
 target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES})
 target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp  ${XFORMS_LIBRARIES} ${PROTOBUF_LIB}  ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES})
 target_link_libraries (lte-softmodem ${LIB_LMS_LIBRARIES})
@@ -2310,7 +2338,7 @@ if (${T_TRACER})
         #all "add_executable" definitions (except tests, rb_tool, updatefw)
         lte-softmodem lte-softmodem-nos1 lte-uesoftmodem lte-uesoftmodem-nos1
         dlsim_tm4 dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim
-        pdcchsim pucchsim prachsim syncsim ulsim
+        pdcchsim pucchsim prachsim syncsim ulsim cu_test du_test
         #all "add_library" definitions
         ITTI RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB F1AP_LIB F1AP
         oai_exmimodevif oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif
diff --git a/openair2/LAYER2/PROTO_AGENT/cu_test.c b/openair2/LAYER2/PROTO_AGENT/cu_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..923b70607cb634d61a55bc3e1b89d4248d8a11fb
--- /dev/null
+++ b/openair2/LAYER2/PROTO_AGENT/cu_test.c
@@ -0,0 +1,169 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "ENB_APP/enb_paramdef.h"
+#include "LAYER2/PROTO_AGENT/proto_agent.h"
+#define BUF_MAX 1400
+
+int recv_client = 0;
+FILE *output;
+
+void usage(char *prg_name)
+{
+  fprintf(stderr, "usage: %s <file or ->\n", prg_name);
+  fprintf(stderr, " - is stdin\n");
+  fprintf(stderr, " received packets are written to stdout\n");
+}
+
+long uelapsed(struct timeval *s, struct timeval *e)
+{
+  return e->tv_sec * 1000000 + e->tv_usec - (s->tv_sec * 1000000 + s->tv_usec);
+}
+
+boolean_t
+pdcp_data_ind(
+  const protocol_ctxt_t* const ctxt_pP,
+  const srb_flag_t   srb_flagP,
+  const MBMS_flag_t  MBMS_flagP,
+  const rb_id_t      rb_idP,
+  const sdu_size_t   sdu_buffer_sizeP,
+  mem_block_t* const sdu_buffer_pP
+)
+{
+  fwrite(sdu_buffer_pP->data, sdu_buffer_sizeP, 1, stdout);
+  free_mem_block(sdu_buffer_pP, __func__);
+  fflush(stdout);
+  recv_client = 1;
+  return 0;
+}
+
+int main(int argc, char *argv[])
+{
+  const cudu_params_t params = {
+    .local_interface = "lo",
+    .local_ipv4_address = "192.168.12.45",
+    .local_port = 6464,
+    .remote_ipv4_address = "192.168.12.45",
+    .remote_port = 6465
+  };
+
+  protocol_ctxt_t p;
+  memset(&p, 0, sizeof p);
+  mem_block_t mem;
+  char s[BUF_MAX];
+  size_t size, totsize = 0;
+  struct timeval t_start, t_end;
+  FILE *f;
+
+  if (argc != 2) {
+    usage(argv[0]);
+    return 1;
+  }
+
+  if (strcmp(argv[1], "-") == 0) {
+    f = stdin;
+  } else {
+    f = fopen(argv[1], "r");
+  }
+  if (!f) {
+    fprintf(stderr, "cannot open %s: %s\n", argv[1], strerror(errno));
+    return 2;
+  }
+
+  pool_buffer_init();
+  if (proto_agent_start(0, &params) != 0) {
+    fprintf(stderr, "error on proto_agent_start()\n");
+    return 3;
+  }
+
+  /* wait for first packet of client */
+  while (!recv_client) sleep(1);
+  fprintf(stderr, "reading file\n");
+
+  /* now send back at the same time */
+  gettimeofday(&t_start, NULL);
+  while ((size = fread(s, 1, BUF_MAX, f)) > 0) {
+    usleep(100);
+    totsize += size;
+    mem.data = &s[0];
+    proto_agent_send_rlc_data_req(&p, 0, 0, 0, 0, 0, size, &mem);
+  }
+  gettimeofday(&t_end, NULL);
+  fclose(f);
+  long us = uelapsed(&t_start, &t_end);
+  fprintf(stderr, "read %ld bytes in %ld ms -> %.3fMB/s, %.3fMbps\n",
+          totsize, us / 1000, ((float) totsize ) / us,
+          ((float) totsize) / us * 8);
+  fprintf(stderr, "check files using 'diff afile bfile'\n");
+
+  /* give some time in case the other direction is slower */
+  sleep(60);
+  return 0;
+}
+
+/*
+ *********************************************************
+ * arbitrary functions, needed for linking (used or not) *
+ *********************************************************
+ */
+
+rlc_op_status_t rlc_data_req     (const protocol_ctxt_t* const ctxt_pP,
+                                  const srb_flag_t   srb_flagP,
+                                  const MBMS_flag_t  MBMS_flagP,
+                                  const rb_id_t      rb_idP,
+                                  const mui_t        muiP,
+                                  confirm_t    confirmP,
+                                  sdu_size_t   sdu_sizeP,
+                                  mem_block_t *sdu_pP
+#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+                                  ,const uint32_t * const sourceL2Id
+                                  ,const uint32_t * const destinationL2Id
+#endif
+                                  )
+{
+  fprintf(stderr, "This should never be called on the CU\n");
+  exit(1);
+}
+
+pthread_t new_thread(void *(*f)(void *), void *b) {
+  pthread_t t;
+  pthread_attr_t att;
+
+  if (pthread_attr_init(&att)){
+    fprintf(stderr, "pthread_attr_init err\n");
+    exit(1);
+  }
+  if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) {
+    fprintf(stderr, "pthread_attr_setdetachstate err\n");
+    exit(1);
+  }
+  if (pthread_create(&t, &att, f, b)) {
+    fprintf(stderr, "pthread_create err\n");
+    exit(1);
+  }
+  if (pthread_attr_destroy(&att)) {
+    fprintf(stderr, "pthread_attr_destroy err\n");
+    exit(1);
+  }
+
+  return t;
+}
+
+int log_header(char *log_buffer, int buffsize, int comp, int level,const char *format)
+{
+  return 0;
+}
+
+int config_get(paramdef_t *params,int numparams, char *prefix)
+{
+  return 0;
+}
+
+int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
+{
+  return 0;
+}
diff --git a/openair2/LAYER2/PROTO_AGENT/du_test.c b/openair2/LAYER2/PROTO_AGENT/du_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..e23503cc74dec288a1e9bfa6f69372a9b461dc1a
--- /dev/null
+++ b/openair2/LAYER2/PROTO_AGENT/du_test.c
@@ -0,0 +1,162 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "ENB_APP/enb_paramdef.h"
+#include "LAYER2/PROTO_AGENT/proto_agent.h"
+
+#define BUF_MAX 1400
+
+void usage(char *prg_name)
+{
+  fprintf(stderr, "usage: %s <file or ->\n", prg_name);
+  fprintf(stderr, " - is stdin\n");
+  fprintf(stderr, " received packets are written to stdout\n");
+}
+
+long uelapsed(struct timeval *s, struct timeval *e)
+{
+  return e->tv_sec * 1000000 + e->tv_usec - (s->tv_sec * 1000000 + s->tv_usec);
+}
+
+
+rlc_op_status_t rlc_data_req     (const protocol_ctxt_t* const ctxt_pP,
+                                  const srb_flag_t   srb_flagP,
+                                  const MBMS_flag_t  MBMS_flagP,
+                                  const rb_id_t      rb_idP,
+                                  const mui_t        muiP,
+                                  confirm_t    confirmP,
+                                  sdu_size_t   sdu_sizeP,
+                                  mem_block_t *sdu_pP
+#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+                                  ,const uint32_t * const sourceL2Id
+                                  ,const uint32_t * const destinationL2Id
+#endif
+                                  )
+{
+  fwrite(sdu_pP->data, sdu_sizeP, 1, stdout);
+  free_mem_block(sdu_pP, __func__);
+  fflush(stdout);
+  return 0;
+}
+
+int main(int argc, char *argv[])
+{
+  const cudu_params_t params = {
+    .local_interface = "lo",
+    .local_ipv4_address = "192.168.12.45",
+    .local_port = 6465,
+    .remote_ipv4_address = "192.168.12.45",
+    .remote_port = 6464
+  };
+
+  protocol_ctxt_t p;
+  memset(&p, 0, sizeof p);
+  mem_block_t mem;
+  char s[BUF_MAX];
+  size_t size, totsize = 0;
+  struct timeval t_start, t_end;
+  FILE *f;
+
+  if (argc != 2) {
+    usage(argv[0]);
+    return 1;
+  }
+
+  if (strcmp(argv[1], "-") == 0) {
+    f = stdin;
+  } else {
+    f = fopen(argv[1], "r");
+  }
+  if (!f) {
+    fprintf(stderr, "cannot open %s: %s\n", argv[1], strerror(errno));
+    return 2;
+  }
+
+  pool_buffer_init();
+  if (proto_agent_start(0, &params) != 0) {
+    fprintf(stderr, "error on proto_agent_start()\n");
+    return 3;
+  }
+
+  gettimeofday(&t_start, NULL);
+  while ((size = fread(s, 1, BUF_MAX, f)) > 0) {
+    usleep(100);
+    totsize += size;
+    mem.data = &s[0];
+    proto_agent_send_pdcp_data_ind(&p, 0, 0, 0, size, &mem);
+  }
+  gettimeofday(&t_end, NULL);
+  fclose(f);
+  long us = uelapsed(&t_start, &t_end);
+  fprintf(stderr, "read %ld bytes in %ld ms -> %.3fMB/s, %.3fMbps\n",
+          totsize, us / 1000, ((float) totsize ) / us,
+          ((float) totsize) / us * 8);
+  fprintf(stderr, "check files using 'diff afile bfile'\n");
+
+  /* wait, we are possibly receiving data */
+  sleep(60);
+  return 0;
+}
+
+/*
+ *********************************************************
+ * arbitrary functions, needed for linking (used or not) *
+ *********************************************************
+ */
+
+boolean_t
+pdcp_data_ind(
+  const protocol_ctxt_t* const ctxt_pP,
+  const srb_flag_t   srb_flagP,
+  const MBMS_flag_t  MBMS_flagP,
+  const rb_id_t      rb_idP,
+  const sdu_size_t   sdu_buffer_sizeP,
+  mem_block_t* const sdu_buffer_pP
+)
+{
+  fprintf(stderr, "This should never be called on the DU\n");
+  exit(1);
+}
+
+pthread_t new_thread(void *(*f)(void *), void *b) {
+  pthread_t t;
+  pthread_attr_t att;
+
+  if (pthread_attr_init(&att)){
+    fprintf(stderr, "pthread_attr_init err\n");
+    exit(1);
+  }
+  if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) {
+    fprintf(stderr, "pthread_attr_setdetachstate err\n");
+    exit(1);
+  }
+  if (pthread_create(&t, &att, f, b)) {
+    fprintf(stderr, "pthread_create err\n");
+    exit(1);
+  }
+  if (pthread_attr_destroy(&att)) {
+    fprintf(stderr, "pthread_attr_destroy err\n");
+    exit(1);
+  }
+
+  return t;
+}
+
+int log_header(char *log_buffer, int buffsize, int comp, int level,const char *format)
+{
+  return 0;
+}
+
+int config_get(paramdef_t *params,int numparams, char *prefix)
+{
+  return 0;
+}
+
+int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
+{
+  return 0;
+}