/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ /*! \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 Navid Nikaein and Lionel GAUTHIER * \date 2009 - 2016 * \version 0.5 * \email navid.nikaein@eurecom.fr * \warning This component can be runned only in user-space * @ingroup pdcp */ #define PDCP_FIFO_C extern int otg_enabled; #include "pdcp.h" #include "pdcp_primitives.h" #include <pthread.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define rtf_put write #define rtf_get read #include "../MAC/mac_extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "NETWORK_DRIVER/LITE/constant.h" //#include "SIMULATION/ETH_TRANSPORT/extern.h" #include "UTIL/OCG/OCG.h" #include "UTIL/OCG/OCG_extern.h" #include "common/utils/LOG/log.h" #include "UTIL/OTG/otg_tx.h" #include "UTIL/FIFO/pad_list.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "platform_constants.h" #include "msc.h" #include "pdcp.h" #include "assertions.h" #include <sys/socket.h> #include <linux/netlink.h> #include "NETWORK_DRIVER/UE_IP/constant.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[MAX_MOBILES_PER_ENB]; extern struct msghdr nas_msg_tx; extern struct msghdr nas_msg_rx; extern uint8_t nfapi_mode; #ifdef UESIM_EXPANSION extern uint16_t inst_pdcp_list[NUMBER_OF_UE_MAX]; #endif extern Packet_OTG_List_t *otg_pdcp_buffer; # include "gtpv1u_eNB_task.h" # include "gtpv1u_eNB_defs.h" extern int gtpv1u_new_data_req( uint8_t enb_module_idP, rnti_t ue_rntiP, uint8_t rab_idP, uint8_t *buffer_pP, uint32_t buf_lenP, uint32_t buf_offsetP); void debug_pdcp_pc5s_sdu(sidelink_pc5s_element *sl_pc5s_msg, char *title) { LOG_I(PDCP,"%s: \nPC5S message, header traffic_type: %d)\n", title, sl_pc5s_msg->pc5s_header.traffic_type); LOG_I(PDCP,"PC5S message, header rb_id: %d)\n", sl_pc5s_msg->pc5s_header.rb_id); LOG_I(PDCP,"PC5S message, header data_size: %d)\n", sl_pc5s_msg->pc5s_header.data_size); LOG_I(PDCP,"PC5S message, header inst: %d)\n", sl_pc5s_msg->pc5s_header.inst); LOG_I(PDCP,"PC5-S message, sourceL2Id: 0x%08x\n)\n", sl_pc5s_msg->pc5s_header.sourceL2Id); LOG_I(PDCP,"PC5-S message, destinationL1Id: 0x%08x\n)\n", sl_pc5s_msg->pc5s_header.destinationL2Id); } //----------------------------------------------------------------------------- int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP) { mem_block_t *sdu_p; int pdcp_nb_sdu_sent = 0; int ret=0; while ((sdu_p = list_get_head (&pdcp_sdu_list)) != NULL && ((pdcp_data_ind_header_t *)(sdu_p->data))->inst == ctxt_pP->module_id) { ((pdcp_data_ind_header_t *)(sdu_p->data))->inst = 0; int rb_id = ((pdcp_data_ind_header_t *)(sdu_p->data))->rb_id; int sizeToWrite= sizeof (pdcp_data_ind_header_t) + ((pdcp_data_ind_header_t *) sdu_p->data)->data_size; if (rb_id == 10) { //hardcoded for PC5-Signaling if( LOG_DEBUGFLAG(DEBUG_PDCP) ) { debug_pdcp_pc5s_sdu((sidelink_pc5s_element *)&(sdu_p->data[sizeof(pdcp_data_ind_header_t)]), "pdcp_fifo_flush_sdus received aPC5S message"); } ret = sendto(pdcp_pc5_sockfd, &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]), sizeof(sidelink_pc5s_element), 0, (struct sockaddr *)&prose_pdcp_addr,sizeof(prose_pdcp_addr) ); } else if (UE_NAS_USE_TUN) { ret = write(nas_sock_fd[ctxt_pP->module_id], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); } else if (ENB_NAS_USE_TUN) { ret = write(nas_sock_fd[0], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); } else if (PDCP_USE_NETLINK) { memcpy(NLMSG_DATA(nas_nlh_tx), (uint8_t *) sdu_p->data, sizeToWrite); nas_nlh_tx->nlmsg_len = sizeToWrite; ret = sendmsg(nas_sock_fd[0],&nas_msg_tx,0); } // PDCP_USE_NETLINK AssertFatal(ret >= 0,"[PDCP_FIFOS] pdcp_fifo_flush_sdus (errno: %d %s)\n", errno, strerror(errno)); list_remove_head (&pdcp_sdu_list); free_mem_block (sdu_p, __func__); pdcp_nb_sdu_sent ++; } return pdcp_nb_sdu_sent; } //----------------------------------------------------------------------------- int pdcp_fifo_read_input_sdus (const protocol_ctxt_t *const ctxt_pP) { pdcp_data_req_header_t pdcp_read_header_g; if (UE_NAS_USE_TUN || ENB_NAS_USE_TUN) { protocol_ctxt_t ctxt = *ctxt_pP; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; pdcp_t *pdcp_p = NULL; int len; rb_id_t rab_id = DEFAULT_RAB_ID; do { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ, 1 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ_BUFFER, 1 ); len = read(UE_NAS_USE_TUN?nas_sock_fd[ctxt_pP->module_id]:nas_sock_fd[0], &nl_rx_buf, NL_MAX_PAYLOAD); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ_BUFFER, 0 ); if (len<=0) continue; if (UE_NAS_USE_TUN) { key = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); } else { ctxt.rnti=pdcp_eNB_UE_instance_to_rnti[0]; ctxt.enb_flag=ENB_FLAG_YES; ctxt.module_id=0; key = PDCP_COLL_KEY_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_YES); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); } LOG_D(PDCP, "PDCP_COLL_KEY_DEFAULT_DRB_VALUE(module_id=%d, rnti=%x, enb_flag=%d)\n", ctxt.module_id, ctxt.rnti, ctxt.enb_flag); if (h_rc == HASH_TABLE_OK) { LOG_D(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d on Rab %d \n", ctxt.frame, ctxt.instance, len, rab_id); LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u][UE %04x][RB %u]\n", ctxt.frame, ctxt.instance, rab_id, len, ctxt.module_id, ctxt.rnti, rab_id); MSC_LOG_RX_MESSAGE((ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), ctxt.instance, rab_id, rab_id, len); pdcp_data_req(&ctxt, SRB_FLAG_NO, rab_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, len, (unsigned char *)nl_rx_buf, PDCP_TRANSMISSION_MODE_DATA , NULL, NULL ); } else { MSC_LOG_RX_DISCARDED_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), ctxt.instance, rab_id, rab_id, len); LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u][UE %04x][RB %u] NON INSTANCIATED INSTANCE key 0x%"PRIx64", DROPPED\n", ctxt.frame, ctxt.instance, rab_id, len, ctxt.module_id, ctxt.rnti, rab_id, key); } } while (len > 0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ, 0 ); return len; } else { /* UE_NAS_USE_TUN */ if (PDCP_USE_NETLINK) { protocol_ctxt_t ctxt_cpy = *ctxt_pP; protocol_ctxt_t ctxt; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; struct pdcp_netlink_element_s *data_p = NULL; /* avoid gcc warnings */ (void)data_p; module_id_t ue_id = 0; pdcp_t *pdcp_p = NULL; //TTN for D2D (PC5S) int prose_addr_len; char send_buf[BUFSIZE], receive_buf[BUFSIZE]; //int optval; int bytes_received; sidelink_pc5s_element *sl_pc5s_msg_recv = NULL; sidelink_pc5s_element *sl_pc5s_msg_send = NULL; //uint32_t sourceL2Id; //uint32_t groupL2Id; //module_id_t module_id = 0; pc5s_header_t *pc5s_header; static unsigned char pdcp_read_state_g =0; int len = 1; int msg_len; rb_id_t rab_id = 0; int rlc_data_req_flag = 3; //TTN for D2D (PC5S) prose_addr_len = sizeof(prose_pdcp_addr); // receive a message from ProSe App memset(receive_buf, 0, BUFSIZE); bytes_received = recvfrom(pdcp_pc5_sockfd, receive_buf, BUFSIZE, 0, (struct sockaddr *) &prose_pdcp_addr, (socklen_t *)&prose_addr_len); // if (bytes_received < 0){ // LOG_E(RRC, "ERROR: Failed to receive from ProSe App\n"); // exit(EXIT_FAILURE); // } if (bytes_received > 0) { pc5s_header = calloc(1, sizeof(pc5s_header_t)); memcpy((void *)pc5s_header, (void *)receive_buf, sizeof(pc5s_header_t)); if (pc5s_header->traffic_type == TRAFFIC_PC5S_SESSION_INIT) { //send reply to ProSe app LOG_D(PDCP,"Received a request to open PDCP socket and establish a new PDCP session ... send response to ProSe App \n"); memset(send_buf, 0, BUFSIZE); sl_pc5s_msg_send = calloc(1, sizeof(sidelink_pc5s_element)); sl_pc5s_msg_send->pc5s_header.traffic_type = TRAFFIC_PC5S_SESSION_INIT; sl_pc5s_msg_send->pc5sPrimitive.status = 1; memcpy((void *)send_buf, (void *)sl_pc5s_msg_send, sizeof(sidelink_pc5s_element)); int prose_addr_len = sizeof(prose_pdcp_addr); int bytes_sent = sendto(pdcp_pc5_sockfd, (char *)send_buf, sizeof(sidelink_pc5s_element), 0, (struct sockaddr *)&prose_pdcp_addr, prose_addr_len); if (bytes_sent < 0) { LOG_E(PDCP, "ERROR: Failed to send to ProSe App\n"); exit(EXIT_FAILURE); } } else if (pc5s_header->traffic_type == TRAFFIC_PC5S_SIGNALLING) { //if containing PC5-S message -> send to other UE LOG_D(PDCP,"Received PC5-S message ... send to the other UE\n"); LOG_D(PDCP,"Received PC5-S message, traffic_type: %d)\n", pc5s_header->traffic_type); LOG_D(PDCP,"Received PC5-S message, rbid: %d)\n", pc5s_header->rb_id); LOG_D(PDCP,"Received PC5-S message, data_size: %d)\n", pc5s_header->data_size); LOG_D(PDCP,"Received PC5-S message, inst: %d)\n", pc5s_header->inst); LOG_D(PDCP,"Received PC5-S message,sourceL2Id: 0x%08x\n)\n", pc5s_header->sourceL2Id); LOG_D(PDCP,"Received PC5-S message,destinationL1Id: 0x%08x\n)\n", pc5s_header->destinationL2Id); #ifdef OAI_EMU // overwrite function input parameters, because only one netlink socket for all instances if (pc5s_header->inst < oai_emulation.info.nb_enb_local) { ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ENB_FLAG_YES; ctxt.module_id = pc5s_header.inst + oai_emulation.info.first_enb_local; ctxt.rnti = oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt.module_id ][pc5s_header->rb_id / LTE_maxDRB + oai_emulation.info.first_ue_local]; rab_id = pc5s_header->rb_id % LTE_maxDRB; } else { ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ENB_FLAG_NO; ctxt.module_id = pc5s_header->inst - oai_emulation.info.nb_enb_local + oai_emulation.info.first_ue_local; ctxt.rnti = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id]; rab_id = pc5s_header->rb_id % LTE_maxDRB; } CHECK_CTXT_ARGS(&ctxt); AssertFatal (rab_id < LTE_maxDRB, "RB id is too high (%u/%d)!\n", rab_id, LTE_maxDRB); /*LGpdcp_read_header.inst = (pc5s_header.inst >= oai_emulation.info.nb_enb_local) ? \ pc5s_header.inst - oai_emulation.info.nb_enb_local+ NB_eNB_INST + oai_emulation.info.first_ue_local : pc5s_header.inst + oai_emulation.info.first_enb_local;*/ #else // OAI_EMU /* TODO: do we have to reset to 0 or not? not for a scenario with 1 UE at least */ // pc5s_header.inst = 0; //#warning "TO DO CORRCT VALUES FOR ue mod id, enb mod id" ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ctxt_cpy.enb_flag; LOG_I(PDCP, "[PDCP] pc5s_header->rb_id = %d\n", pc5s_header->rb_id); if (ctxt_cpy.enb_flag) { ctxt.module_id = 0; rab_id = pc5s_header->rb_id % LTE_maxDRB; ctxt.rnti = pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index]; } else { ctxt.module_id = 0; rab_id = pc5s_header->rb_id % LTE_maxDRB; ctxt.rnti = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id]; } #endif //UE if (!ctxt.enb_flag) { if (rab_id != 0) { if (rab_id == UE_IP_DEFAULT_RAB_ID) { LOG_D(PDCP, "PDCP_COLL_KEY_DEFAULT_DRB_VALUE(module_id=%d, rnti=%x, enb_flag=%d)\n", ctxt.module_id, ctxt.rnti, ctxt.enb_flag); key = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); LOG_D(PDCP,"request key %x : (%d,%x,%d,%d)\n", (uint8_t)key,ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id); } else { rab_id = rab_id % LTE_maxDRB; LOG_I(PDCP, "PDCP_COLL_KEY_VALUE(module_id=%d, rnti=%x, enb_flag=%d, rab_id=%d, SRB_FLAG=%d)\n", ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); key = PDCP_COLL_KEY_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); LOG_I(PDCP,"request key %x : (%d,%x,%d,%d)\n", (uint8_t)key,ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id); } if (h_rc == HASH_TABLE_OK) { rab_id = pdcp_p->rb_id; LOG_I(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d on Rab %d \n", ctxt.frame, pc5s_header->inst, bytes_received, pc5s_header->rb_id); LOG_I(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u][UE %u][RB %u]\n", ctxt.frame, pc5s_header->inst, pc5s_header->rb_id, pc5s_header->data_size, ctxt.module_id, ctxt.rnti, rab_id); MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pc5s_header->inst, pc5s_header->rb_id, rab_id, pc5s_header->data_size); pdcp_data_req( &ctxt, SRB_FLAG_NO, rab_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, pc5s_header->data_size, (unsigned char *)receive_buf, PDCP_TRANSMISSION_MODE_DATA, &pc5s_header->sourceL2Id, &pc5s_header->destinationL2Id ); } else { MSC_LOG_RX_DISCARDED_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pc5s_header->inst, pc5s_header->rb_id, rab_id, pc5s_header->data_size); LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u][UE %u][RB %u] NON INSTANCIATED INSTANCE key 0x%"PRIx64", DROPPED\n", ctxt.frame, pc5s_header->inst, pc5s_header->rb_id, pc5s_header->data_size, ctxt.module_id, ctxt.rnti, rab_id, key); } } else { //if (rab_id == 0) 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][UE %u][RB DEFAULT_RAB_ID %u]\n", ctxt.frame, pc5s_header->inst, pc5s_header->rb_id, pc5s_header->data_size, ctxt.module_id, ctxt.rnti, DEFAULT_RAB_ID); MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL,0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u default rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pc5s_header->inst, pc5s_header->rb_id, DEFAULT_RAB_ID, pc5s_header->data_size); pdcp_data_req ( &ctxt, SRB_FLAG_NO, DEFAULT_RAB_ID, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, pc5s_header->data_size, (unsigned char *)receive_buf, PDCP_TRANSMISSION_MODE_DATA, &pc5s_header->sourceL2Id, &pc5s_header->destinationL2Id ); } } free (sl_pc5s_msg_recv); free (sl_pc5s_msg_send); } } while ((len > 0) && (rlc_data_req_flag !=0)) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ, 1 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ_BUFFER, 1 ); len = recvmsg(nas_sock_fd[0], &nas_msg_rx, 0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ_BUFFER, 0 ); if (len<=0) { // nothing in pdcp NAS socket //LOG_D(PDCP, "[PDCP][NETLINK] Nothing in socket, length %d \n", len); } else { msg_len = len; for (nas_nlh_rx = (struct nlmsghdr *) nl_rx_buf; NLMSG_OK (nas_nlh_rx, msg_len); nas_nlh_rx = NLMSG_NEXT (nas_nlh_rx, msg_len)) { if (nas_nlh_rx->nlmsg_type == NLMSG_DONE) { LOG_D(PDCP, "[PDCP][NETLINK] RX NLMSG_DONE\n"); //return; } if (nas_nlh_rx->nlmsg_type == NLMSG_ERROR) { LOG_D(PDCP, "[PDCP][NETLINK] 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_D(PDCP, "[PDCP][NETLINK] RX pdcp_data_req_header_t inst %u, rb_id %u data_size %d, source L2Id 0x%08x, destination L2Id 0x%08x\n", pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size,pdcp_read_header_g.sourceL2Id, pdcp_read_header_g.destinationL2Id ); } else { LOG_E(PDCP, "[PDCP][NETLINK] 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_D(PDCP, "[PDCP][NETLINK] Something in socket, length %zu\n", nas_nlh_rx->nlmsg_len - sizeof(struct nlmsghdr)); #ifdef OAI_EMU // 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.module_id = pdcp_read_header_g.inst + oai_emulation.info.first_enb_local; ctxt.rnti = oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt.module_id ][pdcp_read_header_g.rb_id / LTE_maxDRB + oai_emulation.info.first_ue_local]; rab_id = pdcp_read_header_g.rb_id % LTE_maxDRB; } else { ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ENB_FLAG_NO; ctxt.module_id = pdcp_read_header_g.inst - oai_emulation.info.nb_enb_local + oai_emulation.info.first_ue_local; ctxt.rnti = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id]; rab_id = pdcp_read_header_g.rb_id % LTE_maxDRB; } CHECK_CTXT_ARGS(&ctxt); AssertFatal (rab_id < LTE_maxDRB, "RB id is too high (%u/%d)!\n", rab_id, LTE_maxDRB); #else // OAI_EMU /* TODO: do we have to reset to 0 or not? not for a scenario with 1 UE at least */ // pdcp_read_header_g.inst = 0; //#warning "TO DO CORRCT VALUES FOR ue mod id, enb mod id" ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ctxt_cpy.enb_flag; LOG_D(PDCP, "[PDCP][NETLINK] pdcp_read_header_g.rb_id = %d, source L2Id = 0x%08x, destination L2Id = 0x%08x \n", pdcp_read_header_g.rb_id, pdcp_read_header_g.sourceL2Id, pdcp_read_header_g.destinationL2Id); if (ctxt_cpy.enb_flag) { ctxt.module_id = 0; rab_id = pdcp_read_header_g.rb_id % LTE_maxDRB; ctxt.rnti = pdcp_eNB_UE_instance_to_rnti[pdcp_read_header_g.rb_id / LTE_maxDRB]; } else { if (nfapi_mode == 3) { #ifdef UESIM_EXPANSION ctxt.module_id = inst_pdcp_list[pdcp_read_header_g.inst]; #else ctxt.module_id = pdcp_read_header_g.inst; #endif } else { ctxt.module_id = 0; } rab_id = pdcp_read_header_g.rb_id % LTE_maxDRB; ctxt.rnti = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id]; } #endif if (ctxt.enb_flag) { if (rab_id != 0) { rab_id = rab_id % LTE_maxDRB; key = PDCP_COLL_KEY_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc == HASH_TABLE_OK) { LOG_D(PDCP, "[FRAME %5u][eNB][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %zu) 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); MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, rab_id, pdcp_read_header_g.data_size); LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u]UE %u][RB %u]\n", ctxt_cpy.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, rab_id); 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 ,NULL, NULL ); } else { LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u][UE %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.module_id, ctxt.rnti, 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_id = 0; ue_id < NB_UE_INST; ue_id++) { if (oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt_cpy.module_id][ue_id] != NOT_A_RNTI) { ctxt.rnti = oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt_cpy.module_id][ue_id]; LOG_D(PDCP, "[FRAME %5u][eNB][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes --->][PDCP][MOD %u][UE %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.module_id, ctxt.rnti, DEFAULT_RAB_ID); pdcp_data_req ( &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 ,NULL, NULL ); } } } } else { // enb_flag if (rab_id != 0) { if (rab_id == UE_IP_DEFAULT_RAB_ID) { LOG_D(PDCP, "PDCP_COLL_KEY_DEFAULT_DRB_VALUE(module_id=%d, rnti=%x, enb_flag=%d)\n", ctxt.module_id, ctxt.rnti, ctxt.enb_flag); key = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); LOG_D(PDCP,"request key %x : (%d,%x,%d,%d)\n", (uint8_t)key,ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id); } else { rab_id = rab_id % LTE_maxDRB; LOG_D(PDCP, "PDCP_COLL_KEY_VALUE(module_id=%d, rnti=%x, enb_flag=%d, rab_id=%d, SRB_FLAG=%d)\n", ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); key = PDCP_COLL_KEY_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); LOG_D(PDCP,"request key %x : (%d,%x,%d,%d)\n", (uint8_t)key,ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id); } if (h_rc == HASH_TABLE_OK) { rab_id = pdcp_p->rb_id; LOG_D(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %zu) 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][UE %u][RB %u]\n", ctxt.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, rab_id); MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, rab_id, pdcp_read_header_g.data_size); if(nfapi_mode == 3) { 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, NULL, NULL ); } else { 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, &pdcp_read_header_g.sourceL2Id, &pdcp_read_header_g.destinationL2Id ); } } else { MSC_LOG_RX_DISCARDED_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL, 0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, rab_id, pdcp_read_header_g.data_size); LOG_D(PDCP, "[FRAME %5u][UE][IP][INSTANCE %u][RB %u][--- PDCP_DATA_REQ / %d Bytes ---X][PDCP][MOD %u][UE %u][RB %u] NON INSTANCIATED INSTANCE key 0x%"PRIx64", DROPPED\n", ctxt.frame, pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, pdcp_read_header_g.data_size, ctxt.module_id, ctxt.rnti, rab_id, key); } } 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][UE %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.module_id, ctxt.rnti, DEFAULT_RAB_ID); MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, NULL,0, MSC_AS_TIME_FMT" DATA-REQ inst %u rb %u default rab %u size %u", MSC_AS_TIME_ARGS(ctxt_pP), pdcp_read_header_g.inst, pdcp_read_header_g.rb_id, DEFAULT_RAB_ID, pdcp_read_header_g.data_size); if(nfapi_mode == 3) { pdcp_data_req ( &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, NULL, NULL ); } else { pdcp_data_req ( &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, &pdcp_read_header_g.sourceL2Id, &pdcp_read_header_g.destinationL2Id ); } } } } } } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_FIFO_READ, 0 ); } return len; } else { /* PDCP_USE_NETLINK */ return 0; } // else PDCP_USE_NETLINK } /* #else UE_NAS_USE_TUN */ } void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t *const ctxt_pP) { module_id_t dst_id; // dst for otg protocol_ctxt_t ctxt; // we need to add conditions to avoid transmitting data when the UE is not RRC connected. if ((otg_enabled==1) && (ctxt_pP->enb_flag == ENB_FLAG_YES)) { // generate DL traffic PROTOCOL_CTXT_SET_BY_MODULE_ID( &ctxt, ctxt_pP->module_id, ctxt_pP->enb_flag, NOT_A_RNTI, ctxt_pP->frame, ctxt_pP->subframe, ctxt_pP->module_id); for (dst_id = 0; dst_id<MAX_MOBILES_PER_ENB; dst_id++) { ctxt.rnti = oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt.module_id][dst_id]; } } } //TTN for D2D (PC5S) void pdcp_pc5_socket_init() { //pthread_attr_t attr; //struct sched_param sched_param; int optval; // flag value for setsockopt //int n; // message byte size //create PDCP socket pdcp_pc5_sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (pdcp_pc5_sockfd < 0) { LOG_E(PDCP,"[pdcp_pc5_socket_init] Error opening socket %d (%d:%s)\n",pdcp_pc5_sockfd,errno, strerror(errno)); exit(EXIT_FAILURE); } optval = 1; setsockopt(pdcp_pc5_sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int)); fcntl(pdcp_pc5_sockfd,F_SETFL,O_NONBLOCK); bzero((char *) &pdcp_sin, sizeof(pdcp_sin)); pdcp_sin.sin_family = AF_INET; pdcp_sin.sin_addr.s_addr = htonl(INADDR_ANY); pdcp_sin.sin_port = htons(PDCP_SOCKET_PORT_NO); // associate the parent socket with a port if (bind(pdcp_pc5_sockfd, (struct sockaddr *) &pdcp_sin, sizeof(pdcp_sin)) < 0) { LOG_E(PDCP,"[pdcp_pc5_socket_init] ERROR: Failed on binding the socket\n"); exit(1); } }