Skip to content
Snippets Groups Projects
pdcp_fifo.c 40.9 KiB
Newer Older
/*******************************************************************************

  Eurecom OpenAirInterface
  Copyright(c) 1999 - 2011 Eurecom

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope 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.

  this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

  Contact Information
  Openair Admin: openair_admin@eurecom.fr
  Openair Tech : openair_tech@eurecom.fr
  Forums       : http://forums.eurecom.fsr/openairinterface
  Address      : Eurecom, 2229, route des crêtes, 06560 Valbonne Sophia Antipolis, France

 *******************************************************************************/
 * \brief pdcp interface with linux IP interface, have a look at http://man7.org/linux/man-pages/man7/netlink.7.html for netlink
 * \author  Lionel GAUTHIER and Navid Nikaein
 * \date 2009
 * \version 0.5
 * \warning This component can be runned only in user-space
 * @ingroup pdcp
 */

#define PDCP_FIFO_C
#define PDCP_DEBUG 1
//#define IDROMEL_NEMO 1

#ifndef OAI_EMU
extern int otg_enabled;
#endif

#include "pdcp.h"
#include "pdcp_primitives.h"

#ifdef USER_MODE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define rtf_put write
#define rtf_get read
#else
#include <rtai_fifos.h>
#endif //USER_MODE

#include "../MAC/extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
#include "NAS/DRIVER/LITE/constant.h"
#include "SIMULATION/ETH_TRANSPORT/extern.h"
#include "UTIL/OCG/OCG.h"
#include "UTIL/OCG/OCG_extern.h"
#include "UTIL/LOG/log.h"
#include "assertions.h"

#ifdef NAS_NETLINK
#include <sys/socket.h>
#include <linux/netlink.h>

extern char nl_rx_buf[NL_MAX_PAYLOAD];
extern struct sockaddr_nl nas_src_addr, nas_dest_addr;
extern struct nlmsghdr *nas_nlh_tx;
extern struct nlmsghdr *nas_nlh_rx;
extern struct iovec nas_iov_tx;
extern struct iovec nas_iov_rx;
extern struct msghdr nas_msg_tx;
extern struct msghdr nas_msg_rx;
unsigned char pdcp_read_state_g = 0;
//unsigned char pdcp_read_payload[MAX_PAYLOAD];
extern Packet_OTG_List_t *otg_pdcp_buffer;
pdcp_data_req_header_t pdcp_read_header_g;

