Newer
Older
/*******************************************************************************
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, 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(const protocol_ctxt_t* const ctxt_pP)
{
//-----------------------------------------------------------------------------
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 (ctxt_pP->enb_flag) {
AssertFatal(0, "Now execution should not go here");
LOG_D(PDCP,"Sending to GTPV1U %d bytes\n", ((pdcp_data_ind_header_t *)(sdu_p->data))->data_size);
/*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 = ctxt_pP->ue_module_id;
GTPV1U_TUNNEL_DATA_REQ(message_p).rab_id; = ((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id;
*/
gtpv1u_new_data_req(
ctxt_pP->enb_module_id, //gtpv1u_data_t *gtpv1u_data_p,
ctxt_pP->ue_module_id,//rb_id/maxDRB, TO DO UE ID
((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id + 4,
&(((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);
continue; // loop again
}
#endif /* defined(ENABLE_USE_MME) */
#ifdef PDCP_DEBUG
LOG_D(PDCP, "PDCP->IP TTI %d INST %d: Preparing %d Bytes of data from rab %d to higher layers\n",
ctxt_pP->frame, ((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
ctxt_pP->frame,
#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_D(PDCP, "PDCP->IP Frame %d INST %d: Sent %d Bytes of data from rab %d to higher layers\n",
ctxt_pP->frame,
((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",
ctxt_pP->frame,
((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id,
((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",
ctxt_pP->frame);
#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",
ctxt_pP->frame,
}
#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 (const protocol_ctxt_t* const ctxt_pP)
{
//-----------------------------------------------------------------------------
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_D(PDCP, "Frame %d: IP->RADIO RECEIVED COMPLETE SDU size %d inst %d rb %d\n",
ctxt_pP->frame,
pdcp_input_sdu_size_read,
pdcp_input_header.inst,
pdcp_input_header.rb_id);
#endif //PDCP_DEBUG
#ifdef IDROMEL_NEMO
#endif
if (ctxt_pP->enb_flag == 0) {
pdcp_p = &pdcp_array_drb_ue[ue_inst][rb_id-1];
ue_inst = pdcp_read_header_g.rb_id / maxDRB;
rb_id = pdcp_read_header_g.rb_id % maxDRB;
pdcp_p = &pdcp_array_drb_eNB[enb_inst][ue_inst][rb_id-1];
}
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 (rb_id < maxDRB, "RB id is too high (%u/%d)!\n", rab_id, maxDRB);
AssertFatal (rb_id > 0 , "RB id is too low (%u/%d)!\n", rab_id, maxDRB);
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",
ctxt_pP->frame,
(ctxt_pP->enb_flag) ? "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) {
ctxt_pP,
SRB_FLAG_NO,
rb_id % maxDRB,
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",
ctxt_pP->frame,
(ctxt_pP->enb_flag) ? "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 (
ctxt_pP,
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");
}
} else if (ctxt_pP->enb_flag) {
// 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_drb_eNB[enb_inst][ue_inst][DEFAULT_RAB_ID-1];
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",
ctxt_pP->frame,
(ctxt_pP->enb_flag) ? "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 (
ctxt_pP,
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",
ctxt_pP->frame,
(ctxt_pP->enb_flag) ? "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 (
ctxt_pP,
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 (const protocol_ctxt_t* const ctxt_pP)
{
#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;
protocol_ctxt_t ctxt;
ctxt_cpy = *ctxt_pP;
while (pdcp_netlink_dequeue_element(ctxt_pP, &data) != 0) {
rab_id = data->pdcp_read_header.rb_id % maxDRB;
rab_id = data->pdcp_read_header.rb_id % maxDRB;
ctxt_cpy.ue_module_id = data->pdcp_read_header.rb_id / maxDRB;
pdcp = &pdcp_array_drb_eNB[ctxt_cpy.enb_module_id][ctxt_cpy.ue_module_id][rab_id-1];
if (ctxt_cpy.enb_flag) {
AssertFatal ((ctxt_cpy.enb_module_id >= oai_emulation.info.first_enb_local) && (oai_emulation.info.nb_enb_local > 0),
AssertFatal ((ctxt_cpy.enb_module_id < (oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local)) && (oai_emulation.info.nb_enb_local > 0),
oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local);
oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
} else {
AssertFatal (ctxt_cpy.ue_module_id < (oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local),
oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
AssertFatal (ctxt_cpy.ue_module_id >= oai_emulation.info.first_ue_local,
oai_emulation.info.first_ue_local);
}
AssertFatal (rab_id < maxDRB, "RB id is too high (%u/%d)!\n", rab_id, maxDRB);
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",
data->pdcp_read_header.inst,
data->pdcp_read_header.rb_id,
data->pdcp_read_header.data_size,
#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*/ ) {
LOG_W(PDCP,"unknown IP traffic type \n");
}
#else // NASMESH driver does not curreenlty support multicast traffic
#endif
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, ctxt_cpy.enb_flag %d eNB_index %d\n",
data->pdcp_read_header.inst, data->pdcp_read_header.rb_id, ctxt_cpy.ue_module_id, ctxt_cpy.enb_flag,ctxt_cpy.enb_module_id);
/* 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_drb_eNB[ctxt_cpy.enb_module_id][ue_id][DEFAULT_RAB_ID-1];
LOG_D(PDCP, "eNB Try Forcing send on DEFAULT_RAB_ID UE %d\n", ue_id);
ctxt.enb_module_id = ctxt_cpy.enb_module_id;
ctxt.ue_module_id = ue_id;
ctxt.frame = ctxt_cpy.frame;
ctxt.enb_flag = ctxt_cpy.enb_flag;
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(
DEFAULT_RAB_ID,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
data->pdcp_read_header.data_size,
}
free(data->data);
free(data);
data = NULL;
}
return 0;
# else /* ENABLE_PDCP_NETLINK_FIFO*/
int len = 1;
rb_id_t rab_id = 0;
protocol_ctxt_t ctxt_cpy;
protocol_ctxt_t ctxt;
ctxt_cpy = *ctxt_pP;
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_ERROR) {
}
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_D(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
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) {
ctxt.frame = ctxt_cpy.frame;
ctxt.enb_flag = ENB_FLAG_YES;
ctxt.ue_module_id = pdcp_read_header_g.rb_id / maxDRB + oai_emulation.info.first_ue_local;
ctxt.enb_module_id = pdcp_read_header_g.inst + oai_emulation.info.first_enb_local;
rab_id = pdcp_read_header_g.rb_id % maxDRB;
ctxt.frame = ctxt_cpy.frame;
ctxt.enb_flag = ENB_FLAG_NO;
ctxt.ue_module_id = pdcp_read_header_g.inst - oai_emulation.info.nb_enb_local + oai_emulation.info.first_ue_local;
ctxt.enb_module_id = 0;
AssertFatal (ctxt.enb_module_id >= oai_emulation.info.first_enb_local,
AssertFatal (ctxt.enb_module_id < (oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local),
oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local);
AssertFatal (ctxt.ue_module_id >= oai_emulation.info.first_ue_local,
AssertFatal (ctxt.ue_module_id < (oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local),
oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
AssertFatal (rab_id < maxDRB, "RB id is too high (%u/%d)!\n", rab_id, maxDRB);
/*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;
#warning "TO DO CORRCT VALUES FOR ue mod id, enb mod id"
ctxt.frame = ctxt_cpy.frame;
if (ctxt_cpy.enb_flag) {
ctxt.enb_flag = ENB_FLAG_YES;
ctxt.ue_module_id = 0;
ctxt.enb_module_id = 0;
rab_id = pdcp_read_header_g.rb_id % maxDRB;
} else {
ctxt.enb_flag = ENB_FLAG_NO;
ctxt.ue_module_id = 0;
ctxt.enb_module_id = 0;
rab_id = pdcp_read_header_g.rb_id % maxDRB;
}
if (pdcp_array_drb_eNB[ctxt.enb_module_id][ctxt.ue_module_id][rab_id-1].instanciated_instance) {
#ifdef PDCP_DEBUG
LOG_D(PDCP, "[FRAME %5u][eNB][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %d) on Rab %d \n",
ctxt.frame,
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",
pdcp_read_header_g.inst,
pdcp_read_header_g.rb_id,
pdcp_read_header_g.data_size,
pdcp_data_req(&ctxt,
SRB_FLAG_NO,
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][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u/%u][RB %u] NON INSTANCIATED INSTANCE, DROPPED\n",
ctxt.frame,
pdcp_read_header_g.inst,
pdcp_read_header_g.rb_id,
pdcp_read_header_g.data_size,
ctxt.enb_module_id,
ctxt.ue_module_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 (ctxt.ue_module_id = 0; ctxt.ue_module_id < NB_UE_INST; ctxt.ue_module_id++) {
if (pdcp_array_drb_eNB[ctxt.enb_module_id][ctxt.ue_module_id][rab_id-1].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",
ctxt.frame,
pdcp_read_header_g.inst,
pdcp_read_header_g.rb_id,
pdcp_read_header_g.data_size,
ctxt.enb_module_id,
ctxt.ue_module_id,
DEFAULT_RAB_ID);
DEFAULT_RAB_ID,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pdcp_read_header_g.data_size,
(unsigned char *)NLMSG_DATA(nas_nlh_rx),
}
}
if (pdcp_array_drb_ue[ctxt.ue_module_id][rab_id-1].instanciated_instance) {
LOG_D(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %d) on Rab %d \n",
ctxt.frame,
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",
ctxt.frame,
pdcp_read_header_g.inst,
pdcp_read_header_g.rb_id,
pdcp_read_header_g.data_size,
ctxt.enb_module_id,
ctxt.ue_module_id,
rab_id);
&ctxt,
SRB_FLAG_NO,
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",
ctxt.frame,
pdcp_read_header_g.inst,
pdcp_read_header_g.rb_id,
pdcp_read_header_g.data_size,
ctxt.enb_module_id,
ctxt.ue_module_id,
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",
ctxt.frame,
pdcp_read_header_g.inst,
pdcp_read_header_g.rb_id,
pdcp_read_header_g.data_size,
ctxt.enb_module_id,
ctxt.ue_module_id,
DEFAULT_RAB_ID);
&ctxt,
SRB_FLAG_NO,
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);
}
}
}
}
}
return len;
# endif
#else // neither NAS_NETLINK nor NAS_FIFO
return 0;
#endif // NAS_NETLINK
}
void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) {
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;
signed long pkt_size=0;
static unsigned int pkt_cnt_enb=0, pkt_cnt_ue=0;
uint8_t pdcp_mode, is_ue=0;
Packet_otg_elt_t *otg_pkt_info=NULL;
int result;
src_id = ctxt_pP->enb_module_id;
// 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 = (ctxt_pP->enb_flag == 1) ? ctxt_pP->enb_module_id : ctxt_pP->ue_module_id+NB_eNB_INST;
//rb_id = (ctxt_pP->enb_flag == 1) ? ctxt_pP->enb_module_id * 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_D(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,ctxt_pP->frame, 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]));
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, ctxt_pP->enb_flag, dst_id ) > 2 /*RRC_CONNECTED*/) { // not needed: this test is already done in update_otg_enb
otg_pkt = (unsigned char*) (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,
pkt_size);
*/
//rb_id = (/*NB_eNB_INST +*/ dst_id -1 ) * MAX_NUM_RB + DTCH;
ctxt.enb_module_id = ctxt_pP->enb_module_id;
ctxt.ue_module_id = dst_id;
ctxt.frame = ctxt_pP->frame;
ctxt.enb_flag = ctxt_pP->enb_flag;
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",
ctxt_pP->enb_module_id, ctxt_pP->frame, pkt_cnt_enb++, module_id, rb_id, module_id, dst_id, pkt_size, pdcp_mode);
result = pdcp_data_req(&ctxt,
SRB_FLAG_NO,
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] Frame %d: sending packet %d from module %d on rab id %d (src %d, dst %d) pkt size %d\n",
ctxt_pP->ue_module_id, ctxt_pP->frame, pkt_cnt_ue++, src_id, rb_id, src_id, dst_id, pkt_size);
ctxt.enb_module_id = dst_id;
ctxt.frame = ctxt_pP->frame;
ctxt.enb_flag = ctxt_pP->enb_flag;
result = pdcp_data_req( &ctxt,
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,"ctxt_pP->frame %d enb %d-> ue %d link not yet established state %d \n", ctxt_pP->frame, eNB_index,dst_id - NB_eNB_INST, mac_get_rrc_status(module_id, ctxt_pP->enb_flag, dst_id - NB_eNB_INST));
}
}
#else
if ((otg_enabled==1) && (ctxt_pP->enb_flag == 1)) { // generate DL traffic
ctime = ctxt_pP->frame * 100;
/*if ((mac_get_rrc_status(eNB_index, ctxt_pP->enb_flag, 0 ) > 2) &&
(mac_get_rrc_status(eNB_index, ctxt_pP->enb_flag, 1 ) > 2)) { */
ctxt.enb_module_id = ctxt_pP->enb_module_id;
ctxt.frame = ctxt_pP->frame;
ctxt.enb_flag = ctxt_pP->enb_flag;
for (dst_id = 0; dst_id<NUMBER_OF_UE_MAX; dst_id++) {
if (mac_get_rrc_status(ctxt_pP->enb_module_id, ctxt_pP->enb_flag, dst_id ) > 2) {
unsigned int temp = 0;
otg_pkt = packet_gen( src_id, dst_id, 0, ctime, &temp );
pkt_size = temp;
ctxt.ue_module_id = dst_id;
pdcp_data_req(&ctxt,
SRB_FLAG_NO,
rb_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
pkt_size,
otg_pkt,
PDCP_TRANSMISSION_MODE_DATA);
LOG_D(OTG,"send packet from module %d on rab id %d (src %d, dst %d) pkt size %d\n", ctxt_pP->enb_module_id, rb_id, src_id, dst_id, pkt_size);
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, ctxt_pP->enb_flag, dst_id ));
}
#endif
}