/* * 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.c * \brief pdcp interface with RLC * \author Navid Nikaein and Lionel GAUTHIER * \date 2009-2012 * \email navid.nikaein@eurecom.fr * \version 1.0 */ #define PDCP_C #define MBMS_MULTICAST_OUT #include "assertions.h" #include "hashtable.h" #include "pdcp.h" #include "pdcp_util.h" #include "pdcp_sequence_manager.h" #include "LAYER2/RLC/rlc.h" #include "LAYER2/MAC/mac_extern.h" #include "RRC/LTE/rrc_proto.h" #include "pdcp_primitives.h" #include "OCG.h" #include "OCG_extern.h" #include "otg_rx.h" #include "common/utils/LOG/log.h" #include <inttypes.h> #include "platform_constants.h" #include "nfapi/oai_integration/vendor_ext.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "msc.h" #include "common/ngran_types.h" #include "targets/COMMON/openairinterface5g_limits.h" #include "targets/RT/USER/lte-softmodem.h" #include "SIMULATION/ETH_TRANSPORT/proto.h" #include "UTIL/OSA/osa_defs.h" #include "openair2/RRC/NAS/nas_config.h" #include "intertask_interface.h" #include "openair3/S1AP/s1ap_eNB.h" #include <pthread.h> # include "gtpv1u_eNB_task.h" # include "gtpv1u.h" #include <openair3/ocp-gtpu/gtp_itf.h> #include "ENB_APP/enb_config.h" extern int otg_enabled; extern uint8_t nfapi_mode; #include "common/ran_context.h" extern RAN_CONTEXT_t RC; hash_table_t *pdcp_coll_p = NULL; #ifdef MBMS_MULTICAST_OUT #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h> #include <unistd.h> static int mbms_socket = -1; #endif uint32_t Pdcp_stats_tx_window_ms[MAX_eNB][MAX_MOBILES_PER_ENB]; uint32_t Pdcp_stats_tx_bytes[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_bytes_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_bytes_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_sn[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_throughput_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_aiat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_aiat_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_aiat_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_tx_iat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_window_ms[MAX_eNB][MAX_MOBILES_PER_ENB]; uint32_t Pdcp_stats_rx[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_bytes[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_bytes_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_bytes_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_sn[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_goodput_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_aiat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_aiat_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_aiat_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_iat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; uint32_t Pdcp_stats_rx_outoforder[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; int pdcp_pc5_sockfd; struct sockaddr_in prose_ctrl_addr; struct sockaddr_in prose_pdcp_addr; struct sockaddr_in pdcp_sin; /* pdcp module parameters and related functions*/ static pdcp_params_t pdcp_params= {0,NULL}; rnti_t pdcp_UE_UE_module_id_to_rnti[MAX_MOBILES_PER_ENB]; rnti_t pdcp_eNB_UE_instance_to_rnti[MAX_MOBILES_PER_ENB]; // for noS1 mode unsigned int pdcp_eNB_UE_instance_to_rnti_index; signed int pdcp_2_nas_irq; pdcp_stats_t UE_pdcp_stats[MAX_MOBILES_PER_ENB]; pdcp_stats_t eNB_pdcp_stats[NUMBER_OF_eNB_MAX]; static pdcp_mbms_t pdcp_mbms_array_ue[MAX_MOBILES_PER_ENB][LTE_maxServiceCount][LTE_maxSessionPerPMCH]; // some constants from openair2/RRC/LTE/MESSAGES/asn1_constants.h static pdcp_mbms_t pdcp_mbms_array_eNB[NUMBER_OF_eNB_MAX][LTE_maxServiceCount][LTE_maxSessionPerPMCH]; // some constants from openair2/RRC/LTE/MESSAGES/asn1_constants.h static sdu_size_t pdcp_input_sdu_remaining_size_to_read; static sdu_size_t pdcp_output_header_bytes_to_write; static sdu_size_t pdcp_output_sdu_bytes_to_write; notifiedFIFO_t pdcp_sdu_list; pdcp_enb_t pdcp_enb[MAX_NUM_CCs]; extern volatile int oai_exit; pthread_t pdcp_stats_thread_desc; void *pdcp_stats_thread(void *param) { FILE *fd; int old_byte_cnt[MAX_MOBILES_PER_ENB][NB_RB_MAX],old_byte_cnt_rx[MAX_MOBILES_PER_ENB][NB_RB_MAX]; for (int i=0;i<MAX_MOBILES_PER_ENB;i++) for (int j=0;j<NB_RB_MAX;j++) { old_byte_cnt[i][j]=0; old_byte_cnt_rx[i][j]=0; } while (!oai_exit) { sleep(1); fd=fopen("PDCP_stats.log","w+"); AssertFatal(fd!=NULL,"Cannot open MAC_stats.log\n"); int drb_id=3; for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { if (pdcp_enb[0].rnti[UE_id]>0) { fprintf(fd,"PDCP: CRNTI %x, DRB %d: tx_bytes %d, DL Throughput %e\n", pdcp_enb[0].rnti[UE_id],drb_id, Pdcp_stats_tx_bytes[0][UE_id][drb_id], (double)((Pdcp_stats_tx_bytes[0][UE_id][drb_id]-old_byte_cnt[UE_id][drb_id])<<3)); fprintf(fd," rx_bytes %d, UL Throughput %e\n", Pdcp_stats_rx_bytes[0][UE_id][drb_id], (double)((Pdcp_stats_rx_bytes[0][UE_id][drb_id]-old_byte_cnt_rx[UE_id][drb_id])<<3)); old_byte_cnt[UE_id][drb_id]=Pdcp_stats_tx_bytes[0][UE_id][drb_id]; old_byte_cnt_rx[UE_id][drb_id]=Pdcp_stats_rx_bytes[0][UE_id][drb_id]; } } fclose(fd); } return(NULL); } uint64_t get_pdcp_optmask(void) { return pdcp_params.optmask; } //----------------------------------------------------------------------------- /* * If PDCP_UNIT_TEST is set here then data flow between PDCP and RLC is broken * and PDCP has no longer anything to do with RLC. In this case, after it's handed * an SDU it appends PDCP header and returns (by filling in incoming pointer parameters) * this mem_block_t to be dissected for testing purposes. For further details see test * code at targets/TEST/PDCP/test_pdcp.c:test_pdcp_data_req() */ boolean_t pdcp_data_req( protocol_ctxt_t *ctxt_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, const mui_t muiP, const confirm_t confirmP, const sdu_size_t sdu_buffer_sizeP, unsigned char *const sdu_buffer_pP, const pdcp_transmission_mode_t modeP, const uint32_t *const sourceL2Id, const uint32_t *const destinationL2Id ) //----------------------------------------------------------------------------- { pdcp_t *pdcp_p = NULL; uint8_t i = 0; uint8_t pdcp_header_len = 0; uint8_t pdcp_tailer_len = 0; uint16_t pdcp_pdu_size = 0; uint16_t current_sn = 0; mem_block_t *pdcp_pdu_p = NULL; rlc_op_status_t rlc_status; boolean_t ret = TRUE; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 : 0; uint16_t pdcp_uid=0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_IN); CHECK_CTXT_ARGS(ctxt_pP); #if T_TRACER if (ctxt_pP->enb_flag != ENB_FLAG_NO) T(T_ENB_PDCP_DL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_buffer_sizeP)); #endif if (sdu_buffer_sizeP == 0) { LOG_W(PDCP, "Handed SDU is of size 0! Ignoring...\n"); return FALSE; } /* * XXX MAX_IP_PACKET_SIZE is 4096, shouldn't this be MAX SDU size, which is 8188 bytes? */ AssertFatal(sdu_buffer_sizeP<= MAX_IP_PACKET_SIZE,"Requested SDU size (%d) is bigger than that can be handled by PDCP (%u)!\n", sdu_buffer_sizeP, MAX_IP_PACKET_SIZE); if (modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT) { AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, NB_RB_MBMS_MAX, ctxt_pP->module_id, ctxt_pP->rnti); } else { if (srb_flagP) { AssertError (rb_idP < 3, return FALSE, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, 3, ctxt_pP->module_id, ctxt_pP->rnti); } else { AssertError (rb_idP < LTE_maxDRB, return FALSE, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); } } key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc != HASH_TABLE_OK) { if (modeP != PDCP_TRANSMISSION_MODE_TRANSPARENT) { LOG_W(PDCP, PROTOCOL_CTXT_FMT" Instance is not configured for rb_id %ld Ignoring SDU...\n", PROTOCOL_CTXT_ARGS(ctxt_pP), rb_idP); ctxt_pP->configured=FALSE; return FALSE; } } else { // instance for a given RB is configured ctxt_pP->configured=TRUE; } if (ctxt_pP->enb_flag == ENB_FLAG_YES) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); } // PDCP transparent mode for MBMS traffic if (modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT) { LOG_D(PDCP, " [TM] Asking for a new mem_block of size %d\n",sdu_buffer_sizeP); pdcp_pdu_p = get_free_mem_block(sdu_buffer_sizeP, __func__); if (pdcp_pdu_p != NULL) { memcpy(&pdcp_pdu_p->data[0], sdu_buffer_pP, sdu_buffer_sizeP); if( LOG_DEBUGFLAG(DEBUG_PDCP) ) { rlc_util_print_hex_octets(PDCP, (unsigned char *)&pdcp_pdu_p->data[0], sdu_buffer_sizeP); LOG_UI(PDCP, "Before rlc_data_req 1, srb_flagP: %d, rb_idP: %ld \n", srb_flagP, rb_idP); } rlc_status = pdcp_params.send_rlc_data_req_func(ctxt_pP, srb_flagP, NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)?MBMS_FLAG_NO:MBMS_FLAG_YES, rb_idP, muiP, confirmP, sdu_buffer_sizeP, pdcp_pdu_p,NULL,NULL); } else { rlc_status = RLC_OP_STATUS_OUT_OF_RESSOURCES; LOG_E(PDCP,PROTOCOL_CTXT_FMT" PDCP_DATA_REQ SDU DROPPED, OUT OF MEMORY \n", PROTOCOL_CTXT_ARGS(ctxt_pP)); } } else { // calculate the pdcp header and trailer size if (srb_flagP) { pdcp_header_len = PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE; pdcp_tailer_len = PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE; } else { pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; pdcp_tailer_len = 0; } pdcp_pdu_size = sdu_buffer_sizeP + pdcp_header_len + pdcp_tailer_len; LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT"Data request notification pdu size %d (header%d, trailer%d)\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), pdcp_pdu_size, pdcp_header_len, pdcp_tailer_len); /* * Allocate a new block for the new PDU (i.e. PDU header and SDU payload) */ pdcp_pdu_p = get_free_mem_block(pdcp_pdu_size, __func__); if (pdcp_pdu_p != NULL) { /* * Create a Data PDU with header and append data * * Place User Plane PDCP Data PDU header first */ if (srb_flagP) { // this Control plane PDCP Data PDU pdcp_control_plane_data_pdu_header pdu_header; pdu_header.sn = pdcp_get_next_tx_seq_number(pdcp_p); current_sn = pdu_header.sn; memset(&pdu_header.mac_i[0],0,PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE); memset(&pdcp_pdu_p->data[sdu_buffer_sizeP + pdcp_header_len],0,PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE); if (pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == FALSE) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); return FALSE; } } else { pdcp_user_plane_data_pdu_header_with_long_sn pdu_header; pdu_header.dc = (modeP == PDCP_TRANSMISSION_MODE_DATA) ? PDCP_DATA_PDU_BIT_SET : PDCP_CONTROL_PDU_BIT_SET; pdu_header.sn = pdcp_get_next_tx_seq_number(pdcp_p); current_sn = pdu_header.sn ; if (pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == FALSE) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); return FALSE; } } /* * Validate incoming sequence number, there might be a problem with PDCP initialization */ if (current_sn > pdcp_calculate_max_seq_num_for_given_size(pdcp_p->seq_num_size)) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Generated sequence number (%"PRIu16") is greater than a sequence number could ever be!\n"\ "There must be a problem with PDCP initialization, ignoring this PDU...\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), current_sn); free_mem_block(pdcp_pdu_p, __func__); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); return FALSE; } LOG_D(PDCP, "Sequence number %d is assigned to current PDU\n", current_sn); /* Then append data... */ memcpy(&pdcp_pdu_p->data[pdcp_header_len], sdu_buffer_pP, sdu_buffer_sizeP); //For control plane data that are not integrity protected, // the MAC-I field is still present and should be padded with padding bits set to 0. // NOTE: user-plane data are never integrity protected for (i=0; i<pdcp_tailer_len; i++) { pdcp_pdu_p->data[pdcp_header_len + sdu_buffer_sizeP + i] = 0x00;// pdu_header.mac_i[i]; } if ((pdcp_p->security_activated != 0) && (((pdcp_p->cipheringAlgorithm) != 0) || ((pdcp_p->integrityProtAlgorithm) != 0))) { if (ctxt_pP->enb_flag == ENB_FLAG_YES) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security); } pdcp_apply_security(ctxt_pP, pdcp_p, srb_flagP, rb_idP % LTE_maxDRB, pdcp_header_len, current_sn, pdcp_pdu_p->data, sdu_buffer_sizeP); if (ctxt_pP->enb_flag == ENB_FLAG_NO) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security); } } /* Print octets of outgoing data in hexadecimal form */ LOG_D(PDCP, "Following content with size %d will be sent over RLC (PDCP PDU header is the first two bytes)\n", pdcp_pdu_size); //util_print_hex_octets(PDCP, (unsigned char*)pdcp_pdu_p->data, pdcp_pdu_size); //util_flush_hex_octets(PDCP, (unsigned char*)pdcp_pdu->data, pdcp_pdu_size); } else { LOG_E(PDCP, "Cannot create a mem_block for a PDU!\n"); if (ctxt_pP->enb_flag == ENB_FLAG_NO) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); } LOG_E(PDCP, "[FRAME %5u][%s][PDCP][MOD %u][RB %ld] PDCP_DATA_REQ SDU DROPPED, OUT OF MEMORY \n", ctxt_pP->frame, (ctxt_pP->enb_flag) ? "eNB" : "UE", ctxt_pP->module_id, rb_idP); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); return FALSE; } /* * Ask sublayer to transmit data and check return value * to see if RLC succeeded */ LOG_DUMPMSG(PDCP,DEBUG_PDCP,(char *)pdcp_pdu_p->data,pdcp_pdu_size, "[MSG] PDCP DL %s PDU on rb_id %ld\n",(srb_flagP)? "CONTROL" : "DATA", rb_idP); if ((pdcp_pdu_p!=NULL) && (srb_flagP == 0) && (ctxt_pP->enb_flag == 1)) { LOG_D(PDCP, "pdcp data req on drb %ld, size %d, rnti %x, node_type %d \n", rb_idP, pdcp_pdu_size, ctxt_pP->rnti, RC.rrc ? RC.rrc[ctxt_pP->module_id]->node_type: -1); if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_DU(RC.rrc[ctxt_pP->module_id]->node_type)) { LOG_E(PDCP, "Can't be DU, bad node type %d \n", RC.rrc[ctxt_pP->module_id]->node_type); ret=FALSE; } else { rlc_status = pdcp_params.send_rlc_data_req_func(ctxt_pP, srb_flagP, MBMS_FLAG_NO, rb_idP, muiP, confirmP, pdcp_pdu_size, pdcp_pdu_p,sourceL2Id, destinationL2Id); ret=FALSE; switch (rlc_status) { case RLC_OP_STATUS_OK: LOG_D(PDCP, "Data sending request over RLC succeeded!\n"); ret=TRUE; break; case RLC_OP_STATUS_BAD_PARAMETER: LOG_W(PDCP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); break; case RLC_OP_STATUS_INTERNAL_ERROR: LOG_W(PDCP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); break; case RLC_OP_STATUS_OUT_OF_RESSOURCES: LOG_W(PDCP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); break; default: LOG_W(PDCP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); break; } // switch case } /* end if node_type is not DU */ } else { // SRB if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { // DL transfer MessageDef *message_p; // Note: the acyual task must be TASK_PDCP_ENB, but this task is not created message_p = itti_alloc_new_message (TASK_PDCP_ENB, 0, F1AP_DL_RRC_MESSAGE); F1AP_DL_RRC_MESSAGE (message_p).rrc_container = &pdcp_pdu_p->data[0] ; F1AP_DL_RRC_MESSAGE (message_p).rrc_container_length = pdcp_pdu_size; F1AP_DL_RRC_MESSAGE (message_p).gNB_CU_ue_id = 0; F1AP_DL_RRC_MESSAGE (message_p).gNB_DU_ue_id = 0; F1AP_DL_RRC_MESSAGE (message_p).old_gNB_DU_ue_id = 0xFFFFFFFF; // unknown F1AP_DL_RRC_MESSAGE (message_p).rnti = ctxt_pP->rnti; F1AP_DL_RRC_MESSAGE (message_p).srb_id = rb_idP; F1AP_DL_RRC_MESSAGE (message_p).execute_duplication = 1; F1AP_DL_RRC_MESSAGE (message_p).RAT_frequency_priority_information.en_dc = 0; itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); //CU_send_DL_RRC_MESSAGE_TRANSFER(ctxt_pP->module_id, message_p); LOG_I(PDCP, "Send F1AP_DL_RRC_MESSAGE with ITTI\n"); ret=TRUE; } else { rlc_status = rlc_data_req(ctxt_pP , srb_flagP , MBMS_FLAG_NO , rb_idP , muiP , confirmP , pdcp_pdu_size , pdcp_pdu_p ,NULL ,NULL ); switch (rlc_status) { case RLC_OP_STATUS_OK: LOG_D(PDCP, "Data sending request over RLC succeeded!\n"); ret=TRUE; break; case RLC_OP_STATUS_BAD_PARAMETER: LOG_W(PDCP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); ret= FALSE; break; case RLC_OP_STATUS_INTERNAL_ERROR: LOG_W(PDCP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); ret= FALSE; break; case RLC_OP_STATUS_OUT_OF_RESSOURCES: LOG_W(PDCP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); ret= FALSE; break; default: LOG_W(PDCP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); ret= FALSE; break; } // switch case } } } if (ctxt_pP->enb_flag == ENB_FLAG_YES) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); } /* * Control arrives here only if rlc_data_req() returns RLC_OP_STATUS_OK * so we return TRUE afterwards */ for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { if (pdcp_enb[ctxt_pP->module_id].rnti[pdcp_uid] == ctxt_pP->rnti ) break; } LOG_D(PDCP,"ueid %d lcid %d tx seq num %d\n", pdcp_uid, (int)(rb_idP+rb_offset), current_sn); Pdcp_stats_tx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn; Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); return ret; } //----------------------------------------------------------------------------- boolean_t pdcp_data_ind( const protocol_ctxt_t *const ctxt_pP, const srb_flag_t srb_flagP, const MBMS_flag_t MBMS_flagP, const rb_id_t rb_idP, const sdu_size_t sdu_buffer_sizeP, mem_block_t *const sdu_buffer_pP ) //----------------------------------------------------------------------------- { pdcp_t *pdcp_p = NULL; uint8_t pdcp_header_len = 0; uint8_t pdcp_tailer_len = 0; pdcp_sn_t sequence_number = 0; volatile sdu_size_t payload_offset = 0; rb_id_t rb_id = rb_idP; boolean_t packet_forwarded = FALSE; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 :0; uint16_t pdcp_uid=0; MessageDef *message_p = NULL; uint8_t *gtpu_buffer_p = NULL; uint32_t rx_hfn_for_count; int pdcp_sn_for_count; int security_ok; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_IN); LOG_DUMPMSG(PDCP,DEBUG_PDCP,(char *)sdu_buffer_pP->data,sdu_buffer_sizeP, "[MSG] PDCP UL %s PDU on rb_id %ld\n", (srb_flagP)? "CONTROL" : "DATA", rb_idP); if (MBMS_flagP) { AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, "RB id is too high (%ld/%d) %u rnti %x!\n", rb_idP, NB_RB_MBMS_MAX, ctxt_pP->module_id, ctxt_pP->rnti); if (ctxt_pP->enb_flag == ENB_FLAG_NO) { LOG_D(PDCP, "e-MBMS Data indication notification for PDCP entity from eNB %u to UE %x " "and radio bearer ID %ld rlc sdu size %d ctxt_pP->enb_flag %d\n", ctxt_pP->module_id, ctxt_pP->rnti, rb_idP, sdu_buffer_sizeP, ctxt_pP->enb_flag); } else { LOG_D(PDCP, "Data indication notification for PDCP entity from UE %x to eNB %u " "and radio bearer ID %ld rlc sdu size %d ctxt_pP->enb_flag %d\n", ctxt_pP->rnti, ctxt_pP->module_id, rb_idP, sdu_buffer_sizeP, ctxt_pP->enb_flag); } } else { rb_id = rb_idP % LTE_maxDRB; AssertError (rb_id < LTE_maxDRB, return FALSE, "RB id is too high (%ld/%d) %u UE %x!\n", rb_id, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); AssertError (rb_id > 0, return FALSE, "RB id is too low (%ld/%d) %u UE %x!\n", rb_id, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_id, srb_flagP); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc != HASH_TABLE_OK) { LOG_W(PDCP, PROTOCOL_CTXT_FMT"Could not get PDCP instance key 0x%"PRIx64"\n", PROTOCOL_CTXT_ARGS(ctxt_pP), key); free_mem_block(sdu_buffer_pP, __func__); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); return FALSE; } } if (sdu_buffer_sizeP == 0) { LOG_W(PDCP, "SDU buffer size is zero! Ignoring this chunk!\n"); return FALSE; } if (ctxt_pP->enb_flag) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); } /* * Parse the PDU placed at the beginning of SDU to check * if incoming SN is in line with RX window */ if (MBMS_flagP == 0 ) { if (srb_flagP) { //SRB1/2 pdcp_header_len = PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE; pdcp_tailer_len = PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE; sequence_number = pdcp_get_sequence_number_of_pdu_with_SRB_sn((unsigned char *)sdu_buffer_pP->data); } else { // DRB pdcp_tailer_len = 0; if (pdcp_p->seq_num_size == 7) { pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_SHORT_SN_HEADER_SIZE; sequence_number = pdcp_get_sequence_number_of_pdu_with_short_sn((unsigned char *)sdu_buffer_pP->data); } else if (pdcp_p->seq_num_size == 12) { pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; sequence_number = pdcp_get_sequence_number_of_pdu_with_long_sn((unsigned char *)sdu_buffer_pP->data); } else { //sequence_number = 4095; LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT"wrong sequence number (%d) for this pdcp entity \n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), pdcp_p->seq_num_size); exit(1); } //uint8_t dc = pdcp_get_dc_filed((unsigned char*)sdu_buffer_pP->data); } /* * Check if incoming SDU is long enough to carry a PDU header */ if (sdu_buffer_sizeP < pdcp_header_len + pdcp_tailer_len ) { LOG_W(PDCP, PROTOCOL_PDCP_CTXT_FMT"Incoming (from RLC) SDU is short of size (size:%d)! Ignoring...\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), sdu_buffer_sizeP); free_mem_block(sdu_buffer_pP, __func__); if (ctxt_pP->enb_flag) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); return FALSE; } #if 0 /* Removed by Cedric */ if (pdcp_is_rx_seq_number_valid(sequence_number, pdcp_p, srb_flagP) == TRUE) { LOG_T(PDCP, "Incoming PDU has a sequence number (%d) in accordance with RX window\n", sequence_number); /* if (dc == PDCP_DATA_PDU ) LOG_D(PDCP, "Passing piggybacked SDU to NAS driver...\n"); else LOG_D(PDCP, "Passing piggybacked SDU to RRC ...\n");*/ } else { Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT"Incoming PDU has an unexpected sequence number (%d), RX window synchronisation have probably been lost!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), sequence_number); /* * XXX Till we implement in-sequence delivery and duplicate discarding * mechanism all out-of-order packets will be delivered to RRC/IP */ LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); return FALSE; } #endif // SRB1/2: control-plane data if (srb_flagP) { /* process as described in 36.323 5.1.2.2 */ if (sequence_number < pdcp_p->next_pdcp_rx_sn) { rx_hfn_for_count = pdcp_p->rx_hfn + 1; pdcp_sn_for_count = sequence_number; } else { rx_hfn_for_count = pdcp_p->rx_hfn; pdcp_sn_for_count = sequence_number; } if (pdcp_p->security_activated == 1) { if (ctxt_pP->enb_flag == ENB_FLAG_NO) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); } security_ok = pdcp_validate_security(ctxt_pP, pdcp_p, srb_flagP, rb_idP, pdcp_header_len, rx_hfn_for_count, pdcp_sn_for_count, sdu_buffer_pP->data, sdu_buffer_sizeP - pdcp_tailer_len) == 0; if (ctxt_pP->enb_flag == ENB_FLAG_NO) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); } } else { security_ok = 1; } if (security_ok == 0) { LOG_W(PDCP, PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDCP SRB PDU\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); /* TODO: indicate integrity verification failure to upper layer */ return FALSE; } if (sequence_number < pdcp_p->next_pdcp_rx_sn) pdcp_p->rx_hfn++; pdcp_p->next_pdcp_rx_sn = sequence_number + 1; if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { pdcp_p->next_pdcp_rx_sn = 0; pdcp_p->rx_hfn++; } rrc_data_ind(ctxt_pP, rb_id, sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len, (uint8_t *)&sdu_buffer_pP->data[pdcp_header_len]); free_mem_block(sdu_buffer_pP, __func__); // free_mem_block(new_sdu, __func__); if (ctxt_pP->enb_flag) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); return TRUE; } /* if (srb_flagP) */ /* * DRBs */ payload_offset=pdcp_header_len;// PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; switch (pdcp_p->rlc_mode) { case RLC_MODE_AM: { /* process as described in 36.323 5.1.2.1.2 */ int reordering_window; if (pdcp_p->seq_num_size == 7) reordering_window = REORDERING_WINDOW_SN_7BIT; else reordering_window = REORDERING_WINDOW_SN_12BIT; if (sequence_number - pdcp_p->last_submitted_pdcp_rx_sn > reordering_window || (pdcp_p->last_submitted_pdcp_rx_sn - sequence_number >= 0 && pdcp_p->last_submitted_pdcp_rx_sn - sequence_number < reordering_window)) { /* TODO: specs say to decipher and do header decompression */ LOG_W(PDCP, PROTOCOL_PDCP_CTXT_FMT"discard PDU, out of\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); /* TODO: indicate integrity verification failure to upper layer */ return FALSE; } else if (pdcp_p->next_pdcp_rx_sn - sequence_number > reordering_window) { pdcp_p->rx_hfn++; rx_hfn_for_count = pdcp_p->rx_hfn; pdcp_sn_for_count = sequence_number; pdcp_p->next_pdcp_rx_sn = sequence_number + 1; } else if (sequence_number - pdcp_p->next_pdcp_rx_sn >= reordering_window) { rx_hfn_for_count = pdcp_p->rx_hfn - 1; pdcp_sn_for_count = sequence_number; } else if (sequence_number >= pdcp_p->next_pdcp_rx_sn) { rx_hfn_for_count = pdcp_p->rx_hfn; pdcp_sn_for_count = sequence_number; pdcp_p->next_pdcp_rx_sn = sequence_number + 1; if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { pdcp_p->next_pdcp_rx_sn = 0; pdcp_p->rx_hfn++; } } else { /* sequence_number < pdcp_p->next_pdcp_rx_sn */ rx_hfn_for_count = pdcp_p->rx_hfn; pdcp_sn_for_count = sequence_number; } if (pdcp_p->security_activated == 1) { if (ctxt_pP->enb_flag == ENB_FLAG_NO) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); } security_ok = pdcp_validate_security(ctxt_pP, pdcp_p, srb_flagP, rb_idP, pdcp_header_len, rx_hfn_for_count, pdcp_sn_for_count, sdu_buffer_pP->data, sdu_buffer_sizeP - pdcp_tailer_len) == 0; if (ctxt_pP->enb_flag == ENB_FLAG_NO) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); } } else { security_ok = 1; } if (security_ok == 0) { LOG_W(PDCP, PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDPC DRB RLC/AM PDU\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); /* TODO: indicate integrity verification failure to upper layer */ return FALSE; } /* TODO: specs say we have to store this PDU in a list and then deliver * stored packets to upper layers according to a well defined * procedure. The code below that deals with delivery is today * too complex to do this properly, so we only send the current * received packet. This is not correct and has to be fixed * some day. * In the meantime, let's pretend the last submitted PDCP SDU * is the current one. * TODO: we also have to deal with re-establishment PDU (control PDUs) * that contain no SDU. */ pdcp_p->last_submitted_pdcp_rx_sn = sequence_number; break; } /* case RLC_MODE_AM */ case RLC_MODE_UM: /* process as described in 36.323 5.1.2.1.3 */ if (sequence_number < pdcp_p->next_pdcp_rx_sn) { pdcp_p->rx_hfn++; } rx_hfn_for_count = pdcp_p->rx_hfn; pdcp_sn_for_count = sequence_number; pdcp_p->next_pdcp_rx_sn = sequence_number + 1; if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { pdcp_p->next_pdcp_rx_sn = 0; pdcp_p->rx_hfn++; } if (pdcp_p->security_activated == 1) { if (ctxt_pP->enb_flag == ENB_FLAG_NO) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); } security_ok = pdcp_validate_security(ctxt_pP, pdcp_p, srb_flagP, rb_idP, pdcp_header_len, rx_hfn_for_count, pdcp_sn_for_count, sdu_buffer_pP->data, sdu_buffer_sizeP - pdcp_tailer_len) == 0; if (ctxt_pP->enb_flag == ENB_FLAG_NO) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); } } else { security_ok = 1; } if (security_ok == 0) { LOG_W(PDCP, PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDPC DRB RLC/UM PDU\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); /* TODO: indicate integrity verification failure to upper layer */ return FALSE; } break; default: LOG_E(PDCP, "bad RLC mode, cannot happen.\n"); exit(1); } /* switch (pdcp_p->rlc_mode) */ } else { /* MBMS_flagP == 0 */ payload_offset=0; } if (otg_enabled==1) { LOG_D(OTG,"Discarding received packed\n"); free_mem_block(sdu_buffer_pP, __func__); if (ctxt_pP->enb_flag) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); return TRUE; } // XXX Decompression would be done at this point /* * After checking incoming sequence number PDCP header * has to be stripped off so here we copy SDU buffer starting * from its second byte (skipping 0th and 1st octets, i.e. * PDCP header) */ if (LINK_ENB_PDCP_TO_GTPV1U) { if ((TRUE == ctxt_pP->enb_flag) && (FALSE == srb_flagP)) { LOG_D(PDCP, "Sending packet to GTP, Calling GTPV1U_ENB_TUNNEL_DATA_REQ ue %x rab %ld len %u\n", ctxt_pP->rnti, rb_id + 4, sdu_buffer_sizeP - payload_offset ); MSC_LOG_TX_MESSAGE( MSC_PDCP_ENB, MSC_GTPU_ENB, NULL,0, "0 GTPV1U_ENB_TUNNEL_DATA_REQ ue %x rab %u len %u", ctxt_pP->rnti, rb_id + 4, sdu_buffer_sizeP - payload_offset); //LOG_T(PDCP,"Sending to GTPV1U %d bytes\n", sdu_buffer_sizeP - payload_offset); gtpu_buffer_p = itti_malloc(TASK_PDCP_ENB, TASK_GTPV1_U, sdu_buffer_sizeP - payload_offset + GTPU_HEADER_OVERHEAD_MAX); AssertFatal(gtpu_buffer_p != NULL, "OUT OF MEMORY"); memcpy(>pu_buffer_p[GTPU_HEADER_OVERHEAD_MAX], &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset); message_p = itti_alloc_new_message(TASK_PDCP_ENB, 0, GTPV1U_ENB_TUNNEL_DATA_REQ); AssertFatal(message_p != NULL, "OUT OF MEMORY"); GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).buffer = gtpu_buffer_p; GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).length = sdu_buffer_sizeP - payload_offset; GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).offset = GTPU_HEADER_OVERHEAD_MAX; GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rnti = ctxt_pP->rnti; GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rab_id = rb_id + 4; itti_send_msg_to_task(TASK_VARIABLE, INSTANCE_DEFAULT, message_p); packet_forwarded = TRUE; } } else { packet_forwarded = FALSE; } #ifdef MBMS_MULTICAST_OUT if ((MBMS_flagP != 0) && (mbms_socket != -1)) { // struct iphdr *ip_header = (struct iphdr *)&sdu_buffer_pP->data[payload_offset]; // struct udphdr *udp_header = (struct udphdr *)&sdu_buffer_pP->data[payload_offset + sizeof(struct iphdr)]; // struct sockaddr_in dest_addr; // dest_addr.sin_family = AF_INET; // dest_addr.sin_port = udp_header->dest; // dest_addr.sin_addr.s_addr = ip_header->daddr; // sendto(mbms_socket, &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset, MSG_DONTWAIT, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); // //packet_forwarded = TRUE; } #endif if (FALSE == packet_forwarded) { notifiedFIFO_elt_t * new_sdu_p = newNotifiedFIFO_elt(sdu_buffer_sizeP - payload_offset + sizeof (pdcp_data_ind_header_t), 0, NULL, NULL); if ((MBMS_flagP == 0) && (pdcp_p->rlc_mode == RLC_MODE_AM)) { pdcp_p->last_submitted_pdcp_rx_sn = sequence_number; } /* * Prepend PDCP indication header which is going to be removed at pdcp_fifo_flush_sdus() */ pdcp_data_ind_header_t * pdcpHead=(pdcp_data_ind_header_t *)NotifiedFifoData(new_sdu_p); memset(pdcpHead, 0, sizeof (pdcp_data_ind_header_t)); pdcpHead->data_size = sdu_buffer_sizeP - payload_offset; AssertFatal((sdu_buffer_sizeP - payload_offset >= 0), "invalid PDCP SDU size!"); // Here there is no virtualization possible // set ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst for IP layer here if (ctxt_pP->enb_flag == ENB_FLAG_NO) { pdcpHead->rb_id = rb_id; if (EPC_MODE_ENABLED) { /* for the UE compiled in S1 mode, we need 1 here * for the UE compiled in noS1 mode, we need 0 * TODO: be sure of this */ if (NFAPI_MODE == NFAPI_UE_STUB_PNF ) { pdcpHead->inst = ctxt_pP->module_id; } else { // nfapi_mode if (UE_NAS_USE_TUN) { pdcpHead->inst = ctxt_pP->module_id; } else { pdcpHead->inst = 1; } } // nfapi_mode } else { if (UE_NAS_USE_TUN) { pdcpHead->inst = ctxt_pP->module_id; } else if (ENB_NAS_USE_TUN) { pdcpHead->inst = 0; } } } else { pdcpHead->rb_id = rb_id + (ctxt_pP->module_id * LTE_maxDRB); pdcpHead->inst = ctxt_pP->module_id; } if( LOG_DEBUGFLAG(DEBUG_PDCP) ) { static uint32_t pdcp_inst = 0; pdcpHead->inst = pdcp_inst++; LOG_D(PDCP, "inst=%d size=%d\n", pdcpHead->inst, pdcpHead->data_size); } memcpy(pdcpHead+1, &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset); if( LOG_DEBUGFLAG(DEBUG_PDCP) ) log_dump(PDCP, pdcpHead+1, min(sdu_buffer_sizeP - payload_offset,30) , LOG_DUMP_CHAR, "Printing first bytes of PDCP SDU before adding it to the list: \n"); pushNotifiedFIFO(&pdcp_sdu_list, new_sdu_p); /* Print octets of incoming data in hexadecimal form */ LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), sdu_buffer_sizeP - payload_offset); //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); } /* Update PDCP statistics */ for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { if (pdcp_enb[ctxt_pP->module_id].rnti[pdcp_uid] == ctxt_pP->rnti ) { break; } } Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; free_mem_block(sdu_buffer_pP, __func__); if (ctxt_pP->enb_flag) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); return TRUE; } void pdcp_update_stats(const protocol_ctxt_t *const ctxt_pP) { uint16_t pdcp_uid = 0; uint8_t rb_id = 0; // these stats are measured for both eNB and UE on per seond basis for (rb_id =0; rb_id < NB_RB_MAX; rb_id ++) { for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { //printf("frame %d and subframe %d \n", pdcp_enb[ctxt_pP->module_id].frame, pdcp_enb[ctxt_pP->module_id].subframe); // tx stats if (Pdcp_stats_tx_window_ms[ctxt_pP->module_id][pdcp_uid] > 0 && pdcp_enb[ctxt_pP->module_id].sfn % Pdcp_stats_tx_window_ms[ctxt_pP->module_id][pdcp_uid] == 0) { // unit: bit/s Pdcp_stats_tx_throughput_w[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]*8; Pdcp_stats_tx_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; Pdcp_stats_tx_bytes_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; if (Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id] > 0) { Pdcp_stats_tx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=(Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]); } else { Pdcp_stats_tx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; } // reset the tmp vars Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; } if (Pdcp_stats_rx_window_ms[ctxt_pP->module_id][pdcp_uid] > 0 && pdcp_enb[ctxt_pP->module_id].sfn % Pdcp_stats_rx_window_ms[ctxt_pP->module_id][pdcp_uid] == 0) { // rx stats Pdcp_stats_rx_goodput_w[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]*8; Pdcp_stats_rx_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; Pdcp_stats_rx_bytes_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; if(Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id] > 0) { Pdcp_stats_rx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]= (Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]); } else { Pdcp_stats_rx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; } // reset the tmp vars Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; } } } } //----------------------------------------------------------------------------- void pdcp_run ( const protocol_ctxt_t *const ctxt_pP ) //----------------------------------------------------------------------------- { if (ctxt_pP->enb_flag) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); } pdcp_enb[ctxt_pP->module_id].sfn++; // range: 0 to 18,446,744,073,709,551,615 pdcp_enb[ctxt_pP->module_id].frame=ctxt_pP->frame; // 1023 pdcp_enb[ctxt_pP->module_id].subframe= ctxt_pP->subframe; pdcp_update_stats(ctxt_pP); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_IN); MessageDef *msg_p; int result; protocol_ctxt_t ctxt; do { // Checks if a message has been sent to PDCP sub-task itti_poll_msg (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, &msg_p); if (msg_p != NULL) { switch (ITTI_MSG_ID(msg_p)) { case RRC_DCCH_DATA_REQ: PROTOCOL_CTXT_SET_BY_MODULE_ID( &ctxt, RRC_DCCH_DATA_REQ (msg_p).module_id, RRC_DCCH_DATA_REQ (msg_p).enb_flag, RRC_DCCH_DATA_REQ (msg_p).rnti, RRC_DCCH_DATA_REQ (msg_p).frame, 0, RRC_DCCH_DATA_REQ (msg_p).eNB_index); LOG_D(PDCP, PROTOCOL_CTXT_FMT"Received %s from %s: instance %ld, rb_id %ld, muiP %d, confirmP %d, mode %d\n", PROTOCOL_CTXT_ARGS(&ctxt), ITTI_MSG_NAME (msg_p), ITTI_MSG_ORIGIN_NAME(msg_p), ITTI_MSG_DESTINATION_INSTANCE (msg_p), RRC_DCCH_DATA_REQ (msg_p).rb_id, RRC_DCCH_DATA_REQ (msg_p).muip, RRC_DCCH_DATA_REQ (msg_p).confirmp, RRC_DCCH_DATA_REQ (msg_p).mode); LOG_D(PDCP, "Before calling pdcp_data_req from pdcp_run! RRC_DCCH_DATA_REQ (msg_p).rb_id: %ld \n", RRC_DCCH_DATA_REQ (msg_p).rb_id); result = pdcp_data_req (&ctxt, SRB_FLAG_YES, RRC_DCCH_DATA_REQ (msg_p).rb_id, RRC_DCCH_DATA_REQ (msg_p).muip, RRC_DCCH_DATA_REQ (msg_p).confirmp, RRC_DCCH_DATA_REQ (msg_p).sdu_size, RRC_DCCH_DATA_REQ (msg_p).sdu_p, RRC_DCCH_DATA_REQ (msg_p).mode, NULL, NULL ); if (result != TRUE) LOG_E(PDCP, "PDCP data request failed!\n"); // Message buffer has been processed, free it now. result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_REQ (msg_p).sdu_p); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); break; case RRC_PCCH_DATA_REQ: { sdu_size_t sdu_buffer_sizeP; sdu_buffer_sizeP = RRC_PCCH_DATA_REQ(msg_p).sdu_size; uint8_t CC_id = RRC_PCCH_DATA_REQ(msg_p).CC_id; uint8_t ue_index = RRC_PCCH_DATA_REQ(msg_p).ue_index; RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_paging[ue_index] = sdu_buffer_sizeP; if (sdu_buffer_sizeP > 0) { memcpy(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].paging[ue_index], RRC_PCCH_DATA_REQ(msg_p).sdu_p, sdu_buffer_sizeP); } //paging pdcp log LOG_D(PDCP, "PDCP Received RRC_PCCH_DATA_REQ CC_id %d length %d \n", CC_id, sdu_buffer_sizeP); } break; default: LOG_E(PDCP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); break; } result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } } while(msg_p != NULL); // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer // if (LINK_ENB_PDCP_TO_GTPV1U && ctxt_pP->enb_flag == ENB_FLAG_NO) { if (!EPC_MODE_ENABLED || ctxt_pP->enb_flag == ENB_FLAG_NO ) { pdcp_fifo_read_input_sdus(ctxt_pP); } // PDCP -> NAS/IP traffic: RX if (ctxt_pP->enb_flag) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); } pdcp_fifo_flush_sdus(ctxt_pP); if (ctxt_pP->enb_flag) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); } if (ctxt_pP->enb_flag) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_OUT); } //----------------------------------------------------------------------------- void pdcp_mbms_run ( const protocol_ctxt_t *const ctxt_pP ) //----------------------------------------------------------------------------- { // if (ctxt_pP->enb_flag) { // start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); // } else { // start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); // } // pdcp_enb[ctxt_pP->module_id].sfn++; // range: 0 to 18,446,744,073,709,551,615 // pdcp_enb[ctxt_pP->module_id].frame=ctxt_pP->frame; // 1023 // pdcp_enb[ctxt_pP->module_id].subframe= ctxt_pP->subframe; // pdcp_update_stats(ctxt_pP); // VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_IN); // MessageDef *msg_p; //int result; //protocol_ctxt_t ctxt; // do { // // Checks if a message has been sent to PDCP sub-task // itti_poll_msg (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, &msg_p); // // if (msg_p != NULL) { // switch (ITTI_MSG_ID(msg_p)) { // case RRC_DCCH_DATA_REQ: // PROTOCOL_CTXT_SET_BY_MODULE_ID( // &ctxt, // RRC_DCCH_DATA_REQ (msg_p).module_id, // RRC_DCCH_DATA_REQ (msg_p).enb_flag, // RRC_DCCH_DATA_REQ (msg_p).rnti, // RRC_DCCH_DATA_REQ (msg_p).frame, // 0, // RRC_DCCH_DATA_REQ (msg_p).eNB_index); // LOG_D(PDCP, PROTOCOL_CTXT_FMT"Received %s from %s: instance %d, rb_id %d, muiP %d, confirmP %d, mode %d\n", // PROTOCOL_CTXT_ARGS(&ctxt), // ITTI_MSG_NAME (msg_p), // ITTI_MSG_ORIGIN_NAME(msg_p), // ITTI_MSG_DESTINATION_INSTANCE (msg_p), // RRC_DCCH_DATA_REQ (msg_p).rb_id, // RRC_DCCH_DATA_REQ (msg_p).muip, // RRC_DCCH_DATA_REQ (msg_p).confirmp, // RRC_DCCH_DATA_REQ (msg_p).mode); // LOG_D(PDCP, "Before calling pdcp_data_req from pdcp_run! RRC_DCCH_DATA_REQ (msg_p).rb_id: %d \n", RRC_DCCH_DATA_REQ (msg_p).rb_id); // result = pdcp_data_req (&ctxt, // SRB_FLAG_YES, // RRC_DCCH_DATA_REQ (msg_p).rb_id, // RRC_DCCH_DATA_REQ (msg_p).muip, // RRC_DCCH_DATA_REQ (msg_p).confirmp, // RRC_DCCH_DATA_REQ (msg_p).sdu_size, // RRC_DCCH_DATA_REQ (msg_p).sdu_p, // RRC_DCCH_DATA_REQ (msg_p).mode, // NULL, NULL // ); // // if (result != TRUE) // LOG_E(PDCP, "PDCP data request failed!\n"); // // // Message buffer has been processed, free it now. // result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_REQ (msg_p).sdu_p); // AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); // break; // // case RRC_PCCH_DATA_REQ: { // sdu_size_t sdu_buffer_sizeP; // sdu_buffer_sizeP = RRC_PCCH_DATA_REQ(msg_p).sdu_size; // uint8_t CC_id = RRC_PCCH_DATA_REQ(msg_p).CC_id; // uint8_t ue_index = RRC_PCCH_DATA_REQ(msg_p).ue_index; // RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_paging[ue_index] = sdu_buffer_sizeP; // // if (sdu_buffer_sizeP > 0) { // memcpy(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].paging[ue_index], RRC_PCCH_DATA_REQ(msg_p).sdu_p, sdu_buffer_sizeP); // } // // //paging pdcp log // LOG_D(PDCP, "PDCP Received RRC_PCCH_DATA_REQ CC_id %d length %d \n", CC_id, sdu_buffer_sizeP); // } // break; // // default: // LOG_E(PDCP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); // break; // } // // result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); // AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); // } // } while(msg_p != NULL); // // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer // if (LINK_ENB_PDCP_TO_GTPV1U && ctxt_pP->enb_flag == ENB_FLAG_NO) { //if (EPC_MODE_ENABLED || ctxt_pP->enb_flag == ENB_FLAG_NO ) { pdcp_fifo_read_input_mbms_sdus_fromtun(ctxt_pP); //} // PDCP -> NAS/IP traffic: RX // if (ctxt_pP->enb_flag) { // start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); // } else { // start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); // } // //pdcp_fifo_flush_mbms_sdus(ctxt_pP); // if (ctxt_pP->enb_flag) { // stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); // } else { // stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); // } // // if (ctxt_pP->enb_flag) { // stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); // } else { // stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); // } // // VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_OUT); } void pdcp_init_stats_UE(module_id_t mod, uint16_t uid) { Pdcp_stats_tx_window_ms[mod][uid] = 100; Pdcp_stats_rx_window_ms[mod][uid] = 100; for (int i = 0; i < NB_RB_MAX; ++i) { Pdcp_stats_tx_bytes[mod][uid][i] = 0; Pdcp_stats_tx_bytes_w[mod][uid][i] = 0; Pdcp_stats_tx_bytes_tmp_w[mod][uid][i] = 0; Pdcp_stats_tx[mod][uid][i] = 0; Pdcp_stats_tx_w[mod][uid][i] = 0; Pdcp_stats_tx_tmp_w[mod][uid][i] = 0; Pdcp_stats_tx_sn[mod][uid][i] = 0; Pdcp_stats_tx_throughput_w[mod][uid][i] = 0; Pdcp_stats_tx_aiat[mod][uid][i] = 0; Pdcp_stats_tx_aiat_w[mod][uid][i] = 0; Pdcp_stats_tx_aiat_tmp_w[mod][uid][i] = 0; Pdcp_stats_tx_iat[mod][uid][i] = 0; Pdcp_stats_rx[mod][uid][i] = 0; Pdcp_stats_rx_w[mod][uid][i] = 0; Pdcp_stats_rx_tmp_w[mod][uid][i] = 0; Pdcp_stats_rx_bytes[mod][uid][i] = 0; Pdcp_stats_rx_bytes_w[mod][uid][i] = 0; Pdcp_stats_rx_bytes_tmp_w[mod][uid][i] = 0; Pdcp_stats_rx_sn[mod][uid][i] = 0; Pdcp_stats_rx_goodput_w[mod][uid][i] = 0; Pdcp_stats_rx_aiat[mod][uid][i] = 0; Pdcp_stats_rx_aiat_w[mod][uid][i] = 0; Pdcp_stats_rx_aiat_tmp_w[mod][uid][i] = 0; Pdcp_stats_rx_iat[mod][uid][i] = 0; Pdcp_stats_rx_outoforder[mod][uid][i] = 0; } } void pdcp_add_UE(const protocol_ctxt_t *const ctxt_pP) { int i, ue_flag=1; //, ret=-1; to be decied later for (i=0; i < MAX_MOBILES_PER_ENB; i++) { if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti) { ue_flag=-1; break; } } if (ue_flag == 1 ) { for (i=0; i < MAX_MOBILES_PER_ENB ; i++) { if (pdcp_enb[ctxt_pP->module_id].rnti[i] == 0 ) { pdcp_enb[ctxt_pP->module_id].rnti[i]=ctxt_pP->rnti; pdcp_enb[ctxt_pP->module_id].uid[i]=i; pdcp_enb[ctxt_pP->module_id].num_ues++; printf("add new uid is %d %x\n\n", i, ctxt_pP->rnti); pdcp_init_stats_UE(ctxt_pP->module_id, i); // ret=1; break; } } } //return ret; } //----------------------------------------------------------------------------- boolean_t pdcp_remove_UE( const protocol_ctxt_t *const ctxt_pP ) //----------------------------------------------------------------------------- { LTE_DRB_Identity_t srb_id = 0; LTE_DRB_Identity_t drb_id = 0; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; int i; // check and remove SRBs first for(int i = 0; i<MAX_MOBILES_PER_ENB; i++) { if(pdcp_eNB_UE_instance_to_rnti[i] == ctxt_pP->rnti) { pdcp_eNB_UE_instance_to_rnti[i] = NOT_A_RNTI; break; } } for (srb_id=1; srb_id<3; srb_id++) { key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); h_rc = hashtable_remove(pdcp_coll_p, key); } for (drb_id=0; drb_id<LTE_maxDRB; drb_id++) { key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); h_rc = hashtable_remove(pdcp_coll_p, key); } (void)h_rc; /* remove gcc warning "set but not used" */ // remove ue for pdcp enb inst for (i=0; i < MAX_MOBILES_PER_ENB; i++) { if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti ) { LOG_I(PDCP, "remove uid is %d/%d %x\n", i, pdcp_enb[ctxt_pP->module_id].uid[i], pdcp_enb[ctxt_pP->module_id].rnti[i]); pdcp_enb[ctxt_pP->module_id].uid[i]=0; pdcp_enb[ctxt_pP->module_id].rnti[i]=0; pdcp_enb[ctxt_pP->module_id].num_ues--; break; } } return 1; } //----------------------------------------------------------------------------- boolean_t rrc_pdcp_config_asn1_req ( const protocol_ctxt_t *const ctxt_pP, LTE_SRB_ToAddModList_t *const srb2add_list_pP, LTE_DRB_ToAddModList_t *const drb2add_list_pP, LTE_DRB_ToReleaseList_t *const drb2release_list_pP, const uint8_t security_modeP, uint8_t *const kRRCenc_pP, uint8_t *const kRRCint_pP, uint8_t *const kUPenc_pP, LTE_PMCH_InfoList_r9_t *const pmch_InfoList_r9_pP, rb_id_t *const defaultDRB ) //----------------------------------------------------------------------------- { long int lc_id = 0; LTE_DRB_Identity_t srb_id = 0; long int mch_id = 0; rlc_mode_t rlc_type = RLC_MODE_NONE; LTE_DRB_Identity_t drb_id = 0; LTE_DRB_Identity_t *pdrb_id_p = NULL; uint8_t drb_sn = 12; uint8_t srb_sn = 5; // fixed sn for SRBs uint8_t drb_report = 0; long int cnt = 0; uint16_t header_compression_profile = 0; config_action_t action = CONFIG_ACTION_ADD; LTE_SRB_ToAddMod_t *srb_toaddmod_p = NULL; LTE_DRB_ToAddMod_t *drb_toaddmod_p = NULL; pdcp_t *pdcp_p = NULL; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; hash_key_t key_defaultDRB = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_defaultDRB_rc; int i,j; LTE_MBMS_SessionInfoList_r9_t *mbms_SessionInfoList_r9_p = NULL; LTE_MBMS_SessionInfo_r9_t *MBMS_SessionInfo_p = NULL; LOG_T(PDCP, PROTOCOL_CTXT_FMT" %s() SRB2ADD %p DRB2ADD %p DRB2RELEASE %p\n", PROTOCOL_CTXT_ARGS(ctxt_pP), __FUNCTION__, srb2add_list_pP, drb2add_list_pP, drb2release_list_pP); // srb2add_list does not define pdcp config, we use rlc info to setup the pdcp dcch0 and dcch1 channels if (srb2add_list_pP != NULL) { for (cnt=0; cnt<srb2add_list_pP->list.count; cnt++) { srb_id = srb2add_list_pP->list.array[cnt]->srb_Identity; srb_toaddmod_p = srb2add_list_pP->list.array[cnt]; rlc_type = RLC_MODE_AM; lc_id = srb_id; key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc == HASH_TABLE_OK) { action = CONFIG_ACTION_MODIFY; LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_MODIFY key 0x%"PRIx64"\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); } else { action = CONFIG_ACTION_ADD; pdcp_p = calloc(1, sizeof(pdcp_t)); h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); if (h_rc != HASH_TABLE_OK) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64" FAILED\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); free(pdcp_p); return TRUE; } else { LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64"\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); } } if (srb_toaddmod_p->rlc_Config) { switch (srb_toaddmod_p->rlc_Config->present) { case LTE_SRB_ToAddMod__rlc_Config_PR_NOTHING: break; case LTE_SRB_ToAddMod__rlc_Config_PR_explicitValue: switch (srb_toaddmod_p->rlc_Config->choice.explicitValue.present) { case LTE_RLC_Config_PR_NOTHING: break; default: pdcp_config_req_asn1 ( ctxt_pP, pdcp_p, SRB_FLAG_YES, rlc_type, action, lc_id, mch_id, srb_id, srb_sn, 0, // drb_report 0, // header compression security_modeP, kRRCenc_pP, kRRCint_pP, kUPenc_pP); break; } break; case LTE_SRB_ToAddMod__rlc_Config_PR_defaultValue: pdcp_config_req_asn1 ( ctxt_pP, pdcp_p, SRB_FLAG_YES, rlc_type, action, lc_id, mch_id, srb_id, srb_sn, 0, // drb_report 0, // header compression security_modeP, kRRCenc_pP, kRRCint_pP, kUPenc_pP); // already the default values break; default: DevParam(srb_toaddmod_p->rlc_Config->present, ctxt_pP->module_id, ctxt_pP->rnti); break; } } } } // reset the action if (drb2add_list_pP != NULL) { for (cnt=0; cnt<drb2add_list_pP->list.count; cnt++) { drb_toaddmod_p = drb2add_list_pP->list.array[cnt]; drb_id = drb_toaddmod_p->drb_Identity;// + drb_id_offset; if (drb_toaddmod_p->logicalChannelIdentity) { lc_id = *(drb_toaddmod_p->logicalChannelIdentity); } else { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" logicalChannelIdentity is missing in DRB-ToAddMod information element!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); continue; } if (lc_id == 1 || lc_id == 2) { LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity = %ld is invalid in RRC message when adding DRB!\n", PROTOCOL_CTXT_ARGS(ctxt_pP), lc_id); continue; } DevCheck4(drb_id < LTE_maxDRB, drb_id, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc == HASH_TABLE_OK) { action = CONFIG_ACTION_MODIFY; LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_MODIFY key 0x%"PRIx64"\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); } else { action = CONFIG_ACTION_ADD; pdcp_p = calloc(1, sizeof(pdcp_t)); h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); // save the first configured DRB-ID as the default DRB-ID if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); h_defaultDRB_rc = hashtable_insert(pdcp_coll_p, key_defaultDRB, pdcp_p); } else { h_defaultDRB_rc = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB } if (h_defaultDRB_rc != HASH_TABLE_OK) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD default DRB key 0x%"PRIx64" FAILED\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key_defaultDRB); free(pdcp_p); return TRUE; } else if (h_rc != HASH_TABLE_OK) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64" FAILED\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); free(pdcp_p); return TRUE; } else { LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64"\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); } } if (drb_toaddmod_p->pdcp_Config) { if (drb_toaddmod_p->pdcp_Config->discardTimer) { // set the value of the timer } if (drb_toaddmod_p->pdcp_Config->rlc_AM) { drb_report = drb_toaddmod_p->pdcp_Config->rlc_AM->statusReportRequired; drb_sn = LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits; // default SN size rlc_type = RLC_MODE_AM; } if (drb_toaddmod_p->pdcp_Config->rlc_UM) { drb_sn = drb_toaddmod_p->pdcp_Config->rlc_UM->pdcp_SN_Size; rlc_type =RLC_MODE_UM; } switch (drb_toaddmod_p->pdcp_Config->headerCompression.present) { case LTE_PDCP_Config__headerCompression_PR_NOTHING: case LTE_PDCP_Config__headerCompression_PR_notUsed: header_compression_profile=0x0; break; case LTE_PDCP_Config__headerCompression_PR_rohc: // parse the struc and get the rohc profile if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0001) { header_compression_profile=0x0001; } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0002) { header_compression_profile=0x0002; } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0003) { header_compression_profile=0x0003; } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0004) { header_compression_profile=0x0004; } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0006) { header_compression_profile=0x0006; } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0101) { header_compression_profile=0x0101; } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0102) { header_compression_profile=0x0102; } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0103) { header_compression_profile=0x0103; } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0104) { header_compression_profile=0x0104; } else { header_compression_profile=0x0; LOG_W(PDCP,"unknown header compresion profile\n"); } // set the applicable profile break; default: LOG_W(PDCP,PROTOCOL_PDCP_CTXT_FMT"[RB %ld] unknown drb_toaddmod->PDCP_Config->headerCompression->present \n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), drb_id); break; } pdcp_config_req_asn1 ( ctxt_pP, pdcp_p, SRB_FLAG_NO, rlc_type, action, lc_id, mch_id, drb_id, drb_sn, drb_report, header_compression_profile, security_modeP, kRRCenc_pP, kRRCint_pP, kUPenc_pP); } } } if (drb2release_list_pP != NULL) { for (cnt=0; cnt<drb2release_list_pP->list.count; cnt++) { pdrb_id_p = drb2release_list_pP->list.array[cnt]; drb_id = *pdrb_id_p; key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc != HASH_TABLE_OK) { LOG_E(PDCP, PROTOCOL_CTXT_FMT" PDCP REMOVE FAILED drb_id %ld\n", PROTOCOL_CTXT_ARGS(ctxt_pP), drb_id); continue; } lc_id = pdcp_p->lcid; action = CONFIG_ACTION_REMOVE; pdcp_config_req_asn1 ( ctxt_pP, pdcp_p, SRB_FLAG_NO, rlc_type, action, lc_id, mch_id, drb_id, 0, 0, 0, security_modeP, kRRCenc_pP, kRRCint_pP, kUPenc_pP); h_rc = hashtable_remove(pdcp_coll_p, key); if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { // default DRB being removed. nevertheless this shouldn't happen as removing default DRB is not allowed in standard key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); h_defaultDRB_rc = hashtable_get(pdcp_coll_p, key_defaultDRB, (void **)&pdcp_p); if (h_defaultDRB_rc == HASH_TABLE_OK) { h_defaultDRB_rc = hashtable_remove(pdcp_coll_p, key_defaultDRB); } else { LOG_E(PDCP, PROTOCOL_CTXT_FMT" PDCP REMOVE FAILED default DRB\n", PROTOCOL_CTXT_ARGS(ctxt_pP)); } } else { key_defaultDRB = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB } } } if (pmch_InfoList_r9_pP != NULL) { for (i=0; i<pmch_InfoList_r9_pP->list.count; i++) { mbms_SessionInfoList_r9_p = &(pmch_InfoList_r9_pP->list.array[i]->mbms_SessionInfoList_r9); for (j=0; j<mbms_SessionInfoList_r9_p->list.count; j++) { MBMS_SessionInfo_p = mbms_SessionInfoList_r9_p->list.array[j]; if (0/*MBMS_SessionInfo_p->sessionId_r9*/) lc_id = MBMS_SessionInfo_p->sessionId_r9->buf[0]; else lc_id = MBMS_SessionInfo_p->logicalChannelIdentity_r9; mch_id = MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[2]; //serviceId is 3-octet string // mch_id = j; // can set the mch_id = i if (ctxt_pP->enb_flag) { drb_id = (mch_id * LTE_maxSessionPerPMCH ) + lc_id ;//+ (LTE_maxDRB + 3)*MAX_MOBILES_PER_ENB; // 1 if (pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == TRUE) { action = CONFIG_ACTION_MBMS_MODIFY; } else { action = CONFIG_ACTION_MBMS_ADD; } } else { drb_id = (mch_id * LTE_maxSessionPerPMCH ) + lc_id; // + (LTE_maxDRB + 3); // 15 if (pdcp_mbms_array_ue[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == TRUE) { action = CONFIG_ACTION_MBMS_MODIFY; } else { action = CONFIG_ACTION_MBMS_ADD; } } LOG_I(PDCP, "lc_id (%02ld) mch_id(%02x,%02x,%02x) drb_id(%ld) action(%d)\n", lc_id, MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[0], MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[1], MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[2], drb_id, action); pdcp_config_req_asn1 ( ctxt_pP, NULL, // unused for MBMS SRB_FLAG_NO, RLC_MODE_NONE, action, lc_id, mch_id, drb_id, 0, // unused for MBMS 0, // unused for MBMS 0, // unused for MBMS 0, // unused for MBMS NULL, // unused for MBMS NULL, // unused for MBMS NULL); // unused for MBMS } } } return 0; } //----------------------------------------------------------------------------- boolean_t pdcp_config_req_asn1 ( const protocol_ctxt_t *const ctxt_pP, pdcp_t *const pdcp_pP, const srb_flag_t srb_flagP, const rlc_mode_t rlc_modeP, const config_action_t actionP, const uint16_t lc_idP, const uint16_t mch_idP, const rb_id_t rb_idP, const uint8_t rb_snP, const uint8_t rb_reportP, const uint16_t header_compression_profileP, const uint8_t security_modeP, uint8_t *const kRRCenc_pP, uint8_t *const kRRCint_pP, uint8_t *const kUPenc_pP) //----------------------------------------------------------------------------- { switch (actionP) { case CONFIG_ACTION_ADD: DevAssert(pdcp_pP != NULL); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { pdcp_pP->is_ue = FALSE; pdcp_add_UE(ctxt_pP); //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; // pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; if( srb_flagP == SRB_FLAG_NO ) { for(int i = 0; i<MAX_MOBILES_PER_ENB; i++) { if(pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] == NOT_A_RNTI) { break; } pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; } pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; } //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; } else { pdcp_pP->is_ue = TRUE; pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; } pdcp_pP->is_srb = (srb_flagP == SRB_FLAG_YES) ? TRUE : FALSE; pdcp_pP->lcid = lc_idP; pdcp_pP->rb_id = rb_idP; pdcp_pP->header_compression_profile = header_compression_profileP; pdcp_pP->status_report = rb_reportP; if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits) { pdcp_pP->seq_num_size = 12; pdcp_pP->maximum_pdcp_rx_sn = (1 << 12) - 1; } else if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) { pdcp_pP->seq_num_size = 7; pdcp_pP->maximum_pdcp_rx_sn = (1 << 7) - 1; } else { pdcp_pP->seq_num_size = 5; pdcp_pP->maximum_pdcp_rx_sn = (1 << 5) - 1; } pdcp_pP->rlc_mode = rlc_modeP; pdcp_pP->next_pdcp_tx_sn = 0; pdcp_pP->next_pdcp_rx_sn = 0; pdcp_pP->tx_hfn = 0; pdcp_pP->rx_hfn = 0; pdcp_pP->last_submitted_pdcp_rx_sn = 4095; pdcp_pP->first_missing_pdu = -1; LOG_I(PDCP, PROTOCOL_PDCP_CTXT_FMT" Action ADD LCID %d (%s id %ld) " "configured with SN size %d bits and RLC %s\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), lc_idP, (srb_flagP == SRB_FLAG_YES) ? "SRB" : "DRB", rb_idP, pdcp_pP->seq_num_size, (rlc_modeP == RLC_MODE_AM ) ? "AM" : (rlc_modeP == RLC_MODE_TM) ? "TM" : "UM"); /* Setup security */ if (security_modeP != 0xff) { pdcp_config_set_security( ctxt_pP, pdcp_pP, rb_idP, lc_idP, security_modeP, kRRCenc_pP, kRRCint_pP, kUPenc_pP); } break; case CONFIG_ACTION_MODIFY: DevAssert(pdcp_pP != NULL); pdcp_pP->header_compression_profile=header_compression_profileP; pdcp_pP->status_report = rb_reportP; pdcp_pP->rlc_mode = rlc_modeP; /* Setup security */ if (security_modeP != 0xff) { pdcp_config_set_security( ctxt_pP, pdcp_pP, rb_idP, lc_idP, security_modeP, kRRCenc_pP, kRRCint_pP, kUPenc_pP); } if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) { pdcp_pP->seq_num_size = 7; } else if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits) { pdcp_pP->seq_num_size = 12; } else { pdcp_pP->seq_num_size=5; } LOG_I(PDCP,PROTOCOL_PDCP_CTXT_FMT" Action MODIFY LCID %d " "RB id %ld reconfigured with SN size %d and RLC %s \n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), lc_idP, rb_idP, rb_snP, (rlc_modeP == RLC_MODE_AM) ? "AM" : (rlc_modeP == RLC_MODE_TM) ? "TM" : "UM"); break; case CONFIG_ACTION_REMOVE: DevAssert(pdcp_pP != NULL); //#warning "TODO pdcp_module_id_to_rnti" //pdcp_module_id_to_rnti[ctxt_pP.module_id ][dst_id] = NOT_A_RNTI; LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_REMOVE LCID %d RBID %ld configured\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), lc_idP, rb_idP); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { // pdcp_remove_UE(ctxt_pP); } /* Security keys */ if (pdcp_pP->kUPenc != NULL) { free(pdcp_pP->kUPenc); } if (pdcp_pP->kRRCint != NULL) { free(pdcp_pP->kRRCint); } if (pdcp_pP->kRRCenc != NULL) { free(pdcp_pP->kRRCenc); } memset(pdcp_pP, 0, sizeof(pdcp_t)); break; case CONFIG_ACTION_MBMS_ADD: case CONFIG_ACTION_MBMS_MODIFY: LOG_D(PDCP," %s service_id/mch index %d, session_id/lcid %d, rbid %ld configured\n", //PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), actionP == CONFIG_ACTION_MBMS_ADD ? "CONFIG_ACTION_MBMS_ADD" : "CONFIG_ACTION_MBMS_MODIFY", mch_idP, lc_idP, rb_idP); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = TRUE ; pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].rb_id = rb_idP; } else { pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = TRUE ; pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].rb_id = rb_idP; } break; case CONFIG_ACTION_SET_SECURITY_MODE: pdcp_config_set_security( ctxt_pP, pdcp_pP, rb_idP, lc_idP, security_modeP, kRRCenc_pP, kRRCint_pP, kUPenc_pP); break; default: DevParam(actionP, ctxt_pP->module_id, ctxt_pP->rnti); break; } return 0; } //----------------------------------------------------------------------------- void pdcp_config_set_security( const protocol_ctxt_t *const ctxt_pP, pdcp_t *const pdcp_pP, const rb_id_t rb_idP, const uint16_t lc_idP, const uint8_t security_modeP, uint8_t *const kRRCenc, uint8_t *const kRRCint, uint8_t *const kUPenc) //----------------------------------------------------------------------------- { DevAssert(pdcp_pP != NULL); if ((security_modeP >= 0) && (security_modeP <= 0x77)) { pdcp_pP->cipheringAlgorithm = security_modeP & 0x0f; pdcp_pP->integrityProtAlgorithm = (security_modeP>>4) & 0xf; LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_SET_SECURITY_MODE: cipheringAlgorithm %d integrityProtAlgorithm %d\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), pdcp_pP->cipheringAlgorithm, pdcp_pP->integrityProtAlgorithm); pdcp_pP->kRRCenc = kRRCenc; pdcp_pP->kRRCint = kRRCint; pdcp_pP->kUPenc = kUPenc; /* Activate security */ pdcp_pP->security_activated = 1; MSC_LOG_EVENT( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, "0 Set security ciph %X integ %x UE %"PRIx16" ", pdcp_pP->cipheringAlgorithm, pdcp_pP->integrityProtAlgorithm, ctxt_pP->rnti); } else { MSC_LOG_EVENT( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, "0 Set security failed UE %"PRIx16" ", ctxt_pP->rnti); LOG_E(PDCP,PROTOCOL_PDCP_CTXT_FMT" bad security mode %d", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), security_modeP); } } //----------------------------------------------------------------------------- void rrc_pdcp_config_req ( const protocol_ctxt_t *const ctxt_pP, const srb_flag_t srb_flagP, const uint32_t actionP, const rb_id_t rb_idP, const uint8_t security_modeP) //----------------------------------------------------------------------------- { pdcp_t *pdcp_p = NULL; hash_key_t key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); hashtable_rc_t h_rc; h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc == HASH_TABLE_OK) { /* * Initialize sequence number state variables of relevant PDCP entity */ switch (actionP) { case CONFIG_ACTION_ADD: pdcp_p->is_srb = srb_flagP; pdcp_p->rb_id = rb_idP; if (ctxt_pP->enb_flag == ENB_FLAG_NO) { pdcp_p->is_ue = TRUE; pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; } else { pdcp_p->is_ue = FALSE; } pdcp_p->next_pdcp_tx_sn = 0; pdcp_p->next_pdcp_rx_sn = 0; pdcp_p->tx_hfn = 0; pdcp_p->rx_hfn = 0; /* SN of the last PDCP SDU delivered to upper layers */ pdcp_p->last_submitted_pdcp_rx_sn = 4095; if (rb_idP < DTCH) { // SRB pdcp_p->seq_num_size = 5; } else { // DRB pdcp_p->seq_num_size = 12; } pdcp_p->first_missing_pdu = -1; LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Config request : Action ADD: radio bearer id %ld (already added) configured\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), rb_idP); break; case CONFIG_ACTION_MODIFY: break; case CONFIG_ACTION_REMOVE: LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_REMOVE: radio bearer id %ld configured\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), rb_idP); pdcp_p->next_pdcp_tx_sn = 0; pdcp_p->next_pdcp_rx_sn = 0; pdcp_p->tx_hfn = 0; pdcp_p->rx_hfn = 0; pdcp_p->last_submitted_pdcp_rx_sn = 4095; pdcp_p->seq_num_size = 0; pdcp_p->first_missing_pdu = -1; pdcp_p->security_activated = 0; h_rc = hashtable_remove(pdcp_coll_p, key); break; case CONFIG_ACTION_SET_SECURITY_MODE: if ((security_modeP >= 0) && (security_modeP <= 0x77)) { pdcp_p->cipheringAlgorithm= security_modeP & 0x0f; pdcp_p->integrityProtAlgorithm = (security_modeP>>4) & 0xf; LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_SET_SECURITY_MODE: cipheringAlgorithm %d integrityProtAlgorithm %d\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), pdcp_p->cipheringAlgorithm, pdcp_p->integrityProtAlgorithm ); } else { LOG_W(PDCP,PROTOCOL_PDCP_CTXT_FMT" bad security mode %d", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), security_modeP); } break; default: DevParam(actionP, ctxt_pP->module_id, ctxt_pP->rnti); break; } } else { switch (actionP) { case CONFIG_ACTION_ADD: pdcp_p = calloc(1, sizeof(pdcp_t)); h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); if (h_rc != HASH_TABLE_OK) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" PDCP ADD FAILED\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); free(pdcp_p); } else { pdcp_p->is_srb = srb_flagP; pdcp_p->rb_id = rb_idP; if (ctxt_pP->enb_flag == ENB_FLAG_NO) { pdcp_p->is_ue = TRUE; pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; } else { pdcp_p->is_ue = FALSE; } pdcp_p->next_pdcp_tx_sn = 0; pdcp_p->next_pdcp_rx_sn = 0; pdcp_p->tx_hfn = 0; pdcp_p->rx_hfn = 0; /* SN of the last PDCP SDU delivered to upper layers */ pdcp_p->last_submitted_pdcp_rx_sn = 4095; if (rb_idP < DTCH) { // SRB pdcp_p->seq_num_size = 5; } else { // DRB pdcp_p->seq_num_size = 12; } pdcp_p->first_missing_pdu = -1; LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Inserting PDCP instance in collection key 0x%"PRIx64"\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), key); LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Config request : Action ADD: radio bearer id %ld configured\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), rb_idP); } break; case CONFIG_ACTION_REMOVE: LOG_D(PDCP, PROTOCOL_CTXT_FMT" CONFIG_REQ PDCP CONFIG_ACTION_REMOVE PDCP instance not found\n", PROTOCOL_CTXT_ARGS(ctxt_pP)); break; default: LOG_E(PDCP, PROTOCOL_CTXT_FMT" CONFIG_REQ PDCP NOT FOUND\n", PROTOCOL_CTXT_ARGS(ctxt_pP)); } } } pdcp_data_ind_func_t get_pdcp_data_ind_func() { return pdcp_params.pdcp_data_ind_func; } void pdcp_set_rlc_data_req_func(send_rlc_data_req_func_t send_rlc_data_req) { pdcp_params.send_rlc_data_req_func = send_rlc_data_req; } void pdcp_set_pdcp_data_ind_func(pdcp_data_ind_func_t pdcp_data_ind) { pdcp_params.pdcp_data_ind_func = pdcp_data_ind; } uint64_t pdcp_module_init( uint64_t pdcp_optmask ) { /* temporary enforce netlink when UE_NAS_USE_TUN is set, this is while switching from noS1 as build option to noS1 as config option */ if ( pdcp_optmask & UE_NAS_USE_TUN_BIT) { pdcp_params.optmask = pdcp_params.optmask | PDCP_USE_NETLINK_BIT ; } pdcp_params.optmask = pdcp_params.optmask | pdcp_optmask ; LOG_I(PDCP, "pdcp init,%s %s\n", ((LINK_ENB_PDCP_TO_GTPV1U)?"usegtp":""), ((PDCP_USE_NETLINK)?"usenetlink":"")); if (PDCP_USE_NETLINK) { nas_getparams(); if(UE_NAS_USE_TUN) { int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 )? MAX_MOBILES_PER_ENB : 1; netlink_init_tun("ue",num_if); if (IS_SOFTMODEM_NOS1) nas_config(1, 1, 2, "ue"); netlink_init_mbms_tun("uem"); nas_config_mbms(1, 2, 2, "uem"); LOG_I(PDCP, "UE pdcp will use tun interface\n"); } else if(ENB_NAS_USE_TUN) { netlink_init_tun("enb",1); nas_config(1, 1, 1, "enb"); if(pdcp_optmask & ENB_NAS_USE_TUN_W_MBMS_BIT){ netlink_init_mbms_tun("enm"); nas_config_mbms(1, 2, 1, "enm"); LOG_I(PDCP, "ENB pdcp will use mbms tun interface\n"); } LOG_I(PDCP, "ENB pdcp will use tun interface\n"); } else { LOG_I(PDCP, "pdcp will use kernel modules\n"); netlink_init(); } }else{ if(pdcp_optmask & ENB_NAS_USE_TUN_W_MBMS_BIT){ LOG_W(PDCP, "ENB pdcp will use tun interface for MBMS\n"); netlink_init_mbms_tun("enm"); nas_config_mbms_s1(1, 2, 1, "enm"); }else LOG_E(PDCP, "ENB pdcp will not use tun interface\n"); } pthread_create(&pdcp_stats_thread_desc,NULL,pdcp_stats_thread,NULL); return pdcp_params.optmask ; } //----------------------------------------------------------------------------- void pdcp_free ( void *pdcp_pP ) //----------------------------------------------------------------------------- { pdcp_t *pdcp_p = (pdcp_t *)pdcp_pP; if (pdcp_p != NULL) { if (pdcp_p->kUPenc != NULL) { free(pdcp_p->kUPenc); } if (pdcp_p->kRRCint != NULL) { free(pdcp_p->kRRCint); } if (pdcp_p->kRRCenc != NULL) { free(pdcp_p->kRRCenc); } memset(pdcp_pP, 0, sizeof(pdcp_t)); free(pdcp_pP); } } //----------------------------------------------------------------------------- void pdcp_module_cleanup (void) //----------------------------------------------------------------------------- { } //----------------------------------------------------------------------------- void pdcp_layer_init(void) //----------------------------------------------------------------------------- { module_id_t instance; int i,j; mbms_session_id_t session_id; mbms_service_id_t service_id; /* * Initialize SDU list */ initNotifiedFIFO(&pdcp_sdu_list); pdcp_coll_p = hashtable_create ((LTE_maxDRB + 2) * NUMBER_OF_UE_MAX, NULL, pdcp_free); AssertFatal(pdcp_coll_p != NULL, "UNRECOVERABLE error, PDCP hashtable_create failed"); for (instance = 0; instance < MAX_MOBILES_PER_ENB; instance++) { for (service_id = 0; service_id < LTE_maxServiceCount; service_id++) { for (session_id = 0; session_id < LTE_maxSessionPerPMCH; session_id++) { memset(&pdcp_mbms_array_ue[instance][service_id][session_id], 0, sizeof(pdcp_mbms_t)); } } pdcp_eNB_UE_instance_to_rnti[instance] = NOT_A_RNTI; } pdcp_eNB_UE_instance_to_rnti_index = 0; for (instance = 0; instance < NUMBER_OF_eNB_MAX; instance++) { for (service_id = 0; service_id < LTE_maxServiceCount; service_id++) { for (session_id = 0; session_id < LTE_maxSessionPerPMCH; session_id++) { memset(&pdcp_mbms_array_eNB[instance][service_id][session_id], 0, sizeof(pdcp_mbms_t)); } } } #ifdef MBMS_MULTICAST_OUT mbms_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (mbms_socket == -1) LOG_W(PDCP, "Could not create RAW socket, MBMS packets will not be put to the network\n"); #endif LOG_I(PDCP, "PDCP layer has been initialized\n"); pdcp_output_sdu_bytes_to_write=0; pdcp_output_header_bytes_to_write=0; pdcp_input_sdu_remaining_size_to_read=0; memset(pdcp_enb, 0, sizeof(pdcp_enb_t)); memset(Pdcp_stats_tx_window_ms, 0, sizeof(Pdcp_stats_tx_window_ms)); memset(Pdcp_stats_rx_window_ms, 0, sizeof(Pdcp_stats_rx_window_ms)); for (i = 0; i < MAX_eNB; i++) { for (j = 0; j < MAX_MOBILES_PER_ENB; j++) { Pdcp_stats_tx_window_ms[i][j]=100; Pdcp_stats_rx_window_ms[i][j]=100; } } memset(Pdcp_stats_tx, 0, sizeof(Pdcp_stats_tx)); memset(Pdcp_stats_tx_w, 0, sizeof(Pdcp_stats_tx_w)); memset(Pdcp_stats_tx_tmp_w, 0, sizeof(Pdcp_stats_tx_tmp_w)); memset(Pdcp_stats_tx_bytes, 0, sizeof(Pdcp_stats_tx_bytes)); memset(Pdcp_stats_tx_bytes_w, 0, sizeof(Pdcp_stats_tx_bytes_w)); memset(Pdcp_stats_tx_bytes_tmp_w, 0, sizeof(Pdcp_stats_tx_bytes_tmp_w)); memset(Pdcp_stats_tx_sn, 0, sizeof(Pdcp_stats_tx_sn)); memset(Pdcp_stats_tx_throughput_w, 0, sizeof(Pdcp_stats_tx_throughput_w)); memset(Pdcp_stats_tx_aiat, 0, sizeof(Pdcp_stats_tx_aiat)); memset(Pdcp_stats_tx_iat, 0, sizeof(Pdcp_stats_tx_iat)); memset(Pdcp_stats_rx, 0, sizeof(Pdcp_stats_rx)); memset(Pdcp_stats_rx_w, 0, sizeof(Pdcp_stats_rx_w)); memset(Pdcp_stats_rx_tmp_w, 0, sizeof(Pdcp_stats_rx_tmp_w)); memset(Pdcp_stats_rx_bytes, 0, sizeof(Pdcp_stats_rx_bytes)); memset(Pdcp_stats_rx_bytes_w, 0, sizeof(Pdcp_stats_rx_bytes_w)); memset(Pdcp_stats_rx_bytes_tmp_w, 0, sizeof(Pdcp_stats_rx_bytes_tmp_w)); memset(Pdcp_stats_rx_sn, 0, sizeof(Pdcp_stats_rx_sn)); memset(Pdcp_stats_rx_goodput_w, 0, sizeof(Pdcp_stats_rx_goodput_w)); memset(Pdcp_stats_rx_aiat, 0, sizeof(Pdcp_stats_rx_aiat)); memset(Pdcp_stats_rx_iat, 0, sizeof(Pdcp_stats_rx_iat)); memset(Pdcp_stats_rx_outoforder, 0, sizeof(Pdcp_stats_rx_outoforder)); } //----------------------------------------------------------------------------- void pdcp_layer_cleanup (void) //----------------------------------------------------------------------------- { //list_free (&pdcp_sdu_list); while(pollNotifiedFIFO(&pdcp_sdu_list)) {}; hashtable_destroy(&pdcp_coll_p); #ifdef MBMS_MULTICAST_OUT if(mbms_socket != -1) { close(mbms_socket); mbms_socket = -1; } #endif }