From 1f213b0b8e24bcc7498534b965b952173a5e8e3e Mon Sep 17 00:00:00 2001
From: Navid Nikaein <navid.nikaein@eurecom.fr>
Date: Tue, 5 Jan 2016 11:33:40 +0100
Subject: [PATCH] * add options to enb configuration file for the enb agent *
 add timer api for the periodic and oneshot operations * create enb agent task

---
 common/utils/itti/timer.c                     |  16 +-
 openair2/COMMON/tasks_def.h                   |   2 +
 openair2/ENB_APP/MESSAGES/V2/progran.proto    |   2 +-
 openair2/ENB_APP/enb_agent.c                  | 247 +++++++++++----
 openair2/ENB_APP/enb_agent.h                  |  13 +-
 openair2/ENB_APP/enb_agent_common.c           | 284 +++++++++++++++++-
 openair2/ENB_APP/enb_agent_common.h           | 165 +++++++++-
 openair2/ENB_APP/enb_agent_defs.h             | 142 +++++++++
 openair2/ENB_APP/enb_agent_handler.c          |  58 ++--
 openair2/ENB_APP/enb_agent_mac.c              |  45 ++-
 openair2/ENB_APP/enb_agent_mac.h              |  12 +-
 openair2/ENB_APP/enb_app.c                    |   7 +-
 openair2/ENB_APP/enb_config.c                 |  43 +++
 openair2/ENB_APP/enb_config.h                 |   3 +
 openair2/UTIL/LOG/log.c                       |   8 +
 openair2/UTIL/LOG/log.h                       |   1 +
 .../enb.band7.agent.oaisim.local_no_mme.conf  | 153 ++++++++++
 17 files changed, 1059 insertions(+), 142 deletions(-)
 create mode 100644 openair2/ENB_APP/enb_agent_defs.h
 create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf

diff --git a/common/utils/itti/timer.c b/common/utils/itti/timer.c
index 864ab16746..683efd1279 100644
--- a/common/utils/itti/timer.c
+++ b/common/utils/itti/timer.c
@@ -94,9 +94,8 @@ int timer_handle_signal(siginfo_t *info)
   timer_p = (struct timer_elm_s *)info->si_ptr;
 
   // LG: To many traces for msc timer:
-  // TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer);
-
-#if defined(ENABLE_ITTI)
+  TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer);
+  printf("Timer with id 0x%lx has expired\n", (long)timer_p->timer);
 
   task_id = timer_p->task_id;
   instance = timer_p->instance;
@@ -106,7 +105,6 @@ int timer_handle_signal(siginfo_t *info)
 
   timer_expired_p->timer_id = (long)timer_p->timer;
   timer_expired_p->arg      = timer_p->timer_arg;
-#endif
 
   /* Timer is a one shot timer, remove it */
   if (timer_p->type == TIMER_ONE_SHOT) {
@@ -123,13 +121,16 @@ int timer_handle_signal(siginfo_t *info)
       TMR_DEBUG("Failed to delete timer 0x%lx\n", (long)timer_p->timer);
     }
   }
-#ifdefined ENABLE_ITTI
+
   /* Notify task of timer expiry */
   if (itti_send_msg_to_task(task_id, instance, message_p) < 0) {
     TMR_DEBUG("Failed to send msg TIMER_HAS_EXPIRED to task %u\n", task_id);
     free(message_p);
     return -1;
   }
+
+#if defined(ENB_AGENT_SB_IF)
+
 #endif 
 
   return 0;
@@ -209,6 +210,11 @@ int timer_setup(
             type == TIMER_PERIODIC ? "periodic" : "single shot",
             *timer_id, interval_sec, interval_us);
 
+  printf("Requesting new %s timer with id 0x%lx that expires within "
+            "%d sec and %d usec\n",
+            type == TIMER_PERIODIC ? "periodic" : "single shot",
+            *timer_id, interval_sec, interval_us);
+
   timer_p->timer = timer;
 
   /* Lock the queue and insert the timer at the tail */
diff --git a/openair2/COMMON/tasks_def.h b/openair2/COMMON/tasks_def.h
index 5e0f8bd211..6cd74c3aed 100644
--- a/openair2/COMMON/tasks_def.h
+++ b/openair2/COMMON/tasks_def.h
@@ -63,6 +63,8 @@ TASK_DEF(TASK_X2AP,     TASK_PRIORITY_MED,          200)
 TASK_DEF(TASK_SCTP,     TASK_PRIORITY_MED,          200)
 ///   eNB APP task
 TASK_DEF(TASK_ENB_APP,  TASK_PRIORITY_MED,          200)
+///   eNB Agent task
+TASK_DEF(TASK_ENB_AGENT,  TASK_PRIORITY_MED,          200)
 
 // UE tasks and sub-tasks:
 //// Layer 2 and Layer 1 sub-tasks
diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto
index 4f989361a9..995cd6861b 100644
--- a/openair2/ENB_APP/MESSAGES/V2/progran.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto
@@ -37,7 +37,7 @@ enum progran_err {
 	MSG_NOT_VALIDATED = -8;
 	MSG_OUT_DATED = -9;
 
-
+	
 	// other erros
 	UNEXPECTED = -100;	
 }	
diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c
index c9a00ae9ce..7003a2c638 100644
--- a/openair2/ENB_APP/enb_agent.c
+++ b/openair2/ENB_APP/enb_agent.c
@@ -27,43 +27,82 @@
 
  *******************************************************************************/
 
-/*! \file 
- * \brief 
- * \author 
+/*! \file enb_agent.h
+ * \brief top level enb agent receive thread and itti task
+ * \author Navid Nikaein and Xenofon Foukas
  * \date 2016
  * \version 0.1
  */
 
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <string.h>
-#include <unistd.h>
-
 #include "enb_agent_common.h"
-#include "link_manager.h"
 #include "log.h"
 #include "enb_agent.h"
 
-typedef uint8_t xid_t;  
+#include "assertions.h"
+
+
+enb_agent_instance_t enb_agent[NUM_MAX_ENB_AGENT];
+msg_context_t shared_ctxt[NUM_MAX_ENB_AGENT];
+/* this could also go into enb_agent struct*/ 
+enb_agent_info_t  enb_agent_info;
 
-// tx and rx shared context 
-typedef struct {
-  message_queue_t       *tx_mq;
-  message_queue_t       *rx_mq;
-  xid_t                 tx_xid;
-  xid_t                 rx_xid; 
-} msg_context_t;
-msg_context_t shared_ctxt;
+char in_ip[40];
+static uint16_t in_port;
 
-void *send_thread(void *arg);
-void *receive_thread(void *arg);
+//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);
+
+/* 
+ * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller 
+ * and can interact with other itti tasks
+*/
+void *enb_agent_task(void *args){
+
+  MessageDef                     *msg_p           = NULL;
+  const char                     *msg_name        = NULL;
+  instance_t                      instance;
+  int                             result;
+
+
+  itti_mark_task_ready(TASK_ENB_AGENT);
+
+  do {
+    // Wait for a message
+    itti_receive_msg (TASK_ENB_AGENT, &msg_p);
+    DevAssert(msg_p != NULL);
+    msg_name = ITTI_MSG_NAME (msg_p);
+    instance = ITTI_MSG_INSTANCE (msg_p);
+
+    switch (ITTI_MSG_ID(msg_p)) {
+    case TERMINATE_MESSAGE:
+      itti_exit_task ();
+      break;
+
+    case MESSAGE_TEST:
+      LOG_I(ENB_AGENT, "Received %s\n", ITTI_MSG_NAME(msg_p));
+      break;
+    
+    case TIMER_HAS_EXPIRED:
+      enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, &msg_p->ittiMsg.timer_has_expired.arg);
+      break;
+
+    default:
+      LOG_E(ENB_AGENT, "Received unexpected message %s\n", msg_name);
+      break;
+    }
+
+    result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
+    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+  } while (1);
 
