From dc9cada6c2f3841677ce00801f3ec7c3c95fe3b2 Mon Sep 17 00:00:00 2001
From: Navid Nikaein <navid.nikaein@eurecom.fr>
Date: Fri, 8 Dec 2017 18:05:42 +0100
Subject: [PATCH] Add PDCP stats and update agent and RAN APIs

---
 cmake_targets/CMakeLists.txt                  |   2 +
 .../CONTROL_MODULES/MAC/flexran_agent_mac.c   |   2 +-
 .../CONTROL_MODULES/PDCP/flexran_agent_pdcp.c | 168 ++++++++++
 .../CONTROL_MODULES/PDCP/flexran_agent_pdcp.h |  64 ++++
 .../PDCP/flexran_agent_pdcp_defs.h            |  63 ++++
 .../CONTROL_MODULES/RRC/flexran_agent_rrc.c   | 314 +++++++-----------
 .../CONTROL_MODULES/RRC/flexran_agent_rrc.h   |  52 ++-
 .../RRC/flexran_agent_rrc_defs.h              |  64 ++--
 openair2/ENB_APP/MESSAGES/V2/flexran.proto    |   1 +
 .../ENB_APP/MESSAGES/V2/stats_common.proto    |  21 ++
 .../ENB_APP/MESSAGES/V2/stats_messages.proto  |   6 +-
 .../ENB_APP/MESSAGES/V2/time_common.proto     |   1 +
 openair2/ENB_APP/flexran_agent.c              |   3 +
 openair2/ENB_APP/flexran_agent.h              |   1 +
 openair2/ENB_APP/flexran_agent_defs.h         |   5 +
 openair2/ENB_APP/flexran_agent_extern.h       |   7 +
 openair2/ENB_APP/flexran_agent_handler.c      |  25 +-
 openair2/ENB_APP/flexran_agent_ran_api.c      |  90 +++++
 openair2/ENB_APP/flexran_agent_ran_api.h      |  55 +++
 openair2/LAYER2/PDCP_v10.1.0/pdcp.c           | 187 ++++++++---
 openair2/LAYER2/PDCP_v10.1.0/pdcp.h           |  46 ++-
 21 files changed, 880 insertions(+), 297 deletions(-)
 create mode 100644 openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c
 create mode 100644 openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h
 create mode 100644 openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 734bfccf2d..6399f02ef0 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -762,6 +762,7 @@ include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/DEFS")
 include_directories("${OPENAIR2_DIR}/ENB_APP")
 include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC")
 include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC")
+include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP")
 include_directories("${OPENAIR2_DIR}/UTIL/OSA")
 include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds6.1.1/liblfds611/inc")
 include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds7.0.0/liblfds700/inc")
@@ -852,6 +853,7 @@ if (FLEXRAN_AGENT_SB_IF)
     ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common_internal.c
     ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
     ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
