From 11b2f829367c39ab7479a0b410cd62e773d24117 Mon Sep 17 00:00:00 2001
From: Xenofon Foukas <x.foukas@sms.ed.ac.uk>
Date: Thu, 7 Jan 2016 17:41:51 +0200
Subject: [PATCH] Integrated timer to work with periodic report messages and
 agent tasks

---
 openair2/ENB_APP/enb_agent.c         | 116 ++++++++++--------
 openair2/ENB_APP/enb_agent_common.c  |   2 +-
 openair2/ENB_APP/enb_agent_common.h  |  16 +--
 openair2/ENB_APP/enb_agent_handler.c |  22 +++-
 openair2/ENB_APP/enb_agent_mac.c     | 169 +++++++++++++++++++++++++--
 openair2/ENB_APP/enb_agent_mac.h     |  13 +++
 6 files changed, 268 insertions(+), 70 deletions(-)

diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c
index e8a4466b26..dbefc60502 100644
--- a/openair2/ENB_APP/enb_agent.c
+++ b/openair2/ENB_APP/enb_agent.c
@@ -53,7 +53,7 @@ static uint16_t in_port;
 void *send_thread(void *args);
 void *receive_thread(void *args);
 pthread_t new_thread(void *(*f)(void *), void *b);
-err_code_t enb_agent_timeout(void* args);
+Protocol__ProgranMessage *enb_agent_timeout(void* args);
 
 /* 
  * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller 
@@ -61,6 +61,13 @@ err_code_t enb_agent_timeout(void* args);
 */
 void *enb_agent_task(void *args){
 
+  msg_context_t         *d = (msg_context_t *) args;
+  Protocol__ProgranMessage *msg;
+  void *data;
+  int size;
+  err_code_t err_code;
+  int                   priority;
+
   MessageDef                     *msg_p           = NULL;
   const char                     *msg_name        = NULL;
   instance_t                      instance;
@@ -86,7 +93,15 @@ void *enb_agent_task(void *args){
       break;
     
     case TIMER_HAS_EXPIRED:
-      enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, &msg_p->ittiMsg.timer_has_expired.arg);
+      msg = enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg);
+      if (msg != NULL){
+	data=enb_agent_send_message(msg,&size);
+	if (message_put(d->tx_mq, data, size, priority)){
+	  err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING;
+	  goto error;
+	}
+	LOG_D(ENB_AGENT,"sent message with size %d\n", size);
+      }
       break;
 
     default:
@@ -96,46 +111,49 @@ void *enb_agent_task(void *args){
 
     result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
     AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+    continue;
+  error:
+    LOG_E(ENB_AGENT,"enb_agent_task: error %d occured\n",err_code);
   } while (1);
 
   return NULL;
 }
 
-void *send_thread(void *args) {
-
-#ifdef TEST_TIMER
-
-  msg_context_t         *d = args;
-  void                  *data;
-  int                   size;
-  int                   priority;
-
-  struct timeval t1, t2;
-  long long t;
-  struct timespec ts;
-  unsigned int delay = 250*1000;
-  while(1) {
-    gettimeofday(&t1, NULL);
-    enb_agent_sleep_until(&ts, delay);
-    gettimeofday(&t2, NULL);
-    t = ((t2.tv_sec * 1000000) + t2.tv_usec) - ((t1.tv_sec * 1000000) + t1.tv_usec);
-    LOG_I(ENB_AGENT, "Call to sleep_until(%d) took %lld us\n", delay, t);
-    sleep(1);
-  }
-
-#endif
-  /* while (1) {
-    // need logic for the timer, and 
-    usleep(10);
-    if (message_put(d->tx_mq, data, size, priority)) goto error;
-    }*/
-
-  return NULL;
-
-error:
-  printf("receive_thread: there was an error\n");
-  return NULL;
-}
+/* void *send_thread(void *args) { */
+
+/* #ifdef TEST_TIMER */
+
+/*   msg_context_t         *d = args; */
+/*   void                  *data; */
+/*   int                   size; */
+/*   int                   priority; */
+
+/*   struct timeval t1, t2; */
+/*   long long t; */
+/*   struct timespec ts; */
+/*   unsigned int delay = 250*1000; */
+/*   while(1) { */
+/*     gettimeofday(&t1, NULL); */
+/*     enb_agent_sleep_until(&ts, delay); */
+/*     gettimeofday(&t2, NULL); */
+/*     t = ((t2.tv_sec * 1000000) + t2.tv_usec) - ((t1.tv_sec * 1000000) + t1.tv_usec); */
+/*     LOG_I(ENB_AGENT, "Call to sleep_until(%d) took %lld us\n", delay, t); */
+/*     sleep(1); */
+/*   } */
+
+/* #endif */
+/*   /\* while (1) { */
+/*     // need logic for the timer, and  */
+/*     usleep(10); */
+/*     if (message_put(d->tx_mq, data, size, priority)) goto error; */
+/*     }*\/ */
+
+/*   return NULL; */
+
+/* error: */
+/*   printf("receive_thread: there was an error\n"); */
+/*   return NULL; */
+/* } */
 
 void *receive_thread(void *args) {
 
@@ -290,25 +308,25 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){
    * start the enb agent task for tx and interaction with the underlying network function
    */ 
   
-  if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, NULL) < 0) {
+  if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, (void *) &shared_ctxt[mod_id]) < 0) {
     LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n");
     return -1;
   }
 
 