-void *send_thread(void *arg) {
+  return NULL;
+}
+/*
+void *send_thread(void *args) {
 
-  msg_context_t         *d = arg;
+  msg_context_t         *d = args;
   void                  *data;
   int                   size;
   int                   priority;
@@ -81,10 +120,10 @@ error:
   printf("receive_thread: there was an error\n");
   return NULL;
 }
+*/
+void *receive_thread(void *args) {
 
-void *receive_thread(void *arg) {
-
-  msg_context_t         *d = arg;
+  msg_context_t         *d = args;
   void                  *data;
   int                   size;
   int                   priority;
@@ -97,10 +136,10 @@ void *receive_thread(void *arg) {
       err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING;
       goto error;
     }
-    LOG_D(ENB_APP,"received message with size %d\n", size);
+    LOG_D(ENB_AGENT,"received message with size %d\n", size);
   
     
-    msg=enb_agent_handle_message(d->rx_xid, data, size);
+    msg=enb_agent_handle_message(d->mod_id, d->rx_xid, data, size);
 
     free(data);
     
@@ -115,7 +154,7 @@ void *receive_thread(void *arg) {
 	err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING;
 	goto error;
       }
-      LOG_D(ENB_APP,"sent message with size %d\n", size);
+      LOG_D(ENB_AGENT,"sent message with size %d\n", size);
     }
     
   }
@@ -123,7 +162,7 @@ void *receive_thread(void *arg) {
   return NULL;
 
 error:
-  printf("receive_thread: error %d occured\n",err_code);
+  LOG_E(ENB_AGENT,"receive_thread: error %d occured\n",err_code);
   return NULL;
 }
 
@@ -153,50 +192,146 @@ pthread_t new_thread(void *(*f)(void *), void *b) {
   return t;
 }
 
-int enb_agent_start(){
-
-  socket_link_t   *link;
-  message_queue_t *send_queue;
-  message_queue_t *receive_queue;
-  link_manager_t  *manager;
+int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){
 
-  LOG_I(ENB_APP,"starting enb agent client\n");
+  // 
+  set_enb_vars(mod_id, RAN_LTE_OAI);
+  enb_agent[mod_id].mod_id = mod_id;
+  enb_agent_info.nb_modules+=1;
+  
+  /* 
+   * check the configuration
+   */ 
+  if (enb_properties->properties[mod_id]->enb_agent_ipv4_address != NULL) {
+    strncpy(in_ip, enb_properties->properties[mod_id]->enb_agent_ipv4_address, sizeof(in_ip) );
+    in_ip[sizeof(in_ip) - 1] = 0; // terminate string
+  } else {
+    strcpy(in_ip, DEFAULT_ENB_AGENT_IPv4_ADDRESS ); 
+  }
+  
+  if (enb_properties->properties[mod_id]->enb_agent_port != 0 ) {
+    in_port = enb_properties->properties[mod_id]->enb_agent_port;
+  } else {
+    in_port = DEFAULT_ENB_AGENT_PORT ;
+  }
+  LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n",  
+	enb_agent[mod_id].mod_id,
+	in_ip,
+	in_port);
+
+  //#define TEST_TIMER 0    
+#if !defined TEST_TIMER
+
+  /* 
+   * create a socket 
+   */ 
+  enb_agent[mod_id].link = new_link_client(in_ip, in_port);
+  if (enb_agent[mod_id].link == NULL) goto error;
+  
+  LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n",  
+	enb_agent[mod_id].mod_id,
+	in_ip,
+	in_port);
+  /* 
+   * create a message queue
+   */ 
+  
+  enb_agent[mod_id].send_queue = new_message_queue();
+  if (enb_agent[mod_id].send_queue == NULL) goto error;
+  enb_agent[mod_id].receive_queue = new_message_queue();
+  if (enb_agent[mod_id].receive_queue == NULL) goto error;
+  
+  /* 
+   * create a link manager 
+   */ 
+  
+  enb_agent[mod_id].manager = create_link_manager(enb_agent[mod_id].send_queue, enb_agent[mod_id].receive_queue, enb_agent[mod_id].link);
+  if (enb_agent[mod_id].manager == NULL) goto error;
 
-  link = new_link_client("127.0.0.1", 2210);
-  if (link == NULL) goto error;
+  memset(&shared_ctxt, 0, sizeof(msg_context_t));
+  
+  shared_ctxt[mod_id].mod_id = mod_id;
+  shared_ctxt[mod_id].tx_mq =  enb_agent[mod_id].send_queue;
+  shared_ctxt[mod_id].rx_mq =  enb_agent[mod_id].receive_queue;
 
-  send_queue = new_message_queue();
-  if (send_queue == NULL) goto error;
-  receive_queue = new_message_queue();
-  if (receive_queue == NULL) goto error;
+  /* 
+   * start the enb agent rx thread 
+   */ 
+  
+  new_thread(receive_thread, &shared_ctxt[mod_id]);
 
-  manager = create_link_manager(send_queue, receive_queue, link);
-  if (manager == NULL) goto error;
+#endif 
+  
+  /* 
+   * initilize a timer 
+   */ 
+  
+  enb_agent_init_timer();
+  
+  
+  
+  /* 
+   * 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) {
+    LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n");
+    return -1;
+  }
 
 
-  memset(&shared_ctxt, 0, sizeof(msg_context_t));
-  
-  shared_ctxt.tx_mq = send_queue;
-  shared_ctxt.rx_mq = receive_queue;
+#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;
+  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 
 
-  new_thread(receive_thread, &shared_ctxt);
-  
   //  new_thread(send_thread, &shared_ctxt);
 
-  // while (1) pause();
+  //while (1) pause();
 
-  printf("client ends\n");
+  LOG_I(ENB_AGENT,"client ends\n");
   return 0;
 
 error:
-  printf("there was an error\n");
+  LOG_I(ENB_AGENT,"there was an error\n");
   return 1;
 
 }
 
 
 
-int enb_agent_stop(){
+int enb_agent_stop(mid_t mod_id){
+  
+  int i=0;
 
+  enb_agent_destroy_timers();
+  for ( i =0; i < enb_agent_info.nb_modules; i++) {
+  
+    destroy_link_manager(enb_agent[i].manager);
+  
+    destroy_message_queue(enb_agent[i].send_queue);
+    destroy_message_queue(enb_agent[i].receive_queue);
+  
+    close_link(enb_agent[i].link);
+  }
+}
 
+
+
+err_code_t enb_agent_timeout(void* 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);
+  
+  return 0;
 }
diff --git a/openair2/ENB_APP/enb_agent.h b/openair2/ENB_APP/enb_agent.h
index 89d1d9e0c2..1a53841d45 100644
--- a/openair2/ENB_APP/enb_agent.h
+++ b/openair2/ENB_APP/enb_agent.h
@@ -28,9 +28,9 @@
 
  *******************************************************************************/
 