+    ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c
     ${OPENAIR2_DIR}/ENB_APP/flexran_agent.c
     ${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c
     ${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c
diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
index 60cdba76aa..736cdb67e0 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
+++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
@@ -128,7 +128,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id,
                               rlc_reports[j]->retransmission_queue_hol_delay = 100;
                               rlc_reports[j]->has_retransmission_queue_hol_delay = 0;
                               //TODO DONE:Set current size of the pending message in bytes
-                              rlc_reports[j]->status_pdu_size = flexran_get_tx_queue_size(enb_id, i, j + 1);
+                              rlc_reports[j]->status_pdu_size = flexran_get_num_pdus_buffer(enb_id , i, j + 1);
                               rlc_reports[j]->has_status_pdu_size = 1;
 
                         }
diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c
new file mode 100644
index 0000000000..ecc40cd89a
--- /dev/null
+++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c
@@ -0,0 +1,168 @@
+/*
+ * 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.0  (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
+ */ 
+
+/*! \file flexran_agent_pdcp.c
+ * \brief FlexRAN agent Control Module PDCP 
+ * \author shahab SHARIAT BAGHERI
+ * \date 2017
+ * \version 0.1
+ */
+
+#include "flexran_agent_pdcp.h"
+
+
+/*Trigger boolean for PDCP measurement*/
+bool triggered_pdcp = false;
+/*Flags showing if a pdcp agent has already been registered*/
+unsigned int pdcp_agent_registered[NUM_MAX_ENB];
+
+/*Array containing the Agent-PDCP interfaces*/
+AGENT_PDCP_xface *agent_pdcp_xface[NUM_MAX_ENB];
+
+// NUMBER_OF_UE_MAX
+
+void flexran_agent_pdcp_aggregate_stats(const mid_t mod_id,
+					const mid_t ue_id,
+					Protocol__FlexPdcpStats *pdcp_aggr_stats){
+
+  int lcid=0;
+  /* only calculate the DRBs */ 
+  //LOG_I(FLEXRAN_AGENT, "enb %d ue %d \n", mod_id, ue_id);
+  
+  for (lcid=NUM_MAX_SRB ; lcid < NUM_MAX_SRB + NUM_MAX_DRB; lcid++){
+    
+    pdcp_aggr_stats->pkt_tx += flexran_get_pdcp_tx(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_tx_bytes += flexran_get_pdcp_tx_bytes(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_tx_rate_s += flexran_get_pdcp_tx_rate_s(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_tx_throughput_s += flexran_get_pdcp_tx_throughput_s(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_tx_aiat += flexran_get_pdcp_tx_aiat(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_tx_aiat_s += flexran_get_pdcp_tx_aiat_s(mod_id,ue_id,lcid);
+    
+      
+    pdcp_aggr_stats->pkt_rx += flexran_get_pdcp_rx(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_rx_bytes += flexran_get_pdcp_rx_bytes(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_rx_rate_s += flexran_get_pdcp_rx_rate_s(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_rx_goodput_s += flexran_get_pdcp_rx_goodput_s(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_rx_aiat += flexran_get_pdcp_rx_aiat(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_rx_aiat_s += flexran_get_pdcp_rx_aiat_s(mod_id,ue_id,lcid);
+    pdcp_aggr_stats->pkt_rx_oo += flexran_get_pdcp_rx_oo(mod_id,ue_id,lcid);
+    
+  }
+  
+}
+
+
+int flexran_agent_pdcp_stats_reply(mid_t mod_id,       
+				   const report_config_t *report_config,
+				   Protocol__FlexUeStatsReport **ue_report,
+				   Protocol__FlexCellStatsReport **cell_report) {
+  
+  
+  // Protocol__FlexHeader *header;
+  int i, j, k;
+  // int cc_id = 0;
+ 
+  
+  /* Allocate memory for list of UE reports */
+  if (report_config->nr_ue > 0) {
+    
+    for (i = 0; i < report_config->nr_ue; i++) {
+
+      /* Check flag for creation of buffer status report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PDCP_STATS) {
+	
+	Protocol__FlexPdcpStats *pdcp_aggr_stats;
+	pdcp_aggr_stats = malloc(sizeof(Protocol__FlexPdcpStats));
+	if (pdcp_aggr_stats == NULL)
+	  goto error;
+	protocol__flex_pdcp_stats__init(pdcp_aggr_stats);
+	
+	flexran_agent_pdcp_aggregate_stats(mod_id, i, pdcp_aggr_stats);
+
+	pdcp_aggr_stats->has_pkt_tx=1;
+	pdcp_aggr_stats->has_pkt_tx_bytes =1;
+	pdcp_aggr_stats->has_pkt_tx_rate_s=1; 
+	pdcp_aggr_stats->has_pkt_tx_throughput_s =1;
+	pdcp_aggr_stats->has_pkt_tx_aiat =1; 
+	pdcp_aggr_stats->has_pkt_tx_aiat_s =1;
+
+	pdcp_aggr_stats->pkt_tx_sn = flexran_get_pdcp_tx_sn(mod_id, i, DEFAULT_DRB);
+	pdcp_aggr_stats->has_pkt_tx_sn =1;
+	
+	pdcp_aggr_stats->has_pkt_rx =1;
+	pdcp_aggr_stats->has_pkt_rx_bytes =1; 
+	pdcp_aggr_stats->has_pkt_rx_rate_s =1;
+	pdcp_aggr_stats->has_pkt_rx_goodput_s =1;
+	pdcp_aggr_stats->has_pkt_rx_aiat =1;
+	pdcp_aggr_stats->has_pkt_rx_aiat_s =1;
+	pdcp_aggr_stats->has_pkt_rx_oo =1;
+
+	pdcp_aggr_stats->pkt_rx_sn = flexran_get_pdcp_rx_sn(mod_id, i, DEFAULT_DRB);
+	pdcp_aggr_stats->has_pkt_rx_sn =1;
+
+	ue_report[i]->pdcp_stats = pdcp_aggr_stats;
+
+      }
+    }
+  }  else {
+    LOG_D(FLEXRAN_AGENT, "no UE\n");
+  }     
+  
+  return 0;
+  
+ error:
+  LOG_W(FLEXRAN_AGENT, "Can't allocate PDCP stats\n");
+  
+  /* if (cell_report != NULL)
+        free(cell_report);
+  if (ue_report != NULL)
+        free(ue_report);
+  */
+  return -1;
+}
+
+
+
+int flexran_agent_register_pdcp_xface(mid_t mod_id, AGENT_PDCP_xface *xface) {
+  if (pdcp_agent_registered[mod_id]) {
+    LOG_E(PDCP, "PDCP agent for eNB %d is already registered\n", mod_id);
+    return -1;
+  }
+
+  //xface->flexran_pdcp_stats_measurement = NULL;
+
+  pdcp_agent_registered[mod_id] = 1;
+  agent_pdcp_xface[mod_id] = xface;
+
+  return 0;
+}
+
+int flexran_agent_unregister_pdcp_xface(mid_t mod_id, AGENT_PDCP_xface *xface) {
+
+  //xface->agent_ctxt = NULL;
+  //xface->flexran_pdcp_stats_measurement = NULL;
+
+  
+  pdcp_agent_registered[mod_id] = 0;
+  agent_pdcp_xface[mod_id] = NULL;
+
+  return 0;
+}
diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h
new file mode 100644
index 0000000000..a962390c00
--- /dev/null
+++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h
@@ -0,0 +1,64 @@
+/*
+ * 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.0  (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
+ */ 
+
+/*! \file flexran_agent_pdcp.h
+ * \brief FlexRAN agent Control Module PDCP header
+ * \author shahab SHARIAT BAGHERI 
+ * \date 2017
+ * \version 0.1
+ */
+
+#ifndef FLEXRAN_AGENT_PDCP_H_
+#define FLEXRAN_AGENT_PDCP_H_
+
+#include "header.pb-c.h"
+#include "flexran.pb-c.h"
+#include "stats_messages.pb-c.h"
+#include "stats_common.pb-c.h"
+
+
+#include "flexran_agent_common.h"
+#include "flexran_agent_defs.h"
+#include "flexran_agent_pdcp_defs.h"
+#include "flexran_agent_ran_api.h"
+
+/**********************************
+ * FlexRAN agent - technology PDCP API
+ **********************************/
+
+/* Send to the controller all the pdcp stat updates that occured during this subframe*/
+int flexran_agent_pdcp_stats_reply(mid_t mod_id,       
+          const report_config_t *report_config,
+           Protocol__FlexUeStatsReport **ue_report,
+           Protocol__FlexCellStatsReport **cell_report);
+
+/* Get the stats from RAN API and aggregate them per USER*/
+void flexran_agent_pdcp_aggregate_stats(const mid_t mod_id,
+					const mid_t ue_id,
+					Protocol__FlexPdcpStats *pdcp_aggr_stats);
+
+/*Register technology specific interface callbacks*/
+int flexran_agent_register_pdcp_xface(mid_t mod_id, AGENT_PDCP_xface *xface);
+
+/*Unregister technology specific callbacks*/
+int flexran_agent_unregister_pdcp_xface(mid_t mod_id, AGENT_PDCP_xface*xface);
+
+#endif
diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h
new file mode 100644
index 0000000000..46bdf744de
--- /dev/null
+++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h
@@ -0,0 +1,63 @@
+/*
+ * 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.0  (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 __FLEXRAN_AGENT_PDCP_PRIMITIVES_H__
+#define __FLEXRAN_AGENT_PDCP_PRIMITIVES_H__
+
+#include "flexran_agent_defs.h"
+#include "flexran.pb-c.h"
+#include "header.pb-c.h"
+
+ /*PDCP aggregated Packet stats  */
+/*
+typedef struct  pdcp_aggr_stats_s {
+  int32_t rnti; 
+
+  int32_t pkt_tx;
+  int32_t pkt_tx_bytes;
+  int32_t pkt_tx_sn;
+  int32_t pkt_tx_rate_s;
+  int32_t pkt_tx_throughput_s;
+  int32_t pkt_tx_aiat;
+  int32_t pkt_tx_aiat_s;
+
+  int32_t pkt_rx;
+  int32_t pkt_rx_bytes;
+  int32_t pkt_rx_sn;
+  int32_t pkt_rx_rate_s;
+  int32_t pkt_rx_goodput_s;
+  int32_t pkt_rx_aiat;
+  int32_t pkt_rx_aiat_s;
+  int32_t pkt_rx_oo;
+
+  
+} pdcp_aggr_stats_t;
+*/
+
+/* FLEXRAN AGENT-PDCP Interface */
+typedef struct {
+  
+  
+  // PDCP statistics
+  void (*flexran_pdcp_stats_measurement)(mid_t mod_id, uint16_t rnti, uint16_t seq_num,  uint32_t size);
+  
+} AGENT_PDCP_xface;
+
+#endif
diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
index d48d12d670..e70d2a3d97 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
@@ -33,33 +33,15 @@
 
 #include "log.h"
 
+/*Trigger boolean for RRC measurement*/
+bool triggered_rrc = false;
 
-/*Flags showing if a rrc agent has already been registered*/
+/*Flags showing if an rrc agent has already been registered*/
 unsigned int rrc_agent_registered[NUM_MAX_ENB];
 
 /*Array containing the Agent-RRC interfaces*/
 AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB];
 
-/* Ringbuffer related structs used for maintaining the dl rrc config messages */
-//message_queue_t *rrc_dl_config_queue;
-struct lfds700_misc_prng_state rrc_ps[NUM_MAX_ENB];
-struct lfds700_ringbuffer_element *rrc_dl_config_array[NUM_MAX_ENB];
-struct lfds700_ringbuffer_state rrc_ringbuffer_state[NUM_MAX_ENB];
-
-
-
-void flexran_agent_init_rrc_agent(mid_t mod_id) {
-  lfds700_misc_library_init_valid_on_current_logical_core();
-  lfds700_misc_prng_init(&rrc_ps[mod_id]);
-  int num_elements = RINGBUFFER_SIZE + 1;
-  //Allow RINGBUFFER_SIZE messages to be stored in the ringbuffer at any time
-  rrc_dl_config_array[mod_id] = malloc( sizeof(struct lfds700_ringbuffer_element) *  num_elements);
-  lfds700_ringbuffer_init_valid_on_current_logical_core( &rrc_ringbuffer_state[mod_id], rrc_dl_config_array[mod_id], num_elements, &rrc_ps[mod_id], NULL );
-}
-
-
-
-
 
 void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) {
   int size;
@@ -280,156 +262,26 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) {
 /* this is called by RRC as a part of rrc xface  . The controller previously requested  this*/ 
 void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t*  measResults) {
 
-  // int i, m, k;
-  int                   priority = 0; // Warning Preventing
-  void                  *data;
-  int                   size;
-  err_code_t             err_code;
-  Protocol__FlexUeStatsReport **ue_report;
-  Protocol__FlexCellStatsReport **cell_report;
-  Protocol__FlexStatsReply *stats_reply_msg;
-  Protocol__FlexranMessage *msg;
-
-  Protocol__FlexHeader *header;
-  int xid = 0;
-  int i;
-
-  if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0)
-    goto error;
-
-
-
-  stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply));
-
-  if (stats_reply_msg == NULL)
-    goto error;
-
-  protocol__flex_stats_reply__init(stats_reply_msg);
-  stats_reply_msg->header = header;
-  stats_reply_msg->n_ue_report = 1;
-  stats_reply_msg->n_cell_report = 1;
-
-/****** LOCK ******************************************************************/
-  // pthread_spin_lock(&rrc_meas_t_lock);
-
-  // struct rrc_meas_trigg *ctxt;
-  // ctxt = rrc_meas_get_trigg(p->rnti, p->meas->measId);
-
-  // pthread_spin_unlock(&rrc_meas_t_lock);
-/****** UNLOCK ****************************************************************/
-
-  // if (ctxt == NULL) {
-
-  //   flexran_RRC_meas_reconf(p->rnti, -1, p->meas->measId, NULL, NULL);
-  //    Free the measurement report received from UE. 
-  //   ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas);
-  //   /* Free the params. */
-  //   free(p);
-  //   return 0;
-  // }
-
-
-  /* Check here whether trigger is registered in agent and then proceed.
-  */
-  // if (em_has_trigger(mod_id, ctxt->t_id, RRC_MEAS_TRIGGER) == 0) {
-
-  //   flexran_RRC_meas_reconf(p->rnti, -1, p->meas->measId, NULL, NULL);
-  //   /* Trigger does not exist in agent so remove from wrapper as well. */
-  //   if (rrc_meas_rem_trigg(ctxt) < 0) {
-  //     goto error;
-  //   }
-  // }
-
-  
-
-
-  /* Set the RNTI of the UE. */
-  // repl->rnti = p->rnti;
-  /* Set the request status. */
-  // if (p->reconfig_success == 0) {
-  //   repl->status = STATS_REQ_STATUS__SREQS_FAILURE;
-  //   goto error;
-  // }
-  /* Successful outcome. */
-  // repl->status = STATS_REQ_STATUS__SREQS_SUCCESS;
-  /* Set the measurement ID of measurement. */
-  // repl->has_measid = 1;
-  // repl->measid = measResults->measId;
-  /* Fill the Primary Cell RSRP and RSRQ. */
-  // repl->has_pcell_rsrp = 1;
-  // repl->has_pcell_rsrq = 1;
-  // #ifdef Rel10
-    // repl->has_pcell_rsrp = 1;
-    // repl->has_pcell_rsrq = 1;
-    // repl->pcell_rsrp = measResults2->measResultPCell.rsrpResult - 140;
-    // repl->pcell_rsrq = (measResults2->measResultPCell.rsrqResult)/2 - 20;
-
-    ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * 1);
-          if (ue_report == NULL)
-            goto error;
-
-    for (i = 0; i < 1; i++) {
-
-      ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport));
-       if(ue_report[i] == NULL)
-          goto error;
-      protocol__flex_ue_stats_report__init(ue_report[i]);
-      ue_report[i]->rnti = flexran_get_ue_crnti(mod_id, 0);
-      ue_report[i]->has_rnti = 1;
-       ue_report[i]->flags = 65536;
-       ue_report[i]->has_flags = 1;
-  
-    }
-
-    cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * 1);
-    if (cell_report == NULL)
-       goto error;
-  
-     for (i = 0; i < 1; i++) {
-
-      cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport));
-      if(cell_report[i] == NULL)
-          goto error;
+  int i, m, k;
+  // int                   priority = 0; // Warning Preventing
+  // void                  *data;
+  // int                   size;
+  err_code_t             err_code = -100;
+  triggered_rrc = true;
+  int num;
 
-      protocol__flex_cell_stats_report__init(cell_report[i]);
-      cell_report[i]->carrier_index = 0; //report_config->cc_report_type[i].cc_id;
-      cell_report[i]->has_carrier_index = 1;
-      cell_report[i]->flags = 0; // report_config->cc_report_type[i].cc_report_flags;
-      cell_report[i]->has_flags = 1;
-     }
- 
+  num = flexran_get_num_ues (mod_id);
 
-    Protocol__FlexRrcMeasurements *rrc_measurements;
-    rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements));
-    if (rrc_measurements == NULL)
-        goto error;
-    protocol__flex_rrc_measurements__init(rrc_measurements);
-                            
-    rrc_measurements->measid = measResults->measId;
-    rrc_measurements->has_measid = 1;
+  meas_stats = malloc(sizeof(rrc_meas_stats) * num); 
 
-    rrc_measurements->pcell_rsrp = measResults->measResultPCell.rsrpResult - 140;
-    rrc_measurements->has_pcell_rsrp = 1;
-
-    rrc_measurements->pcell_rsrq = (measResults->measResultPCell.rsrqResult)/2 - 20;                          
-    rrc_measurements->has_pcell_rsrq = 1 ;
-
-    ue_report[0]->rrc_measurements = rrc_measurements;
-
-
-
-   
-
-  // #else
-  //   repl->has_pcell_rsrp = 1;
-  //   repl->has_pcell_rsrq = 1;
-  //   repl->pcell_rsrp = RSRP_meas_mapping[meas->
-  //                       measResultServCell.rsrpResult];
-  //   repl->pcell_rsrq = RSRQ_meas_mapping[meas->
-  //                       measResultServCell.rsrqResult];
-  // #endif
-
-  // repl->neigh_meas = NULL;
+  for (i = 0; i < num; i++){
+    meas_stats[i].rnti = flexran_get_ue_crnti(mod_id, i);
+    meas_stats[i].meas_id = measResults->measId;
+    meas_stats[i].rsrp = measResults->measResultPCell.rsrpResult - 140;
+    meas_stats[i].rsrq = (measResults->measResultPCell.rsrqResult)/2 - 20;                          
+    
+  }
+    // repl->neigh_meas = NULL;
 
   // if (meas->measResultNeighCells != NULL) {
   //   /*
@@ -595,34 +447,34 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t*  measResults
   // free(p);
 
 
-  stats_reply_msg->cell_report = cell_report;
+  // stats_reply_msg->cell_report = cell_report;
     
-  stats_reply_msg->ue_report = ue_report;
+  // stats_reply_msg->ue_report = ue_report;
   
-  msg = malloc(sizeof(Protocol__FlexranMessage));
-  if(msg == NULL)
-    goto error;
-  protocol__flexran_message__init(msg);
-  msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG;
-  msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME;
-  msg->stats_reply_msg = stats_reply_msg;
+  // msg = malloc(sizeof(Protocol__FlexranMessage));
+  // if(msg == NULL)
+  //   goto error;
+  // protocol__flexran_message__init(msg);
+  // msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG;
+  // msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME;
+  // msg->stats_reply_msg = stats_reply_msg;
   
-  data = flexran_agent_pack_message(msg, &size);
+  // data = flexran_agent_pack_message(msg, &size);
   
   
-  if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) {
+  // if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) {
   
-    err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING;
-    goto error;
-  }
+  //   err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING;
+  //   goto error;
+  // }
   