-#ifdef TEST_TIMER
+  //#ifdef TEST_TIMER
   long timer_id=0;
   enb_agent_timer_args_t timer_args;
   memset (&timer_args, 0, sizeof(enb_agent_timer_args_t));
   timer_args.mod_id = mod_id;
-  timer_args.cc_actions= ENB_AGENT_ACTION_APPLY;
-  timer_args.cc_report_flags = PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE;
-  timer_args.ue_actions =  ENB_AGENT_ACTION_SEND;
-  timer_args.ue_report_flags = PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR | PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI;
+  //timer_args.cc_actions= ENB_AGENT_ACTION_APPLY;
+  //timer_args.cc_report_flags = PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE;
+  //timer_args.ue_actions =  ENB_AGENT_ACTION_SEND;
+  //timer_args.ue_report_flags = PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR | PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI;
   enb_agent_create_timer(1, 0, ENB_AGENT_DEFAULT, mod_id, ENB_AGENT_TIMER_TYPE_PERIODIC, enb_agent_timeout,(void*)&timer_args, &timer_id);
-#endif 
+  //#endif 
 
-  new_thread(send_thread, &shared_ctxt);
+  //new_thread(send_thread, &shared_ctxt);
 
   //while (1) pause();
  
@@ -342,15 +360,15 @@ int enb_agent_stop(mid_t mod_id){
 
 
 
-err_code_t enb_agent_timeout(void* args){
+Protocol__ProgranMessage *enb_agent_timeout(void* args){
 
   //  enb_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args));
   //memcpy (timer_args, args, sizeof(*timer_args));
   enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args;
   
   LOG_I(ENB_AGENT, "enb_agent %d timeout\n", timer_args->mod_id);
-  LOG_I(ENB_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags);
-  LOG_I(ENB_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags);
+  //LOG_I(ENB_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags);
+  //LOG_I(ENB_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags);
   
-  return 0;
+  return NULL;
 }
diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c
index 490658c671..0417f4956e 100644
--- a/openair2/ENB_APP/enb_agent_common.c
+++ b/openair2/ENB_APP/enb_agent_common.c
@@ -311,7 +311,7 @@ uint16_t get_sfn_sf (mid_t mod_id) {
   
   frame = (uint16_t) get_current_frame(mod_id);
   subframe = (uint16_t) get_current_subframe(mod_id);
-  sfn_sf = (frame << 12) | subframe;
+  sfn_sf = (subframe << 12) | frame;
   return sfn_sf;
 }
 
diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h
index d12d3849ec..31d882d0c9 100644
--- a/openair2/ENB_APP/enb_agent_common.h
+++ b/openair2/ENB_APP/enb_agent_common.h
@@ -86,6 +86,8 @@ Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id,
 						    uint8_t *data, 
 						    uint32_t size);
 
+Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args);
+
 void * enb_agent_send_message(Protocol__ProgranMessage *msg, 
 			      uint32_t * size);
 