-/*! \file 
- * \brief 
- * \author 
+/*! \file enb_agent.h
+ * \brief top level enb agent  
+ * \author Navid Nikaein and Xenofon Foukas
  * \date 2016
  * \version 0.1
  */
@@ -38,10 +38,13 @@
 #ifndef ENB_AGENT_H_
 #define ENB_AGENT_H_
 
+#include "enb_config.h" // for enb properties
+#include "enb_agent_common.h"
 
-int enb_agent_start();
+int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties);
 
-int enb_agent_stop();
+int enb_agent_stop(mid_t mod_id);
 
+void *enb_agent_task(void *args);
 
 #endif
diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c
index 848c10b6fa..c2653f4c85 100644
--- a/openair2/ENB_APP/enb_agent_common.c
+++ b/openair2/ENB_APP/enb_agent_common.c
@@ -27,9 +27,9 @@
 
  *******************************************************************************/
 
-/*! \file 
- * \brief 
- * \author 
+/*! \file enb_agent_common.c
+ * \brief common primitives for all agents 
+ * \author Navid Nikaein and Xenofon Foukas
  * \date 2016
  * \version 0.1
  */
@@ -39,6 +39,12 @@
 #include "log.h"
 
 
+void * enb[NUM_MAX_ENB_AGENT];
+void * enb_ue[NUM_MAX_ENB_AGENT];
+/*
+ * message primitives
+ */
+
 int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size) {
 
   *size = protocol__progran_message__get_packed_size(msg);
@@ -52,7 +58,7 @@ int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *
   return 0;
   
  error:
-  LOG_E(ENB_APP, "an error occured\n"); // change the com
+  LOG_E(ENB_AGENT, "an error occured\n"); // change the com
   return -1;
 }
 
@@ -74,9 +80,7 @@ int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage
 
 
 
-
-
-int prp_create_header(uint32_t xid, Protocol__PrpType type,  Protocol__PrpHeader **header) {
+int prp_create_header(xid_t xid, Protocol__PrpType type,  Protocol__PrpHeader **header) {
   
   *header = malloc(sizeof(Protocol__PrpHeader));
   if(*header == NULL)
@@ -98,7 +102,7 @@ int prp_create_header(uint32_t xid, Protocol__PrpType type,  Protocol__PrpHeader
 }
 
 
-int enb_agent_hello(uint32_t xid, const void *params, Protocol__ProgranMessage **msg) {
+int enb_agent_hello(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg) {
  
   Protocol__PrpHeader *header;
   if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_HELLO, &header) != 0)
@@ -150,7 +154,7 @@ int enb_agent_destroy_hello(Protocol__ProgranMessage *msg) {
 }
 
 
-int enb_agent_echo_request(uint32_t xid, const void* params, Protocol__ProgranMessage **msg) {
+int enb_agent_echo_request(mid_t mod_id, xid_t xid, const void* params, Protocol__ProgranMessage **msg) {
   Protocol__PrpHeader *header;
   if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REQUEST, &header) != 0)
     goto error;
@@ -199,7 +203,7 @@ int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg) {
 
 
 
-int enb_agent_echo_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg) {
+int enb_agent_echo_reply(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg) {
   Protocol__PrpHeader *header;
   if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REPLY, &header) != 0)
     goto error;
@@ -246,3 +250,263 @@ int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) {
   LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
   return -1;
 }
