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
*******************************************************************************/
/*! \file pdcp_fifo.c
* \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"
winckel
committed
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/FIFO/pad_list.h"
#include "platform_constants.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 int nas_sock_fd;
extern struct msghdr nas_msg_tx;
extern struct msghdr nas_msg_rx;
#define MAX_PAYLOAD 1600
//unsigned char pdcp_read_payload[MAX_PAYLOAD];
#endif
extern Packet_OTG_List_t *otg_pdcp_buffer;
//-----------------------------------------------------------------------------
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;
#if defined(NAS_NETLINK) && defined(LINUX)
int ret = 0;
#endif
((pdcp_data_ind_header_t *)(sdu_p->data))->inst = 0;
#endif
#if defined(LINK_PDCP_TO_GTPV1U)
if (enb_flagP) {
LOG_I(PDCP,"Sending to GTPV1U\n");
/*message_p = itti_alloc_new_message(TASK_PDCP_ENB, GTPV1U_TUNNEL_DATA_REQ);
GTPV1U_TUNNEL_DATA_REQ(message_p).buffer = &(((uint8_t *) sdu_p->data)[sizeof (pdcp_data_ind_header_t)]);
GTPV1U_TUNNEL_DATA_REQ(message_p).length = ((pdcp_data_ind_header_t *)(sdu_p->data))->data_size;
GTPV1U_TUNNEL_DATA_REQ(message_p).ue_module_id = ue_mod_idP;
GTPV1U_TUNNEL_DATA_REQ(message_p).rab_id; = ((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id;
*/
gtpv1u_new_data_req(
enb_mod_idP, //gtpv1u_data_t *gtpv1u_data_p,
ue_mod_idP,//rb_id/NB_RB_MAX, TO DO UE ID
((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id, //was 0 default RAB ID
&(((uint8_t *) sdu_p->data)[sizeof (pdcp_data_ind_header_t)]),
((pdcp_data_ind_header_t *)(sdu_p->data))->data_size);
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_I(OTG,"After GTPV1U\n");
continue; // loop again
}
#endif /* defined(ENABLE_USE_MME) */
#ifdef PDCP_DEBUG
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);
#endif //PDCP_DEBUG
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);
}
#ifdef NAS_FIFO
&(((uint8_t *) sdu->data)[sizeof (pdcp_data_ind_header_t) - pdcp_output_header_bytes_to_write]),
#else
#ifdef NAS_NETLINK
#ifdef LINUX
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;
#endif //LINUX
#endif //NAS_NETLINK
bytes_wrote = pdcp_output_header_bytes_to_write;
#endif //NAS_FIFO
#ifdef PDCP_DEBUG
LOG_I(PDCP, "Frame %d Sent %d Bytes of header to Nas_mesh\n",
frameP,
bytes_wrote);
#endif //PDCP_DEBUG
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;
#ifdef NAS_FIFO
bytes_wrote = rtf_put (PDCP2NAS_FIFO, &(sdu->data[sizeof (pdcp_data_ind_header_t)]), pdcp_output_sdu_bytes_to_write);
#else
#ifdef NAS_NETLINK
#ifdef LINUX
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;
}
#endif // LINUX
#endif //NAS_NETLINK
bytes_wrote= pdcp_output_sdu_bytes_to_write;
#endif // NAS_FIFO
#ifdef PDCP_DEBUG
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);
#endif //PDCP_DEBUG
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");
}
#ifdef NAS_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])),
#else // NAS_FIFO
bytes_wrote = pdcp_output_sdu_bytes_to_write;
#endif // NAS_FIFO
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)) {
#ifdef PDCP_DEBUG
LOG_I(PDCP, "Frame %d : Trigger NAS RX interrupt\n",
frameP);
#endif //PDCP_DEBUG
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)
{
//-----------------------------------------------------------------------------
sdu_size_t bytes_read = 0;
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 {
#ifdef PDCP_DEBUG
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);
#endif //PDCP_DEBUG
#ifdef IDROMEL_NEMO
#endif
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,
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,
rb_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pdcp_input_header.data_size,
pdcp_input_sdu_buffer,
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,
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,
rb_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pdcp_input_header.data_size,
pdcp_input_sdu_buffer,
PDCP_TRANSMISSION_MODE_TRANSPARENT);
AssertFatal (result == TRUE, "PDCP data request failed!\n");
}
// 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,
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,
DEFAULT_RAB_ID,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pdcp_input_header.data_size,
pdcp_input_sdu_buffer,
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,
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,
DEFAULT_RAB_ID,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pdcp_input_header.data_size,
pdcp_input_sdu_buffer,
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)
{
#ifdef NAS_NETLINK
# 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) {
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,
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_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
#endif
pdcp_data_req(enb_mod_idP,
ue_mod_idP,
frameP,
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);
/* 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,
DEFAULT_RAB_ID,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
data->pdcp_read_header.data_size,
data->data,
}
}
} else {
LOG_D(PDCP, "Forcing send on DEFAULT_RAB_ID\n");
pdcp_data_req(
enb_mod_idP,
ue_mod_idP,
frameP,
DEFAULT_RAB_ID,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
data->pdcp_read_header.data_size,
data->data,
}
free(data->data);
free(data);
data = NULL;
}
return 0;
# else /* ENABLE_PDCP_NETLINK_FIFO*/
int len = 1;
rb_id_t rab_id = 0;
while (len > 0) {
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);
} else {
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()
#ifdef PDCP_DEBUG
LOG_I(PDCP, "[PDCP][FIFO] Something in socket, length %d \n",
nas_nlh_rx->nlmsg_len - sizeof(struct nlmsghdr));
#endif
//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) {
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 {
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
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 (rab_id != 0) {
if (pdcp_array_eNB[enb_mod_idP][ue_mod_idP][rab_id].instanciated_instance) {
#ifdef PDCP_DEBUG
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);
#endif
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),
} else {
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,
DEFAULT_RAB_ID,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pdcp_read_header_g.data_size,
(unsigned char *)NLMSG_DATA(nas_nlh_rx),
}
}
}
} 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,
rab_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pdcp_read_header_g.data_size,
(unsigned char *)NLMSG_DATA(nas_nlh_rx),
} 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,
DEFAULT_RAB_ID,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pdcp_read_header_g.data_size,
(unsigned char *)NLMSG_DATA(nas_nlh_rx),
}
}
}
}
}
return len;
# endif
#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;
nguyennd
committed
// 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 ) {
rlc_util_print_hex_octets(PDCP,
(unsigned char*)otg_pkt,
pkt_size);
//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));
}
}
#else
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);
}*/
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 ));
}
#endif
}