From a99e1a95af4d7a4953409e2b26539993dac37b88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Leroy?= <frederic.leroy@b-com.com>
Date: Thu, 21 Jul 2016 15:37:00 +0200
Subject: [PATCH] API/USER: move _user_api_id to nas_user_t

---
 openair3/NAS/UE/API/USER/user_api.c           | 145 +++++++-----------
 openair3/NAS/UE/API/USER/user_api.h           |  32 ++--
 openair3/NAS/UE/API/USER/user_api_defs.h      |  45 ++++++
 openair3/NAS/UE/API/USER/user_indication.c    |   4 +-
 openair3/NAS/UE/API/USER/user_indication.h    |   5 +-
 openair3/NAS/UE/EMM/IdleMode.c                |  18 ++-
 openair3/NAS/UE/EMM/IdleMode.h                |   2 +-
 .../EMM/SAP/EmmDeregisteredNoCellAvailable.c  |   4 +-
 .../UE/EMM/SAP/EmmDeregisteredPlmnSearch.c    |   6 +-
 .../NAS/UE/EMM/SAP/EmmRegisteredInitiated.c   |   6 +-
 openair3/NAS/UE/EMM/emm_main.c                |   6 +-
 openair3/NAS/UE/EMM/emm_main.h                |   2 +-
 openair3/NAS/UE/EMM/emm_proc.h                |   6 +-
 .../ESM/DedicatedEpsBearerContextActivation.c |   4 +-
 .../ESM/DefaultEpsBearerContextActivation.c   |   4 +-
 .../NAS/UE/ESM/EpsBearerContextDeactivation.c |   6 +-
 openair3/NAS/UE/ESM/esm_ebr.c                 |   4 +-
 openair3/NAS/UE/ESM/esm_ebr.h                 |   4 +-
 openair3/NAS/UE/ESM/esm_ebr_context.c         |   6 +-
 openair3/NAS/UE/UEprocess.c                   |  27 ++--
 openair3/NAS/UE/nas_ue_task.c                 |  13 +-
 openair3/NAS/UE/nas_user.c                    |   7 +-
 openair3/NAS/UE/user_defs.h                   |   3 +-
 23 files changed, 196 insertions(+), 163 deletions(-)
 create mode 100644 openair3/NAS/UE/API/USER/user_api_defs.h

diff --git a/openair3/NAS/UE/API/USER/user_api.c b/openair3/NAS/UE/API/USER/user_api.c
index 9fa6ebc0a9..c71b59b443 100644
--- a/openair3/NAS/UE/API/USER/user_api.c
+++ b/openair3/NAS/UE/API/USER/user_api.c
@@ -45,7 +45,6 @@ Description     Implements the API used by the NAS layer running in the UE
 #include "device.h"
 #include "nas_user.h"
 
-#include "at_command.h"
 #include "at_response.h"
 #include "at_error.h"
 #include "esm_ebr.h"
@@ -69,42 +68,12 @@ Description     Implements the API used by the NAS layer running in the UE
 /*
  * Asynchronous notification procedure handlers
  */
-static int _user_api_registration_handler(unsigned char id, const void* data, size_t size);
-static int _user_api_location_handler(unsigned char id, const void* data, size_t size);
-static int _user_api_network_handler(unsigned char id, const void* data, size_t size);
-static int _user_api_pdn_connection_handler(unsigned char id, const void* data, size_t size);
-
-static int _user_api_send(at_response_t* data);
-
-/* -------------------
- * Connection endpoint
- * -------------------
- *      The connection endpoint is used to send/receive data to/from the
- *      user application layer. Its definition depends on the underlaying
- *      mechanism chosen to communicate (network socket, I/O terminal device).
- *      A connection endpoint is handled using an identifier, and functions
- *      used to retreive the file descriptor actually allocated by the system,
- *      to receive data, to send data, and to perform clean up when connection
- *      is shut down.
- *      Only one single end to end connection with the user is managed at a
- *      time.
- */
-static struct {
-  /* Connection endpoint reference  */
-  void* endpoint;
-  /* Connection endpoint handlers */
-  void*   (*open) (int, const char*, const char*);
-  int     (*getfd)(const void*);
-  ssize_t (*recv) (void*, char*, size_t);
-  ssize_t (*send) (const void*, const char*, size_t);
-  void    (*close)(void*);
-} _user_api_id;
-
-#define USER_API_OPEN(a, b, c)  _user_api_id.open(a, b, c)
-#define USER_API_GETFD()  _user_api_id.getfd(_user_api_id.endpoint)
-#define USER_API_RECV(a, b) _user_api_id.recv(_user_api_id.endpoint, a, b)
-#define USER_API_SEND(a, b) _user_api_id.send(_user_api_id.endpoint, a, b)
-#define USER_API_CLOSE()  _user_api_id.close(_user_api_id.endpoint)
+static int _user_api_registration_handler(user_api_id_t *user_api_id, unsigned char id, const void* data, size_t size);
+static int _user_api_location_handler(user_api_id_t *user_api_id, unsigned char id, const void* data, size_t size);
+static int _user_api_network_handler(user_api_id_t *user_api_id, unsigned char id, const void* data, size_t size);
+static int _user_api_pdn_connection_handler(user_api_id_t *user_api_id, unsigned char id, const void* data, size_t size);
+
+static int _user_api_send(user_api_id_t *user_api_id, at_response_t* data);
 
 /*
  * The buffer used to receive data from the user application layer
@@ -141,7 +110,7 @@ static char _user_api_send_buffer[USER_API_SEND_BUFFER_SIZE];
  **              Others:        _user_api_id                               **
  **                                                                        **
  ***************************************************************************/
