Files
openairinterface5g/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
T
Xenofon Foukas db4769bc35 Fixes to L2NFAPI_NOS1 dataplane traffic forwarding
This commit fixes a bug that makes the dataplane traffic of all the
emulated UEs to go through the interface of the first UE (oaitun_ue1).

The fix uses the last octet of the IP assigned to each UE to map it to its
UE_id, which is then used to get its RNTI and the correct PDCP queue.
For the emulator to work properly, the routing tables of the emulated UEs
must also be set. This patch introduces a script (setup_routes.sh) in
cmake_targets/tools that configures the routing tables. This script
must be run at the UE host machine once the UEs have successfully attached,
passing the number of emulated UEs as the argument. For example, in the
case of 16 emulated UEs, one must run "./setup_routes.sh 16".
2021-05-24 16:33:12 +01:00

2526 lines
97 KiB
C

/*
* 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(&gtpu_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
}