@@ -107,7 +109,7 @@ int get_current_frame(mid_t mod_id);
 int get_current_subframe(mid_t mod_id);
 
 /*Return the frame and subframe number in compact 16-bit format.
-  Bits 0-3 frame, rest for subframe. Required by progRAN protocol*/
+  Bits 0-3 subframe, rest for frame. Required by progRAN protocol*/
 uint16_t get_sfn_sf (mid_t mod_id);
 
 int get_num_ues(mid_t mod_id);
@@ -137,7 +139,7 @@ int get_ue_wcqi (mid_t mod_id, mid_t ue_id);
 
 
 /* Type of the callback executed when the timer expired */
-typedef err_code_t (*enb_agent_timer_callback_t)(void*);
+typedef Protocol__ProgranMessage *(*enb_agent_timer_callback_t)(void*);
 
 typedef enum {
   /* oneshot timer:  */
@@ -169,13 +171,7 @@ typedef enum {
 
 typedef struct enb_agent_timer_args_s{
   mid_t            mod_id;
-
-  agent_action_t   cc_actions;
-  uint32_t         cc_report_flags;
-
-  agent_action_t   ue_actions;
-  uint32_t         ue_report_flags;
-
+  Protocol__ProgranMessage *msg;
 } enb_agent_timer_args_t;
 
 
@@ -225,7 +221,7 @@ struct enb_agent_timer_element_s * get_timer_entry(long timer_id);
 
 
 
-err_code_t enb_agent_process_timeout(long timer_id, void* timer_args);
+Protocol__ProgranMessage * enb_agent_process_timeout(long timer_id, void* timer_args);
 
 int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b);
 
diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c
index 8c2b9e010a..2841f9b6e5 100644
--- a/openair2/ENB_APP/enb_agent_handler.c
+++ b/openair2/ENB_APP/enb_agent_handler.c
@@ -133,11 +133,28 @@ void * enb_agent_send_message(Protocol__ProgranMessage *msg,
  error : 
   LOG_E(ENB_AGENT,"errno %d occured\n",err_code);
   
-  return NULL; 
+  return NULL;   
+}
+
+Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args) {
+  err_code_t err_code;
+  enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args;
+
+  Protocol__ProgranMessage *timed_task, *reply_message;
+  timed_task = timer_args->msg;
+   err_code = ((*messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message));
+  if ( err_code < 0 ){
+    goto error;
+  }
+
+  return reply_message;
   
+ error:
+  LOG_E(ENB_AGENT,"errno %d occured\n",err_code);
+  return NULL;
 }
 
