diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 197b94699cf4cc01edd36bf200e4b98d003bcf7f..6fa30b2b35e8ce53f31a19b08c5ba164efef7ea0 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -477,7 +477,7 @@ add_boolean_option(MESSAGE_CHART_GENERATOR False         "For generating sequenc
 add_boolean_option(MESSAGE_CHART_GENERATOR_RLC_MAC False "trace RLC-MAC exchanges in sequence diagrams")
 add_boolean_option(MESSAGE_CHART_GENERATOR_PHY     False "trace some PHY exchanges in sequence diagrams")
 
-add_boolean_option(ENB_AGENT                   True         "enable eNB agent to inteface with a SDN contrller")
+add_boolean_option(ENB_AGENT_SB_IF             True         "enable eNB agent to inteface with a SDN contrller")
 
 ########################
 # Include order
@@ -693,7 +693,7 @@ include_directories("${OPENAIR_DIR}")
 
 # Utilities Library
 ################
-if (ENB_AGENT)
+if (ENB_AGENT_SB_IF)
   # set the version of protobuf messages, V3 not supported yet
   add_list1_option(PRPT_VERSION V2 "PRPT MSG  protobuf  grammar version" V2 V3)
   
@@ -730,7 +730,8 @@ if (ENB_AGENT)
     ${PRPT_source}
     )
   set(PRPT_MSG_LIB PRPT_MSG)
-  include_directories ("${PRPT_C_DIR}")
+  #message("prpt c dir is : ${PRPT_C_DIR}")
+  include_directories (${PRPT_C_DIR})
 
   add_library(ASYNC_IF
     ${OPENAIR2_DIR}/UTIL/ASYNC_IF/socket_link.c
@@ -740,6 +741,18 @@ if (ENB_AGENT)
   set(ASYNC_IF_LIB ASYNC_IF)
   include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF)
 
+ add_library(ENB_AGENT
+    ${OPENAIR2_DIR}/ENB_APP/enb_agent_handler.c
+    ${OPENAIR2_DIR}/ENB_APP/enb_agent_common.c
+    ${OPENAIR2_DIR}/ENB_APP/enb_agent_mac.c
+    ${OPENAIR2_DIR}/ENB_APP/enb_agent.c
+    )
+  set(ENB_AGENT_LIB ENB_AGENT)
+  #include_directories(${OPENAIR2_DIR}/ENB_APP)
+  
+  set(PROTOBUF_LIB "protobuf-c")
+  
+  #set(PROTOBUF_LIB "protobuf") #for Cpp
 endif()
 
 
@@ -1647,15 +1660,16 @@ add_executable(oaisim_nos1
 target_include_directories(oaisim_nos1 PUBLIC  ${OPENAIR_TARGETS}/SIMU/USER)
 target_link_libraries (oaisim_nos1
   -Wl,--start-group
-  RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB}  ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB}
+  RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB}  ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} 
   -Wl,--end-group )
 
 target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES})
 target_link_libraries (oaisim_nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES}  ${NETTLE_LIBRARIES}  ${option_HW_lib}
-  ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES})
+  ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES} ${PROTOBUF_LIB})
 #Force link with forms, regardless XFORMS option
 target_link_libraries (oaisim_nos1 forms)
 
+#message("protobuflib is  ${PROTOBUF_LIB}")
 
 # Unitary tests for each piece of L1: example, mbmssim is MBMS L1 simulator
 #####################################
diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template
index a9055101501a3c6a5ee1212e7c8f50258274dc1b..7bdf252352b9ea786f625fbf6fdb426874eecfaf 100644
--- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template
+++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template
@@ -48,7 +48,7 @@ set (  NEW_FFT True )
 set (  NO_RRM True )
 set (  OAI_EMU True )
 set (  OAISIM True )
-set (  OAI_NW_DRIVER_TYPE_ETHERNET True )
+set (  OAI_NW_DRIVER_TYPE_ETHERNET False )
 set (  OAI_NW_DRIVER_USE_NETLINK True )
 set (  OPENAIR1 True )
 set (  OPENAIR2 True )
diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto
index f25613d86d2f9b6f9a6fbc8d4f9fe43b03e06849..b2319c8220cd3c513bdb7b53fff9e1888059168a 100644
--- a/openair2/ENB_APP/MESSAGES/V2/header.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/header.proto
@@ -3,7 +3,7 @@ package protocol;
 message prp_header {
 	optional uint32 version = 1;
 	optional uint32 type = 2;
-	optional uint32 xid = 3;
+	optional uint32 xid = 4;
 }
 
 enum prp_type {
@@ -16,3 +16,4 @@ enum prp_type {
      PRPT_STATS_REQUEST = 3;
      PRPT_STATS_REPLY = 4;
 }
+
diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto
index e631762946dbeda89dea518ba061c6cef2e227db..363592d6e3220e637fd2afba764b979602aade79 100644
--- a/openair2/ENB_APP/MESSAGES/V2/progran.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto
@@ -1,10 +1,12 @@
+//'syntax = "proto2";' 
 package protocol;
 
 import "stats_messages.proto";
 import "header.proto";
 
 message progran_message {
-        oneof msg {
+       required progran_direction msg_dir = 100;
+	oneof msg {
               prp_hello hello_msg = 1;
               prp_echo_request echo_request_msg = 2;
 	      prp_echo_reply echo_reply_msg = 3;
@@ -13,6 +15,32 @@ message progran_message {
 	}
 }
 
+enum progran_direction {
+     //option allow_alias = true;
+     NOT_SET = 0;
+     INITIATING_MESSAGE = 1;
+     SUCCESSFUL_OUTCOME=2;
+     UNSUCCESSFUL_OUTCOME=3;	
+}
+	
+enum progran_err {
+        option allow_alias = true;
+	// message errors
+	NO_ERR = 0;	
+	MSG_DEQUEUING = -1;
+	MSG_ENQUEUING = -2;
+	MSG_DECODING = -3;
+	MSG_ENCODING = -4;
+	MSG_BUILD = -5;
+	MSG_NOT_SUPPORTED = -6; 
+	MSG_NOT_HANDLED = -7;
+	MSG_NOT_VALIDATED = -8;
+	MSG_OUT_DATED = -9;
+
+
+	// other erros
+	UNEXPECTED = -100;	
+}	
 
 //
 // Maintenance and discovery messages
@@ -34,7 +62,6 @@ message prp_echo_reply {
 }
 
 
-
 //
 // Statistics request and reply message
 //
diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c
new file mode 100644
index 0000000000000000000000000000000000000000..c9a00ae9ce10ca338cdcde97746f7fa7bc558cb8
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent.c
@@ -0,0 +1,202 @@
+/*******************************************************************************
+    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.
+
+ *******************************************************************************/
+
+/*! \file 
+ * \brief 
+ * \author 
+ * \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;  
+
+// 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;
+
+void *send_thread(void *arg);
+void *receive_thread(void *arg);
+pthread_t new_thread(void *(*f)(void *), void *b);
+
+void *send_thread(void *arg) {
+
+  msg_context_t         *d = arg;
+  void                  *data;
+  int                   size;
+  int                   priority;
+
+  
+  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 *arg) {
+
+  msg_context_t         *d = arg;
+  void                  *data;
+  int                   size;
+  int                   priority;
+  err_code_t             err_code;
+
+  Protocol__ProgranMessage *msg;
+  
+  while (1) {
+    if (message_get(d->rx_mq, &data, &size, &priority)){
+      err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING;
+      goto error;
+    }
+    LOG_D(ENB_APP,"received message with size %d\n", size);
+  
+    
+    msg=enb_agent_handle_message(d->rx_xid, data, size);
+
+    free(data);
+    
+    d->rx_xid = ((d->rx_xid)+1)%4;
+    d->tx_xid = d->rx_xid;
+  
+    // check if there is something to send back to the controller
+    if (msg != NULL){
+      data=enb_agent_send_message(d->tx_xid,msg,&size);
+     
+      if (message_put(d->tx_mq, data, size, priority)){
+	err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING;
+	goto error;
+      }
+      LOG_D(ENB_APP,"sent message with size %d\n", size);
+    }
+    
+  }
+
+  return NULL;
+
+error:
+  printf("receive_thread: error %d occured\n",err_code);
+  return NULL;
+}
+
+
+/* utility function to create a thread */
+pthread_t new_thread(void *(*f)(void *), void *b) {
+  pthread_t t;
+  pthread_attr_t att;
+
+  if (pthread_attr_init(&att)){ 
+    fprintf(stderr, "pthread_attr_init err\n"); 
+    exit(1); 
+  }
+  if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) { 
+    fprintf(stderr, "pthread_attr_setdetachstate err\n"); 
+    exit(1); 
+  }
+  if (pthread_create(&t, &att, f, b)) { 
+    fprintf(stderr, "pthread_create err\n"); 
+    exit(1); 
+  }
+  if (pthread_attr_destroy(&att)) { 
+    fprintf(stderr, "pthread_attr_destroy err\n"); 
+    exit(1); 
+  }
+
+  return t;
+}
+
+int enb_agent_start(){
+
+  socket_link_t   *link;
+  message_queue_t *send_queue;
+  message_queue_t *receive_queue;
+  link_manager_t  *manager;
+
+  LOG_I(ENB_APP,"starting enb agent client\n");
+
+  link = new_link_client("127.0.0.1", 2210);
+  if (link == NULL) goto error;
+
+  send_queue = new_message_queue();
+  if (send_queue == NULL) goto error;
+  receive_queue = new_message_queue();
+  if (receive_queue == NULL) goto error;
+
+  manager = create_link_manager(send_queue, receive_queue, link);
+  if (manager == NULL) goto error;
+
+
+  memset(&shared_ctxt, 0, sizeof(msg_context_t));
+  
+  shared_ctxt.tx_mq = send_queue;
+  shared_ctxt.rx_mq = receive_queue;
+
+  new_thread(receive_thread, &shared_ctxt);
+  
+  //  new_thread(send_thread, &shared_ctxt);
+
+  // while (1) pause();
+
+  printf("client ends\n");
+  return 0;
+
+error:
+  printf("there was an error\n");
+  return 1;
+
+}
+
+
+
+int enb_agent_stop(){
+
+
+}
diff --git a/openair2/ENB_APP/enb_agent.h b/openair2/ENB_APP/enb_agent.h
new file mode 100644
index 0000000000000000000000000000000000000000..89d1d9e0c2b9d58ebee52c3d325681269377b5d5
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent.h
@@ -0,0 +1,47 @@
+
+/*******************************************************************************
+    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.
+
+ *******************************************************************************/
+
+/*! \file 
+ * \brief 
+ * \author 
+ * \date 2016
+ * \version 0.1
+ */
+
+#ifndef ENB_AGENT_H_
+#define ENB_AGENT_H_
+
+
+int enb_agent_start();
+
+int enb_agent_stop();
+
+
+#endif
diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c
new file mode 100644
index 0000000000000000000000000000000000000000..d71a5a6accae7c478a58a170d1f8f84403b1b1f6
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_common.c
@@ -0,0 +1,246 @@
+/*******************************************************************************
+    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.
+
+ *******************************************************************************/
+
+/*! \file 
+ * \brief 
+ * \author 
+ * \date 2016
+ * \version 0.1
+ */
+
+
+#include "enb_agent_common.h"
+#include "log.h"
+
+
+int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size) {
+
+  *size = protocol__progran_message__get_packed_size(msg);
+  
+  *buf = malloc(*size);
+  if (buf == NULL)
+    goto error;
+  
+  protocol__progran_message__pack(msg, *buf);
+  
+  return 0;
+  
+ error:
+  LOG_E(ENB_APP, "an error occured\n"); // change the com
+  return -1;
+}
+
+
+
+/* We assume that the buffer size is equal to the message size.
+   Should be chekced durint Tx/Rx */
+int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg) {
+  *msg = protocol__progran_message__unpack(NULL, size, data);
+  if (*msg == NULL)
+    goto error;
+  
+  return 0;
+  
+ error:
+  //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+
+
+
+
+int prp_create_header(uint32_t xid, Protocol__PrpType type,  Protocol__PrpHeader **header) {
+  
+  *header = malloc(sizeof(Protocol__PrpHeader));
+  if(*header == NULL)
+    goto error;
+  
+  protocol__prp_header__init(*header);
+  (*header)->version = PROGRAN_VERSION;
+  (*header)->has_version = 1; 
+  // check if the type is set
+  (*header)->type = type;
+  (*header)->has_type = 1;
+  (*header)->xid = xid;
+  (*header)->has_xid = 1;
+  return 0;
+
+ error:
+  LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+
+int enb_agent_hello(uint32_t xid, Protocol__ProgranMessage **msg) {
+ 
+  Protocol__PrpHeader *header;
+  if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_HELLO, &header) != 0)
+    goto error;
+
+  Protocol__PrpHello *hello_msg;
+  hello_msg = malloc(sizeof(Protocol__PrpHello));
+  if(hello_msg == NULL)
+    goto error;
+  protocol__prp_hello__init(hello_msg);
+  hello_msg->header = header;
+
+  *msg = malloc(sizeof(Protocol__ProgranMessage));
+  if(*msg == NULL)
+    goto error;
+  
+  protocol__progran_message__init(*msg);
+  (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG;
+  (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE;
+  (*msg)->hello_msg = hello_msg;
+  return 0;
+  
+ error:
+  if(header != NULL)
+    free(header);
+  if(hello_msg != NULL)
+    free(hello_msg);
+  if(*msg != NULL)
+    free(*msg);
+  LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+
+int enb_agent_destroy_hello_message(Protocol__ProgranMessage *msg) {
+  
+  if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG)
+    goto error;
+  
+  free(msg->hello_msg->header);
+  free(msg->hello_msg);
+  free(msg);
+  return 0;
+
+ error:
+  LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+
+int enb_agent_echo_request(uint32_t xid, Protocol__ProgranMessage **msg) {
+  Protocol__PrpHeader *header;
+  if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REQUEST, &header) != 0)
+    goto error;
+
+  Protocol__PrpEchoRequest *echo_request_msg;
+  echo_request_msg = malloc(sizeof(Protocol__PrpEchoRequest));
+  if(echo_request_msg == NULL)
+    goto error;
+  protocol__prp_echo_request__init(echo_request_msg);
+  echo_request_msg->header = header;
+
+  *msg = malloc(sizeof(Protocol__ProgranMessage));
+  if(*msg == NULL)
+    goto error;
+  protocol__progran_message__init(*msg);
+  (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG;
+  (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE;
+  (*msg)->echo_request_msg = echo_request_msg;
+  return 0;
+
+ error:
+  if(header != NULL)
+    free(header);
+  if(echo_request_msg != NULL)
+    free(echo_request_msg);
+  if(*msg != NULL)
+    free(*msg);
+  //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+
+int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg) {
+  if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG)
+    goto error;
+  
+  free(msg->echo_request_msg->header);
+  free(msg->echo_request_msg);
+  free(msg);
+  return 0;
+  
+ error:
+  LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+
+
+int enb_agent_echo_reply(uint32_t xid, Protocol__ProgranMessage **msg) {
+  Protocol__PrpHeader *header;
+  if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REPLY, &header) != 0)
+    goto error;
+
+  Protocol__PrpEchoReply *echo_reply_msg;
+  echo_reply_msg = malloc(sizeof(Protocol__PrpEchoReply));
+  if(echo_reply_msg == NULL)
+    goto error;
+  protocol__prp_echo_reply__init(echo_reply_msg);
+  echo_reply_msg->header = header;
+
+  *msg = malloc(sizeof(Protocol__ProgranMessage));
+  if(*msg == NULL)
+    goto error;
+  protocol__progran_message__init(*msg);
+  (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG;
+  (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME;
+  (*msg)->echo_reply_msg = echo_reply_msg;
+  return 0;
+
+ error:
+  if(header != NULL)
+    free(header);
+  if(echo_reply_msg != NULL)
+    free(echo_reply_msg);
+  if(*msg != NULL)
+    free(*msg);
+  LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+
+int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) {
+  if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG)
+    goto error;
+  
+  free(msg->echo_reply_msg->header);
+  free(msg->echo_reply_msg);
+  free(msg);
+  return 0;
+  
+ error:
+  LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..3fb0d366acb79d55632f3d95e7ea4ef2c3d6ed38
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_common.h
@@ -0,0 +1,88 @@
+/*******************************************************************************
+    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.
+
+ *******************************************************************************/
+
+/*! \file 
+ * \brief 
+ * \author 
+ * \date 2016
+ * \version 0.1
+ */
+
+
+
+#ifndef ENB_AGENT_COMMON_H_
+#define ENB_AGENT_COMMON_H_
+
+
+#include "header.pb-c.h"
+#include "progran.pb-c.h"
+#include "stats_messages.pb-c.h"
+#include "stats_common.pb-c.h"
+
+#define PROGRAN_VERSION 0
+
+typedef int (*enb_agent_message_decoded_callback)(
+	uint32_t xid,
+	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 enb_agent_hello(uint32_t xid, Protocol__ProgranMessage **msg);
+int enb_agent_destroy_hello(Protocol__ProgranMessage *msg);
+
+int enb_agent_echo_request(uint32_t xid, Protocol__ProgranMessage **msg);
+int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg);
+
+int enb_agent_echo_reply(uint32_t xid, Protocol__ProgranMessage **msg);
+int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg);
+
+
+Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, 
+						    uint8_t *data, 
+						    uint32_t size);
+
+void * enb_agent_send_message(uint32_t xid, 
+			      Protocol__ProgranMessage *msg, 
+			      uint32_t * size);
+
+
+#endif
+
+
+
+
+
+
+
diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c
new file mode 100644
index 0000000000000000000000000000000000000000..2b9509f48efcb3119eedeb2dee6e632425325d08
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_handler.c
@@ -0,0 +1,133 @@
+/*******************************************************************************
+    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.
+
+ *******************************************************************************/
+
+/*! \file 
+ * \brief 
+ * \author 
+ * \date 2016
+ * \version 0.1
+ */
+
+
+#include "enb_agent_common.h"
+#include "enb_agent_mac.h"
+#include "log.h"
+
+#include "assertions.h"
+
+enb_agent_message_decoded_callback messages_callback[][3] = {
+  {enb_agent_hello, enb_agent_hello,0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG*/
+  {enb_agent_echo_request, enb_agent_echo_reply,0}, /**/
+  {0, enb_agent_mac_reply,0}, /*stats*/
+  {0,0,0},
+
+};
+
+static const char *enb_agent_direction2String[] = {
+  "", /* not_set  */
+  "originating message", /* originating message */
+  "successfull outcome", /* successfull outcome */
+  "unsuccessfull outcome", /* unsuccessfull outcome */
+};
+
+
+Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, 
+						    uint8_t *data, 
+						    uint32_t size){
+  
+  Protocol__ProgranMessage *message;
+  err_code_t err_code;
+  DevAssert(data != NULL);
+
+  if (enb_agent_deserialize_message(data, size, &message) < 0) {
+    err_code= PROTOCOL__PROGRAN_ERR__MSG_DECODING;
+    goto error; 
+  }
+  
+  if ((message->msg_case > sizeof(messages_callback) / (3*sizeof(enb_agent_message_decoded_callback))) || 
+      (message->msg_dir > PROTOCOL__PROGRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){
+    err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_HANDLED;
+      goto error;
+  }
+    
+  if (messages_callback[message->msg_case][message->msg_dir] == NULL) {
+    err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_SUPPORTED;
+    goto error;
+
+  }
+
+  err_code= ((*messages_callback[message->msg_case-1][message->msg_dir-1])(xid, &message));
+  if ( err_code < 0 ){
+    goto error;
+  }
+  
+  return message;
+  
+error:
+  LOG_E(ENB_APP,"errno %d occured\n",err_code);
+  return err_code;
+
+}
+
+
+
+void * enb_agent_send_message(uint32_t xid, 
+			   Protocol__ProgranMessage *msg, 
+			   uint32_t * size){
+
+  void * buffer;
+  err_code_t err_code = PROTOCOL__PROGRAN_ERR__NO_ERR;
+  
+  if (enb_agent_serialize_message(msg, &buffer, size) < 0 ) {
+    err_code = PROTOCOL__PROGRAN_ERR__MSG_ENCODING;
+    goto error;
+  }
+  
+  // free the msg --> later keep this in the data struct and just update the values
+  enb_agent_mac_destroy_stats_reply(msg);
+  
+  DevAssert(buffer !=NULL);
+
+  LOG_D(ENB_APP,"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; 
+  
+}
+
+
+
+
+
+
+
+
diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c
new file mode 100644
index 0000000000000000000000000000000000000000..0399d53d18371d0fc378dcf9f2ea02d180ce7187
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_mac.c
@@ -0,0 +1,552 @@
+/*******************************************************************************
+    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.
+
+ *******************************************************************************/
+
+/*! \file 
+ * \brief 
+ * \author 
+ * \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_reply(uint32_t xid, Protocol__ProgranMessage **msg){
+  
+  void *buffer;
+  int size;
+  err_code_t err_code;
+  // test code 
+
+
+  // Create and serialize a stats reply message. This would be done by one of the agents
+  // Let's assume that we want the power headroom, the pending CEs for UEs 1 & 2 and their
+  // DL CQI reports as well as the noise and interference for cell 1
+  report_config_t report_config;
+
+  // We set the flags indicating what kind of stats we need for each UE. Both UEs will have
+  // the same flags in this example
+  uint32_t ue_flags = 0;
+  // Set the power headroom flag
+  ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH;
+  // Set the pending CEs flag
+  ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS;
+  // Set the DL CQI report flag
+  ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI;
+
+  // We do the same with the Cell flags
+  uint32_t c_flags = 0;
+  // Set the noise and interference flag
+  c_flags |= PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE;
+
+  // We create the appropriate configurations
+  ue_report_type_t ue_configs[2];
+  cc_report_type_t cell_configs[1];
+
+  // Create the config for UE with RNTI 1
+  ue_report_type_t ue1_config;
+  ue1_config.ue_rnti = 1;
+  ue1_config.ue_report_flags = ue_flags;
+
+  // Do the same for UE with RNTI 2
+  ue_report_type_t ue2_config;
+  ue2_config.ue_rnti = 2;
+  ue2_config.ue_report_flags = ue_flags;
+
+  // Add them to the UE list
+  ue_configs[0] = ue1_config;
+  ue_configs[1] = ue2_config;
+  
+  // Do the same for cell with id 1  
+  cc_report_type_t c1_config;
+  c1_config.cc_id = 1;
+  c1_config.cc_report_flags = c_flags;
+
+  // Add them to the cell list
+  cell_configs[0] = c1_config;
+
+  //Create the full report configuration
+  report_config.nr_ue = 2;
+  report_config.nr_cc = 1;
+  report_config.ue_report_type = ue_configs;
+  report_config.cc_report_type = cell_configs;
+
+  if (enb_agent_mac_stats_reply(xid, &report_config, msg) < 0 ){
+    err_code = PROTOCOL__PROGRAN_ERR__MSG_BUILD;
+    goto error;
+  }
+
+  return 0;
+
+ error :
+  LOG_E(ENB_APP, "errno %d occured\n", err_code);
+  return err_code;
+}
+
+int enb_agent_mac_stats_reply(uint32_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;
+  
+  
+  if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REPLY, &header) != 0)
+    goto error;
+
+  Protocol__PrpStatsReply *stats_reply_msg;
+  stats_reply_msg = malloc(sizeof(Protocol__PrpStatsReply));
+  if (stats_reply_msg == NULL)
+    goto error;
+  protocol__prp_stats_reply__init(stats_reply_msg);
+  stats_reply_msg->header = header;
+
+  stats_reply_msg->n_ue_report = report_config->nr_ue;
+  stats_reply_msg->n_cell_report = report_config->nr_cc;
+
+  Protocol__PrpUeStatsReport **ue_report;
+  Protocol__PrpCellStatsReport **cell_report;
+
+  
+  /* Allocate memory for list of UE reports */
+  if (report_config->nr_ue > 0) {
+    ue_report = malloc(sizeof(Protocol__PrpUeStatsReport *) * report_config->nr_ue);
+    if (ue_report == NULL)
+      goto error;
+    for (i = 0; i < report_config->nr_ue; i++) {
+      ue_report[i] = malloc(sizeof(Protocol__PrpUeStatsReport));
+      protocol__prp_ue_stats_report__init(ue_report[i]);
+      ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti;
+      ue_report[i]->has_rnti = 1;
+      ue_report[i]->flags = report_config->ue_report_type[i].ue_report_flags;
+      ue_report[i]->has_flags = 1;
+      /* Check the types of reports that need to be constructed based on flag values */
+
+      /* Check flag for creation of buffer status report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR) {
+	//TODO: Create a report for each LCG (4 elements). See prp_ue_stats_report of
+	// progRAN specifications for more details
+	ue_report[i]->n_bsr = 4;
+	uint32_t *elem;
+	elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr);
+	if (elem == NULL)
+	  goto error;
+	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];
+	}
+	ue_report[i]->bsr = elem;
+      }
+      
+      /* 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]->has_phr = 1;
+      }
+
+      /* Check flag for creation of RLC buffer status report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_RLC_BS) {
+	// TODO: Fill in the actual RLC buffer status reports
+	ue_report[i]->n_rlc_report = 1; // Set this to the number of LCs for this UE
+	Protocol__PrpRlcBsr ** rlc_reports;
+	rlc_reports = malloc(sizeof(Protocol__PrpRlcBsr) * ue_report[i]->n_rlc_report);
+	if (rlc_reports == NULL)
+	  goto error;
+	
+	// Fill the buffer status report for each logical channel of the UE
+	// NN: see LAYER2/openair2_proc.c for rlc status
+	for (j = 0; j < ue_report[i]->n_rlc_report; j++) {
+	  rlc_reports[j] = malloc(sizeof(Protocol__PrpRlcBsr));
+	  if (rlc_reports[j] == NULL)
+	    goto error;
+	  protocol__prp_rlc_bsr__init(rlc_reports[j]);
+	  //TODO:Set logical channel id
+	  rlc_reports[j]->lc_id = 1;
+	  rlc_reports[j]->has_lc_id = 1;
+	  //TODO:Set tx queue size in bytes
+	  rlc_reports[j]->tx_queue_size = 10;
+	  rlc_reports[j]->has_tx_queue_size = 1;
+	  //TODO:Set tx queue head of line delay in ms
+	  rlc_reports[j]->tx_queue_hol_delay = 100;
+	  rlc_reports[j]->has_tx_queue_hol_delay = 1;
+	  //TODO:Set retransmission queue size in bytes
+	  rlc_reports[j]->retransmission_queue_size = 10;
+	  rlc_reports[j]->has_retransmission_queue_size = 1;
+	  //TODO:Set retransmission queue head of line delay in ms
+	  rlc_reports[j]->retransmission_queue_hol_delay = 100;
+	  rlc_reports[j]->has_retransmission_queue_hol_delay = 1;
+	  //TODO:Set current size of the pending message in bytes
+	  rlc_reports[j]->status_pdu_size = 100;
+	  rlc_reports[j]->has_status_pdu_size = 1;
+	}
+	// Add RLC buffer status reports to the full report
+	if (ue_report[i]->n_rlc_report > 0)
+	  ue_report[i]->rlc_report = rlc_reports;
+      }
+
+      /* Check flag for creation of MAC CE buffer status report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS) {
+	// TODO: Fill in the actual MAC CE buffer status report
+	ue_report[i]->pending_mac_ces = -1; /* Use as bitmap. Set one or more of the
+					       PROTOCOL__PRP_CE_TYPE__PRPCET_ values
+					       found in stats_common.pb-c.h. See
+					       prp_ce_type in progRAN specification */
+	ue_report[i]->has_pending_mac_ces = 1;
+      }
+      
+      /* Check flag for creation of DL CQI report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) {
+	// TODO: Fill in the actual DL CQI report for the UE based on its configuration
+	Protocol__PrpDlCqiReport * dl_report;
+	dl_report = malloc(sizeof(Protocol__PrpDlCqiReport));
+	if (dl_report == NULL)
+	  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->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;
+	//TODO:Create the actual CSI reports.
+	Protocol__PrpDlCsi **csi_reports;
+	csi_reports = malloc(sizeof(Protocol__PrpDlCsi *));
+	if (csi_reports == NULL)
+	  goto error;
+	for (j = 0; j < dl_report->n_csi_report; j++) {
+	  csi_reports[j] = malloc(sizeof(Protocol__PrpDlCsi));
+	  if (csi_reports[j] == NULL)
+	    goto error;
+	  protocol__prp_dl_csi__init(csi_reports[j]);
+	  //TODO: the servCellIndex for this report
+	  csi_reports[j]->serv_cell_index = 0;
+	  csi_reports[j]->has_serv_cell_index = 1;
+	  //TODO: the rank indicator value for this cc
+	  csi_reports[j]->ri = 1;
+	  csi_reports[j]->has_ri = 1;
+	  //TODO: the type of CSI report based on the configuration of the UE
+	  //For this example we use type P10, which only needs a wideband value
+	  //The full set of types can be found in stats_common.pb-c.h and
+	  //in the progRAN specifications
+	  csi_reports[j]->type =  PROTOCOL__PRP_CSI_TYPE__PRCSIT_P10;
+	  csi_reports[j]->has_type = 1;
+	  csi_reports[j]->report_case = PROTOCOL__PRP_DL_CSI__REPORT_P10CSI;
+	  Protocol__PrpCsiP10 *csi10;
+	  csi10 = malloc(sizeof(Protocol__PrpCsiP10));
+	  if (csi10 == NULL)
+	    goto error;
+	  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->has_wb_cqi = 1;
+	  //Add the type of measurements to the csi report in the proper union type
+	  csi_reports[j]->p10csi = csi10;
+	}
+	//Add the csi reports to the full DL CQI report
+	dl_report->csi_report = csi_reports;
+	//Add the DL CQI report to the stats report
+	ue_report[i]->dl_cqi_report = dl_report;
+      }
+      
+      /* Check flag for creation of paging buffer status report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PBS) {
+	//TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI
+	//set in the report must be a P-RNTI
+	Protocol__PrpPagingBufferReport *paging_report;
+	paging_report = malloc(sizeof(Protocol__PrpPagingBufferReport));
+	if (paging_report == NULL)
+	  goto error;
+	protocol__prp_paging_buffer_report__init(paging_report);
+	//Set the number of pending paging messages
+	paging_report->n_paging_info = 1;
+	//Provide a report for each pending paging message
+	Protocol__PrpPagingInfo **p_info;
+	p_info = malloc(sizeof(Protocol__PrpPagingInfo *));
+	if (p_info == NULL)
+	  goto error;
+	for (j = 0; j < paging_report->n_paging_info; j++) {
+	  p_info[j] = malloc(sizeof(Protocol__PrpPagingInfo));
+	  if(p_info[j] == NULL)
+	    goto error;
+	  protocol__prp_paging_info__init(p_info[j]);
+	  //TODO: Set paging index. This index is the same that will be used for the scheduling of the
+	  //paging message by the controller
+	  p_info[j]->paging_index = 10;
+	  p_info[j]->has_paging_index = 1;
+	  //TODO:Set the paging message size
+	  p_info[j]->paging_message_size = 100;
+	  p_info[j]->has_paging_message_size = 1;
+	  //TODO: Set the paging subframe
+	  p_info[j]->paging_subframe = 10;
+	  p_info[j]->has_paging_subframe = 1;
+	  //TODO: Set the carrier index for the pending paging message
+	  p_info[j]->carrier_index = 0;
+	  p_info[j]->has_carrier_index = 1;
+	}
+	//Add all paging info to the paging buffer rerport
+	paging_report->paging_info = p_info;
+	//Add the paging report to the UE report
+	ue_report[i]->pbr = paging_report;
+      }
+      
+      /* Check flag for creation of UL CQI report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_UL_CQI) {
+	//Fill in the full UL CQI report of the UE
+	Protocol__PrpUlCqiReport *full_ul_report;
+	full_ul_report = malloc(sizeof(Protocol__PrpUlCqiReport));
+	if(full_ul_report == NULL)
+	  goto error;
+	protocol__prp_ul_cqi_report__init(full_ul_report);
+	//TODO:Set the SFN and SF of the generated report
+	full_ul_report->sfn_sn = 100;
+	full_ul_report->has_sfn_sn = 1;
+	//TODO:Set the number of UL measurement reports based on the types of measurements
+	//configured for this UE and on the servCellIndex
+	full_ul_report->n_cqi_meas = 1;
+	Protocol__PrpUlCqi **ul_report;
+	ul_report = malloc(sizeof(Protocol__PrpUlCqi *) * full_ul_report->n_cqi_meas);
+	if(ul_report == NULL)
+	  goto error;
+	//Fill each UL report of the UE for each of the configured report types
+	for(j = 0; j++; j < full_ul_report->n_cqi_meas) {
+	  ul_report[j] = malloc(sizeof(Protocol__PrpUlCqi));
+	  if(ul_report[j] == NULL)
+	  goto error;
+	  protocol__prp_ul_cqi__init(ul_report[j]);
+	  //TODO: Set the type of the UL report. As an example set it to SRS UL report
+	  // See enum prp_ul_cqi_type in progRAN specification for more details
+	  ul_report[j]->type = PROTOCOL__PRP_UL_CQI_TYPE__PRUCT_SRS;
+	  ul_report[j]->has_type = 1;
+	  //TODO:Set the number of SINR measurements based on the report type
+	  //See struct prp_ul_cqi in progRAN specification for more details
+	  ul_report[j]->n_sinr = 100;
+	  uint32_t *sinr_meas;
+	  sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr);
+	  if (sinr_meas == NULL)
+	    goto error;
+	  //TODO:Set the SINR measurements for the specified type
+	  for (k = 0; k < ul_report[j]->n_sinr; k++) {
+	    sinr_meas[k] = 10;
+	  }
+	  ul_report[j]->sinr = sinr_meas;
+	  //TODO: Set the servCellIndex for this report
+	  ul_report[j]->serv_cell_index = 0;
+	  ul_report[j]->has_serv_cell_index = 1;
+	  //Set the list of UL reports of this UE to the full UL report
+	  full_ul_report->cqi_meas = ul_report;
+	  //Add full UL CQI report to the UE report
+	  ue_report[i]->ul_cqi_report = full_ul_report;
+	}
+      }
+    }
+    /* Add list of all UE reports to the message */
+    stats_reply_msg->ue_report = ue_report;
+  }
+
+  /* Allocate memory for list of cell reports */
+  if (report_config->nr_cc > 0) {
+    cell_report = malloc(sizeof(Protocol__PrpCellStatsReport *) * report_config->nr_cc);
+    if (cell_report == NULL)
+      goto error;
+    // Fill in the Cell reports
+    for (i = 0; i < report_config->nr_cc; i++) {
+      cell_report[i] = malloc(sizeof(Protocol__PrpCellStatsReport));
+      if(ue_report[i] == NULL)
+	goto error;
+      protocol__prp_cell_stats_report__init(cell_report[i]);
+      cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id;
+      cell_report[i]->has_carrier_index = 1;
+      cell_report[i]->flags = report_config->cc_report_type[i].cc_report_flags;
+      cell_report[i]->has_flags = 1;
+
+      /* Check flag for creation of noise and interference report */
+      if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE) {
+	// TODO: Fill in the actual noise and interference report for this cell
+	Protocol__PrpNoiseInterferenceReport *ni_report;
+	ni_report = malloc(sizeof(Protocol__PrpNoiseInterferenceReport));
+	if(ni_report == NULL)
+	  goto error;
+	protocol__prp_noise_interference_report__init(ni_report);
+	// Current frame and subframe number
+	ni_report->sfn_sf = 0;
+	ni_report->has_sfn_sf = 1;
+	// Received interference power in dbm
+	ni_report->rip = 0;
+	ni_report->has_rip = 1;
+	// Thermal noise power in dbm
+	ni_report->tnp = 0;
+	ni_report->has_tnp = 1;
+	cell_report[i]->noise_inter_report = ni_report;
+      }
+    }
+    /* Add list of all cell reports to the message */
+    stats_reply_msg->cell_report = cell_report;
+  }
+  
+  *msg = malloc(sizeof(Protocol__ProgranMessage));
+  if(*msg == NULL)
+    goto error;
+  protocol__progran_message__init(*msg);
+  (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG;
+  (*msg)->msg_dir =  PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME;
+  (*msg)->stats_reply_msg = stats_reply_msg;
+  return 0;
+  
+ error:
+  // TODO: Need to make proper error handling
+  if (header != NULL)
+    free(header);
+  if (stats_reply_msg != NULL)
+    free(stats_reply_msg);
+  if(*msg != NULL)
+    free(*msg);
+  //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
+
+int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) {
+  //TODO: Need to deallocate memory for the stats reply message
+  if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG)
+    goto error;
+  free(msg->stats_reply_msg->header);
+  int i, j, k;
+  
+  Protocol__PrpStatsReply *reply = msg->stats_reply_msg;
+  Protocol__PrpDlCqiReport *dl_report;
+  Protocol__PrpUlCqiReport *ul_report;
+  Protocol__PrpPagingBufferReport *paging_report;
+
+  // Free the memory for the UE reports
+  for (i = 0; i < reply->n_ue_report; i++) {
+    free(reply->ue_report[i]->bsr);
+    for (j = 0; j < reply->ue_report[i]->n_rlc_report; j++) {
+      free(reply->ue_report[i]->rlc_report[j]);
+    }
+    free(reply->ue_report[i]->rlc_report);
+    // If DL CQI report flag was set
+    if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) {
+      dl_report = reply->ue_report[i]->dl_cqi_report;
+      // Delete all CSI reports
+      for (j = 0; j < dl_report->n_csi_report; j++) {
+	//Must free memory based on the type of report
+	switch(dl_report->csi_report[j]->report_case) {
+	case PROTOCOL__PRP_DL_CSI__REPORT_P10CSI:
+	  free(dl_report->csi_report[j]->p10csi);
+	  break;
+	case PROTOCOL__PRP_DL_CSI__REPORT_P11CSI:
+	  free(dl_report->csi_report[j]->p11csi->wb_cqi);
+	  free(dl_report->csi_report[j]->p11csi);
+	  break;
+	case PROTOCOL__PRP_DL_CSI__REPORT_P20CSI:
+	  free(dl_report->csi_report[j]->p20csi);
+	  break;
+	case PROTOCOL__PRP_DL_CSI__REPORT_P21CSI:
+	  free(dl_report->csi_report[j]->p21csi->wb_cqi);
+	  free(dl_report->csi_report[j]->p21csi->sb_cqi);
+	  free(dl_report->csi_report[j]->p21csi);
+	  break;
+	case PROTOCOL__PRP_DL_CSI__REPORT_A12CSI:
+	  free(dl_report->csi_report[j]->a12csi->wb_cqi);
+	  free(dl_report->csi_report[j]->a12csi->sb_pmi);
+	  free(dl_report->csi_report[j]->a12csi);
+	  break;
+	case PROTOCOL__PRP_DL_CSI__REPORT_A22CSI:
+	  free(dl_report->csi_report[j]->a22csi->wb_cqi);
+	  free(dl_report->csi_report[j]->a22csi->sb_cqi);
+	  free(dl_report->csi_report[j]->a22csi->sb_list);
+	  free(dl_report->csi_report[j]->a22csi);
+	  break;
+	case PROTOCOL__PRP_DL_CSI__REPORT_A20CSI:
+	  free(dl_report->csi_report[j]->a20csi->sb_list);
+	  free(dl_report->csi_report[j]->a20csi);
+	  break;
+	case PROTOCOL__PRP_DL_CSI__REPORT_A30CSI:
+	  free(dl_report->csi_report[j]->a30csi->sb_cqi);
+	  free(dl_report->csi_report[j]->a30csi);
+	  break;
+	case PROTOCOL__PRP_DL_CSI__REPORT_A31CSI:
+	  free(dl_report->csi_report[j]->a31csi->wb_cqi);
+	  for (k = 0; k < dl_report->csi_report[j]->a31csi->n_sb_cqi; k++) {
+	    free(dl_report->csi_report[j]->a31csi->sb_cqi[k]);
+	  }
+	  free(dl_report->csi_report[j]->a31csi->sb_cqi);
+	  break;
+	}  
+	
+	free(dl_report->csi_report[j]);
+      }
+      free(dl_report->csi_report);
+      free(dl_report);
+    }
+    // If Paging buffer report flag was set
+    if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PBS) {
+      paging_report = reply->ue_report[i]->pbr;
+      // Delete all paging buffer reports
+      for (j = 0; j < paging_report->n_paging_info; j++) {
+	free(paging_report->paging_info[j]);
+      }
+      free(paging_report->paging_info);
+      free(paging_report);
+    }
+    // If UL CQI report flag was set
+    if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_UL_CQI) {
+      ul_report = reply->ue_report[i]->ul_cqi_report;
+      for (j = 0; j < ul_report->n_cqi_meas; j++) {
+	free(ul_report->cqi_meas[j]->sinr);
+	free(ul_report->cqi_meas[j]);
+      }
+      free(ul_report->cqi_meas);
+    }
+    free(reply->ue_report[i]);
+  }
+  free(reply->ue_report);
+
+  // Free memory for all Cell reports
+  for (i = 0; i < reply->n_cell_report; i++) {
+    free(reply->cell_report[i]->noise_inter_report);
+    free(reply->cell_report[i]);
+  }
+  free(reply->cell_report);
+  
+  free(reply);
+  free(msg);
+  return 0;
+  
+ error:
+  //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__);
+  return -1;
+}
diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d36bbb6a170935132d3e5a1b87cd57cbb5dc2f5
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_mac.h
@@ -0,0 +1,77 @@
+/*******************************************************************************
+    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.
+
+ *******************************************************************************/
+
+/*! \file 
+ * \brief 
+ * \author 
+ * \date 2016
+ * \version 0.1
+ */
+
+#ifndef ENB_AGENT_MAC_H_
+#define ENB_AGENT_MAC_H_
+
+#include "header.pb-c.h"
+#include "progran.pb-c.h"
+#include "stats_messages.pb-c.h"
+#include "stats_common.pb-c.h"
+
+
+/* These types will be used to give
+   instructions for the type of stats reports
+   we need to create */
+typedef struct {
+  uint16_t ue_rnti;
+  uint32_t ue_report_flags; /* Indicates the report elements
+			       required for this UE id. See
+			       ProgRAN specification 1.2.4.2 */
+} ue_report_type_t;
+
+typedef struct {
+  uint16_t cc_id;
+  uint32_t cc_report_flags; /* Indicates the report elements
+			      required for this CC index. See
+			      ProgRAN specification 1.2.4.3 */
+} cc_report_type_t;
+
+typedef struct {
+  int nr_ue;
+  ue_report_type_t *ue_report_type;
+  int nr_cc;
+  cc_report_type_t *cc_report_type;
+} report_config_t;
+
+
+int enb_agent_mac_reply(uint32_t xid, 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_destroy_stats_reply(Protocol__ProgranMessage *msg);
+
+#endif
diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c
index 70fb5ad61f676294814e7a84fe6a1dd400a0a513..d63d89571130f3f23df2fd755f27e6bb170ae64f 100644
--- a/openair2/ENB_APP/enb_app.c
+++ b/openair2/ENB_APP/enb_app.c
@@ -57,6 +57,10 @@
 #   include "gtpv1u_eNB_task.h"
 # endif
 
+#if defined(ENB_AGENT_SB_IF)
+#   include "enb_agent.h"
+#endif
+
 extern unsigned char NB_eNB_INST;
 #endif
 
@@ -310,6 +314,11 @@ void *eNB_app_task(void *args_p)
     configure_rrc(enb_id, enb_properties_p);
   }
 