-   LOG_I(FLEXRAN_AGENT,"RRC Trigger is done  \n");
+  //  LOG_I(FLEXRAN_AGENT,"RRC Trigger is done  \n");
 
   return;
 
-  error:
+  // error:
 
-    LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code);
+    // LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code);
     /* Free the measurement report received from UE. */
     // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas);
     /* Free the params. */
@@ -631,6 +483,98 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t*  measResults
 }
 
 
+int flexran_agent_rrc_stats_reply(mid_t mod_id,       
+          const report_config_t *report_config,
+           Protocol__FlexUeStatsReport **ue_report,
+           Protocol__FlexCellStatsReport **cell_report) {
+
+
+  // Protocol__FlexHeader *header;
+  int i, j, k;
+  // int cc_id = 0;
+  int enb_id = mod_id;
+
+  /* Allocate memory for list of UE reports */
+  if (report_config->nr_ue > 0) {
+
+    for (i = 0; i < report_config->nr_ue; i++) {
+      
+      /* Check flag for creation of buffer status report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) {
+	
+	Protocol__FlexRrcMeasurements *rrc_measurements;
+	rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements));
+	if (rrc_measurements == NULL)
+	  goto error;
+	protocol__flex_rrc_measurements__init(rrc_measurements);
+        
+	if (triggered_rrc){
+	  rrc_measurements->measid = meas_stats[i].meas_id;
+	  rrc_measurements->has_measid = 1;
+	  
+	  rrc_measurements->pcell_rsrp = meas_stats[i].rsrp;
+	  rrc_measurements->has_pcell_rsrp = 1;
+	  
+	  rrc_measurements->pcell_rsrq = meas_stats[i].rsrq;                          
+	  rrc_measurements->has_pcell_rsrq = 1 ;
+	  
+	  ue_report[i]->rrc_measurements = rrc_measurements;
+	  // triggered_rrc = false; // To be decided later
+	}
+      }
+    }       
+  } 
+
+  /* To be extended for RRC layer */ 
+  // if (report_config->nr_cc > 0) { 
+    
+            
+  //           // Fill in the Cell reports
+  //           for (i = 0; i < report_config->nr_cc; i++) {
+
+
+  //                     /* Check flag for creation of noise and interference report */
+  //                     if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) {
+  //                           // TODO: Fill in the actual noise and interference report for this cell
+  //                           Protocol__FlexNoiseInterferenceReport *ni_report;
+  //                           ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport));
+  //                           if(ni_report == NULL)
+  //                             goto error;
+  //                           protocol__flex_noise_interference_report__init(ni_report);
+  //                           // Current frame and subframe number
+  //                           ni_report->sfn_sf = flexran_get_sfn_sf(enb_id);
+  //                           ni_report->has_sfn_sf = 1;
+  //                           //TODO:Received interference power in dbm
+  //                           ni_report->rip = 0;
+  //                           ni_report->has_rip = 1;
+  //                           //TODO:Thermal noise power in dbm
+  //                           ni_report->tnp = 0;
+  //                           ni_report->has_tnp = 1;
+
+  //                           ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0);
+  //                           ni_report->has_p0_nominal_pucch = 1;
+  //                           cell_report[i]->noise_inter_report = ni_report;
+  //                     }
+  //           }
+            
+
+      
+            
+  // }
+
+  return 0;
+
+ error:
+
+  if (cell_report != NULL)
+        free(cell_report);
+  if (ue_report != NULL)
+        free(ue_report);
+
+  return -1;
+}
+
+
 int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface) {
   if (rrc_agent_registered[mod_id]) {
     LOG_E(RRC, "RRC agent for eNB %d is already registered\n", mod_id);
diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
index aa210f9d41..ae26b41621 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
@@ -1,31 +1,23 @@
-/*******************************************************************************
-    OpenAirInterface
-    Copyright(c) 1999 - 2014 Eurecom
-
-    OpenAirInterface is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-
-    OpenAirInterface is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenAirInterface.The full GNU General Public License is
-   included in this distribution in the file called "COPYING". If not,
-   see <http://www.gnu.org/licenses/>.
-
-  Contact Information
-  OpenAirInterface Admin: openair_admin@eurecom.fr
-  OpenAirInterface Tech : openair_tech@eurecom.fr
-  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
-
-  Address      : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
-
- *******************************************************************************/
+/*
+ * 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.0  (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
+ */ 
 
 /*! \file flexran_agent_rrc.h
  * \brief FlexRAN agent Control Module RRC header
@@ -65,6 +57,10 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg);
 /* this is called by RRC as a part of rrc xface  . The controller previously requested  this*/ 
 void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t *);
 
+/* Statistics reply protocol message constructor and destructor */
+int flexran_agent_rrc_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report);
+int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexranMessage *msg);
+
 /*Register technology specific interface callbacks*/
 int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface);
 
diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h
index ad1375171e..a101bab242 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h
@@ -1,31 +1,24 @@
-/*******************************************************************************
-    OpenAirInterface
-    Copyright(c) 1999 - 2016 Eurecom
+/*
+ * 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.0  (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
+ */ 
 
-    OpenAirInterface is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-
-    OpenAirInterface is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenAirInterface.The full GNU General Public License is
-   included in this distribution in the file called "COPYING". If not,
-   see <http://www.gnu.org/licenses/>.
-
-  Contact Information
-  OpenAirInterface Admin: openair_admin@eurecom.fr
-  OpenAirInterface Tech : openair_tech@eurecom.fr
-  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
-
-  Address      : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
-
- *******************************************************************************/
 
 /*! \file flexran_agent_rrc_defs.h
  * \brief FlexRAN agent - RRC interface primitives
@@ -46,11 +39,24 @@
 
 #define RINGBUFFER_SIZE 100
 
+
+typedef struct 
+{
+   int32_t rnti; 
+   int32_t meas_id;
+   int32_t rsrp;
+   int32_t rsrq;
+
+   /*To Be Extended*/
+}rrc_meas_stats;
+
+/* RRC CMI statistics */
+rrc_meas_stats * meas_stats;
+
+
 /* FLEXRAN AGENT-RRC Interface */
 typedef struct {
   
-  /// Inform the controller about the scheduling requests received during the subframe
-  //void (*flexran_agent_send_update_rrc_stats)(mid_t mod_id);
   
    /// Notify the controller for a state change of a particular UE, by sending the proper
   /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER)
diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto
index d79051d201..18eb760cc3 100644
--- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto
@@ -132,6 +132,7 @@ message flex_enb_config_reply {
 	optional flex_header header = 1;
 	optional uint32 eNB_id = 2;		// Unique id to distinguish the eNB
 	repeated flex_cell_config cell_config = 3;
+        optional uint32 device_spec = 4;
 }
 
 message flex_ue_config_request {
diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
index 0d8a565c06..a7d78841a3 100644
--- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
@@ -242,3 +242,24 @@ message flex_eutra_ref_signal_meas {
         optional int32 rsrq = 2;
 
 }
+
+message flex_pdcp_stats {
+
+        optional uint32 pkt_tx = 1;
+        optional uint32 pkt_tx_bytes = 2;
+        optional uint32 pkt_tx_sn = 3;
+        optional uint32 pkt_tx_rate_s = 4;
+	optional uint32 pkt_tx_throughput_s = 5;
+        optional uint32 pkt_tx_aiat = 7;
+	optional uint32 pkt_tx_aiat_s = 8;
+	
+	optional uint32 pkt_rx = 9;
+        optional uint32 pkt_rx_bytes = 10;
+        optional uint32 pkt_rx_sn = 11;
+        optional uint32 pkt_rx_rate_s = 12;
+	optional uint32 pkt_rx_goodput_s = 13;
+        optional uint32 pkt_rx_aiat = 14;
+	optional uint32 pkt_rx_aiat_s = 15;
+        optional uint32 pkt_rx_oo = 16;
+ }
+
diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
index 1ddb19722b..8cad6f4fbe 100644
--- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
@@ -47,7 +47,8 @@ message flex_ue_stats_report {
 	optional flex_dl_cqi_report dl_cqi_report = 7;
 	optional flex_paging_buffer_report pbr = 8;
 	optional flex_ul_cqi_report ul_cqi_report = 9;
-    optional flex_rrc_measurements rrc_measurements = 10;
+        optional flex_rrc_measurements rrc_measurements = 10;
+        optional flex_pdcp_stats pdcp_stats = 11;
 }
 
 //
@@ -84,6 +85,9 @@ enum flex_ue_stats_type {
      FLUST_DL_CQI = 16;
      FLUST_PBS = 32;
      FLUST_UL_CQI = 64;
+     
+     FLUST_PDCP_STATS = 1024; // To be changed
      // To be extended with more types of stats
      FLUST_RRC_MEASUREMENTS = 65536;
+     
 }
diff --git a/openair2/ENB_APP/MESSAGES/V2/time_common.proto b/openair2/ENB_APP/MESSAGES/V2/time_common.proto
index 8bd2497443..baf0c0e9ae 100644
--- a/openair2/ENB_APP/MESSAGES/V2/time_common.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/time_common.proto
@@ -26,5 +26,6 @@ message flex_ul_info {
 	optional uint32 reception_status = 3;
 	optional uint32 tpc = 4;
 	optional uint32 serv_cell_index = 5; 
+        optional uint32 rssi = 6;
 }
 
diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c
index ec984cfa8b..23ac8f02ac 100644
--- a/openair2/ENB_APP/flexran_agent.c
+++ b/openair2/ENB_APP/flexran_agent.c
@@ -267,6 +267,9 @@ int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properti
   AGENT_RRC_xface *rrc_agent_xface = (AGENT_RRC_xface *) malloc(sizeof(AGENT_RRC_xface));
   flexran_agent_register_rrc_xface(mod_id, rrc_agent_xface);
 
+   AGENT_PDCP_xface *pdcp_agent_xface = (AGENT_PDCP_xface *) malloc(sizeof(AGENT_PDCP_xface));
+   flexran_agent_register_pdcp_xface(mod_id, pdcp_agent_xface);
+
   /* 
    * initilize a timer 
    */ 
diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h
index 0ef48e2105..f9205c071f 100644
--- a/openair2/ENB_APP/flexran_agent.h
+++ b/openair2/ENB_APP/flexran_agent.h
@@ -38,6 +38,7 @@
 #include "flexran_agent_ran_api.h"
 #include "flexran_agent_mac.h"
 #include "flexran_agent_rrc.h"
+#include "flexran_agent_pdcp.h"
 #include "log.h"
 #include "assertions.h"
 
diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h
index 0b8822a949..040a8192f6 100644
--- a/openair2/ENB_APP/flexran_agent_defs.h
+++ b/openair2/ENB_APP/flexran_agent_defs.h
@@ -32,11 +32,16 @@
 #include <stdlib.h>
 #include <pthread.h>
 #include <string.h>
+#include <stdbool.h>
+#include <time.h>
 
 #include "link_manager.h"
 
 #define NUM_MAX_ENB 2
+#define NUM_MAX_DRB 8
+#define NUM_MAX_SRB 3
 #define NUM_MAX_UE 2048
+#define DEFAULT_DRB 3
 #define DEFAULT_FLEXRAN_AGENT_IPv4_ADDRESS "127.0.0.1"
 #define DEFAULT_FLEXRAN_AGENT_PORT          2210
 #define DEFAULT_FLEXRAN_AGENT_CACHE        "/mnt/oai_agent_cache"
diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h
index 4df984e1a0..a9af552856 100644
--- a/openair2/ENB_APP/flexran_agent_extern.h
+++ b/openair2/ENB_APP/flexran_agent_extern.h
@@ -33,6 +33,7 @@
 // #include "flexran_agent_defs.h"
 #include "flexran_agent_mac_defs.h"
 #include "flexran_agent_rrc_defs.h"
+#include "flexran_agent_pdcp_defs.h"
 
 //extern msg_context_t shared_ctxt[NUM_MAX_ENB][FLEXRAN_AGENT_MAX];
 
@@ -51,6 +52,12 @@ extern AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB];
 /* Flag indicating whether the VSFs for the RRC control module have been registered */
 extern unsigned int rrc_agent_registered[NUM_MAX_ENB];
 
+/* Control module interface for the communication of the RRC Control Module with the agent */
+extern AGENT_PDCP_xface *agent_pdcp_xface[NUM_MAX_ENB];
+
+/* Flag indicating whether the VSFs for the RRC control module have been registered */
+extern unsigned int pdcp_agent_registered[NUM_MAX_ENB];
+
 /* Requried to know which UEs had a harq updated over some subframe */
 extern int harq_pid_updated[NUMBER_OF_UE_MAX][8];
 extern int harq_pid_round[NUMBER_OF_UE_MAX][8];
diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c
index fc2ed135c8..6ad0b88975 100644
--- a/openair2/ENB_APP/flexran_agent_handler.c
+++ b/openair2/ENB_APP/flexran_agent_handler.c
@@ -143,7 +143,7 @@ void * flexran_agent_pack_message(Protocol__FlexranMessage *msg,
   
   DevAssert(buffer !=NULL);
   
-  LOG_D(FLEXRAN_AGENT,"Serilized the enb mac stats reply (size %d)\n", *size);
+  LOG_D(FLEXRAN_AGENT,"Serilized the eNB-UE stats reply (size %d)\n", *size);
   
   return buffer;
   
@@ -457,7 +457,7 @@ int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *re
 
   }
 
-    /*
+      /*
       MAC reply split
      */
 
@@ -467,7 +467,26 @@ int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *re
         goto error;
     }
 