-err_code_t enb_agent_process_timeout(long timer_id, void* timer_args){
+Protocol__ProgranMessage* enb_agent_process_timeout(long timer_id, void* timer_args){
     
   struct enb_agent_timer_element_s *found = get_timer_entry(timer_id);
  
@@ -148,7 +165,6 @@ err_code_t enb_agent_process_timeout(long timer_id, void* timer_args){
     LOG_W(ENB_AGENT,"null timer args\n");
   
   return found->cb(timer_args);
-  
 
  error:
   LOG_E(ENB_AGENT, "can't get the timer element\n");
diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c
index d2504e4dec..1a21db5e15 100644
--- a/openair2/ENB_APP/enb_agent_mac.c
+++ b/openair2/ENB_APP/enb_agent_mac.c
@@ -48,6 +48,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr
   int size;
   err_code_t err_code;
   xid_t xid;
+  uint32_t usec_interval, sec_interval;
   
   //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 
   int cc_id = 0;
@@ -70,12 +71,13 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr
   switch(stats_req->body_case) {
   case PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ;
     Protocol__PrpCompleteStatsRequest *comp_req = stats_req->complete_stats_request;
-    if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) {
-      //TODO: Must create a periodic report. Implement once the
-      // timer functionality is supported
-      *msg = NULL;
-      return 0;
-    } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) {
+    /* if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) { */
+    /*   //TODO: Must create a periodic report. Implement once the */
+    /*   // timer functionality is supported */
+    /*   *msg = NULL; */
+    /*   return 0; */
+    /* } else */
+    if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) {
       //TODO: Must create an event based report mechanism
       *msg = NULL;
       return 0;
@@ -83,7 +85,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr
       //TODO: Must implement to deactivate the event based reporting
       *msg = NULL;
       return 0;
-    } else { //One-off reporting
+    } else { //One-off or periodical reporting
       //Set the proper flags
       ue_flags = comp_req->ue_report_flags;
       c_flags = comp_req->cell_report_flags;
@@ -114,6 +116,33 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr
 	report_config.cc_report_type[i].cc_id = i;
 	report_config.cc_report_type[i].cc_report_flags = c_flags;
       }
+      /* Check if request was periodical */
+      if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) {
+	/* Create a one off progran message as an argument for the periodical task */
+	Protocol__ProgranMessage *timer_msg;
+	stats_request_config_t request_config;
+	request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS;
+	request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_ONCE;
+	request_config.period = 0; 
+	request_config.config = &report_config;
+	enb_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg);
+	/* Create a timer */
+	long timer_id = 0;
+	enb_agent_timer_args_t *timer_args;
+	timer_args = malloc(sizeof(enb_agent_timer_args_t));
+	memset (timer_args, 0, sizeof(enb_agent_timer_args_t));
+	timer_args->mod_id = enb_id;	
+	timer_args->msg = timer_msg;
+	/*Convert subframes to usec time*/
+	usec_interval = 1000*comp_req->sf;
+	sec_interval = 0;
+	/*add seconds if required*/
+	if (usec_interval >= 1000*1000) {
+	  sec_interval = usec_interval/(1000*1000);
+	  usec_interval = usec_interval%(1000*1000);
+	}
+	enb_agent_create_timer(sec_interval, usec_interval, ENB_AGENT_DEFAULT, enb_id, ENB_AGENT_TIMER_TYPE_PERIODIC, enb_agent_handle_timed_task,(void*) timer_args, &timer_id);
+      }
     }
     break;
   case PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST:;
@@ -172,6 +201,132 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr
   return err_code;
 }
 