+#if defined (ENB_AGENT_SB_IF)
+  printf("\n start enb agent\n");
+  enb_agent_start();
+#endif 
+
 # if defined(ENABLE_USE_MME)
   /* Try to register each eNB */
   registered_enb = 0;
diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c
index c1d4d64ef69b5414b336f0fc363918545575cee9..7d31f476ef947856ef5d5ef215da54140681a023 100644
--- a/targets/SIMU/USER/oaisim.c
+++ b/targets/SIMU/USER/oaisim.c
@@ -90,6 +90,11 @@ uint8_t config_smbv = 0;
 char smbv_ip[16];
 #endif
 
+#if defined(ENB_AGENT_SB_IF)
+#   include "enb_agent.h"
+#endif
+
+
 #include "oaisim_functions.h"
 
 #include "oaisim.h"
@@ -1332,6 +1337,10 @@ main (int argc, char **argv)
   smbv_write_config_from_frame_parms(smbv_fname, &PHY_vars_eNB_g[0][0]->lte_frame_parms);
 #endif
 
+#if defined (ENB_AGENT_SB_IF)
+  enb_agent_start();
+#endif 
+
   // add events to future event list: Currently not used
   //oai_emulation.info.oeh_enabled = 1;
   if (oai_emulation.info.oeh_enabled == 1)