-  
+    /*
+      RRC reply split
+     */
+
+    if (flexran_agent_rrc_stats_reply(enb_id, report_config,  ue_report, cell_report) < 0 ) {
+        err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
+        goto error;
+    }
+   
+
+    /*
+      PDCP reply split
+    */
+    
+    if (flexran_agent_pdcp_stats_reply(enb_id, report_config,  ue_report, cell_report) < 0 ) {
+      err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
+      goto error;
+    }
+
+       
   stats_reply_msg->cell_report = cell_report;
   stats_reply_msg->ue_report = ue_report;
 
diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c
index 0d3145e1d2..01f05b1ba5 100644
--- a/openair2/ENB_APP/flexran_agent_ran_api.c
+++ b/openair2/ENB_APP/flexran_agent_ran_api.c
@@ -179,6 +179,17 @@ int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t chann
   return rlc_status.bytes_in_buffer;
 }
 
+
+int flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) {
+  rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id);
+  uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id);
+  uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id);
+  mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0);
+  return rlc_status.pdus_in_buffer;
+}
+
+
+
 int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) {
   rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id);
   uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id);
@@ -1077,6 +1088,85 @@ void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_
         enb_properties->properties[mod_id]->frame_type[cc_id]=frame_type;
 }
 
+/*********** PDCP  *************/
+
+/*PDCP num tx pdu status flexRAN*/
+uint32_t flexran_get_pdcp_tx(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  if (mod_id <0 || mod_id> MAX_NUM_CCs || ue_id<0 || ue_id> NUMBER_OF_UE_MAX || lcid<0 || lcid>NB_RB_MAX)
+    return -1;
+  return Pdcp_stats_tx[mod_id][ue_id][lcid];
+}
+
+/*PDCP num tx bytes status flexRAN*/
+uint32_t flexran_get_pdcp_tx_bytes(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_tx_bytes[mod_id][ue_id][lcid];
+}
+
+/*PDCP number of transmit packet / second status flexRAN*/
+uint32_t flexran_get_pdcp_tx_rate_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_tx_rate_s[mod_id][ue_id][lcid];
+}
+
+/*PDCP throughput (bit/s) status flexRAN*/
+uint32_t flexran_get_pdcp_tx_throughput_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_tx_throughput_s[mod_id][ue_id][lcid];
+}
+
+/*PDCP tx sequence number flexRAN*/
+uint32_t flexran_get_pdcp_tx_sn(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_tx_sn[mod_id][ue_id][lcid];
+}
+
+/*PDCP tx aggregated packet arrival  flexRAN*/
+uint32_t flexran_get_pdcp_tx_aiat(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_tx_aiat[mod_id][ue_id][lcid];
+}
+
+/*PDCP tx aggregated packet arrival  flexRAN*/
+uint32_t flexran_get_pdcp_tx_aiat_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_tx_aiat_s[mod_id][ue_id][lcid];
+}
+
+
+/*PDCP num rx pdu status flexRAN*/
+uint32_t flexran_get_pdcp_rx(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_rx[mod_id][ue_id][lcid];
+}
+
+/*PDCP num rx bytes status flexRAN*/
+uint32_t flexran_get_pdcp_rx_bytes(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_rx_bytes[mod_id][ue_id][lcid];
+}
+
+/*PDCP number of received packet / second  flexRAN*/
+uint32_t flexran_get_pdcp_rx_rate_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_rx_rate_s[mod_id][ue_id][lcid];
+}
+
+/*PDCP gootput (bit/s) status flexRAN*/
+uint32_t flexran_get_pdcp_rx_goodput_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_rx_goodput_s[mod_id][ue_id][lcid];
+}
+
+/*PDCP rx sequence number flexRAN*/
+uint32_t flexran_get_pdcp_rx_sn(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_rx_sn[mod_id][ue_id][lcid];
+}
+
+/*PDCP rx aggregated packet arrival  flexRAN*/
+uint32_t flexran_get_pdcp_rx_aiat(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_rx_aiat[mod_id][ue_id][lcid];
+}
+
+/*PDCP rx aggregated packet arrival  flexRAN*/
+uint32_t flexran_get_pdcp_rx_aiat_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_rx_aiat_s[mod_id][ue_id][lcid];
+}
+
+/*PDCP num of received outoforder pdu status flexRAN*/
+uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid){
+  return Pdcp_stats_rx_outoforder[mod_id][ue_id][lcid];
+}
 
 
 
diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h
index 9f0313c1ca..4d84251608 100644
--- a/openair2/ENB_APP/flexran_agent_ran_api.h
+++ b/openair2/ENB_APP/flexran_agent_ran_api.h
@@ -39,6 +39,7 @@
 #include "LAYER2/MAC/extern.h"
 #include "LAYER2/RLC/rlc.h"
 #include "SCHED/defs.h"
+#include "pdcp.h"
 #include "RRC/LITE/extern.h"
 #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
 #include "RRC/LITE/rrc_eNB_UE_context.h"
@@ -91,6 +92,9 @@ int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id);
 /* Get the transmission queue size for a UE with a channel_id logical channel id */
 int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id);
 
+/*Get number of pdus in RLC buffer*/
+int flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); 
+
 /* Get the head of line delay for a UE with a channel_id logical channel id */
 int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id);
 
@@ -334,3 +338,54 @@ void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_
 
 /*RRC status flexRAN*/
 int flexran_get_rrc_status(const mid_t mod_id,  const rnti_t  rntiP);