+
+/*
+ * get generic info from RAN
+ */
+
+void set_enb_vars(mid_t mod_id, ran_name_t ran){
+
+  switch (ran){
+  case RAN_LTE_OAI :
+    enb[mod_id] =  (void *)&eNB_mac_inst[mod_id];
+    enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list;
+    break;
+  default :
+    goto error;
+  }
+
+  return; 
+
+ error:
+  LOG_E(ENB_AGENT, "unknown RAN name %d\n", ran);
+}
+
+int get_current_time_ms (mid_t mod_id, int subframe_flag){
+
+  if (subframe_flag == 1){
+    return ((eNB_MAC_INST *)enb[mod_id])->frame*10 + ((eNB_MAC_INST *)enb[mod_id])->subframe;
+  }else {
+    return ((eNB_MAC_INST *)enb[mod_id])->frame*10;
+  }
+   
+}
+
+int get_num_ues (mid_t mod_id){
+
+  return  ((UE_list_t *)enb_ue[mod_id])->num_UEs;
+}
+
+int get_ue_crnti (mid_t mod_id, mid_t ue_id){
+
+  return  ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].crnti;
+}
+
+int get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) {
+
+  return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid];
+}
+
+int get_ue_phr (mid_t mod_id, mid_t ue_id) {
+
+  return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].phr_info;
+}
+
+int get_ue_wcqi (mid_t mod_id, mid_t ue_id) {
+
+  return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi;
+}
+/*
+ * timer primitives
+ */
+
+
+//struct enb_agent_map agent_map;
+
+/* The timer_id might not be the best choice for the comparison */
+int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b){
+
+  //if (a->timer_id) return 0;
+  //if (b->timer_id) return 0;
+  
+  if (a->timer_id < b->timer_id) return -1;
+  if (a->timer_id > b->timer_id) return 1;
+
+  // equal timers
+  return 0;
+}
+
+RB_GENERATE(enb_agent_map,enb_agent_timer_element_s, entry, enb_agent_compare_timer);
+
+err_code_t enb_agent_init_timer(void){
+
+  RB_INIT(&enb_agent_head);
+ 
+  /*
+    struct enb_agent_timer_element_s e;
+  memset(&e, 0, sizeof(enb_agent_timer_element_t));
+  RB_INSERT(enb_agent_map, &agent_map, &e); 
+  */
+ return PROTOCOL__PROGRAN_ERR__NO_ERR;
+}
+
+err_code_t enb_agent_create_timer(uint32_t interval_sec,
+				  uint32_t interval_usec,
+				  agent_id_t     agent_id,
+				  instance_t     instance,
+				  uint32_t timer_type,
+				  enb_agent_timer_callback_t cb,
+				  void*    timer_args,
+				  long *timer_id){
+  
+  struct enb_agent_timer_element_s e;
+//uint32_t timer_id;
+  int ret=-1;
+  
+  if ((interval_sec == 0) && (interval_usec == 0 ))
+    return TIMER_NULL;
+  
+  if (timer_type >= ENB_AGENT_TIMER_TYPE_MAX)
+    return TIMER_TYPE_INVALIDE;
+  
+  if (timer_type  ==   ENB_AGENT_TIMER_TYPE_ONESHOT){ 
+    ret = timer_setup(interval_sec, 
+		      interval_usec, 
+		      TASK_ENB_AGENT, 
+		      instance, 
+		      TIMER_ONE_SHOT,
+		      timer_args,
+		      timer_id);
+    
+    e.type = TIMER_ONE_SHOT;
+  }
+  else if (timer_type  ==   ENB_AGENT_TIMER_TYPE_PERIODIC ){
+    ret = timer_setup(interval_sec, 
+		      interval_usec, 
+		      TASK_ENB_AGENT, 
+		      instance, 
+		      TIMER_PERIODIC,
+		      timer_args,
+		      timer_id);
+    
+    e.type = TIMER_PERIODIC;
+  }
+  
+  if (ret < 0 ) {
+    return TIMER_SETUP_FAILED; 
+  }
+
+  e.agent_id = agent_id;
+  e.instance = instance;
+  e.state = ENB_AGENT_TIMER_STATE_ACTIVE;
+  e.timer_id = *timer_id;
+  e.timer_args = timer_args; 
+  e.cb = cb;
+
+  LOG_I(ENB_AGENT,"created a timer with id 0x%lx  for agent %d, instance %d \n",
+	e.timer_id, e.agent_id, e.instance);
+
+  RB_INSERT(enb_agent_map, &enb_agent_head, &e); 
+  
+   
+  /*
+  struct enb_agent_timer_element_s search;
+  search.timer_id = *timer_id;
+  printf("search 1: %p (expected %p)\n", RB_FIND(enb_agent_map, &enb_agent_head, &search), &e);
+  printf("search 1: %p (expected %p)\n", get_timer_entry(e.timer_id), &e);
+  */      
+  return 0; 
+}
+
+err_code_t enb_agent_destroy_timer(long timer_id){
+  
+  struct enb_agent_timer_element_s *e = get_timer_entry(timer_id);
+
+  if (e != NULL ) {
+    RB_REMOVE(enb_agent_map, &enb_agent_head, &e);
+    free(e);
+  }
+  
+  if (timer_remove(timer_id) < 0 ) 
+    goto error;
+  
+  return 0;
+
+ error:
+  LOG_E(ENB_AGENT, "timer can't be removed\n");
+  return TIMER_REMOVED_FAILED ;
+}
+
+err_code_t enb_agent_destroy_timers(void){
+  
+  struct enb_agent_timer_element_s *e = NULL;
+  
+  RB_FOREACH(e, enb_agent_map, &enb_agent_head) {
+    RB_REMOVE(enb_agent_map, &enb_agent_head, e);
+    timer_remove(e->timer_id); 
+    free(e);
+  }  
+
+  return 0;
+
+}
+
+struct enb_agent_timer_element_s * get_timer_entry(long timer_id) {
+  
+  struct enb_agent_timer_element_s search, *e;
+  memset(&search, 0, sizeof(struct enb_agent_timer_element_s));
+  search.timer_id = timer_id;
+ 
+  return RB_FIND(enb_agent_map, &enb_agent_head, &search); 
+}
+
+/*
+ int i =0;
+  RB_FOREACH(e, enb_agent_map, &enb_agent_head) {
+    printf("%d: %p\n", i, e); i++;
+    }
+*/
+
+/*
+err_code_t enb_agent_stop_timer(uint32_t timer_id){
+  
+  struct enb_agent_timer_element_s *e=NULL;
+  
+  RB_FOREACH(e, enb_agent_map, &enb_agent_head) {
+    if (e->timer_id == timer_id)
+      break;
+  }
+
+  if (e != NULL ) {
+    e->state =  ENB_AGENT_TIMER_STATE_STOPPED;
+  }
+  
+  timer_remove(timer_id);
+  
+  return 0;
+
+}
+
+// this will change the timer_id
+err_code_t enb_agent_restart_timer(uint32_t *timer_id){
+  
+  struct enb_agent_timer_element_s *e=NULL;
+    
+  RB_FOREACH(e, enb_agent_map, &enb_agent_head) {
+    if (e->timer_id == timer_id)
+      break;
+  }
+
+  if (e != NULL ) {
+    e->state =  ENB_AGENT_TIMER_STATE_ACTIVE;
+  }
+  
+  ret = timer_setup(e->interval_sec, 
+		    e->interval_usec, 
+		    e->agent_id, 
+		    e->instance, 
+		    e->type,
+		    e->timer_args,
+		    &timer_id);
+    
+  }
+
+  if (ret < 0 ) {
+    return PROTOCOL__PROGRAN_ERR__TIMER_SETUP_FAILED; 
+  }
+  
+  return 0;
+
+}
+
+*/
diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h
index 3bb6596f2e..eb3de96145 100644
--- a/openair2/ENB_APP/enb_agent_common.h
+++ b/openair2/ENB_APP/enb_agent_common.h
@@ -27,9 +27,9 @@
 
  *******************************************************************************/
 
-/*! \file 
- * \brief 
- * \author 
+/*! \file enb_agent_common.h
+ * \brief common message primitves and utilities 
+ * \author Navid Nikaein and Xenofon Foukas
  * \date 2016
  * \version 0.1
  */
@@ -45,10 +45,20 @@
 #include "stats_messages.pb-c.h"
 #include "stats_common.pb-c.h"
 
+# include "enb_agent_defs.h"
+
+#include "LAYER2/MAC/extern.h"
+#include "LAYER2/RLC/rlc.h"
+
+# include "tree.h"
+# include "intertask_interface.h"
+# include "timer.h"
+
 #define PROGRAN_VERSION 0
 
 typedef int (*enb_agent_message_decoded_callback)(
-	uint32_t xid,
+	mid_t mod_id,
+        xid_t xid,
 	const void *params,
 	Protocol__ProgranMessage **msg
 );
@@ -57,32 +67,163 @@ typedef int (*enb_agent_message_destruction_callback)(
 	Protocol__ProgranMessage *msg
 );
 
-typedef int32_t  err_code_t; 
-
 int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size);
 int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg);
 
-int prp_create_header(uint32_t xid, Protocol__PrpType type, Protocol__PrpHeader **header);
+int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader **header);
 
-int enb_agent_hello(uint32_t xid, const void *params, Protocol__ProgranMessage **msg);
+int enb_agent_hello(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg);
 int enb_agent_destroy_hello(Protocol__ProgranMessage *msg);
 
-int enb_agent_echo_request(uint32_t xid, const void *params, Protocol__ProgranMessage **msg);
+int enb_agent_echo_request(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg);
 int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg);
 
-int enb_agent_echo_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg);
+int enb_agent_echo_reply(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg);
 int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg);
 
 
-Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, 
+Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, 
+						    xid_t xid, 
 						    uint8_t *data, 
 						    uint32_t size);
 