//-----------------------------------------------------------------------------
int pdcp_fifo_flush_sdus(frame_t frameP, eNB_flag_t enb_flagP, module_id_t enb_mod_idP, module_id_t ue_mod_idP)
{
  //-----------------------------------------------------------------------------

  mem_block_t     *sdu_p            = list_get_head (&pdcp_sdu_list);
  int              bytes_wrote      = 0;
  int              pdcp_nb_sdu_sent = 0;
  uint8_t               cont             = 1;
#if defined(NAS_NETLINK) && defined(LINUX)
  int ret = 0;
#endif

  while (sdu_p && cont) {
      //LGmcs_inst = ((pdcp_data_ind_header_t *)(sdu->data))->inst;
      // asjust the instance id when passing sdu to IP
      //((pdcp_data_ind_header_t *)(sdu->data))->inst = (((pdcp_data_ind_header_t *)(sdu->data))->inst >= NB_eNB_INST) ?
      //                                                ((pdcp_data_ind_header_t *)(sdu->data))->inst - NB_eNB_INST +oai_emulation.info.nb_enb_local - oai_emulation.info.first_ue_local :// UE
      //                                                ((pdcp_data_ind_header_t *)(sdu->data))->inst - oai_emulation.info.first_ue_local; // ENB
      ((pdcp_data_ind_header_t *)(sdu_p->data))->inst = 0;
      LOG_I(PDCP, "PDCP->IP TTI %d INST %d: Preparing %d Bytes of data from rab %d to Nas_mesh\n",
          frameP, ((pdcp_data_ind_header_t *)(sdu_p->data))->inst,
          ((pdcp_data_ind_header_t *)(sdu_p->data))->data_size, ((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id);
      cont = 0;
      if (!pdcp_output_sdu_bytes_to_write) {
          if (!pdcp_output_header_bytes_to_write) {
              pdcp_output_header_bytes_to_write = sizeof (pdcp_data_ind_header_t);
          }
          bytes_wrote = rtf_put (PDCP2NAS_FIFO,
              &(((uint8_t *) sdu->data)[sizeof (pdcp_data_ind_header_t) - pdcp_output_header_bytes_to_write]),
              pdcp_output_header_bytes_to_write);
          memcpy(NLMSG_DATA(nas_nlh_tx), &(((uint8_t *) sdu_p->data)[sizeof (pdcp_data_ind_header_t) - pdcp_output_header_bytes_to_write]),
              pdcp_output_header_bytes_to_write);
          nas_nlh_tx->nlmsg_len = pdcp_output_header_bytes_to_write;
          bytes_wrote = pdcp_output_header_bytes_to_write;
          LOG_I(PDCP, "Frame %d Sent %d Bytes of header to Nas_mesh\n",
              frameP,
              bytes_wrote);
          if (bytes_wrote > 0) {
              pdcp_output_header_bytes_to_write = pdcp_output_header_bytes_to_write - bytes_wrote;
              if (!pdcp_output_header_bytes_to_write) { // continue with sdu
                  pdcp_output_sdu_bytes_to_write = ((pdcp_data_ind_header_t *) sdu_p->data)->data_size;
                  bytes_wrote = rtf_put (PDCP2NAS_FIFO, &(sdu->data[sizeof (pdcp_data_ind_header_t)]), pdcp_output_sdu_bytes_to_write);
                  memcpy(NLMSG_DATA(nas_nlh_tx)+sizeof(pdcp_data_ind_header_t), &(sdu_p->data[sizeof (pdcp_data_ind_header_t)]), pdcp_output_sdu_bytes_to_write);
                  nas_nlh_tx->nlmsg_len += pdcp_output_sdu_bytes_to_write;
                  ret = sendmsg(nas_sock_fd,&nas_msg_tx,0);
                  if (ret<0) {
                      LOG_D(PDCP, "[PDCP_FIFOS] sendmsg returns %d (errno: %d)\n", ret, errno);
                      mac_xface->macphy_exit("sendmsg failed for nas_sock_fd\n");
                      break;
                  }
                  bytes_wrote= pdcp_output_sdu_bytes_to_write;
                  LOG_I(PDCP, "PDCP->IP Frame %d INST %d: Sent %d Bytes of data from rab %d to Nas_mesh\n",
                      frameP,
                      ((pdcp_data_ind_header_t *)(sdu_p->data))->inst,
                      bytes_wrote,
                      ((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id);
                  if (bytes_wrote > 0) {
                      pdcp_output_sdu_bytes_to_write -= bytes_wrote;

                      if (!pdcp_output_sdu_bytes_to_write) { // OK finish with this SDU
                          // LOG_D(PDCP, "rb sent a sdu qos_sap %d\n", sapiP);
                          LOG_D(PDCP,
                              "[FRAME %05d][xxx][PDCP][MOD xx/xx][RB %u][--- PDCP_DATA_IND / %d Bytes --->][IP][INSTANCE %u][RB %u]\n",
                              frameP,
                              ((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id%NB_RB_MAX,
                              ((pdcp_data_ind_header_t *)(sdu_p->data))->data_size,
                              ((pdcp_data_ind_header_t *)(sdu_p->data))->inst,
                              ((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id);

                          list_remove_head (&pdcp_sdu_list);
                          free_mem_block (sdu_p);
                          cont = 1;
                          pdcp_nb_sdu_sent += 1;
                          sdu_p = list_get_head (&pdcp_sdu_list);
                      }
                  } else {
                      LOG_W(PDCP, "RADIO->IP SEND SDU CONGESTION!\n");
                  }
              } else {
                  LOG_W(PDCP, "RADIO->IP SEND SDU CONGESTION!\n");
              }
      } else {
          // continue writing sdu
          bytes_wrote = rtf_put (PDCP2NAS_FIFO,
              (uint8_t *) (&(sdu_p->data[sizeof (pdcp_data_ind_header_t) + ((pdcp_data_ind_header_t *) sdu_p->data)->data_size - pdcp_output_sdu_bytes_to_write])),
              pdcp_output_sdu_bytes_to_write);
          bytes_wrote = pdcp_output_sdu_bytes_to_write;
          if (bytes_wrote > 0) {
              pdcp_output_sdu_bytes_to_write -= bytes_wrote;

              if (!pdcp_output_sdu_bytes_to_write) {     // OK finish with this SDU
                  //PRINT_RB_SEND_OUTPUT_SDU ("[PDCP] RADIO->IP SEND SDU\n");
                  list_remove_head (&pdcp_sdu_list);
                  free_mem_block (sdu_p);
                  cont = 1;
                  pdcp_nb_sdu_sent += 1;
                  sdu_p = list_get_head (&pdcp_sdu_list);
                  // LOG_D(PDCP, "rb sent a sdu from rab\n");
              }
          }
      }
  }
#ifdef NAS_FIFO
  if ((pdcp_nb_sdu_sent)) {
      if ((pdcp_2_nas_irq > 0)) {
          LOG_I(PDCP, "Frame %d : Trigger NAS RX interrupt\n",
              frameP);
          rt_pend_linux_srq (pdcp_2_nas_irq);
      } else {
          LOG_E(PDCP, "Frame %d: ERROR IF IP STACK WANTED : NOTIF PACKET(S) pdcp_2_nas_irq not initialized : %d\n",
              frameP,
              pdcp_2_nas_irq);
      }
  }
#endif  //NAS_FIFO

  return pdcp_nb_sdu_sent;
}

//-----------------------------------------------------------------------------
/*
 * returns a positive value if whole bytes that had to be read were read
 * returns zero  value if whole bytes that had to be read were not read at all
 * returns a negative  value if an error was encountered while reading the rt fifo
 */
int pdcp_fifo_read_input_sdus_remaining_bytes (frame_t frameP, eNB_flag_t enb_flagP)
{
  //-----------------------------------------------------------------------------
  rb_id_t                rab_id     = 0;
  pdcp_t                *pdcp_p     = NULL;
  module_id_t            ue_inst    = 0;
  module_id_t            enb_inst   = 0;
  rb_id_t                rb_id      = 0;
  int                    result     = -1;

  // if remaining bytes to read
  if (pdcp_input_sdu_remaining_size_to_read > 0) {
      bytes_read = rtf_get (NAS2PDCP_FIFO,
          &(pdcp_input_sdu_buffer[pdcp_input_sdu_size_read]),
          pdcp_input_sdu_remaining_size_to_read);
      if (bytes_read > 0) {
          LOG_D(PDCP, "[PDCP_FIFOS] Read %d remaining bytes of data from Nas_mesh\n", bytes_read);
          pdcp_input_sdu_remaining_size_to_read = pdcp_input_sdu_remaining_size_to_read - bytes_read;
          pdcp_input_sdu_size_read = pdcp_input_sdu_size_read + bytes_read;
          if (pdcp_input_sdu_remaining_size_to_read != 0) {
              return 0;
          } else {
              LOG_I(PDCP, "Frame %d: IP->RADIO RECEIVED COMPLETE SDU size %d inst %d rb %d\n",
                  frameP,
                  pdcp_input_sdu_size_read,
                  pdcp_input_header.inst,
                  pdcp_input_header.rb_id);
              pdcp_input_sdu_size_read = 0;
              pdcp_read_header_g.inst = 0;
              if (enb_flagP == 0) {
                  ue_inst  = pdcp_read_header_g.inst;
                  rb_id    = pdcp_read_header_g.rb_id % NB_RB_MAX;
                  enb_inst = 0;
                  pdcp_p   = &pdcp_array_ue[ue_inst][rb_id];
              } else {
                  ue_inst  = pdcp_read_header_g.rb_id / NB_RB_MAX;
                  rb_id    = pdcp_read_header_g.rb_id % NB_RB_MAX;
                  enb_inst = pdcp_read_header_g.inst;
                  pdcp_p   = &pdcp_array_eNB[enb_inst][ue_inst][rb_id];
              }
              AssertFatal (enb_inst < NB_eNB_INST, "eNB module id is too high (%u/%d)!\n",       enb_inst, NB_eNB_INST);
              AssertFatal (ue_inst  >= NB_eNB_INST,
                           "UE module id is too low (%u/%d)!\n",
                           ue_inst,
                           NB_eNB_INST);
              AssertFatal (ue_inst  < (NB_eNB_INST + NB_UE_INST),
                           "UE module id is too high (%u/%d)!\n",
                           ue_inst,
                           NB_eNB_INST + NB_UE_INST);
              AssertFatal (rab_id    < NB_RB_MAX,                       "RB id is too high (%u/%d)!\n", rab_id, NB_RB_MAX);

              if (pdcp_input_header.rb_id != 0) {
                  LOG_D(PDCP, "[FRAME %5u][%s][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u/%u][RB %u]\n",
                      frameP,
                      (enb_flagP) ? "eNB" : "UE",
                      pdcp_read_header_g.inst,
                      pdcp_read_header_g.rb_id,
                      pdcp_read_header_g.data_size,
                      enb_inst,
                      ue_inst,
                      rb_id);

                  if (pdcp_p->instanciated_instance) {
                      result = pdcp_data_req (enb_inst,
                          ue_inst,
                          frameP,
                          enb_flagP,
                          rb_id,
                          RLC_MUI_UNDEFINED,
                          RLC_SDU_CONFIRM_NO,
                          pdcp_input_header.data_size,
                          pdcp_input_sdu_buffer,
                          PDCP_TRANSMISSION_MODE_DATA);
                      AssertFatal (result == TRUE, "PDCP data request failed!\n");
                  }

              } else if ((pdcp_input_header.traffic_type == TRAFFIC_IPV6_TYPE_MULTICAST) || (pdcp_input_header.traffic_type == TRAFFIC_IPV4_TYPE_MULTICAST)) {
                  LOG_D(PDCP, "[FRAME %5u][%s][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ on MBMS bearer/ %d Bytes --->][PDCP][MOD %u/%u][RB %u]\n",
                      frameP,
                      (enb_flagP) ? "eNB" : "UE",
                          pdcp_read_header_g.inst,
                          pdcp_read_header_g.rb_id,
                          pdcp_read_header_g.data_size,
                          enb_inst,
                          ue_inst,
                          rb_id);

                  if (pdcp_p->instanciated_instance) {
                      result = pdcp_data_req (
                          enb_inst,
                          ue_inst,
                          frameP,
                          enb_flagP,
                          rb_id,
                          RLC_MUI_UNDEFINED,
                          RLC_SDU_CONFIRM_NO,
                          pdcp_input_header.data_size,
                          pdcp_input_sdu_buffer,
                          PDCP_TRANSMISSION_MODE_DATA); //PDCP_TRANSMISSION_MODE_TRANSPARENT);
                      AssertFatal (result == TRUE, "PDCP data request failed!\n");
                  }

              } else if (enb_flagP) {
                  // is a broadcast packet, we have to send this packet on all default RABS of all connected UEs
                  LOG_D(PDCP, "Checking if could sent on default rabs\n");
                  for (ue_inst = 0; ue_inst < NUMBER_OF_UE_MAX; ue_inst++) {
                      LOG_D(PDCP, "Checking if could sent on default rab id %d\n", DEFAULT_RAB_ID);
                      pdcp_p = &pdcp_array_eNB[enb_inst][ue_inst][DEFAULT_RAB_ID];
                      if (pdcp_p->instanciated_instance) {
                          LOG_D(PDCP, "[FRAME %5u][%s][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u/%u][RB DEFAULT_RAB_ID %u]\n",
                              frameP,
                              (enb_flagP) ? "eNB" : "UE",
                              pdcp_read_header_g.inst,
                              pdcp_read_header_g.rb_id,
                              pdcp_read_header_g.data_size,
                              enb_inst,
                              ue_inst,
                              DEFAULT_RAB_ID);
                          result = pdcp_data_req (
                              enb_inst,
                              ue_inst,
                              frameP,
                              enb_flagP,
                              DEFAULT_RAB_ID,
                              RLC_MUI_UNDEFINED,
                              RLC_SDU_CONFIRM_NO,
                              pdcp_input_header.data_size,
                              pdcp_input_sdu_buffer,
                              PDCP_TRANSMISSION_MODE_DATA);
                          AssertFatal (result == TRUE, "PDCP data request failed!\n");
                      }
                  }
              } else {
                  LOG_D(PDCP, "Forcing send on DEFAULT_RAB_ID\n");
                  LOG_D(PDCP, "[FRAME %5u][%s][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u/%u][RB DEFAULT_RAB_ID %u]\n",
                      frameP,
                      (enb_flagP) ? "eNB" : "UE",
                      pdcp_read_header_g.inst,
                      pdcp_read_header_g.rb_id,
                      pdcp_read_header_g.data_size,
                      enb_inst,
                      ue_inst,
                      DEFAULT_RAB_ID);
                  result = pdcp_data_req (
                      enb_inst,
                      ue_inst,
                      frameP,
                      enb_flagP,
                      DEFAULT_RAB_ID,
                      RLC_MUI_UNDEFINED,
                      RLC_SDU_CONFIRM_NO,
                      pdcp_input_header.data_size,
                      pdcp_input_sdu_buffer,
                      PDCP_TRANSMISSION_MODE_DATA);
                  AssertFatal (result == TRUE, "PDCP data request failed!\n");
              }
              // not necessary
              //memset(pdcp_input_sdu_buffer, 0, MAX_IP_PACKET_SIZE);
              return 1;
          }
      } else {
          return bytes_read;
      }
  }
  return 1;
}

//-----------------------------------------------------------------------------
int pdcp_fifo_read_input_sdus (frame_t frameP, eNB_flag_t enb_flagP, module_id_t ue_mod_idP, module_id_t enb_mod_idP)
# if defined(ENABLE_PDCP_NETLINK_FIFO)
  module_id_t                    ue_id     = 0;
  rb_id_t                        rab_id    = 0;
  pdcp_t                        *pdcp      = NULL;
  pdcp_transmission_mode_t       pdcp_mode = PDCP_TRANSMISSION_MODE_UNKNOWN;
  struct pdcp_netlink_element_s *data      = NULL;

  while (pdcp_netlink_dequeue_element(enb_mod_idP, ue_mod_idP, enb_flagP, &data) != 0) {
      DevAssert(data != NULL);
      if (enb_flagP == 0) {
          rab_id = data->pdcp_read_header.rb_id % NB_RB_MAX;
          pdcp = &pdcp_array_ue[ue_mod_idP][rab_id];
      } else {
          rab_id = data->pdcp_read_header.rb_id % NB_RB_MAX;
          ue_mod_idP = data->pdcp_read_header.rb_id / NB_RB_MAX;
          pdcp = &pdcp_array_eNB[enb_mod_idP][ue_mod_idP][rab_id];
      }
      if (enb_flagP) {
          AssertFatal ((enb_mod_idP >= oai_emulation.info.first_enb_local) && (oai_emulation.info.nb_enb_local > 0),
              "eNB module id is too low (%u/%d)!\n",
              enb_mod_idP,
              oai_emulation.info.first_enb_local);
          AssertFatal ((enb_mod_idP < (oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local)) && (oai_emulation.info.nb_enb_local > 0),
              "eNB module id is too high (%u/%d)!\n",
              enb_mod_idP,
              oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local);
          AssertFatal (ue_mod_idP  < NB_UE_INST,
              "UE module id is too high (%u/%d)!\n",
              ue_mod_idP,
              oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
      } else {
          AssertFatal (ue_mod_idP  < (oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local),
              "UE module id is too high (%u/%d)!\n",
              ue_mod_idP,
              oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
          AssertFatal (ue_mod_idP  >= oai_emulation.info.first_ue_local,
              "UE module id is too low (%u/%d)!\n",
              ue_mod_idP,
              oai_emulation.info.first_ue_local);
      }
      AssertFatal (rab_id    < NB_RB_MAX,                       "RB id is too high (%u/%d)!\n", rab_id, NB_RB_MAX);

      if (rab_id != 0) {
          if (pdcp->instanciated_instance) {
              LOG_D(PDCP, "[FRAME %05d][%s][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ "
                  "/ %d Bytes --->][PDCP][MOD %u/%u][RB %u]\n",
                  frameP,
                  (enb_flagP) ? "eNB" : "UE",
                      data->pdcp_read_header.inst,
                      data->pdcp_read_header.rb_id,
                      data->pdcp_read_header.data_size,
                      enb_mod_idP,
                      ue_mod_idP,
                      rab_id);
#ifdef 	OAI_NW_DRIVER_TYPE_ETHERNET
              if ((data->pdcp_read_header.traffic_type == TRAFFIC_IPV6_TYPE_MULTICAST) /*TRAFFIC_IPV6_TYPE_MULTICAST */ ||
                  (data->pdcp_read_header.traffic_type == TRAFFIC_IPV4_TYPE_MULTICAST) /*TRAFFIC_IPV4_TYPE_MULTICAST */ ||
                  (data->pdcp_read_header.traffic_type == TRAFFIC_IPV4_TYPE_BROADCAST) /*TRAFFIC_IPV4_TYPE_BROADCAST */ ) {
#if defined (Rel10)
                pdcp_mode = PDCP_TRANSMISSION_MODE_DATA; //PDCP_TRANSMISSION_MODE_TRANSPARENT;
#else
                pdcp_mode= PDCP_TRANSMISSION_MODE_DATA;
#endif
              } else if ((data->pdcp_read_header.traffic_type == TRAFFIC_IPV6_TYPE_UNICAST) /* TRAFFIC_IPV6_TYPE_UNICAST */ ||
                  (data->pdcp_read_header.traffic_type == TRAFFIC_IPV4_TYPE_UNICAST) /*TRAFFIC_IPV4_TYPE_UNICAST*/ ) {
                pdcp_mode=  PDCP_TRANSMISSION_MODE_DATA;
              } else {
                  pdcp_mode= PDCP_TRANSMISSION_MODE_DATA;
                  LOG_W(PDCP,"unknown IP traffic type \n");
              }
#else // NASMESH driver does not curreenlty support multicast traffic 
              pdcp_mode = PDCP_TRANSMISSION_MODE_DATA;
              pdcp_data_req(enb_mod_idP,
                  ue_mod_idP,
                  frameP,
                  enb_flagP,
                  rab_id,
                  RLC_MUI_UNDEFINED,
                  RLC_SDU_CONFIRM_NO,
                  data->pdcp_read_header.data_size,
                  data->data,
                  pdcp_mode);
          } else {
              LOG_E(PDCP, "Received packet for non-instanciated instance %u with rb_id %u, UE_index %d, enb_flagP %d eNB_index %d\n",
                  data->pdcp_read_header.inst, data->pdcp_read_header.rb_id, ue_mod_idP, enb_flagP,enb_mod_idP);
      } else if (enb_flagP) {
          /* rb_id = 0, thus interpreated as broadcast and transported as
           * multiple unicast is a broadcast packet, we have to send this
           * packet on all default RABS of all connected UEs
           */
          LOG_D(PDCP, "eNB Try Forcing send on DEFAULT_RAB_ID first_ue_local %u nb_ue_local %u\n", oai_emulation.info.first_ue_local, oai_emulation.info.nb_ue_local);
          for (ue_id = 0; ue_id < NB_UE_INST; ue_id++) {
              pdcp = &pdcp_array_eNB[enb_mod_idP][ue_id][DEFAULT_RAB_ID];
              if (pdcp->instanciated_instance) {
                  LOG_D(PDCP, "eNB Try Forcing send on DEFAULT_RAB_ID UE %d\n", ue_id);
                  pdcp_data_req(
                      enb_mod_idP,
                      ue_id,
                      frameP,
                      enb_flagP,
                      DEFAULT_RAB_ID,
                      RLC_MUI_UNDEFINED,
                      RLC_SDU_CONFIRM_NO,
                      data->pdcp_read_header.data_size,
                      data->data,
                      PDCP_TRANSMISSION_MODE_DATA);
              }
          }
      } else {
          LOG_D(PDCP, "Forcing send on DEFAULT_RAB_ID\n");
          pdcp_data_req(
              enb_mod_idP,
              ue_mod_idP,
              frameP,
              enb_flagP,
              DEFAULT_RAB_ID,
              RLC_MUI_UNDEFINED,
              RLC_SDU_CONFIRM_NO,
              data->pdcp_read_header.data_size,
              data->data,
              PDCP_TRANSMISSION_MODE_DATA);
      }
      free(data->data);
      free(data);
      data = NULL;
  }
  return 0;
# else /* ENABLE_PDCP_NETLINK_FIFO*/
      len = recvmsg(nas_sock_fd, &nas_msg_rx, 0);
      if (len<=0) {
          // nothing in pdcp NAS socket
          //LOG_I(PDCP, "[PDCP][NETLINK] Nothing in socket, length %d \n", len);
      } else {
          for (nas_nlh_rx = (struct nlmsghdr *) nl_rx_buf;
              NLMSG_OK (nas_nlh_rx, len);
              nas_nlh_rx = NLMSG_NEXT (nas_nlh_rx, len)) {
              if (nas_nlh_rx->nlmsg_type == NLMSG_DONE) {
                  LOG_I(PDCP, "[PDCP][FIFO] RX NLMSG_DONE\n");
                  //return;
              }
              if (nas_nlh_rx->nlmsg_type == NLMSG_ERROR) {
                  LOG_I(PDCP, "[PDCP][FIFO] RX NLMSG_ERROR\n");
              }
              if (pdcp_read_state_g == 0) {
                  if (nas_nlh_rx->nlmsg_len == sizeof (pdcp_data_req_header_t) + sizeof(struct nlmsghdr)) {
                      pdcp_read_state_g = 1;  //get
                      memcpy((void *)&pdcp_read_header_g, (void *)NLMSG_DATA(nas_nlh_rx), sizeof(pdcp_data_req_header_t));
                      LOG_I(PDCP, "[PDCP][FIFO] RX pdcp_data_req_header_t inst %u, rb_id %u data_size %d\n",
                          pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size);
                      LOG_E(PDCP, "[PDCP][FIFO] WRONG size %d should be sizeof (pdcp_data_req_header_t) + sizeof(struct nlmsghdr)\n",
                          nas_nlh_rx->nlmsg_len);
                  }
              } else {
                  pdcp_read_state_g = 0;
                  // print_active_requests()
                  LOG_I(PDCP, "[PDCP][FIFO] Something in socket, length %d \n",
                      nas_nlh_rx->nlmsg_len - sizeof(struct nlmsghdr));
                  //memcpy(pdcp_read_payload, (unsigned char *)NLMSG_DATA(nas_nlh_rx), nas_nlh_rx->nlmsg_len - sizeof(struct nlmsghdr));

                  // overwrite function input parameters, because only one netlink socket for all instances
                  if (pdcp_read_header_g.inst < oai_emulation.info.nb_enb_local) {
                      enb_flagP  = 1;
                      ue_mod_idP  = pdcp_read_header_g.rb_id / NB_RB_MAX + oai_emulation.info.first_ue_local;
                      enb_mod_idP = pdcp_read_header_g.inst  +  oai_emulation.info.first_enb_local;
                      rab_id    = pdcp_read_header_g.rb_id % NB_RB_MAX;
                  } else {
                      enb_flagP  = 0;
                      ue_mod_idP  = pdcp_read_header_g.inst - oai_emulation.info.nb_enb_local + oai_emulation.info.first_ue_local;
                      enb_mod_idP = 0;
                      rab_id    = pdcp_read_header_g.rb_id;
                  }
                  AssertFatal (enb_mod_idP >= oai_emulation.info.first_enb_local,
                              "eNB inst is too low (%u/%d)!\n",
                              enb_mod_idP,
                              oai_emulation.info.first_enb_local);
                  AssertFatal (enb_mod_idP < (oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local),
                              "eNB inst is too high (%u/%d)!\n",
                              enb_mod_idP,
                              oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local);
                  AssertFatal (ue_mod_idP  >= oai_emulation.info.first_ue_local,
                               "UE inst is too low (%u/%d)!\n",
                               ue_mod_idP,
                               oai_emulation.info.first_ue_local);
                  AssertFatal (ue_mod_idP  < (oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local),
                               "UE inst is too high (%u/%d)!\n",
                               ue_mod_idP,
                               oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
                  AssertFatal (rab_id    < NB_RB_MAX,                       "RB id is too high (%u/%d)!\n", rab_id, NB_RB_MAX);
#ifdef OAI_EMU
                  /*LGpdcp_read_header.inst = (pdcp_read_header_g.inst >= oai_emulation.info.nb_enb_local) ? \
                          pdcp_read_header_g.inst - oai_emulation.info.nb_enb_local+ NB_eNB_INST + oai_emulation.info.first_ue_local :
                          pdcp_read_header_g.inst +  oai_emulation.info.first_enb_local;*/
#else
                  pdcp_read_header_g.inst = 0;
#endif

                  if (enb_flagP) {
                      if (rab_id != 0) {
                          if (pdcp_array_eNB[enb_mod_idP][ue_mod_idP][rab_id].instanciated_instance) {
                              LOG_I(PDCP, "[FRAME %5u][eNB][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %d) on Rab %d \n",
                                  frameP,
                                  pdcp_read_header_g.inst,
                                  len,
                                  nas_nlh_rx->nlmsg_len-sizeof(struct nlmsghdr),
                                  pdcp_read_header_g.rb_id);
                              LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u/%u][RB %u]\n",
                                  frameP,
                                  pdcp_read_header_g.inst,
                                  pdcp_read_header_g.rb_id,
                                  pdcp_read_header_g.data_size,
                                  enb_mod_idP,
                                  ue_mod_idP,
                                  rab_id);

                              pdcp_data_req(enb_mod_idP,ue_mod_idP,frameP, enb_flagP,
                                  rab_id,
                                  RLC_MUI_UNDEFINED,
                                  RLC_SDU_CONFIRM_NO,
                                  pdcp_read_header_g.data_size,
                                  (unsigned char *)NLMSG_DATA(nas_nlh_rx),
                                  PDCP_TRANSMISSION_MODE_DATA);
                              LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u/%u][RB %u] NON INSTANCIATED INSTANCE, DROPPED\n",
                                  frameP,
                                  pdcp_read_header_g.inst,
                                  pdcp_read_header_g.rb_id,
                                  pdcp_read_header_g.data_size,
                                  enb_mod_idP,
                                  ue_mod_idP,
                                  rab_id);
                      } else  { // rb_id =0, thus interpreated as broadcast and transported as multiple unicast
                          // is a broadcast packet, we have to send this packet on all default RABS of all connected UEs
#warning CODE TO BE REVIEWED, ONLY WORK FOR SIMPLE TOPOLOGY CASES
                          for (ue_mod_idP = 0; ue_mod_idP < NB_UE_INST; ue_mod_idP++) {
                              if (pdcp_array_eNB[enb_mod_idP][ue_mod_idP][rab_id].instanciated_instance == TRUE) {
                                  LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u/%u][RB DEFAULT_RAB_ID %u]\n",
                                      frameP,
                                      pdcp_read_header_g.inst,
                                      pdcp_read_header_g.rb_id,
                                      pdcp_read_header_g.data_size,
                                      enb_mod_idP,
                                      ue_mod_idP,
                                      DEFAULT_RAB_ID);
                                  pdcp_data_req (
                                      enb_mod_idP,
                                      ue_mod_idP,
                                      frameP,
                                      enb_flagP,
                                      DEFAULT_RAB_ID,
                                      RLC_MUI_UNDEFINED,
                                      RLC_SDU_CONFIRM_NO,
                                      pdcp_read_header_g.data_size,
                                      (unsigned char *)NLMSG_DATA(nas_nlh_rx),
                                      PDCP_TRANSMISSION_MODE_DATA);
                      }
                  } else {
                      if (rab_id != 0) {
                          if (pdcp_array_ue[ue_mod_idP][rab_id].instanciated_instance) {
#ifdef PDCP_DEBUG
                              LOG_I(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %d) on Rab %d \n",
                                  frameP,
                                  pdcp_read_header_g.inst,
                                  len,
                                  nas_nlh_rx->nlmsg_len-sizeof(struct nlmsghdr),
                                  pdcp_read_header_g.rb_id);

                              LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u/%u][RB %u]\n",
                                  frameP,
                                  pdcp_read_header_g.inst,
                                  pdcp_read_header_g.rb_id,
                                  pdcp_read_header_g.data_size,
                                  enb_mod_idP,
                                  ue_mod_idP,
                                  rab_id);
#endif
                              pdcp_data_req(
                                  enb_mod_idP,
                                  ue_mod_idP,
                                  frameP,
                                  enb_flagP,
                                  rab_id,
                                  RLC_MUI_UNDEFINED,
                                  RLC_SDU_CONFIRM_NO,
                                  pdcp_read_header_g.data_size,
                                  (unsigned char *)NLMSG_DATA(nas_nlh_rx),
                                  PDCP_TRANSMISSION_MODE_DATA);
                          } else {
                              LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u/%u][RB %u] NON INSTANCIATED INSTANCE, DROPPED\n",
                                  frameP,
                                  pdcp_read_header_g.inst,
                                  pdcp_read_header_g.rb_id,
                                  pdcp_read_header_g.data_size,
                                  enb_mod_idP,
                                  ue_mod_idP,
                                  rab_id);
                          }
                      }  else {
                          LOG_D(PDCP, "Forcing send on DEFAULT_RAB_ID\n");
                          LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u/%u][RB DEFAULT_RAB_ID %u]\n",
                              frameP,
                              pdcp_read_header_g.inst,
                              pdcp_read_header_g.rb_id,
                              pdcp_read_header_g.data_size,
                              enb_mod_idP,
                              ue_mod_idP,
                              DEFAULT_RAB_ID);
                          pdcp_data_req (
                              enb_mod_idP,
                              ue_mod_idP,
                              frameP,
                              enb_flagP,
                              DEFAULT_RAB_ID,
                              RLC_MUI_UNDEFINED,
                              RLC_SDU_CONFIRM_NO,
                              pdcp_read_header_g.data_size,
                              (unsigned char *)NLMSG_DATA(nas_nlh_rx),
                              PDCP_TRANSMISSION_MODE_DATA);
#else // neither NAS_NETLINK nor NAS_FIFO
  return 0;
#endif // NAS_NETLINK
}


void pdcp_fifo_read_input_sdus_from_otg (frame_t frameP, eNB_flag_t enb_flagP, module_id_t ue_mod_idP, module_id_t enb_mod_idP) {
  unsigned char       *otg_pkt=NULL;
  module_id_t          src_id, module_id; // src for otg
  module_id_t          dst_id; // dst for otg
  rb_id_t              rb_id;
  int                  pkt_size=0, pkt_cnt=0;
  uint8_t              pdcp_mode, is_ue=0;
  Packet_otg_elt_t    *otg_pkt_info=NULL;
  int                  result;
  src_id = enb_mod_idP;
  // we need to add conditions to avoid transmitting data when the UE is not RRC connected.
#if defined(USER_MODE) && defined(OAI_EMU)
  if (oai_emulation.info.otg_enabled ==1 ){
      module_id = (enb_flagP == 1) ?  enb_mod_idP : ue_mod_idP;
      //rb_id    = (enb_flagP == 1) ? enb_mod_idP * MAX_NUM_RB + DTCH : (NB_eNB_INST + UE_index -1 ) * MAX_NUM_RB + DTCH ;
      src_id = module_id;
      while ((otg_pkt_info = pkt_list_remove_head(&(otg_pdcp_buffer[module_id]))) != NULL) {
          LOG_I(OTG,"Mod_id %d Frame %d Got a packet (%p), HEAD of otg_pdcp_buffer[%d] is %p and Nb elements is %d\n",
              module_id,frameP, otg_pkt_info, module_id, pkt_list_get_head(&(otg_pdcp_buffer[module_id])), otg_pdcp_buffer[module_id].nb_elements);
          //otg_pkt_info = pkt_list_remove_head(&(otg_pdcp_buffer[module_id]));
          dst_id = (otg_pkt_info->otg_pkt).dst_id;
          module_id = (otg_pkt_info->otg_pkt).module_id;
          rb_id = (otg_pkt_info->otg_pkt).rb_id;
          is_ue = (otg_pkt_info->otg_pkt).is_ue;
          pdcp_mode = (otg_pkt_info->otg_pkt).mode;
          //    LOG_I(PDCP,"pdcp_fifo, pdcp mode is= %d\n",pdcp_mode);

          // generate traffic if the ue is rrc reconfigured state
          // if (mac_get_rrc_status(module_id, enb_flagP, dst_id ) > 2 /*RRC_CONNECTED*/) { // not needed: this test is already done in update_otg_enb
          otg_pkt = (uint8_t*) (otg_pkt_info->otg_pkt).sdu_buffer;
          pkt_size = (otg_pkt_info->otg_pkt).sdu_buffer_size;
          if (otg_pkt != NULL) {
              if (is_ue == 0 ) {
                  //rb_id = (/*NB_eNB_INST +*/ dst_id -1 ) * MAX_NUM_RB + DTCH;
                  LOG_D(OTG,"[eNB %d] Frame %d sending packet %d from module %d on rab id %d (src %d, dst %d) pkt size %d for pdcp mode %d\n",
                      enb_mod_idP, frameP, pkt_cnt++, module_id, rb_id, module_id, dst_id, pkt_size, pdcp_mode);
                  result = pdcp_data_req(enb_mod_idP, ue_mod_idP, frameP, enb_flagP, rb_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, pkt_size, otg_pkt,pdcp_mode);
                  AssertFatal (result == TRUE, "PDCP data request failed!\n");
              }
              else {
                  //rb_id= eNB_index * MAX_NUM_RB + DTCH;
                  LOG_D(OTG,"[UE %d] sending packet from module %d on rab id %d (src %d, dst %d) pkt size %d\n",
                      ue_mod_idP, src_id, rb_id, src_id, dst_id, pkt_size);
                  result = pdcp_data_req( enb_mod_idP,
                                          ue_mod_idP,
                                          frameP,
                                          enb_flagP,
                                          rb_id,
                                          RLC_MUI_UNDEFINED,
                                          RLC_SDU_CONFIRM_NO,
                                          pkt_size,
                                          otg_pkt,
                                          PDCP_TRANSMISSION_MODE_DATA);
                  AssertFatal (result == TRUE, "PDCP data request failed!\n");
              }
              free(otg_pkt);
              otg_pkt = NULL;
          }
          // } //else LOG_D(OTG,"frameP %d enb %d-> ue %d link not yet established state %d  \n", frameP, eNB_index,dst_id - NB_eNB_INST, mac_get_rrc_status(module_id, enb_flagP, dst_id - NB_eNB_INST));
  if ((otg_enabled==1) && (enb_flagP == 1)) { // generate DL traffic
      unsigned int ctime=0;
      ctime = frameP * 100;

      /*if  ((mac_get_rrc_status(eNB_index, enb_flagP, 0 ) > 2) &&
      (mac_get_rrc_status(eNB_index, enb_flagP, 1 ) > 2)) { */
      for (dst_id = 0; dst_id<NUMBER_OF_UE_MAX; dst_id++) {
          if (mac_get_rrc_status(enb_mod_idP, enb_flagP, dst_id ) > 2) {
              otg_pkt=packet_gen(src_id, dst_id, 0, ctime, &pkt_size);
              if (otg_pkt != NULL){
                  rb_id = dst_id * NB_RB_MAX + DTCH;
                  pdcp_data_req(enb_mod_idP, dst_id, frameP, enb_flagP, rb_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO,pkt_size, otg_pkt, PDCP_TRANSMISSION_MODE_DATA);
                  LOG_I(OTG,"send packet from module %d on rab id %d (src %d, dst %d) pkt size %d\n", enb_mod_idP, rb_id, src_id, dst_id, pkt_size);
                  free(otg_pkt);
              }
              /*else {
      LOG_I(OTG,"nothing generated (src %d, dst %d)\n",src_id, dst_id);
      }*/
          }
          /*else {
    LOG_I(OTG,"rrc_status (src %d, dst %d) = %d\n",src_id, dst_id, mac_get_rrc_status(src_id, enb_flagP, dst_id ));