-int user_api_initialize(const char* host, const char* port,
+int user_api_initialize(user_api_id_t *user_api_id, const char* host, const char* port,
                         const char* devname, const char* devparams)
 {
   LOG_FUNC_IN;
@@ -150,35 +119,35 @@ int user_api_initialize(const char* host, const char* port,
 
   if (devname != NULL) {
     /* Initialize device handlers */
-    _user_api_id.open  = device_open;
-    _user_api_id.getfd = device_get_fd;
-    _user_api_id.recv  = device_read;
-    _user_api_id.send  = device_write;
-    _user_api_id.close = device_close;
+    user_api_id->open  = device_open;
+    user_api_id->getfd = device_get_fd;
+    user_api_id->recv  = device_read;
+    user_api_id->send  = device_write;
+    user_api_id->close = device_close;
 
     /* Initialize communication channel */
-    _user_api_id.endpoint = USER_API_OPEN(DEVICE, devname, devparams);
+    user_api_id->endpoint = user_api_id->open(DEVICE, devname, devparams);
 
-    if (_user_api_id.endpoint == NULL) {
+    if (user_api_id->endpoint == NULL) {
       LOG_TRACE(ERROR, "USR-API   - Failed to open connection endpoint, "
                 "%s", strerror(errno));
       LOG_FUNC_RETURN (RETURNerror);
     }
 
     LOG_TRACE(INFO, "USR-API   - User's communication device %d is OPENED "
-              "on %s/%s", user_api_get_fd(), _user_api_send_buffer, devname);
+              "on %s/%s", user_api_get_fd(user_api_id), _user_api_send_buffer, devname);
   } else {
     /* Initialize network socket handlers */
-    _user_api_id.open  = socket_udp_open;
-    _user_api_id.getfd = socket_get_fd;
-    _user_api_id.recv  = socket_recv;
-    _user_api_id.send  = socket_send;
-    _user_api_id.close = socket_close;
+    user_api_id->open  = socket_udp_open;
+    user_api_id->getfd = socket_get_fd;
+    user_api_id->recv  = socket_recv;
+    user_api_id->send  = socket_send;
+    user_api_id->close = socket_close;
 
     /* Initialize communication channel */
-    _user_api_id.endpoint = USER_API_OPEN(SOCKET_SERVER, host, port);
+    user_api_id->endpoint = user_api_id->open(SOCKET_SERVER, host, port);
 
-    if (_user_api_id.endpoint == NULL) {
+    if (user_api_id->endpoint == NULL) {
       const char* error = ( (errno < 0) ?
                             gai_strerror(errno) : strerror(errno) );
       LOG_TRACE(ERROR, "USR-API   - Failed to open connection endpoint, "
@@ -187,7 +156,7 @@ int user_api_initialize(const char* host, const char* port,
     }
 
     LOG_TRACE(INFO, "USR-API   - User's UDP socket %d is BOUND to %s/%s",
-              user_api_get_fd(), _user_api_send_buffer, port);
+              user_api_get_fd(user_api_id), _user_api_send_buffer, port);
   }
 
   /* Register the asynchronous notification handlers */
@@ -232,10 +201,10 @@ int user_api_initialize(const char* host, const char* port,
  **              Others:        None                                       **
  **                                                                        **
  ***************************************************************************/
-int user_api_get_fd(void)
+int user_api_get_fd(user_api_id_t *user_api_id)
 {
   LOG_FUNC_IN;
-  LOG_FUNC_RETURN (USER_API_GETFD());
+  LOG_FUNC_RETURN (user_api_id->getfd(user_api_id->endpoint));
 }
 
 /****************************************************************************
@@ -247,7 +216,6 @@ int user_api_get_fd(void)
  **              before its usage.                                         **
  **                                                                        **
  ** Inputs:      index:         Index of the user data structure to get    **
- **              Others:        _user_data                                 **
  **                                                                        **
  ** Outputs:     Return:        A generic pointer to the user data         **
  **                             structure                                  **
@@ -280,14 +248,14 @@ const void* user_api_get_data(user_at_commands_t *commands, int index)
  **          Others:            _user_api_recv_buffer, _user_api_id        **
  **                                                                        **
  ***************************************************************************/
-int user_api_read_data(int fd)
+int user_api_read_data(user_api_id_t *user_api_id, int fd)
 {
   LOG_FUNC_IN;
 
   int rbytes;
 
   /* Sanity check */
-  int sfd = user_api_get_fd();
+  int sfd = user_api_get_fd(user_api_id);
 
   if (fd != sfd) {
     LOG_TRACE(ERROR, "USR-API   - Endpoint %d is not the one created for communication with the user application layer (%d)", fd, sfd);
@@ -297,7 +265,7 @@ int user_api_read_data(int fd)
   memset(_user_api_recv_buffer, 0, USER_API_RECV_BUFFER_SIZE);
 
   /* Receive data from the user application layer */
-  rbytes = USER_API_RECV(_user_api_recv_buffer, USER_API_RECV_BUFFER_SIZE);
+  rbytes = user_api_id->recv(user_api_id->endpoint, _user_api_recv_buffer, USER_API_RECV_BUFFER_SIZE);
 
   if (rbytes == RETURNerror) {
     LOG_TRACE(ERROR, "USR-API   - recv() failed, %s", strerror(errno));
@@ -345,7 +313,7 @@ int user_api_set_data(char *message)
 
 /****************************************************************************
  **                                                                        **
- ** Name:        user_api_send_data()                                      **
+** Name:        user_api_send_data()                                      **
  **                                                                        **
  ** Description: Send data to the user application layer                   **
  **                                                                        **
@@ -359,9 +327,9 @@ int user_api_set_data(char *message)
  **              Others:        None                                       **
  **                                                                        **
  ***************************************************************************/
-static int _user_api_send_data(int length)
+static int _user_api_send_data(user_api_id_t *user_api_id, int length)
 {
-  int sbytes = USER_API_SEND(_user_api_send_buffer, length);
+  int sbytes = user_api_id->send(user_api_id->endpoint, _user_api_send_buffer, length);
 
   if (sbytes == RETURNerror) {
     LOG_TRACE(ERROR, "USR-API   - send() failed, %s", strerror(errno));
@@ -376,12 +344,12 @@ static int _user_api_send_data(int length)
 
   return sbytes;
 }
-int user_api_send_data(int fd, int length)
+int user_api_send_data(user_api_id_t *user_api_id, int fd, int length)
 {
   LOG_FUNC_IN;
 
   /* Sanity check */
-  int sfd = user_api_get_fd();
+  int sfd = user_api_get_fd(user_api_id);
 
   if (fd != sfd) {
     LOG_TRACE(ERROR, "USR-API   - Endpoint %d is not the one created for communication with the user application layer (%d)", fd, sfd);
@@ -392,7 +360,7 @@ int user_api_send_data(int fd, int length)
   int sbytes = 0;
 
   if (length > 0) {
-    sbytes = _user_api_send_data(length);
+    sbytes = _user_api_send_data(user_api_id, length);
   }
 
   LOG_FUNC_RETURN (sbytes);
@@ -414,12 +382,12 @@ int user_api_send_data(int fd, int length)
  **              Others:        _user_api_id                               **
  **                                                                        **
  ***************************************************************************/
-void user_api_close(int fd)
+void user_api_close(user_api_id_t *user_api_id, int fd)
 {
   LOG_FUNC_IN;
 
   /* Sanity check */
-  int sfd = user_api_get_fd();
+  int sfd = user_api_get_fd(user_api_id);
 
   if (fd != sfd) {
     LOG_TRACE(ERROR, "USR-API   - Endpoint %d is not the one created for communication with the user application layer (%d)", fd, sfd);
@@ -428,8 +396,8 @@ void user_api_close(int fd)
   }
 
   /* Cleanup the connection endpoint */
-  USER_API_CLOSE();
-  _user_api_id.endpoint = NULL;
+  user_api_id->close(user_api_id->endpoint) ;
+  user_api_id->endpoint = NULL;
 
   LOG_FUNC_OUT;
 }
@@ -451,7 +419,7 @@ void user_api_close(int fd)
  **      Others:  _user_api_send_buffer, _user_data          **
  **                                                                        **
  ***************************************************************************/
-int user_api_decode_data(user_at_commands_t *commands, int length)
+int user_api_decode_data(user_api_id_t *user_api_id, user_at_commands_t *commands, int length)
 {
   LOG_FUNC_IN;
 
@@ -479,8 +447,9 @@ int user_api_decode_data(user_at_commands_t *commands, int length)
     bytes = at_error_encode(_user_api_send_buffer, AT_ERROR_SYNTAX,
                             AT_ERROR_OPERATION_NOT_SUPPORTED);
 
+    // FIXME move _user_data call
     /* Send the syntax error code message */
-    (void) _user_api_send_data(bytes);
+    _user_api_send_data(user_api_id, bytes);
   }
 
   LOG_FUNC_RETURN (commands->n_cmd);
@@ -561,7 +530,7 @@ int user_api_encode_data(const void* data, int success_code)
  **      Others:  None                                       **
  **                                                                        **
  ***************************************************************************/
-int user_api_emm_callback(Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT,
+int user_api_emm_callback(user_api_id_t *user_api_id, Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT,
                           const char* data, size_t size)
 {
   LOG_FUNC_IN;
@@ -573,14 +542,14 @@ int user_api_emm_callback(Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT,
      * The list of available operators present in the network has to be
      * displayed to the user application
      */
-    rc = user_ind_notify(USER_IND_PLMN, (void*)data, size);
+    rc = user_ind_notify(user_api_id, USER_IND_PLMN, (void*)data, size);
   } else {
     user_indication_t ind;
     ind.notification.reg.status = stat;
 
     if (size > 0) {
       /* The UE's network registration status has changed */
-      rc = user_ind_notify(USER_IND_REG, (void*)&ind, 0);
+      rc = user_ind_notify(user_api_id, USER_IND_REG, (void*)&ind, 0);
     }
 
     if (rc != RETURNerror) {
@@ -590,7 +559,7 @@ int user_api_emm_callback(Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT,
       ind.notification.loc.tac = tac;
       ind.notification.loc.ci  = ci;
       ind.notification.loc.AcT = AcT;
-      rc = user_ind_notify(USER_IND_LOC, (void*)&ind, 0);
+      rc = user_ind_notify(user_api_id, USER_IND_LOC, (void*)&ind, 0);
     }
   }
 
@@ -618,7 +587,7 @@ int user_api_emm_callback(Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT,
  **      Others:  None                                       **
  **                                                                        **
  ***************************************************************************/
-int user_api_esm_callback(int cid, network_pdn_state_t state)
+int user_api_esm_callback(user_api_id_t *user_api_id, int cid, network_pdn_state_t state)
 {
   LOG_FUNC_IN;
 
@@ -628,7 +597,7 @@ int user_api_esm_callback(int cid, network_pdn_state_t state)
   ind.notification.pdn.cid = cid;
   ind.notification.pdn.status = state;
   /* The status of the specified PDN connection has changed */
-  rc = user_ind_notify(USER_IND_PDN, (void*)&ind, 0);
+  rc = user_ind_notify(user_api_id, USER_IND_PDN, (void*)&ind, 0);
 
   LOG_FUNC_RETURN (rc);
 }
@@ -651,7 +620,7 @@ int user_api_esm_callback(int cid, network_pdn_state_t state)
  **      Others:  None                                       **
  **                                                                        **
  ***************************************************************************/
-static int _user_api_send(at_response_t* data)
+static int _user_api_send(user_api_id_t *user_api_id, at_response_t* data)
 {
   LOG_FUNC_IN;
 
@@ -660,7 +629,7 @@ static int _user_api_send(at_response_t* data)
 
   /* Send the AT command response message to the user application */
   if (bytes != RETURNerror) {
-    bytes = _user_api_send_data(bytes);
+    bytes = _user_api_send_data(user_api_id, bytes);
   }
 
   LOG_FUNC_RETURN (bytes);
@@ -687,7 +656,7 @@ static int _user_api_send(at_response_t* data)
  **      Others:  None                                       **
  **                                                                        **
  ***************************************************************************/
-static int _user_api_registration_handler(unsigned char id, const void* data,
+static int _user_api_registration_handler(user_api_id_t *user_api_id, unsigned char id, const void* data,
     size_t size)
 {
   LOG_FUNC_IN;
@@ -704,7 +673,7 @@ static int _user_api_registration_handler(unsigned char id, const void* data,
   at_response.response.cereg.stat = reg->status;
 
   /* Encode and send the AT command response message to the user */
-  int bytes = _user_api_send(&at_response);
+  int bytes = _user_api_send(user_api_id, &at_response);
 
   LOG_FUNC_RETURN (bytes);
 }
@@ -729,7 +698,7 @@ static int _user_api_registration_handler(unsigned char id, const void* data,
  **      Others:  None                                       **
  **                                                                        **
  ***************************************************************************/
-static int _user_api_location_handler(unsigned char id, const void* data,
+static int _user_api_location_handler(user_api_id_t *user_api_id, unsigned char id, const void* data,
                                       size_t size)
 {
   LOG_FUNC_IN;
@@ -753,7 +722,7 @@ static int _user_api_location_handler(unsigned char id, const void* data,
   }
 
   /* Encode and send the AT command response message to the user */
-  int bytes = _user_api_send(&at_response);
+  int bytes = _user_api_send(user_api_id, &at_response);
 
   LOG_FUNC_RETURN (bytes);
 }
@@ -776,7 +745,7 @@ static int _user_api_location_handler(unsigned char id, const void* data,
  **      Others:  None                                       **
  **                                                                        **
  ***************************************************************************/
-static int _user_api_network_handler(unsigned char id, const void* data,
+static int _user_api_network_handler(user_api_id_t *user_api_id, unsigned char id, const void* data,
                                      size_t size)
 {
   LOG_FUNC_IN;
@@ -789,7 +758,7 @@ static int _user_api_network_handler(unsigned char id, const void* data,
   at_response.response.cops.tst.size = size;
 
   /* Encode and send the AT command response message to the user */
-  int bytes = _user_api_send(&at_response);
+  int bytes = _user_api_send(user_api_id, &at_response);
 
   LOG_FUNC_RETURN (bytes);
 }
@@ -814,7 +783,7 @@ static int _user_api_network_handler(unsigned char id, const void* data,
  **      Others:  None                                       **
  **                                                                        **
  ***************************************************************************/
-static int _user_api_pdn_connection_handler(unsigned char id, const void* data,
+static int _user_api_pdn_connection_handler(user_api_id_t *user_api_id, unsigned char id, const void* data,
     size_t size)
 {
   LOG_FUNC_IN;
@@ -831,7 +800,7 @@ static int _user_api_pdn_connection_handler(unsigned char id, const void* data,
   at_response.response.cgev.code = pdn->status;
 
   /* Encode and send the AT command response message to the user */
-  int bytes = _user_api_send(&at_response);
+  int bytes = _user_api_send(user_api_id, &at_response);
 
   LOG_FUNC_RETURN (bytes);
 }
diff --git a/openair3/NAS/UE/API/USER/user_api.h b/openair3/NAS/UE/API/USER/user_api.h
index b3325417c6..06e489b2bf 100644
--- a/openair3/NAS/UE/API/USER/user_api.h
+++ b/openair3/NAS/UE/API/USER/user_api.h
@@ -43,25 +43,13 @@ Description Implements the API used by the NAS layer running in the UE
 #include "commonDef.h"
 #include "networkDef.h"
 #include "at_command.h"
+#include "user_api_defs.h"
+#include "user_defs.h"
 
 /****************************************************************************/
 /*********************  G L O B A L    C O N S T A N T S  *******************/
 /****************************************************************************/
 
-/****************************************************************************/
-/************************  G L O B A L    T Y P E S  ************************/
-/****************************************************************************/
-
-/*
- * The decoded data received from the user application layer
- */
-typedef struct {
-  int n_cmd;    /* number of user data to be processed    */
-#define USER_DATA_MAX 10
-  at_command_t cmd[USER_DATA_MAX];  /* user data to be processed  */
-} user_at_commands_t;
-
-
 /****************************************************************************/
 /********************  G L O B A L    V A R I A B L E S  ********************/
 /****************************************************************************/
@@ -70,20 +58,20 @@ typedef struct {
 /******************  E X P O R T E D    F U N C T I O N S  ******************/
 /****************************************************************************/
 
-int user_api_initialize(const char* host, const char* port, const char* devname, const char* devparams);
+int user_api_initialize(user_api_id_t *user_api_id, const char* host, const char* port, const char* devname, const char* devparams);
 
-int user_api_emm_callback(Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT, const char* data, size_t size);
-int user_api_esm_callback(int cid, network_pdn_state_t state);
+int user_api_emm_callback(user_api_id_t *user_api_id, Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT, const char* data, size_t size);
+int user_api_esm_callback(user_api_id_t *user_api_id, int cid, network_pdn_state_t state);
 
-int user_api_get_fd(void);
+int user_api_get_fd(user_api_id_t *user_api_id);
 const void* user_api_get_data(user_at_commands_t *commands, int index);
 
-int user_api_read_data(int fd);
+int user_api_read_data(user_api_id_t *user_api_id, int fd);
 int user_api_set_data(char *message);
-int user_api_send_data(int fd, int length);
-void user_api_close(int fd);
+int user_api_send_data(user_api_id_t *user_api_id, int fd, int length);
+void user_api_close(user_api_id_t *user_api_id, int fd);
 
-int user_api_decode_data(user_at_commands_t *commands, int length);
+int user_api_decode_data(user_api_id_t *user_api_id, user_at_commands_t *commands, int length);
 int user_api_encode_data(const void* data, int add_success_code);
 
 #endif /* __USER_API_H__ */
diff --git a/openair3/NAS/UE/API/USER/user_api_defs.h b/openair3/NAS/UE/API/USER/user_api_defs.h
new file mode 100644
index 0000000000..9c43bf36f3
--- /dev/null
+++ b/openair3/NAS/UE/API/USER/user_api_defs.h
@@ -0,0 +1,45 @@
+#ifndef _USER_API_DEFS_H
+#define _USER_API_DEFS_H
+
+#include <sys/types.h>
+#include "at_command.h"
+
+/****************************************************************************/
+/************************  G L O B A L    T Y P E S  ************************/
+/****************************************************************************/
+
+/*
+ * The decoded data received from the user application layer
+ */
+typedef struct {
+  int n_cmd;    /* number of user data to be processed    */
+#define USER_DATA_MAX 10
+  at_command_t cmd[USER_DATA_MAX];  /* user data to be processed  */
+} user_at_commands_t;
+
+/* -------------------
+ * Connection endpoint
+ * -------------------
+ *      The connection endpoint is used to send/receive data to/from the
+ *      user application layer. Its definition depends on the underlaying
+ *      mechanism chosen to communicate (network socket, I/O terminal device).
+ *      A connection endpoint is handled using an identifier, and functions
+ *      used to retreive the file descriptor actually allocated by the system,
+ *      to receive data, to send data, and to perform clean up when connection
+ *      is shut down.
+ *      Only one single end to end connection with the user is managed at a
+ *      time.
+ */
+typedef struct {
+  /* Connection endpoint reference  */
+  void* endpoint;
+  /* Connection endpoint handlers */
+  void*   (*open) (int, const char*, const char*);
+  int     (*getfd)(const void*);
+  ssize_t (*recv) (void*, char*, size_t);
+  ssize_t (*send) (const void*, const char*, size_t);
+  void    (*close)(void*);
+} user_api_id_t;
+
+
+#endif
diff --git a/openair3/NAS/UE/API/USER/user_indication.c b/openair3/NAS/UE/API/USER/user_indication.c
index d7495f46e7..620596005d 100644
--- a/openair3/NAS/UE/API/USER/user_indication.c
+++ b/openair3/NAS/UE/API/USER/user_indication.c
@@ -146,7 +146,7 @@ int user_ind_deregister(user_ind_t ind)
  **    Others:  None                                       **
  **                                                                        **
  ***************************************************************************/
-int user_ind_notify(user_ind_t ind, const void* data, size_t size)
+int user_ind_notify(user_api_id_t *user_api_id, user_ind_t ind, const void* data, size_t size)
 {
   LOG_FUNC_IN;
 
@@ -158,7 +158,7 @@ int user_ind_notify(user_ind_t ind, const void* data, size_t size)
       user_ind_callback_t notify = _user_ind_handler.callback[ind];
 
       if (notify != NULL) {
-        rc = (*notify)(_user_ind_handler.id, data, size);
+        rc = (*notify)(user_api_id, _user_ind_handler.id, data, size);
       }
     } else {
       /* Silently discard not registered notification */
diff --git a/openair3/NAS/UE/API/USER/user_indication.h b/openair3/NAS/UE/API/USER/user_indication.h
index d31a8754e4..39aba424e7 100644
--- a/openair3/NAS/UE/API/USER/user_indication.h
+++ b/openair3/NAS/UE/API/USER/user_indication.h
@@ -43,6 +43,7 @@ Description Defines functions which allow the user application to register
 
 #include "commonDef.h"
 #include "networkDef.h"
+#include "user_api_defs.h"
 
 /****************************************************************************/
 /*********************  G L O B A L    C O N S T A N T S  *******************/
@@ -101,7 +102,7 @@ typedef struct {
 /*
  * Type of procedure executed upon receiving registered notification
  */
-typedef int (*user_ind_callback_t) (unsigned char, const void*, size_t);
+typedef int (*user_ind_callback_t) (user_api_id_t *user_api_id, unsigned char, const void*, size_t);
 
 /****************************************************************************/
 /************************  G L O B A L    T Y P E S  ************************/
@@ -117,6 +118,6 @@ typedef int (*user_ind_callback_t) (unsigned char, const void*, size_t);
 
 int user_ind_register(user_ind_t ind, unsigned char id, user_ind_callback_t cb);
 int user_ind_deregister(user_ind_t ind);
-int user_ind_notify(user_ind_t ind, const void* data, size_t size);
+int user_ind_notify(user_api_id_t *user_api_id, user_ind_t ind, const void* data, size_t size);
 
 #endif /* __USER_IND_H__*/
diff --git a/openair3/NAS/UE/EMM/IdleMode.c b/openair3/NAS/UE/EMM/IdleMode.c
index efecf7d321..8cff0b4ca5 100644
--- a/openair3/NAS/UE/EMM/IdleMode.c
+++ b/openair3/NAS/UE/EMM/IdleMode.c
@@ -594,6 +594,7 @@ int emm_proc_plmn_selection(nas_user_t *user, int index)
 {
   LOG_FUNC_IN;
   emm_data_t *emm_data = user->emm_data;
+  user_api_id_t *user_api_id = user->user_api_id;
   emm_plmn_list_t *emm_plmn_list = user->emm_plmn_list;
 
   int rc = RETURNok;
@@ -613,7 +614,7 @@ int emm_proc_plmn_selection(nas_user_t *user, int index)
          * list of available PLMNs to the user
          */
         index = -1;
-        rc = emm_proc_network_notify(emm_plmn_list, emm_data, emm_plmn_list->hplmn);
+        rc = emm_proc_network_notify(emm_plmn_list, user_api_id, emm_data, emm_plmn_list->hplmn);
 
         if (rc != RETURNok) {
           LOG_TRACE(WARNING, "EMM-IDLE  - Failed to notify "
@@ -685,6 +686,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci,
   int rc = RETURNerror;
   emm_data_t *emm_data = user->emm_data;
   emm_plmn_list_t *emm_plmn_list = user->emm_plmn_list;
+  user_api_id_t *user_api_id = user->user_api_id;
   int index = emm_plmn_list->index;
   int select_next_plmn = FALSE;
 
@@ -706,7 +708,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci,
     emm_plmn_list->param[index].rat = rat;
 
     /* Update the location data and notify EMM that data have changed */
-    rc = emm_proc_location_notify(emm_data, tac, ci , rat);
+    rc = emm_proc_location_notify(user_api_id, emm_data, tac, ci , rat);
 
     if (rc != RETURNok) {
       LOG_TRACE(WARNING, "EMM-IDLE  - Failed to notify location update");
@@ -934,7 +936,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci,
  **          Others:    user->emm_data->                                 **
  **                                                                        **
  ***************************************************************************/
-int emm_proc_registration_notify(emm_data_t *emm_data, Stat_t status)
+int emm_proc_registration_notify(user_api_id_t *user_api_id, emm_data_t *emm_data, Stat_t status)
 {
   LOG_FUNC_IN;
 
@@ -944,7 +946,7 @@ int emm_proc_registration_notify(emm_data_t *emm_data, Stat_t status)
   if (emm_data->stat != status) {
     emm_data->stat = status;
     /* Notify EMM that data has changed */
-    rc = (*_emm_indication_notify)(emm_data, 1);
+    rc = (*_emm_indication_notify)(user_api_id, emm_data, 1);
   }
 
   LOG_FUNC_RETURN (rc);
@@ -968,7 +970,7 @@ int emm_proc_registration_notify(emm_data_t *emm_data, Stat_t status)
  **          Others:    user->emm_data->                                 **
  **                                                                        **
  ***************************************************************************/
-int emm_proc_location_notify(emm_data_t *emm_data, tac_t tac, ci_t ci, AcT_t rat)
+int emm_proc_location_notify(user_api_id_t *user_api_id, emm_data_t *emm_data, tac_t tac, ci_t ci, AcT_t rat)
 {
   LOG_FUNC_IN;
 
@@ -982,7 +984,7 @@ int emm_proc_location_notify(emm_data_t *emm_data, tac_t tac, ci_t ci, AcT_t rat
     emm_data->ci = ci;
     emm_data->rat = rat;
     /* Notify EMM that data has changed */
-    rc = (*_emm_indication_notify)(emm_data, 0);
+    rc = (*_emm_indication_notify)(user_api_id, emm_data, 0);
   }
 
   LOG_FUNC_RETURN (rc);
@@ -1005,14 +1007,14 @@ int emm_proc_location_notify(emm_data_t *emm_data, tac_t tac, ci_t ci, AcT_t rat
  **          Others:    user->emm_data->                                 **
  **                                                                        **
  ***************************************************************************/
-int emm_proc_network_notify(emm_plmn_list_t *emm_plmn_list, emm_data_t *emm_data, int index)
+int emm_proc_network_notify(emm_plmn_list_t *emm_plmn_list, user_api_id_t *user_api_id, emm_data_t *emm_data, int index)
 {
   LOG_FUNC_IN;
 
   /* Update the list of operators present in the network */
   int size = IdleMode_update_plmn_list(emm_plmn_list, emm_data, index);
   /* Notify EMM that data has changed */
-  int rc = (*_emm_indication_notify)(emm_data, size);
+  int rc = (*_emm_indication_notify)(user_api_id, emm_data, size);
 
   LOG_FUNC_RETURN (rc);
 }
diff --git a/openair3/NAS/UE/EMM/IdleMode.h b/openair3/NAS/UE/EMM/IdleMode.h
index e92e14f5cb..e80b4f9134 100644
--- a/openair3/NAS/UE/EMM/IdleMode.h
+++ b/openair3/NAS/UE/EMM/IdleMode.h
@@ -51,7 +51,7 @@ Description Defines the functions used to get information from the list
 /************************  G L O B A L    T Y P E S  ************************/
 /****************************************************************************/
 
-typedef int (*IdleMode_callback_t) (emm_data_t *emm_data, int);
+typedef int (*IdleMode_callback_t) (user_api_id_t *user_api_id, emm_data_t *emm_data, int);
 
 /****************************************************************************/
 /********************  G L O B A L    V A R I A B L E S  ********************/
diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoCellAvailable.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoCellAvailable.c
index 0ea25dbe5f..af9ab5e5be 100644
--- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoCellAvailable.c
+++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoCellAvailable.c
@@ -89,6 +89,8 @@ int EmmDeregisteredNoCellAvailable(nas_user_t *user, const emm_reg_t *evt)
   LOG_FUNC_IN;
 
   int rc = RETURNerror;
+  emm_data_t *emm_data = user->emm_data;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   assert(emm_fsm_get_status(user) == EMM_DEREGISTERED_NO_CELL_AVAILABLE);
 
@@ -108,7 +110,7 @@ int EmmDeregisteredNoCellAvailable(nas_user_t *user, const emm_reg_t *evt)
        * Notify EMM that the MT is currently searching an operator
        * to register to
        */
-      rc = emm_proc_registration_notify(user->emm_data, NET_REG_STATE_ON);
+      rc = emm_proc_registration_notify(user_api_id, emm_data, NET_REG_STATE_ON);
 
       if (rc != RETURNok) {
         LOG_TRACE(WARNING, "EMM-FSM   - "
diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredPlmnSearch.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredPlmnSearch.c
index bcf089e3cc..ed41362f2f 100644
--- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredPlmnSearch.c
+++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredPlmnSearch.c
@@ -85,6 +85,8 @@ Description Implements the EPS Mobility Management procedures executed
 int EmmDeregisteredPlmnSearch(nas_user_t *user, const emm_reg_t *evt)
 {
   LOG_FUNC_IN;
+  emm_data_t *emm_data = user->emm_data;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   int rc = RETURNerror;
 
@@ -95,7 +97,7 @@ int EmmDeregisteredPlmnSearch(nas_user_t *user, const emm_reg_t *evt)
     /*
      * No suitable cell of the selected PLMN has been found to camp on
      */
-    rc = emm_proc_registration_notify(user->emm_data, NET_REG_STATE_DENIED);
+    rc = emm_proc_registration_notify(user_api_id, emm_data, NET_REG_STATE_DENIED);
 
     if (rc != RETURNok) {
       LOG_TRACE(WARNING, "EMM-FSM   - "
@@ -112,7 +114,7 @@ int EmmDeregisteredPlmnSearch(nas_user_t *user, const emm_reg_t *evt)
      * may be selected either automatically or manually.
      * Or the user manually re-selected a PLMN to register to.
      */
-    rc = emm_proc_registration_notify(user->emm_data, NET_REG_STATE_ON);
+    rc = emm_proc_registration_notify(user_api_id, emm_data, NET_REG_STATE_ON);
 
     if (rc != RETURNok) {
       LOG_TRACE(WARNING, "EMM-FSM   - "
diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c
index 1072e31319..c0d5f50ebc 100644
--- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c
+++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c
@@ -83,6 +83,8 @@ int EmmRegisteredInitiated(nas_user_t *user, const emm_reg_t *evt)
   LOG_FUNC_IN;
 
   int rc = RETURNerror;
+  emm_data_t *emm_data = user->emm_data;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   assert(emm_fsm_get_status(user) == EMM_REGISTERED_INITIATED);
 
@@ -140,7 +142,7 @@ int EmmRegisteredInitiated(nas_user_t *user, const emm_reg_t *evt)
       /*
        * Notify EMM that the MT is registered
        */
-      rc = emm_proc_registration_notify(user->emm_data, NET_REG_STATE_HN);
+      rc = emm_proc_registration_notify(user_api_id, emm_data, NET_REG_STATE_HN);
 
       if (rc != RETURNok) {
         LOG_TRACE(WARNING, "EMM-FSM   - "
@@ -167,7 +169,7 @@ int EmmRegisteredInitiated(nas_user_t *user, const emm_reg_t *evt)
       /*
        * Notify EMM that the MT's registration is denied
        */
-      rc = emm_proc_registration_notify(user->emm_data, NET_REG_STATE_DENIED);
+      rc = emm_proc_registration_notify(user_api_id, emm_data, NET_REG_STATE_DENIED);
 
       if (rc != RETURNok) {
         LOG_TRACE(WARNING, "EMM-FSM   - "
diff --git a/openair3/NAS/UE/EMM/emm_main.c b/openair3/NAS/UE/EMM/emm_main.c
index 5b6a44909e..7ec228d963 100644
--- a/openair3/NAS/UE/EMM/emm_main.c
+++ b/openair3/NAS/UE/EMM/emm_main.c
@@ -74,7 +74,7 @@ static int _emm_main_get_plmn_index(emm_plmn_list_t *emm_plmn_list, const char *
  * to the user application
  */
 static emm_indication_callback_t _emm_main_user_callback;
-static int _emm_main_callback(emm_data_t *emm_data, int);
+static int _emm_main_callback(user_api_id_t *user_api_id, emm_data_t *emm_data, int size);
 
 /****************************************************************************/
 /******************  E X P O R T E D    F U N C T I O N S  ******************/
@@ -881,12 +881,12 @@ int emm_main_is_emergency(emm_data_t *emm_data)
  **          Others:    None                                       **
  **                                                                        **
  ***************************************************************************/
-static int _emm_main_callback(emm_data_t *emm_data, int size)
+static int _emm_main_callback(user_api_id_t *user_api_id, emm_data_t *emm_data, int size)
 {
   LOG_FUNC_IN;
 
   /* Forward the notification to the user API */
-  int rc = (*_emm_main_user_callback)(emm_data->stat, emm_data->tac,
+  int rc = (*_emm_main_user_callback)(user_api_id, emm_data->stat, emm_data->tac,
                                       emm_data->ci, emm_data->rat,
                                       emm_data->plist.buffer, size);
 
diff --git a/openair3/NAS/UE/EMM/emm_main.h b/openair3/NAS/UE/EMM/emm_main.h
index fe574f6d3d..1885a42469 100644
--- a/openair3/NAS/UE/EMM/emm_main.h
+++ b/openair3/NAS/UE/EMM/emm_main.h
@@ -57,7 +57,7 @@ Description Defines the EPS Mobility Management procedure call manager,
  * location change, new PLMN becomes available) is notified by the
  * EPS Mobility Management sublayer
  */
-typedef int (*emm_indication_callback_t) (Stat_t, tac_t, ci_t, AcT_t,
+typedef int (*emm_indication_callback_t) (user_api_id_t *user_api_id, Stat_t, tac_t, ci_t, AcT_t,
     const char*, size_t);
 
 /****************************************************************************/
diff --git a/openair3/NAS/UE/EMM/emm_proc.h b/openair3/NAS/UE/EMM/emm_proc.h
index ca307b3f3a..333343b6ca 100644
--- a/openair3/NAS/UE/EMM/emm_proc.h
+++ b/openair3/NAS/UE/EMM/emm_proc.h
@@ -156,8 +156,8 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi, in
  *             Network indication handlers
  *---------------------------------------------------------------------------
  */
-int emm_proc_registration_notify(emm_data_t *emm_data, Stat_t status);
-int emm_proc_location_notify(emm_data_t *emm_data, tac_t tac, ci_t ci, AcT_t rat);
-int emm_proc_network_notify(emm_plmn_list_t *emm_plmn_list, emm_data_t *emm_data, int index);
+int emm_proc_registration_notify(user_api_id_t *user_api_id, emm_data_t *emm_data, Stat_t status);
+int emm_proc_location_notify(user_api_id_t *user_api_id, emm_data_t *emm_data, tac_t tac, ci_t ci, AcT_t rat);
+int emm_proc_network_notify(emm_plmn_list_t *emm_plmn_list, user_api_id_t *user_api_id, emm_data_t *emm_data, int index);
 
 #endif /* __EMM_PROC_H__*/
diff --git a/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c b/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c
index c96a40a1b8..068ec2aef0 100644
--- a/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c
+++ b/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c
@@ -212,6 +212,8 @@ int esm_proc_dedicated_eps_bearer_context_accept(nas_user_t *user, int is_standa
   LOG_FUNC_IN;
 
   int rc;
+  esm_ebr_data_t *esm_ebr_data = user->esm_ebr_data;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   LOG_TRACE(INFO,"ESM-PROC  - Dedicated EPS bearer context activation "
             "accepted by the UE (ebi=%d)", ebi);
@@ -229,7 +231,7 @@ int esm_proc_dedicated_eps_bearer_context_accept(nas_user_t *user, int is_standa
 
   if (rc != RETURNerror) {
     /* Set the EPS bearer context state to ACTIVE */
-    rc = esm_ebr_set_status(user->esm_ebr_data, ebi, ESM_EBR_ACTIVE, ue_triggered);
+    rc = esm_ebr_set_status(user_api_id, esm_ebr_data, ebi, ESM_EBR_ACTIVE, ue_triggered);
 
     if (rc != RETURNok) {
       /* The EPS bearer context was already in ACTIVE state */
diff --git a/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c b/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c
index 02d5671808..92ae9dcd99 100644
--- a/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c
+++ b/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c
@@ -181,6 +181,8 @@ int esm_proc_default_eps_bearer_context_accept(nas_user_t *user, int is_standalo
   LOG_FUNC_IN;
 
   int rc = RETURNok;
+  esm_ebr_data_t *esm_ebr_data = user->esm_ebr_data;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   LOG_TRACE(INFO,"ESM-PROC  - Default EPS bearer context activation "
             "accepted by the UE (ebi=%d)", ebi);
@@ -200,7 +202,7 @@ int esm_proc_default_eps_bearer_context_accept(nas_user_t *user, int is_standalo
 
   if (rc != RETURNerror) {
     /* Set the EPS bearer context state to ACTIVE */
-    rc = esm_ebr_set_status(user->esm_ebr_data, ebi, ESM_EBR_ACTIVE, ue_triggered);
+    rc = esm_ebr_set_status(user_api_id, esm_ebr_data, ebi, ESM_EBR_ACTIVE, ue_triggered);
 
     if (rc != RETURNok) {
       /* The EPS bearer context was already in ACTIVE state */
diff --git a/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c b/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c
index c92ce2c582..0ffb683bf1 100644
--- a/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c
+++ b/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c
@@ -282,6 +282,7 @@ int esm_proc_eps_bearer_context_deactivate_accept(nas_user_t *user, int is_stand
 
   int rc = RETURNok;
   esm_ebr_data_t *esm_ebr_data = user->esm_ebr_data;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   LOG_TRACE(INFO,"ESM-PROC  - EPS bearer context deactivation accepted");
 
@@ -299,7 +300,7 @@ int esm_proc_eps_bearer_context_deactivate_accept(nas_user_t *user, int is_stand
 
   if (rc != RETURNerror) {
     /* Set the EPS bearer context state to INACTIVE */
-    rc = esm_ebr_set_status(esm_ebr_data, ebi, ESM_EBR_INACTIVE, ue_triggered);
+    rc = esm_ebr_set_status(user_api_id, esm_ebr_data, ebi, ESM_EBR_INACTIVE, ue_triggered);
 
     if (rc != RETURNok) {
       /* The EPS bearer context was already in INACTIVE state */
@@ -359,6 +360,7 @@ static int _eps_bearer_release(nas_user_t *user, int ebi, int *pid, int *bid)
 
   int rc = RETURNerror;
   esm_ebr_data_t *esm_ebr_data = user->esm_ebr_data;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   /* Release the EPS bearer context entry */
   ebi = esm_ebr_context_release(user, ebi, pid, bid);
@@ -367,7 +369,7 @@ static int _eps_bearer_release(nas_user_t *user, int ebi, int *pid, int *bid)
     LOG_TRACE(WARNING, "ESM-PROC  - Failed to release EPS bearer context");
   } else {
     /* Set the EPS bearer context state to INACTIVE */
-    rc = esm_ebr_set_status(esm_ebr_data, ebi, ESM_EBR_INACTIVE, FALSE);
+    rc = esm_ebr_set_status(user_api_id, esm_ebr_data, ebi, ESM_EBR_INACTIVE, FALSE);
 
     if (rc != RETURNok) {
       /* The EPS bearer context was already in INACTIVE state */
diff --git a/openair3/NAS/UE/ESM/esm_ebr.c b/openair3/NAS/UE/ESM/esm_ebr.c
index 81d3ff3270..1cf1d4a4e5 100644
--- a/openair3/NAS/UE/ESM/esm_ebr.c
+++ b/openair3/NAS/UE/ESM/esm_ebr.c
@@ -294,7 +294,7 @@ int esm_ebr_release(esm_ebr_data_t *esm_ebr_data,
  **      Return:    RETURNok, RETURNerror                      **
  **                                                                        **
  ***************************************************************************/
-int esm_ebr_set_status(esm_ebr_data_t *esm_ebr_data,
+int esm_ebr_set_status(user_api_id_t *user_api_id, esm_ebr_data_t *esm_ebr_data,
   int ebi, esm_ebr_state status, int ue_requested)
 {
   esm_ebr_context_t *ebr_ctx;
@@ -329,7 +329,7 @@ int esm_ebr_set_status(esm_ebr_data_t *esm_ebr_data,
       /*
        * Notify the user that the state of the EPS bearer has changed
        */
-      (*_esm_ebr_callback)(ebr_ctx->cid,
+      (*_esm_ebr_callback)(user_api_id, ebr_ctx->cid,
                            _esm_ebr_pdn_state[ue_requested][ebr_ctx->is_default_ebr][status]);
       LOG_FUNC_RETURN (RETURNok);
     }
diff --git a/openair3/NAS/UE/ESM/esm_ebr.h b/openair3/NAS/UE/ESM/esm_ebr.h
index adc10de0c4..8e1eaee1a4 100644
--- a/openair3/NAS/UE/ESM/esm_ebr.h
+++ b/openair3/NAS/UE/ESM/esm_ebr.h
@@ -63,7 +63,7 @@ Description Defines functions used to handle state of EPS bearer contexts
  * respect of PDN connection or EPS bearer context is notified by the EPS
  * Session Management sublayer
  */
-typedef int (*esm_indication_callback_t) (int, network_pdn_state_t);
+typedef int (*esm_indication_callback_t) (user_api_id_t *user_api_id, int, network_pdn_state_t);
 
 /****************************************************************************/
 /********************  G L O B A L    V A R I A B L E S  ********************/
@@ -81,7 +81,7 @@ esm_ebr_data_t *esm_ebr_initialize(void);
 int esm_ebr_assign(esm_ebr_data_t *esm_ebr_data, int ebi, int cid, int default_ebr);
 int esm_ebr_release(esm_ebr_data_t *esm_ebr_data, int ebi);
 
-int esm_ebr_set_status(esm_ebr_data_t *esm_ebr_data, int ebi, esm_ebr_state status, int ue_requested);
+int esm_ebr_set_status(user_api_id_t *user_api_id, esm_ebr_data_t *esm_ebr_data, int ebi, esm_ebr_state status, int ue_requested);
 esm_ebr_state esm_ebr_get_status(esm_ebr_data_t *esm_ebr_data, int ebi);
 
 int esm_ebr_is_not_in_use(esm_ebr_data_t *esm_ebr_data, int ebi);
diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.c b/openair3/NAS/UE/ESM/esm_ebr_context.c
index 1f7707c5c3..4ce201260a 100644
--- a/openair3/NAS/UE/ESM/esm_ebr_context.c
+++ b/openair3/NAS/UE/ESM/esm_ebr_context.c
@@ -331,6 +331,8 @@ int esm_ebr_context_release(nas_user_t *user,
   int found = FALSE;
   esm_pdn_t *pdn = NULL;
   esm_data_context_t *esm_ctx;
+  esm_ebr_data_t *esm_ebr_data = user->esm_ebr_data;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   LOG_FUNC_IN;
 
@@ -448,11 +450,11 @@ int esm_ebr_context_release(nas_user_t *user,
           }
 
           /* Set the EPS bearer context state to INACTIVE */
-          esm_ebr_set_status(user->esm_ebr_data, pdn->bearer[i]->ebi,
+          esm_ebr_set_status(user_api_id, esm_ebr_data, pdn->bearer[i]->ebi,
                                     ESM_EBR_INACTIVE, TRUE);
 
           /* Release EPS bearer data */
-          esm_ebr_release(user->esm_ebr_data, pdn->bearer[i]->ebi);
+          esm_ebr_release(esm_ebr_data, pdn->bearer[i]->ebi);
 
           // esm_ebr_release()
           /* Release dedicated EPS bearer data */
diff --git a/openair3/NAS/UE/UEprocess.c b/openair3/NAS/UE/UEprocess.c
index 18756fe4b4..122ee72f6e 100644
--- a/openair3/NAS/UE/UEprocess.c
+++ b/openair3/NAS/UE/UEprocess.c
@@ -70,7 +70,7 @@ static void *_nas_network_mngr(void *);
 static int _nas_set_signal_handler(int signal, void (handler)(int));
 static void _nas_signal_handler(int signal);
 
-static void _nas_clean(int usr_fd, int net_fd);
+static void _nas_clean(user_api_id_t *user_api_id, int usr_fd, int net_fd);
 
 uint8_t usim_test = 0;
 // FIXME user must be set up with right itti message instance
@@ -84,6 +84,8 @@ nas_user_t *user = NULL;
 /****************************************************************************/
 int main(int argc, const char *argv[])
 {
+  // FIXME allocate and put it in user
+  user_api_id_t *user_api_id = NULL;
   /*
    * Get the command line options
    */
@@ -112,19 +114,19 @@ int main(int argc, const char *argv[])
   /*
    * Initialize the User interface
    */
-  if (user_api_initialize (uhost, uport, devpath, devparams) != RETURNok) {
+  if (user_api_initialize (user_api_id, uhost, uport, devpath, devparams) != RETURNok) {
     LOG_TRACE (ERROR, "UE-MAIN   - user_api_initialize() failed");
     exit (EXIT_FAILURE);
   }
 
-  int user_fd = user_api_get_fd ();
+  int user_fd = user_api_get_fd (user_api_id);
 
   /*
    * Initialize the Network interface
    */
   if (network_api_initialize (nhost, nport) != RETURNok) {
     LOG_TRACE (ERROR, "UE-MAIN   - network_api_initialize() failed");
-    user_api_close (user_fd);
+    user_api_close (user_api_id, user_fd);
     exit (EXIT_FAILURE);
   }
 
@@ -161,7 +163,7 @@ int main(int argc, const char *argv[])
   if (pthread_create (&user_mngr, &attr, _nas_user_mngr, &user_fd) != 0) {
     LOG_TRACE (ERROR, "UE-MAIN   - "
                "Failed to create the user management thread");
-    user_api_close (user_fd);
+    user_api_close (user_api_id, user_fd);
     network_api_close (network_fd);
     exit (EXIT_FAILURE);
   }
@@ -175,7 +177,7 @@ int main(int argc, const char *argv[])
                       &network_fd) != 0) {
     LOG_TRACE (ERROR, "UE-MAIN   - "
                "Failed to create the network management thread");
-    user_api_close (user_fd);
+    user_api_close (user_api_id, user_fd);
     network_api_close (network_fd);
     exit (EXIT_FAILURE);
   }
@@ -188,12 +190,12 @@ int main(int argc, const char *argv[])
    */
   while ((user_fd != -1) && (network_fd != -1)) {
     poll (NULL, 0, NAS_SLEEP_TIMEOUT);
-    user_fd = user_api_get_fd ();
+    user_fd = user_api_get_fd (user_api_id);
     network_fd = network_api_get_fd ();
   }
 
   /* Termination cleanup */
-  _nas_clean (user_fd, network_fd);
+  _nas_clean (user_api_id, user_fd, network_fd);
 
   LOG_TRACE
   (WARNING, "UE-MAIN   - NAS main process exited");
@@ -234,7 +236,7 @@ static void *_nas_user_mngr(void *args)
   }
 
   /* Close the connection to the user application layer */
-  user_api_close (*fd);
+  user_api_close (user->user_api_id, *fd);
   LOG_TRACE (WARNING, "UE-MAIN   - "
              "The user connection endpoint manager exited");
 
@@ -383,7 +385,8 @@ static void _nas_signal_handler(int signal)
   LOG_FUNC_IN;
 
   LOG_TRACE (WARNING, "UE-MAIN   - Signal %d received", signal);
-  _nas_clean (user_api_get_fd (), network_api_get_fd ());
+  // FIXME acces to global
+  _nas_clean (user->user_api_id, user_api_get_fd (user->user_api_id), network_api_get_fd ());
   exit (EXIT_SUCCESS);
 
   LOG_FUNC_OUT
@@ -404,7 +407,7 @@ static void _nas_signal_handler(int signal)
  **          Others:    None                                       **
  **                                                                        **
  ***************************************************************************/
-static void _nas_clean(int usr_fd, int net_fd)
+static void _nas_clean(user_api_id_t *user_api_id, int usr_fd, int net_fd)
 {
   LOG_FUNC_IN;
 
@@ -416,7 +419,7 @@ static void _nas_clean(int usr_fd, int net_fd)
   LOG_TRACE (INFO, "UE-MAIN   - "
              "Closing user connection %d and network connection %d",
              usr_fd, net_fd);
-  user_api_close (usr_fd);
+  user_api_close (user_api_id, usr_fd);
   network_api_close (net_fd);
 
   LOG_FUNC_OUT
diff --git a/openair3/NAS/UE/nas_ue_task.c b/openair3/NAS/UE/nas_ue_task.c
index ece175bd05..53b0520933 100644
--- a/openair3/NAS/UE/nas_ue_task.c
+++ b/openair3/NAS/UE/nas_ue_task.c
@@ -78,13 +78,22 @@ void *nas_ue_task(void *args_p)
   {
     /* Initialize user interface (to exchange AT commands with user process) */
     {
-      if (user_api_initialize (NAS_PARSER_DEFAULT_USER_HOSTNAME, NAS_PARSER_DEFAULT_USER_PORT_NUMBER, NULL,
+       user_api_id_t *user_api_id = calloc(1, sizeof(user_api_id_t));
+
+       if (user_api_id == NULL) {
+         LOG_E(NAS, "[UE] Failed to alloc user_api_id_t");
+         // FIXME stop here
+      }
+
+      user->user_api_id = user_api_id;
+
+      if (user_api_initialize (user_api_id, NAS_PARSER_DEFAULT_USER_HOSTNAME, NAS_PARSER_DEFAULT_USER_PORT_NUMBER, NULL,
                                NULL) != RETURNok) {
         LOG_E(NAS, "[UE] user interface initialization failed!");
         exit (EXIT_FAILURE);
       }
 
-      user->fd = user_api_get_fd ();
+      user->fd = user_api_get_fd (user_api_id);
       itti_subscribe_event_fd (TASK_NAS_UE, user->fd);
     }
 
diff --git a/openair3/NAS/UE/nas_user.c b/openair3/NAS/UE/nas_user.c
index 36ba0b7706..da55b3bbf1 100644
--- a/openair3/NAS/UE/nas_user.c
+++ b/openair3/NAS/UE/nas_user.c
@@ -216,13 +216,14 @@ int nas_user_receive_and_process(nas_user_t *user, char *message)
   int nb_command;
   int bytes;
   int i;
+  user_api_id_t *user_api_id = user->user_api_id;
 
   if (message != NULL) {
     /* Set the message in receive buffer (Use to simulate reception of data from UserProcess) */
     bytes = user_api_set_data(message);
   } else {
     /* Read the user data message */
-    bytes = user_api_read_data (user->fd);
+    bytes = user_api_read_data (user_api_id, user->fd);
 
     if (bytes == RETURNerror) {
       /* Failed to read data from the user application layer;
@@ -239,7 +240,7 @@ int nas_user_receive_and_process(nas_user_t *user, char *message)
   }
 
   /* Decode the user data message */
-  nb_command = user_api_decode_data (user->user_at_commands, bytes);
+  nb_command = user_api_decode_data (user_api_id, user->user_at_commands, bytes);
 
   for (i = 0; i < nb_command; i++) {
     /* Get the user data to be processed */
@@ -278,7 +279,7 @@ int nas_user_receive_and_process(nas_user_t *user, char *message)
       }
 
       /* Send the data message to the user */
-      bytes = user_api_send_data (user->fd, bytes);
+      bytes = user_api_send_data (user_api_id, user->fd, bytes);
 
       if (bytes == RETURNerror) {
         /* Failed to send data to the user application layer;
diff --git a/openair3/NAS/UE/user_defs.h b/openair3/NAS/UE/user_defs.h
index 00e713a7d3..c92a5a9388 100644
--- a/openair3/NAS/UE/user_defs.h
+++ b/openair3/NAS/UE/user_defs.h
@@ -53,7 +53,7 @@ Description NAS type definition to manage a user equipment
 #include "EMM/Authentication.h"
 #include "EMM/IdleMode_defs.h"
 #include "API/USIM/usim_api.h"
-#include "API/USER/user_api.h"
+#include "API/USER/user_api_defs.h"
 #include "SecurityModeControl.h"
 #include "userDef.h"
 #include "at_response.h"
@@ -80,6 +80,7 @@ typedef struct {
   at_response_t *at_response; // data structure returned to the user as the result of NAS procedure function call
   //
   user_at_commands_t *user_at_commands; //decoded data received from the user application layer
+  user_api_id_t *user_api_id;
 } nas_user_t;
 
 #endif
-- 
GitLab