-void * enb_agent_send_message(uint32_t xid, 
+void * enb_agent_send_message(xid_t xid, 
 			      Protocol__ProgranMessage *msg, 
 			      uint32_t * size);
 
 
+
+
+
+
+/****************************
+ * get generic info from RAN
+ ****************************/
+
+void set_enb_vars(mid_t mod_id, ran_name_t ran);
+
+int get_current_time_ms (mid_t mod_id, int subframe_flag);
+
+int get_num_ues(mid_t mod_id);
+
+int get_ue_crnti (mid_t mod_id, mid_t ue_id);
+
+int get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid);
+
+int get_ue_phr (mid_t mod_id, mid_t ue_id);
+
+int get_ue_wcqi (mid_t mod_id, mid_t ue_id);
+
+
+
+
+
+
+/*******************
+ * timer primitves
+ *******************/
+
+#define TIMER_NULL                 -1 
+#define TIMER_TYPE_INVALIDE        -2
+#define	TIMER_SETUP_FAILED         -3
+#define	TIMER_REMOVED_FAILED       -4
+#define	TIMER_ELEMENT_NOT_FOUND    -5
+
+
+/* Type of the callback executed when the timer expired */
+typedef err_code_t (*enb_agent_timer_callback_t)(void*);
+
+typedef enum {
+  /* oneshot timer:  */
+  ENB_AGENT_TIMER_TYPE_ONESHOT = 0x0,
+
+  /* periodic timer  */
+  ENB_AGENT_TIMER_TYPE_PERIODIC = 0x1,
+
+  /* Inactive state: initial state for any timer. */
+  ENB_AGENT_TIMER_TYPE_EVENT_DRIVEN = 0x2,
+  
+  /* Max number of states available */
+  ENB_AGENT_TIMER_TYPE_MAX,
+} eNB_agent_timer_type_t;
+
+typedef enum {
+  /* Inactive state: initial state for any timer. */
+  ENB_AGENT_TIMER_STATE_INACTIVE = 0x0,
+
+  /* Inactive state: initial state for any timer. */
+  ENB_AGENT_TIMER_STATE_ACTIVE = 0x1,
+
+  /* Inactive state: initial state for any timer. */
+  ENB_AGENT_TIMER_STATE_STOPPED = 0x2,
+  
+  /* Max number of states available */
+  ENB_AGENT_TIMER_STATE_MAX,
+} eNB_agent_timer_state_t;
+
+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;
+
+} enb_agent_timer_args_t;
+
+
+
+typedef struct enb_agent_timer_element_s{
+  RB_ENTRY(enb_agent_timer_element_s) entry;
+
+  agent_id_t             agent_id;
+  instance_t       instance;
+  
+  eNB_agent_timer_type_t  type;
+  eNB_agent_timer_state_t state;
+
+  uint32_t interval_sec;
+  uint32_t interval_usec;
+
+  long timer_id;  /* Timer id returned by the timer API*/
+  
+  enb_agent_timer_callback_t cb;
+  void* timer_args;
+  
+} enb_agent_timer_element_t;
+
+
+err_code_t enb_agent_init_timer(void);
+
+err_code_t enb_agent_create_timer(uint32_t interval_sec,
+				  uint32_t interval_usec,
+				  agent_id_t     agent_id,
+				  instance_t     instance,
+				  uint32_t timer_type,
+				  enb_agent_timer_callback_t cb,
+				  void*    timer_args,
+				  long *timer_id);
+
+err_code_t enb_agent_destroy_timers(void);
+err_code_t enb_agent_destroy_timer(long timer_id);
+
+err_code_t enb_agent_stop_timer(long timer_id);
+
+err_code_t enb_agent_restart_timer(long *timer_id);
+
+struct enb_agent_timer_element_s * get_timer_entry(long timer_id);
+
+int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b);
+
+err_code_t enb_agent_process_timeout(long timer_id, void* timer_args);
+
+RB_HEAD(enb_agent_map, enb_agent_timer_element_s) enb_agent_head;
+
+/* RB_PROTOTYPE is for .h files */
+RB_PROTOTYPE(enb_agent_map, enb_agent_timer_element_s, entry, enb_agent_compare_timer);
+
+
 #endif
 
 
diff --git a/openair2/ENB_APP/enb_agent_defs.h b/openair2/ENB_APP/enb_agent_defs.h
new file mode 100644
index 0000000000..416e61a431
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_defs.h
@@ -0,0 +1,142 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2016 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.
+
+ *******************************************************************************/
+
+/*! \file enb_agent_defs.h
+ * \brief enb agent common definitions 
+ * \author Navid Nikaein and Xenofon Foukas
+ * \date 2016
+ * \version 0.1
+ */
+#ifndef ENB_AGENT_DEFS_H_
+#define ENB_AGENT_DEFS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "link_manager.h"
+
+#define NUM_MAX_ENB_AGENT 2
+#define DEFAULT_ENB_AGENT_IPv4_ADDRESS "127.0.0.1"
+#define DEFAULT_ENB_AGENT_PORT          2210
+
+typedef enum {
+  
+  ENB_AGENT_DEFAULT=0,
+  
+  ENB_AGENT_PHY=1,
+  ENB_AGENT_MAC=2,
+  ENB_AGENT_RLC=3,
+  ENB_AGENT_PDCP=4,
+  ENB_AGENT_RRC=5,
+  ENB_AGENT_S1AP=6,
+  ENB_AGENT_GTP=7,
+  ENB_AGENT_X2AP=8,
+
+  ENB_AGENT_MAX=9,
+    
+} agent_id_t;
+
+typedef enum {
+  /* no action  */
+  ENB_AGENT_ACTION_NONE = 0x0,
+
+  /* send action  */
+  ENB_AGENT_ACTION_SEND = 0x1,
+
+ /* apply action  */
+  ENB_AGENT_ACTION_APPLY = 0x2,
+
+  /* clear action  */
+  ENB_AGENT_ACTION_CLEAR = 0x4,
+
+  /* write action  */
+  ENB_AGENT_ACTION_WRITE = 0x8,
+
+  /* filter action  */
+  ENB_AGENT_ACTION_FILTER = 0x10,
+
+  /* preprocess action  */
+  ENB_AGENT_ACTION_PREPROCESS = 0x20,
+
+  /* meter action  */
+  ENB_AGENT_ACTION_METER = 0x40,
+  
+  /* Max number of states available */
+  ENB_AGENT_ACTION_MAX = 0x7f,
+} agent_action_t;
+
+
+typedef enum {
+  
+  RAN_LTE_OAI= 0,
+  
+ /* Max number of states available */
+ RAN_NAME_MAX = 0x7f,
+} ran_name_t;
+
+typedef uint8_t xid_t;  
+typedef uint8_t mid_t;  // module or enb id 
+typedef uint8_t lcid_t;
+typedef int32_t  err_code_t; 
+
+// tx and rx shared context 
+typedef struct {
+  mid_t            mod_id;
+  socket_link_t   *link;
+  message_queue_t *send_queue;
+  message_queue_t *receive_queue;
+  link_manager_t  *manager;
+}enb_agent_instance_t;
+
+typedef struct {
+  /* general info */ 
+  uint32_t   nb_modules;
+  
+
+  /* stats */
+
+  uint32_t total_rx_msg;
+  uint32_t total_tx_msg;
+   
+  uint32_t rx_msg[NUM_MAX_ENB_AGENT];
+  uint32_t tx_msg[NUM_MAX_ENB_AGENT];
+
+}enb_agent_info_t;
+
+typedef struct {
+  mid_t                  mod_id;
+  message_queue_t       *tx_mq;
+  message_queue_t       *rx_mq;
+  xid_t                  tx_xid;
+  xid_t                  rx_xid; 
+} msg_context_t;
+
+#endif 
diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c
index 5049e669e9..27536c8b7f 100644
--- a/openair2/ENB_APP/enb_agent_handler.c
+++ b/openair2/ENB_APP/enb_agent_handler.c
@@ -27,9 +27,9 @@
 
  *******************************************************************************/
 
-/*! \file 
- * \brief 
- * \author 
+/*! \file enb_agent_handler.c
+ * \brief enb agent tx and rx message handler 
+ * \author Navid Nikaein and Xenofon Foukas 
  * \date 2016
  * \version 0.1
  */
@@ -67,7 +67,8 @@ static const char *enb_agent_direction2String[] = {
 };
 
 
-Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, 
+Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id,
+						    xid_t xid, 
 						    uint8_t *data, 
 						    uint32_t size){
   
@@ -92,7 +93,7 @@ Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid,
 
   }
 
-  err_code= ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(xid, (void *) decoded_message, &reply_message));
+  err_code = ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(mod_id, xid, (void *) decoded_message, &reply_message));
   if ( err_code < 0 ){
     goto error;
   }
@@ -102,16 +103,16 @@ Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid,
   return reply_message;
   
 error:
-  LOG_E(ENB_APP,"errno %d occured\n",err_code);
-  return err_code;
+  LOG_E(ENB_AGENT,"errno %d occured\n",err_code);
+  return NULL;
 
 }
 
 
 
-void * enb_agent_send_message(uint32_t xid, 
-			   Protocol__ProgranMessage *msg, 
-			   uint32_t * size){
+void * enb_agent_send_message(xid_t xid, 
+			      Protocol__ProgranMessage *msg, 
+			      uint32_t * size){
 
   void * buffer;
   err_code_t err_code = PROTOCOL__PROGRAN_ERR__NO_ERR;
@@ -126,21 +127,32 @@ void * enb_agent_send_message(uint32_t xid,
   err_code = ((*message_destruction_callback[msg->msg_case-1])(msg));
   
   DevAssert(buffer !=NULL);
-
-  LOG_D(ENB_APP,"Serilized the enb mac stats reply (size %d)\n", *size);
-
+  
+  LOG_D(ENB_AGENT,"Serilized the enb mac stats reply (size %d)\n", *size);
+  
   return buffer;
-
-error :
-LOG_E(ENB_APP,"errno %d occured\n",err_code);
-return NULL; 
+  
+ 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){
+    
+  struct enb_agent_timer_element_s *e = get_timer_entry(timer_id);
+  
+  LOG_I(ENB_AGENT, "element %p: timer_id is 0x%lx  0x%lx\n", e, timer_id, e->timer_id);
+   
+  if (e == NULL ) goto error;
+  if (timer_args == NULL)
+    LOG_W(ENB_AGENT,"null timer args\n");
+  
+  return e->cb(timer_args);
+  
 
-
-
-
-
-
-
+ error:
+  LOG_E(ENB_AGENT, "can't get the timer element\n");
+  return TIMER_ELEMENT_NOT_FOUND;
+}
diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c
index 3c188881fb..edf1406296 100644
--- a/openair2/ENB_APP/enb_agent_mac.c
+++ b/openair2/ENB_APP/enb_agent_mac.c
@@ -27,20 +27,18 @@
 
  *******************************************************************************/
 
-/*! \file 
- * \brief 
- * \author 
+/*! \file enb_agent_mac.c
+ * \brief enb agent message handler for MAC layer
+ * \author Navid Nikaein and Xenofon Foukas
  * \date 2016
  * \version 0.1
  */
 
 #include "enb_agent_mac.h"
-#include "enb_agent_common.h"
-#include "LAYER2/MAC/extern.h"
-#include "LAYER2/RLC/rlc.h"
+
 #include "log.h"
 
-int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__ProgranMessage **msg){
+int enb_agent_mac_handle_stats(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg){
   
   // TODO: Must deal with sanitization of input
   // TODO: Must check if RNTIs and cell ids of the request actually exist
@@ -52,11 +50,11 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr
   
   //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 
   int cc_id = 0;
-  int enb_id = 0;
-
-  eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id];
-  UE_list_t *eNB_UE_list= &eNB->UE_list;
+  int enb_id = mod_id;
 
+  //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id];
+  //UE_list_t *eNB_UE_list=  &eNB->UE_list;
+  
   report_config_t report_config;
 
   uint32_t ue_flags = 0;
@@ -90,7 +88,7 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr
       //Create a list of all eNB RNTIs and cells
       
       //Set the number of UEs and create list with their RNTIs stats configs
-      report_config.nr_ue = eNB_UE_list->num_UEs;
+      report_config.nr_ue = get_num_ues(mod_id); //eNB_UE_list->num_UEs
       report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue);
       if (report_config.ue_report_type == NULL) {
 	// TODO: Add appropriate error code
@@ -98,7 +96,7 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr
 	goto error;
       }
       for (i = 0; i < report_config.nr_ue; i++) {
-	report_config.ue_report_type[i].ue_rnti = eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].crnti;
+	report_config.ue_report_type[i].ue_rnti = get_ue_crnti(enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].crnti;
 	report_config.ue_report_type[i].ue_report_flags = ue_flags;
       }
       //Set the number of CCs and create a list with the cell stats configs
@@ -157,7 +155,7 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr
     goto error;
   }
 
-  if (enb_agent_mac_stats_reply(xid, &report_config, msg) < 0 ){
+  if (enb_agent_mac_stats_reply(enb_id, xid, &report_config, msg) < 0 ){
     err_code = PROTOCOL__PROGRAN_ERR__MSG_BUILD;
     goto error;
   }
@@ -168,19 +166,20 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr
   return 0;
 
  error :
-  LOG_E(ENB_APP, "errno %d occured\n", err_code);
+  LOG_E(ENB_AGENT, "errno %d occured\n", err_code);
   return err_code;
 }
 
-int enb_agent_mac_stats_reply(uint32_t xid,
+int enb_agent_mac_stats_reply(mid_t mod_id,
+			      xid_t xid,
 			      const report_config_t *report_config, 
 			      Protocol__ProgranMessage **msg) {
   Protocol__PrpHeader *header;
   int i, j, k;
   int cc_id = 0;
-  int enb_id = 0;
-  eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id];
-  UE_list_t *eNB_UE_list= &eNB->UE_list;
+  int enb_id = mod_id;
+  //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id];
+  //UE_list_t *eNB_UE_list=  &eNB->UE_list;
   
   
   if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REPLY, &header) != 0)
@@ -226,7 +225,7 @@ int enb_agent_mac_stats_reply(uint32_t xid,
 	for (j = 0; j++; j < ue_report[i]->n_bsr) {
 	  // Set the actual BSR for LCG j of the current UE
 	  // NN: we need to know the cc_id here, consider the first one
-	  elem[j] = eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].bsr_info[j];
+	  elem[j] = get_ue_bsr (enb_id, i, j); //eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].bsr_info[j];
 	}
 	ue_report[i]->bsr = elem;
       }
@@ -234,7 +233,7 @@ int enb_agent_mac_stats_reply(uint32_t xid,
       /* Check flag for creation of PRH report */
       if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH) {
 	// TODO: Fill in the actual power headroom value for the RNTI
-	ue_report[i]->phr = eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info;
+	ue_report[i]->phr = get_ue_phr (enb_id, i); // eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info;
 	ue_report[i]->has_phr = 1;
       }
 