+int enb_agent_mac_stats_request(mid_t mod_id,
+				xid_t xid,
+				const stats_request_config_t *report_config, 
+				Protocol__ProgranMessage **msg) {
+  Protocol__PrpHeader *header;
+  int i;
+   
+  if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REQUEST, &header) != 0)
+    goto error;
+  
+  Protocol__PrpStatsRequest *stats_request_msg;
+  stats_request_msg = malloc(sizeof(Protocol__PrpStatsRequest));
+  if(stats_request_msg == NULL)
+    goto error;
+
+  protocol__prp_stats_request__init(stats_request_msg);
+  stats_request_msg->header = header;
+  
+  stats_request_msg->type = report_config->report_type;
+  stats_request_msg->has_type = 1;
+  
+  switch (report_config->report_type) {
+  case PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS:
+    stats_request_msg->body_case =  PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST;
+    Protocol__PrpCompleteStatsRequest *complete_stats;
+    complete_stats = malloc(sizeof(Protocol__PrpCompleteStatsRequest));
+    if(complete_stats == NULL)
+      goto error;
+    protocol__prp_complete_stats_request__init(complete_stats);
+    complete_stats->report_frequency = report_config->report_frequency;
+    complete_stats->has_report_frequency = 1;
+    complete_stats->sf = report_config->period;
+    complete_stats->has_sf = 1;
+    complete_stats->has_cell_report_flags = 1;
+    complete_stats->has_ue_report_flags = 1;
+    if (report_config->config->nr_cc > 0) {
+      complete_stats->cell_report_flags = report_config->config->cc_report_type[0].cc_report_flags;
+    }
+    if (report_config->config->nr_ue > 0) {
+      complete_stats->ue_report_flags = report_config->config->ue_report_type[0].ue_report_flags;
+    }
+    stats_request_msg->complete_stats_request = complete_stats;
+    break;
+  case  PROTOCOL__PRP_STATS_TYPE__PRST_CELL_STATS:
+    stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST;
+     Protocol__PrpCellStatsRequest *cell_stats;
+     cell_stats = malloc(sizeof(Protocol__PrpCellStatsRequest));
+    if(cell_stats == NULL)
+      goto error;
+    protocol__prp_cell_stats_request__init(cell_stats);
+    cell_stats->n_cell = report_config->config->nr_cc;
+    cell_stats->has_flags = 1;
+    if (cell_stats->n_cell > 0) {
+      uint32_t *cells;
+      cells = (uint32_t *) malloc(sizeof(uint32_t)*cell_stats->n_cell);
+      for (i = 0; i < cell_stats->n_cell; i++) {
+	cells[i] = report_config->config->cc_report_type[i].cc_id;
+      }
+      cell_stats->cell = cells;
+      cell_stats->flags = report_config->config->cc_report_type[i].cc_report_flags;
+    }
+    stats_request_msg->cell_stats_request = cell_stats;
+    break;
+  case PROTOCOL__PRP_STATS_TYPE__PRST_UE_STATS:
+    stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_UE_STATS_REQUEST;
+     Protocol__PrpUeStatsRequest *ue_stats;
+     ue_stats = malloc(sizeof(Protocol__PrpUeStatsRequest));
+    if(ue_stats == NULL)
+      goto error;
+    protocol__prp_ue_stats_request__init(ue_stats);
+    ue_stats->n_rnti = report_config->config->nr_ue;
+    ue_stats->has_flags = 1;
+    if (ue_stats->n_rnti > 0) {
+      uint32_t *ues;
+      ues = (uint32_t *) malloc(sizeof(uint32_t)*ue_stats->n_rnti);
+      for (i = 0; i < ue_stats->n_rnti; i++) {
+	ues[i] = report_config->config->ue_report_type[i].ue_rnti;
+      }
+      ue_stats->rnti = ues;
+      ue_stats->flags = report_config->config->ue_report_type[i].ue_report_flags;
+    }
+    stats_request_msg->ue_stats_request = ue_stats;
+    break;
+  default:
+    goto error;
+  }
+  *msg = malloc(sizeof(Protocol__ProgranMessage));
+  if(*msg == NULL)
+    goto error;
+  protocol__progran_message__init(*msg);
+  (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG;
+  (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE;
+  (*msg)->stats_request_msg = stats_request_msg;
+  return 0;
+  
+ error:
+  // TODO: Need to make proper error handling
+  if (header != NULL)
+    free(header);
+  if (stats_request_msg != NULL)
+    free(stats_request_msg);
+  if(*msg != NULL)
+    free(*msg);
+  //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+int enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg) {
+   if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG)
+    goto error;
+  free(msg->stats_request_msg->header);
+  if (msg->stats_request_msg->body_case == PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST) {
+    free(msg->stats_request_msg->cell_stats_request->cell);
+  }
+  if (msg->stats_request_msg->body_case == PROTOCOL__PRP_STATS_REQUEST__BODY_UE_STATS_REQUEST) {
+    free(msg->stats_request_msg->ue_stats_request->rnti);
+  }
+  free(msg->stats_request_msg);
+  free(msg);
+  return 0;
+  
+ error:
+  //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
 int enb_agent_mac_stats_reply(mid_t mod_id,
 			      xid_t xid,
 			      const report_config_t *report_config, 
diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h
index 569eb51e5e..871d6e5ae2 100644
--- a/openair2/ENB_APP/enb_agent_mac.h
+++ b/openair2/ENB_APP/enb_agent_mac.h
@@ -69,11 +69,24 @@ typedef struct {
   cc_report_type_t *cc_report_type;
 } report_config_t;
 
+typedef struct {
+  uint8_t report_type;
+  uint8_t report_frequency;
+  uint16_t period; /*In number of subframes*/
+  report_config_t *config;
+} stats_request_config_t;
+
 
 int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg);
 
+int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__ProgranMessage **msg);
+
+int enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg);
+
 int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg);
 
 int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg);
 
+
+
 #endif
-- 
2.26.2