+
+
+/***************************** PDCP ***********************/
+
+/*PDCP num tx pdu status flexRAN*/
+uint32_t flexran_get_pdcp_tx(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP num tx bytes status flexRAN*/
+uint32_t flexran_get_pdcp_tx_bytes(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP number of transmit packet / second status flexRAN*/
+uint32_t flexran_get_pdcp_tx_rate_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP throughput (bit/s) status flexRAN*/
+uint32_t flexran_get_pdcp_tx_throughput_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP tx sequence number flexRAN*/
+uint32_t flexran_get_pdcp_tx_sn(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP tx aggregated packet arrival  flexRAN*/
+uint32_t flexran_get_pdcp_tx_aiat(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP tx aggregated packet arrival per second flexRAN*/
+uint32_t flexran_get_pdcp_tx_aiat_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+
+/*PDCP num rx pdu status flexRAN*/
+uint32_t flexran_get_pdcp_rx(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP num rx bytes status flexRAN*/
+uint32_t flexran_get_pdcp_rx_bytes(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP number of received packet / second  flexRAN*/
+uint32_t flexran_get_pdcp_rx_rate_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP gootput (bit/s) status flexRAN*/
+uint32_t flexran_get_pdcp_rx_goodput_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP rx sequence number flexRAN*/
+uint32_t flexran_get_pdcp_rx_sn(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP rx aggregated packet arrival  flexRAN*/
+uint32_t flexran_get_pdcp_rx_aiat(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP rx aggregated packet arrival per second flexRAN*/
+uint32_t flexran_get_pdcp_rx_aiat_s(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+/*PDCP num of received outoforder pdu status flexRAN*/
+uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id,  const mid_t ue_id, const lcid_t lcid);
+
+
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
index 8dad83a90a..397a194edf 100644
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
@@ -69,6 +69,7 @@ extern int otg_enabled;
 #endif
 
 
+
 //-----------------------------------------------------------------------------
 /*
  * If PDCP_UNIT_TEST is set here then data flow between PDCP and RLC is broken
@@ -102,6 +103,8 @@ boolean_t pdcp_data_req(
 
   hash_key_t         key             = HASHTABLE_NOT_A_KEY_VALUE;
   hashtable_rc_t     h_rc;
+  uint8_t            rb_offset= (srb_flagP == 0) ? DTCH -1 : 0;
+  uint16_t           pdcp_uid=0;
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_IN);
   CHECK_CTXT_ARGS(ctxt_pP);
 
@@ -152,7 +155,7 @@ boolean_t pdcp_data_req(
     ctxt_pP->configured=TRUE;
   }
     
-  if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
+  if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
     start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req);
   } else {
     start_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req);
@@ -223,7 +226,7 @@ boolean_t pdcp_data_req(
           LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n",
                 PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p));
 
-          if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
+          if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
             stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req);
           } else {
             stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req);
@@ -241,8 +244,9 @@ boolean_t pdcp_data_req(
         if (pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer((unsigned char*)pdcp_pdu_p->data, &pdu_header) == FALSE) {
           LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n",
                 PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p));
+         
+          if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
 
-          if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
             stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req);
           } else {
             stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req);
@@ -264,7 +268,7 @@ boolean_t pdcp_data_req(
 
         free_mem_block(pdcp_pdu_p, __func__);
 
-        if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
+        if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
           stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req);
         } else {
           stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req);
@@ -292,7 +296,7 @@ boolean_t pdcp_data_req(
           (((pdcp_p->cipheringAlgorithm) != 0) ||
            ((pdcp_p->integrityProtAlgorithm) != 0))) {
 
-        if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
+        if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
           start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security);
         } else {
           start_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security);
@@ -387,7 +391,7 @@ boolean_t pdcp_data_req(
     break;
   }
 
-  if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
+  if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
     stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req);
   } else {
     stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req);
@@ -397,16 +401,45 @@ boolean_t pdcp_data_req(
    * Control arrives here only if rlc_data_req() returns RLC_OP_STATUS_OK
    * so we return TRUE afterwards
    */
-  /*
-   if (rb_id>=DTCH) {
-    if (ctxt_pP->enb_flag == 1) {
-      Pdcp_stats_tx[module_id][(rb_id & RAB_OFFSET2 )>> RAB_SHIFT2][(rb_id & RAB_OFFSET)-DTCH]++;
-      Pdcp_stats_tx_bytes[module_id][(rb_id & RAB_OFFSET2 )>> RAB_SHIFT2][(rb_id & RAB_OFFSET)-DTCH] += sdu_buffer_size;
-    } else {
-      Pdcp_stats_tx[module_id][(rb_id & RAB_OFFSET2 )>> RAB_SHIFT2][(rb_id & RAB_OFFSET)-DTCH]++;
-      Pdcp_stats_tx_bytes[module_id][(rb_id & RAB_OFFSET2 )>> RAB_SHIFT2][(rb_id & RAB_OFFSET)-DTCH] += sdu_buffer_size;
-    }
-    }*/
+  
+  for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){
+    if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) 
+      break;
+  }
+
+  //LOG_I(PDCP,"ueid %d lcid %d tx seq num %d\n", pdcp_uid, rb_idP+rb_offset, current_sn);
+  Pdcp_stats_tx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++;
+  Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP;
+  Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn;
+
+  if (Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame *10 + pdcp_subframe) {
+    Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]);
+    Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); 
+  }
+  else {
+    Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 + pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]);
+    Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 + pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]);
+  }
+  
+  
+  Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=ctxt_pP->frame*10+ctxt_pP->subframe;
+  
+  if (pdcp_frame % 100 == 0 ) {  
+    Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset];
+    Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]*8/1000;
+    Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset];
+    
+    Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0;
+    Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0;
+    Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0;
+  }else {
+    Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++;
+    Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP;
+    
+  }
+  
+ 
+  
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT);
   return ret;
 
@@ -436,6 +469,9 @@ pdcp_data_ind(
   boolean_t    packet_forwarded = FALSE;
   hash_key_t      key             = HASHTABLE_NOT_A_KEY_VALUE;
   hashtable_rc_t  h_rc;
+  uint8_t      rb_offset= (srb_flagP == 0) ? DTCH -1 :0;
+  uint16_t     pdcp_uid=0;      
+  uint8_t      oo_flag=0;
 #if defined(LINK_ENB_PDCP_TO_GTPV1U)
   MessageDef  *message_p        = NULL;
   uint8_t     *gtpu_buffer_p    = NULL;
@@ -590,6 +626,7 @@ pdcp_data_ind(
       else
       LOG_D(PDCP, "Passing piggybacked SDU to RRC ...\n");*/
     } else {
+      oo_flag=1;
       LOG_W(PDCP,
             PROTOCOL_PDCP_CTXT_FMT"Incoming PDU has an unexpected sequence number (%d), RX window synchronisation have probably been lost!\n",
             PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p),
@@ -789,6 +826,53 @@ pdcp_data_ind(
     GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rab_id       = rb_id + 4;
     itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p);
     packet_forwarded = TRUE;
+
+     /* Print octets of incoming data in hexadecimal form */
+      LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n",
+            sdu_buffer_sizeP  - payload_offset + (int)sizeof(pdcp_data_ind_header_t),
+            sdu_buffer_sizeP  - payload_offset);
+      //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset);
+      //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset);
+
+      /*
+       * Update PDCP statistics
+       * XXX Following two actions are identical, is there a merge error?
+       */
+      
+      for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){
+     	if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti )
+	  break;
+      }	
+            
+      Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++;
+      Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP  - payload_offset;
+      
+      Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number;
+
+      if (oo_flag == 1 )
+	Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++;
+
+      if (Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame * 10 + pdcp_subframe) {
+	Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]);
+	Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]);
+      } else {
+	Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]);
+	Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]);
+      }
+      Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_frame * 10 +pdcp_subframe;
+            
+      if (pdcp_frame % 102 == 0) {
+	Pdcp_stats_rx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset];
+	Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]*8/1023;
+	Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]= Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset];
+
+	Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0;
+	Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0;
+	Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0;
+      }else {
+	Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++;
+	Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP  - payload_offset);
+      }     
   }
 
 #else
@@ -842,25 +926,8 @@ pdcp_data_ind(
              sdu_buffer_sizeP - payload_offset);
       list_add_tail_eurecom (new_sdu_p, sdu_list_p);
 
-      /* Print octets of incoming data in hexadecimal form */
-      LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n",
-            sdu_buffer_sizeP  - payload_offset + (int)sizeof(pdcp_data_ind_header_t),
-            sdu_buffer_sizeP  - payload_offset);
-      //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset);
-      //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset);
-
-      /*
-       * Update PDCP statistics
-       * XXX Following two actions are identical, is there a merge error?
-       */
-
-      /*if (ctxt_pP->enb_flag == 1) {
-          Pdcp_stats_rx[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH]++;
-          Pdcp_stats_rx_bytes[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH] += sdu_buffer_sizeP;
-        } else {
-          Pdcp_stats_rx[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH]++;
-          Pdcp_stats_rx_bytes[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH] += sdu_buffer_sizeP;
-        }*/
+      
+      
     }
   }
 