@@ -297,7 +296,7 @@ int enb_agent_mac_stats_reply(uint32_t xid,
 	  goto error;
 	protocol__prp_dl_cqi_report__init(dl_report);
 	//TODO:Set the SFN and SF of the last report held in the agent.
-	dl_report->sfn_sn = eNB->frame*10 + eNB->subframe;
+	dl_report->sfn_sn = get_current_time_ms(enb_id, 1);
 	dl_report->has_sfn_sn = 1;
 	//TODO:Set the number of DL CQI reports for this UE. One for each CC
 	dl_report->n_csi_report = 1;
@@ -331,7 +330,7 @@ int enb_agent_mac_stats_reply(uint32_t xid,
 	  protocol__prp_csi_p10__init(csi10);
 	  //TODO: set the wideband value
 	  // NN: this is also depends on cc_id
-	  csi10->wb_cqi = eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi;
+	  csi10->wb_cqi = get_ue_wcqi (enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi;
 	  csi10->has_wb_cqi = 1;
 	  //Add the type of measurements to the csi report in the proper union type
 	  csi_reports[j]->p10csi = csi10;
diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h
index e22253cf27..6584111825 100644
--- a/openair2/ENB_APP/enb_agent_mac.h
+++ b/openair2/ENB_APP/enb_agent_mac.h
@@ -27,9 +27,9 @@
 
  *******************************************************************************/
 
-/*! \file 
- * \brief 
- * \author 
+/*! \file enb_agent_mac.h
+ * \brief enb agent message handler APIs for MAC layer
+ * \author  Navid Nikaein and Xenofon Foukas
  * \date 2016
  * \version 0.1
  */
@@ -42,6 +42,8 @@
 #include "stats_messages.pb-c.h"
 #include "stats_common.pb-c.h"
 
+#include "enb_agent_common.h"
+
 
 /* These types will be used to give
    instructions for the type of stats reports
@@ -68,9 +70,9 @@ typedef struct {
 } report_config_t;
 
 
-int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__ProgranMessage **msg);
+int enb_agent_mac_handle_stats(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg);
 
-int enb_agent_mac_stats_reply(uint32_t xid, const report_config_t *report_config, 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);
 
diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c
index d63d895711..b20d0912d8 100644
--- a/openair2/ENB_APP/enb_app.c
+++ b/openair2/ENB_APP/enb_app.c
@@ -315,8 +315,11 @@ void *eNB_app_task(void *args_p)
   }
 
 #if defined (ENB_AGENT_SB_IF)
-  printf("\n start enb agent\n");
-  enb_agent_start();
+  
+  for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
+    printf("\n start enb agent %d\n", enb_id);
+    enb_agent_start(enb_id, enb_properties_p);
+  }
 #endif 
 
 # if defined(ENABLE_USE_MME)
diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c
index 07e0ffa640..39bd5028d8 100755
--- a/openair2/ENB_APP/enb_config.c
+++ b/openair2/ENB_APP/enb_config.c
@@ -170,6 +170,11 @@
 #define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U         "ENB_IPV4_ADDRESS_FOR_S1U"
 #define ENB_CONFIG_STRING_ENB_PORT_FOR_S1U              "ENB_PORT_FOR_S1U"
 
+#define ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG     "NETWORK_CONTROLLER"
+#define ENB_CONFIG_STRING_ENB_AGENT_INTERFACE_NAME      "ENB_AGENT_INTERFACE_NAME"
+#define ENB_CONFIG_STRING_ENB_AGENT_IPV4_ADDRESS        "ENB_AGENT_IPV4_ADDRESS"
+#define ENB_CONFIG_STRING_ENB_AGENT_PORT                "ENB_AGENT_PORT"
+
 
 #define ENB_CONFIG_STRING_ASN1_VERBOSITY                   "Asn1_verbosity"
 #define ENB_CONFIG_STRING_ASN1_VERBOSITY_NONE              "none"
@@ -275,6 +280,14 @@ static void enb_config_display(void)
       printf( "\tMNC:                \t%02"PRIu16":\n",enb_properties.properties[i]->mnc);
     }
 
+#if defined(ENB_AGENT_SB_IF)
+    printf( "\nENB AGENT CONFIG : \n\n");
+    printf( "\tInterface name:           \t%s:\n",enb_properties.properties[i]->enb_agent_interface_name);
+    printf( "\tInterface IP Address:     \t%s:\n",enb_properties.properties[i]->enb_agent_ipv4_address);
+    printf( "\tInterface PORT:           \t%d:\n\n",enb_properties.properties[i]->enb_agent_port);
+    
+#endif 
+
     for (j=0; j< enb_properties.properties[i]->nb_cc; j++) {
       printf( "\teutra band for CC %d:         \t%"PRId16":\n",j,enb_properties.properties[i]->eutra_band[j]);
       printf( "\tdownlink freq for CC %d:      \t%"PRIu64":\n",j,enb_properties.properties[i]->downlink_frequency[j]);
@@ -571,6 +584,9 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
   char             *address                       = NULL;
   char             *cidr                          = NULL;
   char             *astring                       = NULL;
+  char*             enb_agent_interface_name      = NULL;
+  char*             enb_agent_ipv4_address        = NULL;
+  libconfig_int     enb_agent_port                = 0;
   libconfig_int     otg_ue_id                     = 0;
   char*             otg_app_type                  = NULL;
   char*             otg_bg_traffic                = NULL;
@@ -2190,6 +2206,33 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
               }
             }
           }
+	  
+	  // Network Controller 
+	  subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG);
+
+          if (subsetting != NULL) {
+            if (  (
+                   config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_AGENT_INTERFACE_NAME,
+                                                 (const char **)&enb_agent_interface_name)
+                   && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_AGENT_IPV4_ADDRESS,
+                                                    (const char **)&enb_agent_ipv4_address)
+                   && config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_AGENT_PORT,
+                                                &enb_agent_port)
+                 )
+              ) {
+              enb_properties.properties[enb_properties_index]->enb_agent_interface_name = strdup(enb_agent_interface_name);
+              cidr = enb_agent_ipv4_address;
+              address = strtok(cidr, "/");
+	      enb_properties.properties[enb_properties_index]->enb_agent_ipv4_address = strdup(address);
+	      /*  if (address) {
+                IPV4_STR_ADDR_TO_INT_NWBO (address, enb_properties.properties[enb_properties_index]->enb_agent_ipv4_address, "BAD IP ADDRESS FORMAT FOR eNB Agent !\n" );
+		}*/
+
+              enb_properties.properties[enb_properties_index]->enb_agent_port = enb_agent_port;
+             
+            }
+          }
+	  
 
           // OTG _CONFIG
           setting_otg = config_setting_get_member (setting_enb, ENB_CONF_STRING_OTG_CONFIG);
diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h
index 113681dafe..7182628de0 100755
--- a/openair2/ENB_APP/enb_config.h
+++ b/openair2/ENB_APP/enb_config.h
@@ -203,6 +203,9 @@ typedef struct Enb_properties_s {
   char               *enb_interface_name_for_S1_MME;
   in_addr_t           enb_ipv4_address_for_S1_MME;
 
+  char               *enb_agent_interface_name;
+  in_addr_t           enb_agent_ipv4_address;
+  tcp_udp_port_t      enb_agent_port;
   // otg config
   /* Nb of OTG elements */
   uint8_t            num_otg_elements;
diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c
index abbdbc01ab..f8326be820 100755
--- a/openair2/UTIL/LOG/log.c
+++ b/openair2/UTIL/LOG/log.c
@@ -333,6 +333,14 @@ int logInit (void)
   g_log->log_component[ENB_APP].filelog = 0;
   g_log->log_component[ENB_APP].filelog_name = "";
 
+  g_log->log_component[ENB_AGENT].name = "ENB_AGENT";
+  g_log->log_component[ENB_AGENT].level = LOG_DEBUG;
+  g_log->log_component[ENB_AGENT].flag = LOG_MED;
+  g_log->log_component[ENB_AGENT].interval = 1;
+  g_log->log_component[ENB_AGENT].fd = 0;
+  g_log->log_component[ENB_AGENT].filelog = 0;
+  g_log->log_component[ENB_AGENT].filelog_name = "";
+  
   g_log->log_component[TMR].name = "TMR";
   g_log->log_component[TMR].level = LOG_EMERG;
   g_log->log_component[TMR].flag = LOG_MED;
diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h
index c6abbfa001..1eb68f6e44 100755
--- a/openair2/UTIL/LOG/log.h
+++ b/openair2/UTIL/LOG/log.h
@@ -264,6 +264,7 @@ typedef enum {
   RAL_ENB,
   RAL_UE,
   ENB_APP,
+  ENB_AGENT,
   TMR,
   USIM,
   LOCALIZE,
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf
new file mode 100644
index 0000000000..045a2855a0
--- /dev/null
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf
@@ -0,0 +1,153 @@
+Active_eNBs = ( "eNB_Eurecom_LTEBox");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+eNBs =
+(
+ {
+    ////////// Identification parameters:
+    eNB_ID    =  0xe00;
+
+    cell_type =  "CELL_MACRO_ENB";
+
+    eNB_name  =  "eNB_Eurecom_LTEBox";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code  =  "1";
+
+    mobile_country_code =  "208";
+
+    mobile_network_code =  "10";
+
+       ////////// Physical parameters:
+
+    component_carriers = (
+      {
+        frame_type					      = "FDD";
+        tdd_config 					      = 3;
+        tdd_config_s            			      = 0;
+        prefix_type             			      = "NORMAL";
+        eutra_band              			      = 7;
+        downlink_frequency      			      = 2680000000L;
+        uplink_frequency_offset 			      = -120000000;
+        Nid_cell					              = 0;
+        N_RB_DL                 			      = 25;
+        Nid_cell_mbsfn          			      = 0;
+        nb_antennas_tx          			      = 1;
+        nb_antennas_rx          			      = 1;
+        tx_gain                                   = 25;
+        rx_gain                                   = 20;
+        prach_root              			      = 0;
+        prach_config_index      			      = 0;
+        prach_high_speed        			      = "DISABLE";
+        prach_zero_correlation  			      = 1;
+        prach_freq_offset       			      = 2;
+        pucch_delta_shift       			      = 1;
+        pucch_nRB_CQI           			      = 1;
+        pucch_nCS_AN            			      = 0;
+        pucch_n1_AN             			      = 32;
+        pdsch_referenceSignalPower 			      = 0;
+        pdsch_p_b                  			      = 0;
+        pusch_n_SB                 			      = 1;
+        pusch_enable64QAM          			      = "DISABLE";
+        pusch_hoppingMode                         = "interSubFrame";
+        pusch_hoppingOffset                       = 0;
+        pusch_groupHoppingEnabled  			      = "ENABLE";
+        pusch_groupAssignment      			      = 0;
+        pusch_sequenceHoppingEnabled		   	  = "DISABLE";
+        pusch_nDMRS1                              = 0;
+        phich_duration                            = "NORMAL";
+        phich_resource                            = "ONESIXTH";
+        srs_enable                                = "DISABLE";
+        /*  srs_BandwidthConfig                   =;
+        srs_SubframeConfig                        =;
+        srs_ackNackST                             =;
+        srs_MaxUpPts                              =;*/
+
+        pusch_p0_Nominal                          = -108;
+        pusch_alpha                               = "AL1";
+        pucch_p0_Nominal                          = -108;
+        msg3_delta_Preamble                       = 6;
+        pucch_deltaF_Format1                      = "deltaF2";
+        pucch_deltaF_Format1b                     = "deltaF3";
+        pucch_deltaF_Format2                      = "deltaF0";
+        pucch_deltaF_Format2a                     = "deltaF0";
+        pucch_deltaF_Format2b		    	      = "deltaF0";
+
+        rach_numberOfRA_Preambles                 = 64;
+        rach_preamblesGroupAConfig                = "DISABLE";
+        /*
+        rach_sizeOfRA_PreamblesGroupA             = ;
+        rach_messageSizeGroupA                    = ;
+        rach_messagePowerOffsetGroupB             = ;
+        */
+        rach_powerRampingStep                     = 2;
+        rach_preambleInitialReceivedTargetPower   = -100;
+        rach_preambleTransMax                     = 10;
+        rach_raResponseWindowSize                 = 10;
+        rach_macContentionResolutionTimer         = 48;
+        rach_maxHARQ_Msg3Tx                       = 4;
+
+        pcch_default_PagingCycle                  = 128;
+        pcch_nB                                   = "oneT";
+        bcch_modificationPeriodCoeff			  = 2;
+        ue_TimersAndConstants_t300			      = 1000;
+        ue_TimersAndConstants_t301			      = 1000;
+        ue_TimersAndConstants_t310			      = 1000;
+        ue_TimersAndConstants_t311			      = 10000;
+        ue_TimersAndConstants_n310			      = 20;
+        ue_TimersAndConstants_n311			      = 1;
+      }
+    );
+
+    ////////// MME parameters:
+    mme_ip_address      = ( { ipv4       = "0.0.0.0";
+                              ipv6       = "0::0";
+                              active     = "yes";
+                              preference = "ipv4";
+                            }
+                          );
+
+    NETWORK_INTERFACES :
+    {
+        ENB_INTERFACE_NAME_FOR_S1_MME            = "none";
+        ENB_IPV4_ADDRESS_FOR_S1_MME              = "0.0.0.0/24";
+
+        ENB_INTERFACE_NAME_FOR_S1U               = "none";
+        ENB_IPV4_ADDRESS_FOR_S1U                 = "0.0.0.0/24";
+        ENB_PORT_FOR_S1U                         = 2153; # Spec 2152
+    };
+
+     NETWORK_CONTROLLER :
+    {
+        ENB_AGENT_INTERFACE_NAME            = "eth0";
+        ENB_AGENT_IPV4_ADDRESS              = "127.0.0.1/24";
+	ENB_AGENT_PORT	 		    = 2210;
+    };
+
+    log_config :
+    {
+      global_log_level                      ="trace";
+      global_log_verbosity                  ="medium";
+      hw_log_level                          ="info";
+      hw_log_verbosity                      ="medium";
+      phy_log_level                         ="trace";
+      phy_log_verbosity                     ="medium";
+      mac_log_level                         ="trace";
+      mac_log_verbosity                     ="medium";
+      rlc_log_level                         ="trace";
+      rlc_log_verbosity                     ="medium";
+      pdcp_log_level                        ="trace";
+      pdcp_log_verbosity                    ="medium";
+      rrc_log_level                         ="trace";
+      rrc_log_verbosity                     ="medium";
+      gtpu_log_level                        ="debug";
+      gtpu_log_verbosity                    ="medium";
+      udp_log_level                         ="debug";
+      udp_log_verbosity                     ="medium";
+      osa_log_level                         ="debug";
+      osa_log_verbosity                     ="low";
+   };
+
+  }
+);
-- 
2.26.2