@@ -891,6 +958,9 @@ pdcp_run (
 )
 //-----------------------------------------------------------------------------
 {
+
+  pdcp_frame =ctxt_pP->frame;
+  pdcp_subframe= ctxt_pP->subframe;
 #if defined(ENABLE_ITTI)
   MessageDef   *msg_p;
   const char   *msg_name;
@@ -1139,7 +1209,7 @@ rrc_pdcp_config_asn1_req (
           return TRUE;
 
       } else {
-          LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64"\n",
+	  LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64"\n",
                 PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p),
                 key);
         }
@@ -1470,12 +1540,19 @@ pdcp_config_req_asn1 (
   uint8_t         *const        kUPenc_pP)
 //-----------------------------------------------------------------------------
 {
-
+  int i; 
   switch (actionP) {
   case CONFIG_ACTION_ADD:
     DevAssert(pdcp_pP != NULL);
     if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
       pdcp_pP->is_ue = FALSE;
+      for (i=0; i < NUMBER_OF_UE_MAX; i++) {
+	if (pdcp_pP->rnti[i] != 0 ) continue ; // skip active ues
+        pdcp_pP->rnti[i]=ctxt_pP->rnti;
+	pdcp_pP->uid[i]=i;
+        pdcp_num_ues++;
+        break;
+	}
       //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti;
       pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti;
       //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % NUMBER_OF_UE_MAX;
@@ -1575,6 +1652,18 @@ pdcp_config_req_asn1 (
           lc_idP,
           rb_idP);
 
+   if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
+	
+	for (i=0; i < NUMBER_OF_UE_MAX; i++) {
+        if (pdcp_pP->rnti[i] == ctxt_pP->rnti ) {
+          pdcp_pP->rnti[i]=0;
+          pdcp_pP->uid[i]=0;
+          pdcp_num_ues--;
+          break;
+        }
+	}
+	}
+
     /* Security keys */
     if (pdcp_pP->kUPenc != NULL) {
       free(pdcp_pP->kUPenc);
@@ -1826,13 +1915,14 @@ rrc_pdcp_config_req (
 
 
 //-----------------------------------------------------------------------------
-// TODO PDCP module initialization code might be removed
+ 
 int
 pdcp_module_init (
   void
 )
 //-----------------------------------------------------------------------------
 {
+ 
 #ifdef PDCP_USE_RT_FIFO
   int ret;
 
@@ -1952,14 +2042,27 @@ void pdcp_layer_init(void)
   pdcp_input_sdu_remaining_size_to_read=0;
 
   memset(Pdcp_stats_tx, 0, sizeof(Pdcp_stats_tx));
+  memset(Pdcp_stats_tx_s, 0, sizeof(Pdcp_stats_tx_s));
   memset(Pdcp_stats_tx_bytes, 0, sizeof(Pdcp_stats_tx_bytes));
-  memset(Pdcp_stats_tx_bytes_last, 0, sizeof(Pdcp_stats_tx_bytes_last));
-  memset(Pdcp_stats_tx_rate, 0, sizeof(Pdcp_stats_tx_rate));
+  memset(Pdcp_stats_tx_bytes_s, 0, sizeof(Pdcp_stats_tx_bytes_s));
+  memset(Pdcp_stats_tx_rate_s, 0, sizeof(Pdcp_stats_tx_rate_s));
+  memset(Pdcp_stats_tx_sn, 0, sizeof(Pdcp_stats_tx_sn));
+  memset(Pdcp_stats_tx_throughput_s, 0, sizeof(Pdcp_stats_tx_throughput_s));
+  memset(Pdcp_stats_tx_aiat, 0, sizeof(Pdcp_stats_tx_aiat));
+  memset(Pdcp_stats_tx_iat, 0, sizeof(Pdcp_stats_tx_iat));
+  
 
   memset(Pdcp_stats_rx, 0, sizeof(Pdcp_stats_rx));
+  memset(Pdcp_stats_rx_s, 0, sizeof(Pdcp_stats_rx_s));
   memset(Pdcp_stats_rx_bytes, 0, sizeof(Pdcp_stats_rx_bytes));
-  memset(Pdcp_stats_rx_bytes_last, 0, sizeof(Pdcp_stats_rx_bytes_last));
-  memset(Pdcp_stats_rx_rate, 0, sizeof(Pdcp_stats_rx_rate));
+  memset(Pdcp_stats_rx_bytes_s, 0, sizeof(Pdcp_stats_rx_bytes_s));
+  memset(Pdcp_stats_rx_rate_s, 0, sizeof(Pdcp_stats_rx_rate_s));
+  memset(Pdcp_stats_rx_sn, 0, sizeof(Pdcp_stats_rx_sn));
+  memset(Pdcp_stats_rx_goodput_s, 0, sizeof(Pdcp_stats_rx_goodput_s));
+  memset(Pdcp_stats_rx_aiat, 0, sizeof(Pdcp_stats_rx_aiat));
+  memset(Pdcp_stats_rx_iat, 0, sizeof(Pdcp_stats_rx_iat));
+  memset(Pdcp_stats_rx_outoforder, 0, sizeof(Pdcp_stats_rx_outoforder));
+    
 }
 
 //-----------------------------------------------------------------------------
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
index 94084273d1..fb3e02b299 100644
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
@@ -94,15 +94,41 @@ extern int             pdcp_instance_cnt;
 int init_pdcp_thread(void);
 void cleanup_pdcp_thread(void);
 
+public_pdcp(frame_t pdcp_frame);
+public_pdcp(sub_frame_t pdcp_subframe);
+public_pdcp(uint16_t pdcp_num_ues);
+
+
+public_pdcp(uint32_t Pdcp_stats_tx_bytes[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_bytes_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_sn[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_rate_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_throughput_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_aiat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_aiat_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_aiat_tmp_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_tx_iat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+
+public_pdcp(uint32_t Pdcp_stats_rx[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_bytes[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_bytes_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_sn[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_rate_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_goodput_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_aiat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_aiat_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_aiat_tmp_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_iat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+public_pdcp(uint32_t Pdcp_stats_rx_outoforder[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]);
+
+
+/*Packet Probing for agent PDCP*/
+//public_pdcp(uint64_t *pdcp_packet_counter);
+//public_pdcp(uint64_t *pdcp_size_packet);
 
-public_pdcp(unsigned int Pdcp_stats_tx[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]);
-public_pdcp(unsigned int Pdcp_stats_tx_bytes[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]);
-public_pdcp(unsigned int Pdcp_stats_tx_bytes_last[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]);
-public_pdcp(unsigned int Pdcp_stats_tx_rate[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]);
-public_pdcp(unsigned int Pdcp_stats_rx[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]);
-public_pdcp(unsigned int Pdcp_stats_rx_bytes[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]);
-public_pdcp(unsigned int Pdcp_stats_rx_bytes_last[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]);
-public_pdcp(unsigned int Pdcp_stats_rx_rate[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]);
 
 typedef struct pdcp_stats_s {
   time_stats_t pdcp_run;
@@ -125,6 +151,10 @@ typedef struct pdcp_s {
   boolean_t is_ue;
   boolean_t is_srb;
 
+ // used for eNB stats generation
+  uint16_t uid[NUMBER_OF_UE_MAX]; // local to pdcp
+  rnti_t rnti[NUMBER_OF_UE_MAX];
+
   /* Configured security algorithms */
   uint8_t cipheringAlgorithm;
   uint8_t integrityProtAlgorithm;
-- 
2.26.2