L2_interface_nb_iot.c 168 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/* 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.0  (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 l2_interface_nb_iot.c
 * \brief layer 2 interface, used to support different RRC sublayer
 * \author Raymond Knopp and Navid Nikaein
 * \date 2010-2014
 * \version 1.0
 * \company Eurecom
 * \email: raymond.knopp@eurecom.fr
 */
#include "PHY/defs.h"
30
#include "PHY/INIT/defs_nb_iot.h"
31 32 33 34
#include "SCHED/defs.h"
#include "platform_types.h"
#include "defs_nb_iot.h" //RRC
#include "LAYER2/MAC/defs_nb_iot.h" //MAC
35
#include "LAYER2/MAC/defs.h" // MAC because see the PHY functions
36 37 38 39 40 41 42
#include "extern.h"
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log.h"
#include "UTIL/OCG/OCG_vars.h"
#include "rrc_eNB_UE_context.h"
#include "pdcp_primitives.h"
#include "pdcp.h"
43 44
#include "pdcp_util.h"
#include "rlc.h"
45 46 47
#include "msc.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "gtpv1u.h"
48
#include "osa_defs.h"
49 50
#include "pdcp_sequence_manager.h"
#include "UTIL/OTG/otg_rx.h"
51
#include "openair2/PHY_INTERFACE/IF_Module_nb_iot.h"
52
#include "openair1/SCHED/IF_Module_L1_primitives_nb_iot.h"
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

#ifdef PHY_EMUL
#include "SIMULATION/simulation_defs.h"
extern EMULATION_VARS *Emul_vars;
extern eNB_MAC_INST *eNB_mac_inst;
extern UE_MAC_INST *UE_mac_inst;
#endif

#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
#endif

//#define RRC_DATA_REQ_DEBUG
#define DEBUG_RRC 1

//to add into platform types
typedef boolean_t srb1bis_flag_t;
70
#define SRB1BIS_FLAG_NO		FALSE
71 72
#define SRB1BIS_FLAG_YES	TRUE //defined in interTask-interface = 1

73 74 75 76
typedef boolean_t mib_flag_t;
#define MIB_FLAG_YES	TRUE
#define MIB_FLAG_NO		FALSE

77
//mui_t mui_NB=0;
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

//XXX MP: just temporary usage since i put in one single file all the primitives modified (but they should be relocated in the
//proper file where they are defined as indicated in the comments

//XXX access of protected variables in pdcp.h
extern unsigned int           pdcp_eNB_UE_instance_to_rnti_index;
extern rnti_t                 pdcp_eNB_UE_instance_to_rnti[NUMBER_OF_UE_MAX];
extern list_t                 pdcp_sdu_list;
//extern struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP);
//extern eNB_MAC_INST_NB *eNB;
extern void rlc_tm_init ( const protocol_ctxt_t* const  ctxt_pP, rlc_tm_entity_t * const rlcP);
extern void rlc_tm_set_debug_infos(
        const protocol_ctxt_t* const  ctxt_pP,
        rlc_tm_entity_t * const       rlcP,
        const srb_flag_t              srb_flagP,
        const rb_id_t                 rb_idP,
        const logical_chan_id_t chan_idP);
extern void rlc_tm_configure(
        const protocol_ctxt_t* const  ctxt_pP,
        rlc_tm_entity_t * const rlcP,
        const boolean_t is_uplink_downlinkP);
extern void     rlc_am_rx (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_data_ind);
extern tbs_size_t            mac_rlc_serialize_tb   (char*, list_t);
extern struct mac_data_ind mac_rlc_deserialize_tb (
		  char     *buffer_pP,
		  const tb_size_t tb_sizeP,
		  num_tb_t  num_tbP,
		  crc_t    *crcs_pP);
106 107 108 109
extern void rlc_am_init_timer_poll_retransmit(
	    const protocol_ctxt_t* const ctxt_pP,
	    rlc_am_entity_t* const       rlc_pP,
	    const uint32_t               time_outP);
110

111 112 113 114 115 116 117 118 119 120 121 122 123 124
//pointer function in rlc.h file
extern void (*rlc_rrc_data_ind_NB)(
                const protocol_ctxt_t* const ctxtP,
                const rb_id_t     rb_idP,
                const sdu_size_t  sdu_sizeP,
                const uint8_t   * const sduP,
				const srb1bis_flag_t srb1bis_flag);
extern void (*rlc_rrc_data_conf)(
        const protocol_ctxt_t* const ctxtP,
        const rb_id_t         rb_idP,
        const mui_t           muiP,
        const rlc_tx_status_t statusP);


125 126 127

/*---------------------------------RRC-MAC-----------------------------------*/

128 129 130 131 132
/*
 * This function is used to configured MAC and PHY layer. In the latter case, we first do a mapping of OAI params to the FAPI-like once
 * by filling the PHY_COnfig structure
 */

133 134 135 136 137
//defined in MAC/config.c
//FIXME: this function has no implication in terms of logical channel configuration for MAC
int NB_rrc_mac_config_req_eNB(
			   module_id_t       				Mod_idP,
			   int                              CC_idP,
138
			   int								rntiP,
139 140 141
			   int                              physCellId, // is the NcellID for NB-IoT
			   int                              p_eNB, //number of eNB TX antenna ports (1 or 2 for NB-IoT)
			   int								p_rx_eNB,// number of eNB Rx antenna ports (1 or 2 for NB-IoT)
142
			   int                              Ncp,
143
			   int								Ncp_UL,
144 145
//FIXME: frequencyBandIndicator (eutra_band) in sib1 (as Rymond Implementation) (is a long not an int!!)//XXX this param is set in the do_sib1_nb and is directly taken from the .config file
			   long                             eutra_band,
146 147 148
			   struct NS_PmaxList_NB_r13        *frequencyBandInfo, //optional SIB1
			   struct MultiBandInfoList_NB_r13  *multiBandInfoList, //optional SIB1
			   struct DL_Bitmap_NB_r13          *dl_bitmap, //optional SIB1
149
			   long*                            eutraControlRegionSize, //optional sib1, is defined only when we are in in-band operation mode (same PCI or different PCI)
150 151 152
			   long*							nrs_CRS_PoweSIwindowsizerOffset, //optional
//			   uint8_t                          *SIwindowsize, //maybe no more needed because TDD only
//			   uint16_t                         *SIperiod, //maybe no more needed because TDD only
153 154 155 156 157
			   uint32_t                         dl_CarrierFreq,
			   uint32_t                         ul_CarrierFreq,
			   BCCH_BCH_Message_NB_t            *mib_NB,
			   RadioResourceConfigCommonSIB_NB_r13_t   *radioResourceConfigCommon,
			   struct PhysicalConfigDedicated_NB_r13  *physicalConfigDedicated,
158
			   MAC_MainConfig_NB_r13_t                *mac_MainConfig, //most probably not needed since only used at UE side
159 160 161 162 163
			   long                             logicalChannelIdentity,//FIXME: decide how to use it
			   LogicalChannelConfig_NB_r13_t          *logicalChannelConfig //FIXME: decide how to use it
			   )
{

164
 /*XXX to review with the Raymond implementation*/
165

166 167 168

  int UE_id = -1;
  //eNB_MAC_INST_NB *eNB = &eNB_mac_inst_NB[Mod_idP];
169
  //UE_list_NB_t *UE_list= &eNB_mac_inst_NB->UE_list;
170
  UE_id = find_UE_id(Mod_idP, rntiP);
171 172 173

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN);

174 175 176
  config_INFO->get_MIB = 0;
  config_INFO->get_COMMON = 0;
  config_INFO->get_DEDICATED = 0;
177

178 179 180 181
  config_INFO->mod_id = Mod_idP;
  config_INFO->CC_id = CC_idP;


182 183 184


  if (mib_NB!=NULL ) {
185

186 187 188
   //if(eNB_mac_inst == NULL) l2_init_eNB(); //TODO MP: to be included in the MAC/main.c

   //mac_top_init_eNB(); //TODO MP:  to be included in the MAC/main.c
189

190

191 192 193
    eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].mib_NB           = mib_NB;
    eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].physCellId     = physCellId;
    eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].p_eNB          = p_eNB;
194
    eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].p_rx_eNB		= p_rx_eNB;
195
    eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].Ncp            = Ncp;
196
    eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].Ncp_UL         = Ncp_UL;
197 198 199
    eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].eutra_band     = eutra_band;
    eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].dl_CarrierFreq = dl_CarrierFreq;

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
//  NB_phy_config_mib_eNB(Mod_idP,
//		  	  	  	  	CC_idP,
//						eutra_band,
//						physCellId,
//						Ncp,
//						p_eNB,
//						dl_CarrierFreq,
//						ul_CarrierFreq);
//				  //mib_NB->message.operationModeInfo_r13); XXX check if needed or not

    /*
     * Following the FAPI like approach:
     * 1)fill the PHY_Config_t structure (PHY_INTERFACE/IF_Module_nb_iot.h)
     * 2)Call the PHY_config_req for trigger the NB_phy_config_mib_eNB()
     */

216 217 218 219

    //XXX where rymond allocate memory for cfg??
    if(config_INFO->cfg == NULL) LOG_E(MAC, "NB_rrc_mac_config_req_eNB: trying to configure PHY but no config.request message in config_INFO is allocated\n");

220 221
    config_INFO->get_MIB = 1;
    config_INFO->rnti = rntiP;
222
    config_INFO->frequency_band_indicator = (uint8_t)eutra_band; // guarda raimon
223 224 225 226 227
    config_INFO->cfg->sch_config.physical_cell_id.value = physCellId;
    config_INFO->cfg->subframe_config.dl_cyclic_prefix_type.value = Ncp;
    config_INFO->cfg->subframe_config.ul_cyclic_prefix_type.value = Ncp_UL;
    config_INFO->cfg->rf_config.tx_antenna_ports.value = p_eNB;
    config_INFO->cfg->rf_config.rx_antenna_ports.value = p_rx_eNB;
228 229 230
    config_INFO->dl_CarrierFreq = dl_CarrierFreq; //guarda raymond is in rf_config
    config_INFO->ul_CarrierFreq = ul_CarrierFreq; //guarda raymond

231 232 233 234 235

    switch (mib_NB->message.operationModeInfo_r13.present)
    {
    //FAPI specs pag 135
    case MasterInformationBlock_NB__operationModeInfo_r13_PR_inband_SamePCI_r13:
236 237 238
		config_INFO->cfg->nb_iot_config.operating_mode.value = 0;
		config_INFO->cfg->nb_iot_config.prb_index.value = mib_NB->message.operationModeInfo_r13.choice.inband_SamePCI_r13.eutra_CRS_SequenceInfo_r13; //see TS 36.213 ch 16.0
		config_INFO->cfg->nb_iot_config.assumed_crs_aps.value = -1; //is not defined so we put a negative value
239

240
		if(eutraControlRegionSize == NULL)
241
			LOG_E(RRC, "NB_rrc_mac_config_req_eNB: operation mode is in-band but eutraControlRegionSize is not defined");
242
		else
243
			config_INFO->cfg->nb_iot_config.control_region_size.value = *eutraControlRegionSize;
244

245 246
		break;
    case MasterInformationBlock_NB__operationModeInfo_r13_PR_inband_DifferentPCI_r13:
247
    	config_INFO->cfg->nb_iot_config.operating_mode.value = 1;
248 249

    	//XXX problem: fapi think to define also eutra_CRS_sequenceInfo also for in band with different PCI but the problem is that we don-t have it
250
    	//config_INFO->nb_iot_config.prb_index.value = mib_NB->message.operationModeInfo_r13.choice.inband_DifferentPCI_r13 XXX (see FAPI specs pag 135)
251

252
    	config_INFO->cfg->nb_iot_config.assumed_crs_aps.value = mib_NB->message.operationModeInfo_r13.choice.inband_DifferentPCI_r13.eutra_NumCRS_Ports_r13;
253

254
		if(eutraControlRegionSize == NULL)
255
			LOG_E(RRC, "NB_rrc_mac_config_req_eNB: operation mode is in-band but eutraControlRegionSize is not defined");
256
		else
257
			config_INFO->cfg->nb_iot_config.control_region_size.value = *eutraControlRegionSize;
258

259 260
    	break;
    case MasterInformationBlock_NB__operationModeInfo_r13_PR_guardband_r13:
261
    	config_INFO->cfg->nb_iot_config.operating_mode.value = 2;
262 263 264 265

    	//XXX problem: fapi think to define also eutra_CRS_sequenceInfo also for in band with different PCI but the problem is that we don-t have it
    	//config_INFO->nb_iot_config.prb_index = mib_NB->message.operationModeInfo_r13.choice.guardband_r13; XXX (see FAPI specs pag 135)

266 267
    	config_INFO->cfg->nb_iot_config.control_region_size.value = -1; //should not being defined so we put a negative value
		config_INFO->cfg->nb_iot_config.assumed_crs_aps.value = -1; //is not defined so we put a negative value
268 269
    	break;
    case MasterInformationBlock_NB__operationModeInfo_r13_PR_standalone_r13:
270 271 272 273
    	config_INFO->cfg->nb_iot_config.operating_mode.value = 3;
    	config_INFO->cfg->nb_iot_config.prb_index.value = -1; // is not defined for this case (put a negative value)
    	config_INFO->cfg->nb_iot_config.control_region_size.value = -1;//is not defined so we put a negative value
		config_INFO->cfg->nb_iot_config.assumed_crs_aps.value = -1; //is not defined so we put a negative value
274 275 276 277 278 279
    	break;
    default:
    	LOG_E(RRC, "NB_rrc_mac_config_req_eNB: NB-IoT operating Mode (MIB-NB) not valid\n");
    	break;
    }

280 281 282 283
    if(if_inst->PHY_config_req)
    	if_inst->PHY_config_req(config_INFO); //for trigger the NB_phy_config_mib_eNB()
    else
    	LOG_E(RRC, "NB_rrc_mac_config_req_eNB: PHY_config_req pointer function is NULL\n");
284

285 286 287 288
  }


  if (radioResourceConfigCommon!=NULL) {
289

290 291
	  if(config_INFO->cfg == NULL) LOG_E(MAC, "NB_rrc_mac_config_req_eNB: trying to configure PHY but no config.request message in config_INFO is allocated\n");

292 293
	  config_INFO->get_COMMON = 1;

294
      LOG_I(MAC,"[CONFIG]SIB2/3-NB radioResourceConfigCommon Contents (partial)\n");
295

296 297
      LOG_I(MAC,"[CONFIG]npusch_ConfigCommon_r13.dmrs_Config_r13->threeTone_CyclicShift_r13= %ld\n", radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->threeTone_CyclicShift_r13);
      LOG_I(MAC,"[CONFIG]npusch_ConfigCommon_r13.dmrs_Config_r13->sixTone_CyclicShift_r13= %ld\n", radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->sixTone_CyclicShift_r13);
298
      LOG_I(MAC,"[CONFIG]npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupHoppingEnabled_r13= %d\n", radioResourceConfigCommon->npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupHoppingEnabled_r13);
299
      LOG_I(MAC,"[CONFIG]npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupAssignmentNPUSCH_r13= %ld\n", radioResourceConfigCommon->npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupAssignmentNPUSCH_r13);
300

301 302 303 304 305

      eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].radioResourceConfigCommon = radioResourceConfigCommon;

      if (ul_CarrierFreq>0) eNB_mac_inst_NB[Mod_idP].common_channels[CC_idP].ul_CarrierFreq   = ul_CarrierFreq;

306 307 308 309 310

      /*
       * Following the FAPI like approach:
       * 1)fill the PHY_Config_t structure (PHY_INTERFACE/IF_Module_nb_iot.h)
       * 1.1) check for how many NPRACH resources has been set and enable the corresponding parameter
311
       * 1.2)fill the structure PHY_Config_t (shared structure of the IF_Module
312 313 314 315 316
       * 2)Call the PHY_config_req for trigger the NB_phy_config_sib2_eNB()
       */

      /*NPRACH Resources*/

317 318
      NPRACH_Parameters_NB_r13_t* nprach_parameter;

319 320 321
	  config_INFO->cfg->nb_iot_config.nprach_config_0_enabled.value = 0;
	  config_INFO->cfg->nb_iot_config.nprach_config_1_enabled.value = 0;
	  config_INFO->cfg->nb_iot_config.nprach_config_2_enabled.value = 0;
322 323 324 325 326 327

      switch(radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.size)
      {
      case 0:
    	  break;
      case 1:
328
    	  nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[0];
329 330 331 332 333 334 335
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_enabled.value = 1;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_start_time.value = nprach_parameter->nprach_StartTime_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
336 337 338 339 340 341
    	  //MP: missed configuration for FAPI-style structure (I have added on my own byt maybe are not needed)
    	  config_INFO->extra_phy_parms.nprach_config_0_subcarrier_MSG3_range_start = nprach_parameter->nprach_SubcarrierMSG3_RangeStart_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_max_num_preamble_attempt_CE = nprach_parameter->maxNumPreambleAttemptCE_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_num_repetitions_RA = nprach_parameter->npdcch_NumRepetitions_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_startSF_CSS_RA = nprach_parameter->npdcch_StartSF_CSS_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_offset_RA = nprach_parameter->npdcch_Offset_RA_r13;
342
    	  //rsrp_ThresholdsPrachInfoList_r13 /*OPTIONAL*/
343

344 345
    	  break;
      case 2:
346
    	  nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[0];
347 348 349 350 351 352 353
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_enabled.value = 1;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_start_time.value = nprach_parameter->nprach_StartTime_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
354 355 356 357 358 359 360 361
    	  //MP: missed configuration for FAPI-style structure (I have added on my own byt maybe are not needed)
    	  config_INFO->extra_phy_parms.nprach_config_0_subcarrier_MSG3_range_start = nprach_parameter->nprach_SubcarrierMSG3_RangeStart_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_max_num_preamble_attempt_CE = nprach_parameter->maxNumPreambleAttemptCE_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_num_repetitions_RA = nprach_parameter->npdcch_NumRepetitions_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_startSF_CSS_RA = nprach_parameter->npdcch_StartSF_CSS_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_offset_RA = nprach_parameter->npdcch_Offset_RA_r13;
    	  //rsrp_ThresholdsPrachInfoList_r13 /*OPTIONAL*/

362 363

    	  nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[1];
364 365 366 367 368 369 370
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_enabled.value = 1;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_start_time.value = nprach_parameter->nprach_StartTime_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
371 372 373 374 375 376 377
    	  //MP: missed configuration for FAPI-style structure (I have added on my own byt maybe are not needed)
    	  config_INFO->extra_phy_parms.nprach_config_1_subcarrier_MSG3_range_start = nprach_parameter->nprach_SubcarrierMSG3_RangeStart_r13;
    	  config_INFO->extra_phy_parms.nprach_config_1_max_num_preamble_attempt_CE = nprach_parameter->maxNumPreambleAttemptCE_r13;
    	  config_INFO->extra_phy_parms.nprach_config_1_npdcch_num_repetitions_RA = nprach_parameter->npdcch_NumRepetitions_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_1_npdcch_startSF_CSS_RA = nprach_parameter->npdcch_StartSF_CSS_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_1_npdcch_offset_RA = nprach_parameter->npdcch_Offset_RA_r13;
    	  //rsrp_ThresholdsPrachInfoList_r13 /*OPTIONAL*/
378 379
    	  break;
      case 3:
380
    	  nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[0];
381 382 383 384 385 386 387
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_enabled.value = 1;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_start_time.value = nprach_parameter->nprach_StartTime_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_0_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
388 389 390 391 392 393 394 395
    	  //MP: missed configuration for FAPI-style structure (I have added on my own byt maybe are not needed)
    	  config_INFO->extra_phy_parms.nprach_config_0_subcarrier_MSG3_range_start = nprach_parameter->nprach_SubcarrierMSG3_RangeStart_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_max_num_preamble_attempt_CE = nprach_parameter->maxNumPreambleAttemptCE_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_num_repetitions_RA = nprach_parameter->npdcch_NumRepetitions_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_startSF_CSS_RA = nprach_parameter->npdcch_StartSF_CSS_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_0_npdcch_offset_RA = nprach_parameter->npdcch_Offset_RA_r13;
    	  //rsrp_ThresholdsPrachInfoList_r13 /*OPTIONAL*/

396 397

    	  nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[1];
398 399 400 401 402 403 404
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_enabled.value = 1;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_start_time.value = nprach_parameter->nprach_StartTime_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_1_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
405 406 407 408 409 410 411
    	  //MP: missed configuration for FAPI-style structure (I have added on my own byt maybe are not needed)
    	  config_INFO->extra_phy_parms.nprach_config_1_subcarrier_MSG3_range_start = nprach_parameter->nprach_SubcarrierMSG3_RangeStart_r13;
    	  config_INFO->extra_phy_parms.nprach_config_1_max_num_preamble_attempt_CE = nprach_parameter->maxNumPreambleAttemptCE_r13;
    	  config_INFO->extra_phy_parms.nprach_config_1_npdcch_num_repetitions_RA = nprach_parameter->npdcch_NumRepetitions_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_1_npdcch_startSF_CSS_RA = nprach_parameter->npdcch_StartSF_CSS_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_1_npdcch_offset_RA = nprach_parameter->npdcch_Offset_RA_r13;
    	  //rsrp_ThresholdsPrachInfoList_r13 /*OPTIONAL*/
412

413 414

    	  nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[2];
415 416 417 418 419 420 421
    	  config_INFO->cfg->nb_iot_config.nprach_config_2_enabled.value = 1;
    	  config_INFO->cfg->nb_iot_config.nprach_config_2_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_2_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_2_start_time.value = nprach_parameter->nprach_StartTime_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_2_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_2_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
    	  config_INFO->cfg->nb_iot_config.nprach_config_2_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
422 423 424 425 426 427 428 429
    	  //MP: missed configuration for FAPI-style structure (I have added on my own byt maybe are not needed)
    	  config_INFO->extra_phy_parms.nprach_config_2_subcarrier_MSG3_range_start = nprach_parameter->nprach_SubcarrierMSG3_RangeStart_r13;
    	  config_INFO->extra_phy_parms.nprach_config_2_max_num_preamble_attempt_CE = nprach_parameter->maxNumPreambleAttemptCE_r13;
    	  config_INFO->extra_phy_parms.nprach_config_2_npdcch_num_repetitions_RA = nprach_parameter->npdcch_NumRepetitions_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_2_npdcch_startSF_CSS_RA = nprach_parameter->npdcch_StartSF_CSS_RA_r13;
    	  config_INFO->extra_phy_parms.nprach_config_2_npdcch_offset_RA = nprach_parameter->npdcch_Offset_RA_r13;
    	  //rsrp_ThresholdsPrachInfoList_r13 /*OPTIONAL*/
    	  break;
430

431 432 433 434 435 436
    	  break;
      default:
    	  LOG_E(RRC,"NB_rrc_mac_config_req_eNB: nprach_ParametersList size not valid\n");

      }

437 438 439
      /*NPDSCH ConfigCommon*/

      //FIXME: MP: FAPI specs define a range of value [0-255]==[0db - 63.75db] with 0.25db step -- corrispondence in 3GPP specs???
440
      config_INFO->cfg->rf_config.reference_signal_power.value = radioResourceConfigCommon->npdsch_ConfigCommon_r13.nrs_Power_r13;
441 442 443

      /*NPUSCH ConfigCommon*/

444
      //a pointer to the first element of the list
445
      config_INFO->extra_phy_parms.ack_nack_numRepetitions_MSG4 = radioResourceConfigCommon->npusch_ConfigCommon_r13.ack_NACK_NumRepetitions_Msg4_r13.list.array[0];
446 447 448


      if(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13 != NULL)/* OPTIONAL */
449 450 451
      {
    	  /* OPTIONAL */
    	  if(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->threeTone_BaseSequence_r13!= NULL)
452
    		  config_INFO->cfg->nb_iot_config.three_tone_base_sequence.value  = *(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->threeTone_BaseSequence_r13);
453 454
    	  /* OPTIONAL */
    	  if(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->sixTone_BaseSequence_r13!= NULL)
455
    		  config_INFO->cfg->nb_iot_config.six_tone_base_sequence.value = *(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->sixTone_BaseSequence_r13);
456 457
    	  /* OPTIONAL */
		  if(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->twelveTone_BaseSequence_r13!= NULL)
458
			  config_INFO->cfg->nb_iot_config.twelve_tone_base_sequence.value = *(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->twelveTone_BaseSequence_r13);
459

460 461
		  config_INFO->cfg->nb_iot_config.three_tone_cyclic_shift.value = radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->threeTone_CyclicShift_r13;
		  config_INFO->cfg->nb_iot_config.six_tone_cyclic_shift.value = radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->sixTone_CyclicShift_r13;
462 463
      }

464 465 466

      //NOTE: MP: FAPI specs for UL RS Configurations seems to be targeted for LTE and not for NB-IoT
      if(radioResourceConfigCommon->npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupHoppingEnabled_r13 == TRUE)
467
    	  config_INFO->cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; //RS_GROUP_HOPPING (FAPI specs pag 127)
468
      else
469
    	  config_INFO->cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0;//RS_NO_HOPPING
470

471
      config_INFO->cfg->uplink_reference_signal_config.group_assignment.value = radioResourceConfigCommon->npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupAssignmentNPUSCH_r13;
472

473 474 475 476
      //Some missed parameters are in UL_CONFIG.request message (P7) in FAPI specs. and not configured through P5 procedure
	   //ack_NACK_NumRepetitions_Msg4_r13
	   //srs_SubframeConfig_r13 /* OPTIONAL */

477 478
	  /*DL GAP config */
      if(radioResourceConfigCommon->dl_Gap_r13 !=NULL)/* OPTIONAL */
479
      {
480 481 482 483
    	  config_INFO->cfg->nb_iot_config.dl_gap_config_enable.value = 1;
    	  config_INFO->cfg->nb_iot_config.dl_gap_threshold.value = radioResourceConfigCommon->dl_Gap_r13->dl_GapThreshold_r13;
		  config_INFO->cfg->nb_iot_config.dl_gap_duration_coefficient.value = radioResourceConfigCommon->dl_Gap_r13->dl_GapDurationCoeff_r13;
		  config_INFO->cfg->nb_iot_config.dl_gap_periodicity.value = radioResourceConfigCommon->dl_Gap_r13->dl_GapPeriodicity_r13;
484 485
      }
      else
486
    	  config_INFO->cfg->nb_iot_config.dl_gap_config_enable.value = 0;
487 488


489 490
	  /*UL Power Control ConfigCommon*/
      //nothing defined in FAPI specs
491 492 493
      config_INFO->extra_phy_parms.p0_nominal_npusch = radioResourceConfigCommon->uplinkPowerControlCommon_r13.p0_NominalNPUSCH_r13;
      config_INFO->extra_phy_parms.alpha = radioResourceConfigCommon->uplinkPowerControlCommon_r13.alpha_r13;
      config_INFO->extra_phy_parms.delta_preamle_MSG3 = radioResourceConfigCommon->uplinkPowerControlCommon_r13.deltaPreambleMsg3_r13;
494

495 496 497
	  /*RACH Config Common*/
      //nothing defined in FAPI specs

498 499 500 501 502

      if(if_inst->PHY_config_req)
      	if_inst->PHY_config_req(config_INFO); //for trigger the NB_phy_config_sib2_eNB()
      else
      	LOG_E(RRC, "NB_rrc_mac_config_req_eNB: PHY_config_req pointer function is NULL\n");
503 504 505 506 507 508

      //     NB_phy_config_sib2_eNB(
      //    		  Mod_idP,
      //    		  CC_idP,
      //			  radioResourceConfigCommon
      //			  );
509 510 511 512

  }

  if (logicalChannelConfig!= NULL) {
513 514 515 516


	if(config_INFO->cfg == NULL) LOG_E(MAC, "NB_rrc_mac_config_req_eNB: trying to configure PHY but no config.request message in config_INFO is allocated\n");

517 518 519
    if (UE_id == -1) {
      LOG_E(MAC,"%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, __LINE__, __FUNCTION__);
    } else {
520 521
    	//logical channel group not defined for nb-iot --> no UL specific Parameter
    	// or at least LCGID should be set to 0 for NB-IoT (See TS 36.321 ch 6.1.3.1) so no make sense to store this
522 523 524 525 526
    }
  }


  if (physicalConfigDedicated != NULL) {
527

528 529 530

	if(config_INFO->cfg == NULL) LOG_E(MAC, "NB_rrc_mac_config_req_eNB: trying to configure PHY but no config.request message in config_INFO is allocated\n");

531 532 533 534
    if (UE_id == -1)
      LOG_E(MAC,"%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, __LINE__, __FUNCTION__);
    else
    {
535
    	config_INFO->get_DEDICATED = 1;
536 537 538
    	config_INFO->rnti = UE_RNTI(Mod_idP, UE_id);
    	config_INFO->phy_config_dedicated = physicalConfigDedicated;

539 540 541 542
        if(if_inst->PHY_config_req)
        	if_inst->PHY_config_req(config_INFO); //for trigger the NB_phy_config_dedicated_eNB()
        else
        	LOG_E(RRC, "NB_rrc_mac_config_req_eNB: PHY_config_req pointer function is NULL\n");
543 544 545 546 547 548

//    	NB_phy_config_dedicated_eNB(
//    								Mod_idP,
//									CC_idP,
//									UE_RNTI(Mod_idP, UE_id),
//									physicalConfigDedicated);
549

550 551 552 553 554 555 556 557
    }
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT);
  return(0);

}

558
//-------------------------------------------------------
559
//New
560 561
int npdsch_rep_to_array[3] ={4,8,16}; //TS 36.213 Table 16.4.1.3-3
int sib1_startFrame_to_array[4] = {0,16,32,48};//TS 36.213 Table 16.4.1.3-4
562
//New----------------------------------------------------
563
//return -1 whenever no SIB1-NB transmission occur.
564
//return sib1_startFrame when transmission occur in the current frame
565
uint32_t is_SIB1_NB(
566 567 568 569
		const frame_t    		frameP,
		long					schedulingInfoSIB1,//from the mib
		int						physCellId, //by configuration
		NB_IoT_eNB_NDLSCH_t		*ndlsch_SIB1
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
		)
{
	uint8_t nb_rep=0; // number of sib1-nb repetitions within the 256 radio frames
	uint32_t sib1_startFrame;
	uint32_t sib1_NB_period = 256;//from specs TS 36.331 (rf)
	uint8_t index;
	int offset;
	int period_nb; // the number of the actual period over the 1024 frames



			/*SIB1
	         *
	         * the entire scheduling of SIB1-NB is based on the SchedulingInfoSIB1 of MIB-NB
	         *
	         * SIB1-NB transmission occurs in subframe #4 of every other frame in 16 continuous frames (i.e. alternate frames)
	         * schedule with a periodicity of 2560 ms (256 Radio Frames) and repetitions (4, 8 or 16) are made, equally spaced
	         * within the 2560 ms period
	         *
589 590
	         * 0.0) check the input parameters
	         * 0)find the SIB1-NB period number over the 1024 frames in which the actual frame fall
591 592 593
	         * 1)from the schedulingInfoSIB1 of MIB-NB and the physCell_id we deduce the starting radio frame
	         * 2)check if the actual frame is after the staring radio frame
	         * 3)check if the actual frame is within a SIB1-transmission interval
594
	         * 4)based on the starting radio frame we can state  when SIB1-NB is transmitted in odd or even frame (commented)
595 596
	         * (if the starting frame is even (0,16,32,48) then SIB1-NB is transmitted in even frames, if starting frame is odd (1)
	         * we can state that SIB1-NB will be transmitted in every odd frame since repetitions are 16 in 256 radio frame period)
597 598
	         * 4bis) we do a for loop over the 16 continuous frame (hopping by 2) for check if the frame is considered in that interval

599 600 601 602 603 604
	         *
	         * *0) is necessary because at least i need to know in which of the even frames the repetition are -> is based on the offset
	         * *in 1023 frames there are exactly 4 period of SIB1-NB
	         **/


605 606 607 608 609 610 611

    		if(schedulingInfoSIB1 > 11 || schedulingInfoSIB1 < 0){
    			LOG_E(RRC, "is_SIB1_NB: schedulingInfoSIB1 value not allowed");
    			return 0;
    		}


612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
		  //SIB1-NB period number
		  period_nb = (int) frameP/sib1_NB_period;


	      //number of repetitions
	      nb_rep = npdsch_rep_to_array[schedulingInfoSIB1%3];

	      //based on number of rep. and the physical cell id we derive the starting radio frame (TS 36.213 Table 16.4.1.3-3/4)
	      switch(nb_rep)
	      {
	      case 4:
	    	  //physCellId%4 possible value are 0,1,2,3
	    	  sib1_startFrame = sib1_startFrame_to_array[physCellId%4];
	    	  break;
	      case 8:
	    	  //physCellId%2possible value are 0,1
	    	  sib1_startFrame = sib1_startFrame_to_array[physCellId%2];
	    	  break;
	      case 16:
	    	  //physCellId%2 possible value are 0,1
	    	  if(physCellId%2 == 0)
	    		  sib1_startFrame = 0;
	    	  else
	    		  sib1_startFrame = 1; // the only case in which the starting frame is odd
	    	  break;
	      default:
	    	  LOG_E(RRC, "Number of repetitions %d not allowed", nb_rep);
639
	    	  return -1;
640 641 642 643 644
	      }

	      //check the actual frame w.r.t SIB1-NB starting frame
	      if(frameP < sib1_startFrame + period_nb*256){
	    	  LOG_T(RRC, "the actual frame %d is before the SIB1-NB starting frame %d of the period--> bcch_sdu_legnth = 0", frameP, sib1_startFrame + period_nb*256);
645
	    	  return -1;
646 647 648 649 650 651 652 653 654 655 656 657 658 659
	      }


	      //calculate offset between SIB1-NB repetitions (repetitions are equally spaced)
	      offset = (sib1_NB_period-(16*nb_rep))/nb_rep;
	      /*
	       * possible offset results (even numbers):
	       * nb_rep= 4 ---> offset = 48
	       * nb_rep = 8 --> offset = 16
	       * nb_rep = 16 --> offset = 0
	       */



660
	      //loop over the SIB1-NB period
661 662 663 664
	      for( int i = 0; i < nb_rep; i++)
	      {
	    	  //find the correct sib1-nb repetition interval in which the actual frame is

665
	    	  //this is the start frame of a repetition
666 667
	    	  index = sib1_startFrame+ i*(16+offset) + period_nb*256;

668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
	    	  //the actual frame is in a gap between two consecutive repetitions
	    	  if(frameP < index)
	    	  {
	    		  	ndlsch_SIB1->sib1_rep_start = 0;
	    		  	ndlsch_SIB1->relative_sib1_frame = 0;
	    	  	    return -1;
	    	  }
	    	  //this is needed for ndlsch_procedure
	    	  else if(frameP == index)
	    	  {
	    		  //the actual frame is the start of a new repetition (SIB1-NB should be retransmitted)
	    		  ndlsch_SIB1->sib1_rep_start = 1;
	    		  ndlsch_SIB1->relative_sib1_frame = 1;
	    		  return sib1_startFrame;
	    	  }
	    	  else
	    		  ndlsch_SIB1->sib1_rep_start = 0;

	    	  //check in the current SIB1_NB repetition
	    	  if(frameP>= index && frameP <= (index+15))
688 689 690
	    	  {
	    		  //find if the actual frame is one of the "every other frame in 16 continuous frame" in which SIB1-NB is transmitted

691 692 693 694 695 696
	    		  for(int y = 0; y < 16; y += 2) //every other frame (increment by 2)
	    		  {
	    			  if(frameP == index + y)
	    			  {
	    				  //this flag tell which is the number of the current frame w.r.t the 8th (over the continuous 16) in a repetition
	    				  ndlsch_SIB1->relative_sib1_frame = y/2 + 1; //1st, 2nd, 3rd,...
697
	    				  return sib1_startFrame;
698
	    			  }
699 700
	    		  }

701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
	    		  //if we are here means that the frame was inside the repetition interval but not considered for SIB1-NB transmission
	    		  ndlsch_SIB1->relative_sib1_frame = 0;
	    		  return -1;

//XXX this part has been commented because in case that the "relative_sib1_frame" flag is not needed is necessary just a simple check if even or odd frame depending on sib1_startFrame

//	    		  if(sib1_startFrame%2 != 0){ // means that the starting frame was 1 --> sib1-NB is transmitted in every odd frame
//	    			  if(frameP%2 == 1){ //the actual frame is odd
//	    				  return sib1_startFrame;
//	    			 }
//	    		  }
//
//	    		  //in all other starting frame cases SIB1-NB is transmitted in the even frames inside the corresponding repetition interval
//	    		  if(frameP%2 == 0){ // SIB1-NB is transmitted
//	    			  return sib1_startFrame;
//	    		  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------
718 719 720 721
	    	  }

	      }

722
	      return -1;
723
}
724

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
//New----------------------------------------------------
//Function for check if the current frame is the start of a new SIB1-NB period
uint8_t is_SIB1_NB_start(
		const frame_t    		frameP,
		long					schedulingInfoSIB1,//from the mib
		int						physCellId //by configuration
		)
{
	uint8_t nb_rep=0; // number of sib1-nb repetitions within the 256 radio frames
	uint32_t sib1_startFrame;
	uint32_t sib1_NB_period = 256;//from specs TS 36.331 (rf)
	uint8_t index;
	int offset;
	int period_nb; // the number of the actual period over the 1024 frames


    		if(schedulingInfoSIB1 > 11 || schedulingInfoSIB1 < 0){
    			LOG_E(RRC, "is_SIB1_NB: schedulingInfoSIB1 value not allowed");
    			return 0;
    		}

	      //number of repetitions
	      nb_rep = npdsch_rep_to_array[schedulingInfoSIB1%3];

	      //based on number of rep. and the physical cell id we derive the starting radio frame (TS 36.213 Table 16.4.1.3-3/4)
	      switch(nb_rep)
	      {
	      case 4:
	    	  //physCellId%4 possible value are 0,1,2,3
	    	  sib1_startFrame = sib1_startFrame_to_array[physCellId%4];
	    	  break;
	      case 8:
	    	  //physCellId%2possible value are 0,1
	    	  sib1_startFrame = sib1_startFrame_to_array[physCellId%2];
	    	  break;
	      case 16:
	    	  //physCellId%2 possible value are 0,1
	    	  if(physCellId%2 == 0)
	    		  sib1_startFrame = 0;
	    	  else
	    		  sib1_startFrame = 1; // the only case in which the starting frame is odd
	    	  break;
	      default:
	    	  LOG_E(RRC, "Number of repetitions %d not allowed", nb_rep);
	    	  return -1;
	      }

	      if((frameP-sib1_startFrame)%256 == 0)
	    	  return 0;
	      else
	    	  return -1;

}
//-------------------------------------------------------

780 781 782 783 784 785 786 787 788
//---------------------------------------------------------------------------
//New
int si_windowLength_to_rf[7]={16,32,48,64,96,128,160}; //TS 36.331  v14.2.1 pag 587
int si_repPattern_to_nb[4]={2,4,8,16};
int si_period_to_nb[7]={64,128,256,512,1024,2048,4096};
//New---------------------------------------------------------------------------
boolean_t is_SIB23_NB(
		const frame_t     	frameP,
		const frame_t		h_frameP, // the HSFN (increased by 1 every SFN wrap around) (10 bits)
789 790
		long				si_period, //SI-periodicity (value given by the Enumerative of the SIB1-NB)
		long				si_windowLength_ms, //Si-windowlength (ms) received as an enumerative (see the IE of SIB1-NB)
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
		long*				si_RadioFrameOffset, //Optional
		long				si_RepetitionPattern // is given as an Enumerated
		)
{

	long w_start; //start of the si-window
	long nb_periods; // number of si_periodicity inside an HSFN (1024 rf)
	long si_offset; // offset for the starting of the SI-window
	long si_windowLength;
	long si_pattern;
	long hsfn_in_periodicity;
	long si_periodicity;


	/*
806
	 * SIB23-NB
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
	 *
	 * The entire scheduling of the SI-Message is given by SIB1-NB information
	 *
	 * Parameters:
	 * -si_windowlenght(w) (millisecond) (same for all SI messages)
	 * -si_radioFrameOffset (radio frame) (same for all SI messages) //optional
	 * -si_periodicity (T) (radioframe)
	 * -si_repetitionPattern (long)
	 *
	 * Staring of the SI-Window: (TS 36.331 ch 5.2.3a)
	 * >Since we have only 1 entry in the SchedulingInfoList (SIB23-NB) --> n=1
	 * >therefore  x = (n-1)*w = 0
	 * >Staring subframe = #0
	 * >Starting Frame = (HSFN*1024 + SFN) mod T = FLOOR(x/10 = 0) + si_radioFrameOffset = si_radioFrameOffset
	 *
	 *Procedure
	 *0) get the si_period in frame and check if the actual frame is in an HSFN interval that will include an si-window
	 *0.1)check si_window value is not a spare and get the si_windowLength in radio frames
	 *0.2)check si-window length and si-periodicity relation make sense
	 *0.3) get the si_repetitionPattern
	 *0.4)Since the si_offset is optional, whenever is not defined we put to 0 that value otherwise we use the value defined
	 *1)consider the number of time of si_periodiciy within 1 HFSN (1024) because after SFN wrap around
	 *2)evaluate the start of the si_window and check over the nb_periodicity if the current frame is within one of them
	 *3)check is the si_offset is even or odd
	 *
	 *NOTE1:
	 *(due to the si_repetitionPattern that start from the first frame of the si_window used and any value is even)
	 *-if si_offset is even: the radio frame for SI-Transmission must be even (following the repPattern)
	 *-if si_offset is odd:  the radio frame for the SI-Transmission must be odd (following the pattern)
	 *
	 *NOTE2:
	 *the starting frame (thanks to HSFN) is always between 0-1023 --> the working interval to be considered
	 *the nb_periods is not affected by the offset since maxOffset = 15 but the minPeriodicity = 64
	 *
	 */

	if(si_period == SchedulingInfo_NB_r13__si_Periodicity_r13_spare)
	{
		LOG_E(RRC, "is_SIB23_NB: Invalid parameters in SIB1-NB --> si_periodicity not defined (spare value)\n");
						return FALSE;
	}

849
	//translate the enumerative into numer of Radio Frames
850 851 852
	si_periodicity = si_period_to_nb[si_period];

	//check if the actual frame is within an HSFN interval that will include si-window (relation with the si-periodicity)
853
	//this could happen when the si-periodicity is larger than a HSFN interval (1024 rf)
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
	hsfn_in_periodicity = (int) si_periodicity/1024;

	if(hsfn_in_periodicity > 1){//periodicity is larger than 1024rf (HSFN) and  not in all the hsfn a transmission will occurr

		if(h_frameP%hsfn_in_periodicity != 0)// is not an hsfn inside the periodicity in which a transmission will occurr
		{
		LOG_I(RRC, "the actual HSFN correspond to an interval in which a SIB23 transmission will not occurr\n");
		return FALSE;
		}
	}

	if(si_windowLength_ms == SystemInformationBlockType1_NB__si_WindowLength_r13_spare1){
		LOG_E(RRC, "is_SIB23_NB: Invalid parameters in SIB1-NB --> si_windowLength not defined (spare value)\n");
				return FALSE;
	}

870
	//get the si_window from enumerative into Radio FRames
871 872 873 874 875 876 877
	si_windowLength = si_windowLength_to_rf[si_windowLength_ms];

	if(si_windowLength > si_periodicity){
		LOG_E(RRC, "is_SIB23_NB: Invalid parameters in SIB1-NB --> si_windowLength > si_periodicity\n");
		return FALSE;
	}

878
	//get the si_pattern from the enumerative
879 880
	si_pattern = si_repPattern_to_nb[si_RepetitionPattern];

881
	if(si_RadioFrameOffset == NULL)//may is not defined since is optional
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922
	{
		LOG_I(RRC, "si_RadioFrame offset was NULL --> set = 0\n");
		si_offset = 0;
	}
	else{
		si_offset = *(si_RadioFrameOffset);
	}


	//check how many nb_of periods in 1 hsfn
	if(si_periodicity >= 1024){
		nb_periods = 1;
	}
	else
		nb_periods = 1024L / si_periodicity; // can get: 16,8,4,2 based on si_peridicity values


	for(int i = 0; i < nb_periods; i++) {

		w_start = si_offset+(i*si_periodicity); //if si_periodicity >= 1024--> imax =0

	    if(frameP >= w_start && frameP <= w_start + si_windowLength -1)
	    {
	    	//this implementation is quite inefficent --> loop through the si-window
	    	for(int x= 0; x < si_windowLength/si_pattern; x++)
	    	{
	    		 if(frameP == w_start +x*si_pattern)
	    			 return 1;
	    	}

	    	return 0; //the frame is in the si_window bu not belongs to the repetition pattern
	    }

	    if(w_start > frameP)// the frame is out of the si_window in the current period
	    	return FALSE;
	}

	return FALSE;
}

//defined in L2_interface
923 924
//function called by eNB_dlsch_ulsch_scheduler--> Schedule_SI (eNB_scheduler_bch) for getting the bcch_sdu_legnth (BCCH case for SIBs and MIB)
//Function called in schedule_RA for getting RRCConnectionSetup message (Msg4) length of rrc_sdu_length (CCCH case)
925
//Function will be called by schedule_MIB??? when subframe#0
926 927 928 929
int8_t NB_mac_rrc_data_req_eNB(
  const module_id_t Mod_idP,
  const int         CC_id,
  const frame_t     frameP,
930
  const frame_t		h_frameP,
931
  const sub_frame_t   subframeP, //need for the case in which both SIB1-NB and SIB23-NB will be scheduled in the same frame
932 933
  const rb_id_t     Srb_id,
  uint8_t*    const buffer_pP,
934 935
  long				schedulingInfoSIB1,//from the mib
  int				physCellId, //from the MAC instance-> common_channel
936
  mib_flag_t		mib_flag
937 938
)
{
939
  SRB_INFO_NB *Srb_info;
940
  uint8_t Sdu_size=0;
941

942 943 944 945 946 947

#ifdef DEBUG_RRC
  int i;
  LOG_T(RRC,"[eNB %d] NB_mac_rrc_data_req_eNB to SRB ID=%d\n",Mod_idP,Srb_id);
#endif

948

949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
    if((Srb_id & RAB_OFFSET) == BCCH){


     // Requesting for the MIB-NB
      if(mib_flag == MIB_FLAG_YES){

    	  //XXX to be check when MIB-NB should be initialized
    	  if (eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_MIB_NB == 255) {
    	       LOG_E(RRC,"[eNB %d] MAC Request for MIB-NB and MIB-NB not initialized\n",Mod_idP);
    	       mac_xface->macphy_exit("NB_mac_rrc_data_req_eNB:  MAC Request for MIB-NB and MIB-NB not initialized");
    	   }

    	  memcpy(&buffer_pP[0],
    	      	eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].MIB_NB,
    	      	eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_MIB_NB);
964

965
    	  	//XXX RRC_MAC_BCCH_DATA_REQ message not implemented in MAC layer (eNB_scheduler.c under ITTI)
966

967 968
    	  	#ifdef DEBUG_RRC
    	      LOG_T(RRC,"[eNB %d] Frame %d : BCCH request => MIB_NB\n",Mod_idP,frameP);
969

970 971 972
    	     for (i=0; i<eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_MIB_NB; i++) {
    	      		    LOG_T(RRC,"%x.",buffer_pP[i]);
    	      	}
973

974 975 976
    	      		    LOG_T(RRC,"\n");
    	    #endif

977
    	    return (eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_MIB_NB); //exit from the function
978 979 980 981
      }

      //Requesting for SI Message
      //XXX to be check when it is initialized
982
      if(eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].SI.Active==0) { //is set when we call openair_rrc_on function
983
    	  LOG_E(RRC, "SI value on the carrier = 0");
984 985 986
        return 0;
      }

987 988 989
      if(schedulingInfoSIB1 > 11 || schedulingInfoSIB1 < 0){
    	  LOG_E(RRC, "schedulingInfoSIB1 value incorrect");
    	  return 0;
990 991 992
      }


993 994
      /*check if SIBs are initialized*/
      //FIXME to be check when both are initialize and if make sense to have it
995 996
            if (eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_SIB1_NB == 255) {
              LOG_E(RRC,"[eNB %d] MAC Request for SIB1-NB and SIB1-NB not initialized\n",Mod_idP);
997
              mac_xface->macphy_exit("NB_mac_rrc_data_req_eNB:  MAC Request for SIB1-NB and SIB1-NB not initialized");
998 999 1000 1001
            }

            if (eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_SIB23_NB == 255) {
                    LOG_E(RRC,"[eNB %d] MAC Request for SIB23-NB and SIB23-NB not initialized\n",Mod_idP);
1002
                    mac_xface->macphy_exit("NB_mac_rrc_data_req_eNB:  MAC Request for SIB23-NB and SIB23-NB not initialized");
1003 1004 1005
            }


1006 1007 1008 1009
///XXX Following FAPI implementation in principle we should only take care of get the PDU from the MAC only when the SIB1-NB period Start

         //sib1-NB scheduled in subframe #4
         if(subframeP == 4 && is_SIB1_NB_start(frameP,schedulingInfoSIB1, physCellId)!= -1){
1010

1011 1012 1013
			  memcpy(&buffer_pP[0],
					  eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].SIB1_NB,
					  eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_SIB1_NB);
1014

1015
			  //XXX RRC_MAC_BCCH_DATA_REQ message not implemented in MAC layer (eNB_scheduler.c under ITTI)
1016

1017

1018 1019
			#ifdef DEBUG_RRC
			   LOG_T(RRC,"[eNB %d] Frame %d : BCCH request => SIB1_NB\n",Mod_idP,frameP);
1020

1021 1022 1023
			   for (i=0; i<eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_SIB1_NB; i++) {
			    LOG_T(RRC,"%x.",buffer_pP[i]);
			    }
1024

1025 1026
			    LOG_T(RRC,"\n");
			#endif
1027

1028 1029
			    return (eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_SIB1_NB);
         }
1030

1031
         //check for SIB23-Transmission
1032

1033 1034 1035 1036 1037 1038 1039
         for(int i = 0; i<  eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sib1_NB->schedulingInfoList_r13.list.count; i++){
        	 if(is_SIB23_NB(frameP,h_frameP,
        		 eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sib1_NB->schedulingInfoList_r13.list.array[i]->si_Periodicity_r13,
				 eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sib1_NB->si_WindowLength_r13,
				 eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sib1_NB->si_RadioFrameOffset_r13,
				 eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sib1_NB->schedulingInfoList_r13.list.array[i]->si_RepetitionPattern_r13))
        	 {
1040

1041 1042 1043
        	 memcpy(&buffer_pP[0],
        			eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].SIB23_NB,
        	    	eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_SIB23_NB);
1044

1045 1046
        	    #ifdef DEBUG_RRC
        	    	LOG_T(RRC,"[eNB %d] Frame %d BCCH request => SIB 2-3\n",Mod_idP,frameP);
1047

1048 1049 1050
        	    	for (i=0; i<eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_SIB23_NB; i++) {
        	    		    LOG_T(RRC,"%x.",buffer_pP[i]);
        	    		 }
1051

1052 1053
        	    		 LOG_T(RRC,"\n");
        	    #endif
1054

1055 1056 1057
        	    return(eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].sizeof_SIB23_NB);
        	 }
         }
1058 1059 1060
        return(0);
    }

1061 1062
    //called when is requested the Msg4 transmission (RRCConnectionSetup)
    if( (Srb_id & RAB_OFFSET ) == CCCH) {
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
      LOG_T(RRC,"[eNB %d] Frame %d CCCH request (Srb_id %d)\n",Mod_idP,frameP, Srb_id);

      if(eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].Srb0.Active==0) {
        LOG_E(RRC,"[eNB %d] CCCH Not active\n",Mod_idP);
        return -1;
      }

      Srb_info=&eNB_rrc_inst_NB[Mod_idP].carrier[CC_id].Srb0;

      // check if data is there for MAC
      if(Srb_info->Tx_buffer.payload_size>0) { //Fill buffer
        LOG_D(RRC,"[eNB %d] CCCH (%p) has %d bytes (dest: %p, src %p)\n",Mod_idP,Srb_info,Srb_info->Tx_buffer.payload_size,buffer_pP,Srb_info->Tx_buffer.Payload);

1076 1077 1078 1079 1080
        //RRC_MAC_CCCH_DATA_REQ not implemented in MAC/eNB_scheduler.c

        memcpy(buffer_pP, //CCCH_pdu.payload[0]
        	   Srb_info->Tx_buffer.Payload,Srb_info->Tx_buffer.payload_size);

1081 1082 1083 1084 1085 1086
        Sdu_size = Srb_info->Tx_buffer.payload_size;
        Srb_info->Tx_buffer.payload_size=0;
      }

      return (Sdu_size);
    }
1087

1088 1089 1090 1091
  return(0);
}

//defined in L2_interface
1092
//called by rx_sdu only in case of CCCH message (e.g RRCConnectionRequest-NB - SRB0) --> is used for a direct communication between MAC and RRC
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
int8_t NB_mac_rrc_data_ind_eNB(
  const module_id_t     module_idP,
  const int             CC_id,
  const frame_t         frameP,
  const sub_frame_t     sub_frameP,
  const rnti_t          rntiP,
  const rb_id_t         srb_idP,//could be skipped since always go through the CCCH channel
  const uint8_t*        sduP,
  const sdu_size_t      sdu_lenP
)
{
1104
  SRB_INFO_NB *Srb_info;
1105 1106 1107 1108 1109 1110
  protocol_ctxt_t ctxt;
  sdu_size_t      sdu_size = 0;

  /* for no gcc warnings */
  (void)sdu_size;

1111
  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, rntiP, frameP, sub_frameP,module_idP);
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177

    Srb_info = &eNB_rrc_inst_NB[module_idP].carrier[CC_id].Srb0;
    LOG_T(RRC,"[eNB %d] Received SDU for CCCH on SRB %d\n",module_idP,Srb_info->Srb_id);


    //this messages are used by the RRC if ITTI enabled
#if defined(ENABLE_ITTI)
    {
      MessageDef *message_p;
      int msg_sdu_size = sizeof(RRC_MAC_CCCH_DATA_IND (message_p).sdu);

      if (sdu_lenP > msg_sdu_size) {
        LOG_E(RRC, "SDU larger than CCCH SDU buffer size (%d, %d)", sdu_lenP, msg_sdu_size);
        sdu_size = msg_sdu_size;
      } else {
        sdu_size = sdu_lenP;
      }

      message_p = itti_alloc_new_message (TASK_MAC_ENB, RRC_MAC_CCCH_DATA_IND);
      RRC_MAC_CCCH_DATA_IND (message_p).frame     = frameP;
      RRC_MAC_CCCH_DATA_IND (message_p).sub_frame = sub_frameP;
      RRC_MAC_CCCH_DATA_IND (message_p).rnti      = rntiP;
      RRC_MAC_CCCH_DATA_IND (message_p).sdu_size  = sdu_size;
      RRC_MAC_CCCH_DATA_IND (message_p).CC_id = CC_id;
      memset (RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE);
      memcpy (RRC_MAC_CCCH_DATA_IND (message_p).sdu, sduP, sdu_size);
      itti_send_msg_to_task (TASK_RRC_ENB, ctxt.instance, message_p);
    }
#else

    if (sdu_lenP > 0) {
      memcpy(Srb_info->Rx_buffer.Payload,sduP,sdu_lenP);
      Srb_info->Rx_buffer.payload_size = sdu_lenP;
      rrc_eNB_decode_ccch_NB(&ctxt, Srb_info, CC_id);
    }

#endif
  return(0);

}


//defined in L2_interface
void NB_mac_eNB_rrc_ul_failure(
		const module_id_t mod_idP,
	    const int CC_idP,
	    const frame_t frameP,
	    const sub_frame_t subframeP,
	    const rnti_t rntiP)
{
  struct rrc_eNB_ue_context_NB_s* ue_context_p = NULL;
  ue_context_p = rrc_eNB_get_ue_context_NB(
                   &eNB_rrc_inst_NB[mod_idP],
                   rntiP);

  if (ue_context_p != NULL) {
    LOG_I(RRC,"Frame %d, Subframe %d: UE %x UL failure, activating timer\n",frameP,subframeP,rntiP);
    ue_context_p->ue_context.ul_failure_timer=1;
  }
  else {
    LOG_W(RRC,"Frame %d, Subframe %d: UL failure: UE %x unknown \n",frameP,subframeP,rntiP);
  }
  NB_rrc_mac_remove_ue(mod_idP,rntiP);
}


1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196

//defined in eNB_scheduler_primitives.c
void dump_ue_list_NB(UE_list_NB_t *listP, int ul_flag)
{
  int j;

  if ( ul_flag == 0 ) {
    for (j=listP->head; j>=0; j=listP->next[j]) {
      LOG_T(MAC,"node %d => %d\n",j,listP->next[j]);
    }
  } else {
    for (j=listP->head_ul; j>=0; j=listP->next_ul[j]) {
      LOG_T(MAC,"node %d => %d\n",j,listP->next_ul[j]);
    }
  }
}



1197 1198 1199 1200 1201 1202
//defined in eNB_scheduler_primitives.c
int NB_rrc_mac_remove_ue(
		module_id_t mod_idP,
		rnti_t rntiP)
{
  int i;
1203
  UE_list_NB_t *UE_list = &eNB_mac_inst_NB[mod_idP].UE_list;
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
  int UE_id = find_UE_id(mod_idP,rntiP); //may should be changed
  int pCC_id;

  if (UE_id == -1) {
printf("MAC: cannot remove UE rnti %x\n", rntiP);
    LOG_W(MAC,"NB_rrc_mac_remove_ue: UE %x not found\n", rntiP);
    mac_phy_remove_ue(mod_idP, rntiP); //PHY/defs.h
    return 0;
  }

  pCC_id = UE_PCCID(mod_idP,UE_id);

printf("MAC: remove UE %d rnti %x\n", UE_id, rntiP);
  LOG_I(MAC,"Removing UE %d from Primary CC_id %d (rnti %x)\n",UE_id,pCC_id, rntiP);
1218
  dump_ue_list_NB(UE_list,0);
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235

  UE_list->active[UE_id] = FALSE;
  UE_list->num_UEs--;

  // clear all remaining pending transmissions
  UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0]  = 0;
  UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1]  = 0;
  UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2]  = 0;
  UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3]  = 0;

  UE_list->UE_template[pCC_id][UE_id].rnti              = NOT_A_RNTI;
  UE_list->UE_template[pCC_id][UE_id].ul_active         = FALSE;
  eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti                        = NOT_A_RNTI;
  eNB_ulsch_info[mod_idP][pCC_id][UE_id].status                      = S_UL_NONE;
  eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti                        = NOT_A_RNTI;
  eNB_dlsch_info[mod_idP][pCC_id][UE_id].status                      = S_DL_NONE;

1236
  mac_phy_remove_ue(mod_idP,rntiP); //PHY/defs.h
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257

  // check if this has an RA process active
  RA_TEMPLATE_NB *RA_template;
  for (i=0;i<NB_RA_PROC_MAX;i++) {

    RA_template = (RA_TEMPLATE_NB *)&eNB_mac_inst[mod_idP].common_channels[pCC_id].RA_template[i];
    if (RA_template->rnti == rntiP){
      RA_template->RA_active=FALSE;
      RA_template->generate_rar=0;
      RA_template->generate_Msg4=0;
      RA_template->wait_ack_Msg4=0;
      RA_template->timing_offset=0;
      RA_template->RRC_timer=20;
      RA_template->rnti = 0;
      //break;
    }
  }

  return 0;
}

1258 1259


1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
//defined in L2_interface
void NB_mac_eNB_rrc_ul_in_sync(
				const module_id_t mod_idP,
			    const int CC_idP,
			    const frame_t frameP,
			    const sub_frame_t subframeP,
			    const rnti_t rntiP)
{
  struct rrc_eNB_ue_context_NB_s* ue_context_p = NULL;
  ue_context_p = rrc_eNB_get_ue_context_NB(
                   &eNB_rrc_inst_NB[mod_idP],
                   rntiP);

  if (ue_context_p != NULL) {
    LOG_I(RRC,"Frame %d, Subframe %d: UE %x to UL in synch\n",
          frameP, subframeP, rntiP);
    ue_context_p->ue_context.ul_failure_timer = 0;
  } else {
    LOG_E(RRC,"Frame %d, Subframe %d: UE %x unknown \n",
          frameP, subframeP, rntiP);
  }
}

//defined in L2_interface
int NB_mac_eNB_get_rrc_status(
  const module_id_t Mod_idP,
  const rnti_t      rntiP
)
{
1289
  struct rrc_eNB_ue_context_NB_s* ue_context_p = NULL;
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
  ue_context_p = rrc_eNB_get_ue_context_NB(
                   &eNB_rrc_inst_NB[Mod_idP],
                   rntiP);

  if (ue_context_p != NULL) {
    return(ue_context_p->ue_context.Status);
  } else {
    return RRC_INACTIVE;
  }
}

/*----------------------------------RRC-PDCP--------------------------------------*/

1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
//defined in pdcp_security.c
static
uint32_t pdcp_get_next_count_tx_NB(pdcp_t *const pdcp_pP, const srb_flag_t srb_flagP, const uint16_t pdcp_sn);

//-----------------------------------------------------------------------------
static
uint32_t pdcp_get_next_count_tx_NB(
  pdcp_t * const pdcp_pP,
  const srb_flag_t srb_flagP,
  const uint16_t pdcp_sn
)
{
  uint32_t count; //32 bits

  /* For TX COUNT = TX_HFN << length of SN | pdcp SN */
  if (srb_flagP) {
    /* 5 bits length SN */
    count = ((pdcp_pP->tx_hfn << 5)  | (pdcp_sn & 0x001F));
  } else { //DRB
    /*Default is the 7 bits length SN TS 36.323 ch 6.2.4*/
    count = ((pdcp_pP->tx_hfn << 7) | (pdcp_sn & 0x007F)); //FIXME: MP: to be check if ok
  }

  LOG_D(PDCP, "[OSA] TX COUNT = 0x%08x\n", count);

  return count;
}


1332 1333 1334 1335 1336 1337 1338 1339 1340

//defined in pdcp_security.c
//called in NB_pdcp_data_req
//-----------------------------------------------------------------------------
int
NB_pdcp_apply_security(
  const protocol_ctxt_t* const ctxt_pP,
  pdcp_t        *const pdcp_pP,
  const srb_flag_t     srb_flagP,
1341
  const rb_id_t        rb_id, //rb_idP % maxDRB_NB_r13 = rb_id % 2 --> 0,1
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
  const uint8_t        pdcp_header_len,
  const uint16_t       current_sn,
  uint8_t       * const pdcp_pdu_buffer,
  const uint16_t      sdu_buffer_size
)
{
  uint8_t *buffer_encrypted = NULL;
  stream_cipher_t encrypt_params;

  DevAssert(pdcp_pP != NULL);
  DevAssert(pdcp_pdu_buffer != NULL);
  DevCheck(rb_id < NB_RB_MAX_NB_IOT && rb_id >= 0, rb_id, NB_RB_MAX_NB_IOT, 0);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_IN);

  encrypt_params.direction  = (pdcp_pP->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK;
  encrypt_params.bearer     = rb_id - 1;
1359
  encrypt_params.count      = pdcp_get_next_count_tx_NB(pdcp_pP, srb_flagP, current_sn); //XXX (warning) because static defined in pdcp_security.c
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404
  encrypt_params.key_length = 16;

  if (srb_flagP) {
    /* SRBs */
    uint8_t *mac_i;

    LOG_D(PDCP, "[OSA][RB %d] %s Applying control-plane security %d \n",
          rb_id, (pdcp_pP->is_ue != 0) ? "UE -> eNB" : "eNB -> UE", pdcp_pP->integrityProtAlgorithm);

    encrypt_params.message    = pdcp_pdu_buffer;
    encrypt_params.blength    = (pdcp_header_len + sdu_buffer_size) << 3;
    encrypt_params.key        = pdcp_pP->kRRCint + 16; // + 128;

    mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size];

    /* Both header and data parts are integrity protected for
     * control-plane PDUs */
    stream_compute_integrity(pdcp_pP->integrityProtAlgorithm,
                             &encrypt_params,
                             mac_i);

    encrypt_params.key = pdcp_pP->kRRCenc;  // + 128  // bit key
  } else {
    LOG_D(PDCP, "[OSA][RB %d] %s Applying user-plane security\n",
          rb_id, (pdcp_pP->is_ue != 0) ? "UE -> eNB" : "eNB -> UE");

    encrypt_params.key = pdcp_pP->kUPenc;//  + 128;
  }

  encrypt_params.message    = &pdcp_pdu_buffer[pdcp_header_len];
  encrypt_params.blength    = sdu_buffer_size << 3;

  buffer_encrypted = &pdcp_pdu_buffer[pdcp_header_len];

  /* Apply ciphering if any requested */
  stream_encrypt(pdcp_pP->cipheringAlgorithm,
                 &encrypt_params,
                 &buffer_encrypted);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_OUT);

  return 0;
}


1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
//FIXME for the moment we not configure PDCP for SRB1bis (but used as it is SRB1)
//defined in pdcp.c
boolean_t NB_rrc_pdcp_config_asn1_req (
  const protocol_ctxt_t* const  ctxt_pP,
  SRB_ToAddModList_NB_r13_t  *const srb2add_list_pP,
  DRB_ToAddModList_NB_r13_t  *const drb2add_list_pP,
  DRB_ToReleaseList_NB_r13_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,
  rb_id_t                 *const defaultDRB,
1417
  long						LCID //its only for check purposes (if correctly called could be deleted)
1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
)
{
  long int        lc_id          = 0;
  DRB_Identity_t  srb_id         = 0;
  rlc_mode_t      rlc_type       = RLC_MODE_NONE;
  DRB_Identity_t  drb_id         = 0;
  DRB_Identity_t *pdrb_id_p      = NULL;
  uint8_t         drb_sn         = 7; //SN for NB-IoT DRB TS 36.323 Table 6.3.2.1 (user data plane)
  uint8_t         srb_sn         = 5; // fixed sn for SRBs (control plane)
  uint8_t         drb_report     = 0; //may not supported in NB-IoT
  long int        cnt            = 0;
  uint16_t        header_compression_profile = 0; //no compression
  config_action_t action         = CONFIG_ACTION_ADD;
  SRB_ToAddMod_NB_r13_t *srb_toaddmod_p = NULL;
  DRB_ToAddMod_NB_r13_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;

  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) {

1451
	  if(LCID == DCCH0_NB) //SRB1bis
1452
	  	{
1453
		  LOG_E(PDCP,"PDCP Configuration for SRB1bis not allowed\n");
1454
		  return 0;
1455 1456 1457 1458 1459 1460 1461 1462
		}
	  else
	   {
		  //is SRB1
		  srb_id = DCCH1;
		  lc_id = srb_id;
	   }

1463 1464 1465 1466 1467
	/*Security Mode Failure*/
    if(security_modeP == -1){

    	LOG_D(PDCP, "SecurityModeFailure --> NB_rrc_pdcp_config_asn1_req --> Disabling security for srb2add_list_pP\n");

1468
    	for(int cnt=0; cnt< srb2add_list_pP->list.count; cnt++)
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
    	   {

    	    key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ENB_FLAG_YES, srb_id, SRB_FLAG_YES);
    	    h_rc = hashtable_get(pdcp_coll_p,key, (void**)&pdcp_p);

    	    if(h_rc != HASH_TABLE_OK){
    	       LOG_I(PDCP, "SecurityModeFailure --> NB_rrc_pdcp_config_asn1_req not available pdcp entity for disable security for this SRB");
    	    	    	continue;
    	      }

    	    pdcp_config_set_security(
    	        	  ctxt_pP,
    	        	  pdcp_p,
    	        	  srb_id,//DCCH1
    	        	  lc_id, //1
    	        	  security_modeP,// should be -1
    	        	  kRRCenc_pP,//Should be NULL
    	        	  kRRCint_pP,//Should be NULL
    	        	  kUPenc_pP //Should be NULL
					  );

    	      }
    	return 0;
    }

1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548
    for (cnt=0; cnt<srb2add_list_pP->list.count; cnt++) {
      srb_toaddmod_p = srb2add_list_pP->list.array[cnt];
      rlc_type = RLC_MODE_AM; //only mode available in NB-IOT

      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 all ok should get h_rc = HASH_TABLE_OK

        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_r13) {
        switch (srb_toaddmod_p->rlc_Config_r13->present) {
        case SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_NOTHING:
          break;

        case SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_explicitValue:
          switch (srb_toaddmod_p->rlc_Config_r13->choice.explicitValue.present) {
          case RLC_Config_NB_r13_PR_NOTHING:
            break;

          default:
        	  //configure the pdcp depend on the action
        	  //is a switch case on the "action" parameter
            NB_pdcp_config_req_asn1 (
              ctxt_pP,
              pdcp_p,
              SRB_FLAG_YES,
              rlc_type,
              action,
              lc_id,
              srb_id,
              srb_sn, //rb_sn
              0, // drb_report
1549
              0, // header compression no for SRBs
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
              security_modeP,
              kRRCenc_pP,
              kRRCint_pP,
              kUPenc_pP);
            break;
          }

          break;

        case SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_defaultValue:
        	NB_pdcp_config_req_asn1 (
        	              ctxt_pP,
        	              pdcp_p,
        	              SRB_FLAG_YES,
        	              rlc_type,
        	              action,
        	              lc_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_r13->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_r13;// + drb_id_offset;
      if (drb_toaddmod_p->logicalChannelIdentity_r13) {
        lc_id = *(drb_toaddmod_p->logicalChannelIdentity_r13);
      } else {
        LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" logicalChannelIdentity is missing in DRB-ToAddMod-NB information element!\n",
              PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p));
        continue;
      }

      if (lc_id == 1 || lc_id == 2 || lc_id == 3) {
        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 < maxDRB_NB_r13, drb_id, maxDRB_NB_r13, 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_r13) {
        if (drb_toaddmod_p->pdcp_Config_r13->discardTimer_r13) {
1651
          //TODO: set the value of the timer
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834
        }

        if (drb_toaddmod_p->pdcp_Config_r13) {
          //Status report operation is not defined for NB-IoT
          rlc_type = RLC_MODE_AM;
        }


        switch (drb_toaddmod_p->pdcp_Config_r13->headerCompression_r13.present) {
        case PDCP_Config_NB_r13__headerCompression_r13_PR_NOTHING:
        case PDCP_Config_NB_r13__headerCompression_r13_PR_notUsed:
          header_compression_profile=0x0;
          break;

        case PDCP_Config_NB_r13__headerCompression_r13_PR_rohc:

          // parse the struc and get the rohc profile
          //XXX MP: for NB-IoT only some profiles are defined in PDCP-Config-NB IE
          if(drb_toaddmod_p->pdcp_Config_r13->headerCompression_r13.choice.rohc.profiles_r13.profile0x0002) {
            header_compression_profile=0x0002;
          } else if(drb_toaddmod_p->pdcp_Config_r13->headerCompression_r13.choice.rohc.profiles_r13.profile0x0003) {
            header_compression_profile=0x0003;
          } else if(drb_toaddmod_p->pdcp_Config_r13->headerCompression_r13.choice.rohc.profiles_r13.profile0x0004) {
            header_compression_profile=0x0004;
          } else if(drb_toaddmod_p->pdcp_Config_r13->headerCompression_r13.choice.rohc.profiles_r13.profile0x0006) {
            header_compression_profile=0x0006;
          } else if(drb_toaddmod_p->pdcp_Config_r13->headerCompression_r13.choice.rohc.profiles_r13.profile0x0102) {
            header_compression_profile=0x0102;
          } else if(drb_toaddmod_p->pdcp_Config_r13->headerCompression_r13.choice.rohc.profiles_r13.profile0x0103) {
            header_compression_profile=0x0103;
          } else if(drb_toaddmod_p->pdcp_Config_r13->headerCompression_r13.choice.rohc.profiles_r13.profile0x0104) {
            header_compression_profile=0x0104;
          } else {
            header_compression_profile=0x0;
            LOG_W(PDCP,"unknown header compression profile\n");
          }

          // set the applicable profile
          break;

        default:
          LOG_W(PDCP,PROTOCOL_PDCP_CTXT_FMT"[RB %ld] unknown drb_toaddmod->PDCP_Config_NB->headerCompression->present \n",
                PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), drb_id);
          break;
        }

        NB_pdcp_config_req_asn1 (
          ctxt_pP,
          pdcp_p,
          SRB_FLAG_NO,
          rlc_type,
          action,
          lc_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, srb_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;
      NB_pdcp_config_req_asn1 (
        ctxt_pP,
        pdcp_p,
        SRB_FLAG_NO,
        rlc_type,
        action,
        lc_id,
        drb_id,
        0, //drb_sn
        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
      }
    }
  }
  return 0;
}

//defined in pdcp.c --> should be called only by a SRB1 (is internal to PDCP so is not an interface)
//-----------------------------------------------------------------------------
boolean_t
NB_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, //rlc_type
  const config_action_t         actionP,
  const uint16_t                lc_idP, // 1 = SRB1 // 3 = SRB1bis // >= 4 for DRBs
  const rb_id_t                 rb_idP,
  const uint8_t                 rb_snP, //5 if srb_sn // 7 is drb_sn // 0 if drb_sn to be removed
  const uint8_t                 rb_reportP, //not for SRBand not for NB-IOT
  const uint16_t                header_compression_profileP, //not for SRB only DRB
  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:

      pdcp_pP->is_ue = FALSE; //is an eNB PDCP
      pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = 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 == 7) { //the only applicable for NB-IoT RLC-AM DRBs
      pdcp_pP->seq_num_size = PDCP_SN_7BIT;
    } else { //control plane (SRBs)
      pdcp_pP->seq_num_size = PDCP_SN_5BIT;
    }

    //check on RLC mode (in principle should not exist)
    if(rlc_modeP == RLC_MODE_UM)
    {
    	LOG_E(PDCP,"Error: NB-IoT cannot work in RLC-UM mode\n" );
    	return (0);
    }

    pdcp_pP->rlc_mode                         = rlc_modeP;
    pdcp_pP->next_pdcp_tx_sn                  = 0;
    pdcp_pP->next_pdcp_rx_sn                  = 0;
    pdcp_pP->next_pdcp_rx_sn_before_integrity = 0;
    pdcp_pP->tx_hfn                           = 0;
    pdcp_pP->rx_hfn                           = 0;
    pdcp_pP->last_submitted_pdcp_rx_sn        = 4095; //MP: ??
    pdcp_pP->first_missing_pdu                = -1;
    pdcp_pP->rx_hfn_offset                    = 0;

    LOG_N(PDCP, PROTOCOL_PDCP_CTXT_FMT" Action ADD  LCID %d (%s id %d) "
            "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" : "TM");
    /* Setup security */
    if (security_modeP != 0xff) {
1835

1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072
      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 == 7) {
      pdcp_pP->seq_num_size = 7;
    } else {
      pdcp_pP->seq_num_size=5;
    }

    LOG_N(PDCP,PROTOCOL_PDCP_CTXT_FMT" Action MODIFY LCID %d "
            "RB id %d 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" : "TM");
    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 %d configured\n",
          PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP),
          lc_idP,
          rb_idP);

    /* 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_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;
}

//defined in L2_interface/pdcp.c
//FIXME SRB1bis should bypass the pdcp
//Distinction between different SRBs will be done by means of rd_id
uint8_t NB_rrc_data_req(
  const protocol_ctxt_t*   const ctxt_pP,
  const rb_id_t                  rb_idP,
  const mui_t                    muiP,
  const confirm_t                confirmP,
  const sdu_size_t               sdu_sizeP,
  uint8_t*                 const buffer_pP,
  const pdcp_transmission_mode_t modeP //when go through SRB1bis should be set as Transparent mode
)
{
  MSC_LOG_TX_MESSAGE(
    ctxt_pP->enb_flag ? MSC_RRC_ENB : MSC_RRC_UE,
    ctxt_pP->enb_flag ? MSC_PDCP_ENB : MSC_PDCP_UE,
    buffer_pP,
    sdu_sizeP,
    MSC_AS_TIME_FMT"RRC_DCCH_DATA_REQ UE %x MUI %d size %u",
    MSC_AS_TIME_ARGS(ctxt_pP),
    ctxt_pP->rnti,
    muiP,
    sdu_sizeP);

  //check srb1bis (preliminar)
  if(rb_idP == 3 && modeP != PDCP_TRANSMISSION_MODE_TRANSPARENT)
	  LOG_E(PDCP,"ERROR: SRB1bis should go through PDCP transparently");

  //FIXME: the following type of messages are used by the pdcp_run function in pdcp.c --> should be left?(put out from ITTI)
#if defined(ENABLE_ITTI)
  {
    MessageDef *message_p;
    // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling).
    uint8_t *message_buffer;

    message_buffer = itti_malloc (
                       ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE,
                       ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE,
                       sdu_sizeP);

    memcpy (message_buffer, buffer_pP, sdu_sizeP);

    message_p = itti_alloc_new_message (ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, RRC_DCCH_DATA_REQ);
    RRC_DCCH_DATA_REQ (message_p).frame     = ctxt_pP->frame;
    RRC_DCCH_DATA_REQ (message_p).enb_flag  = ctxt_pP->enb_flag;
    RRC_DCCH_DATA_REQ (message_p).rb_id     = rb_idP;
    RRC_DCCH_DATA_REQ (message_p).muip      = muiP;
    RRC_DCCH_DATA_REQ (message_p).confirmp  = confirmP;
    RRC_DCCH_DATA_REQ (message_p).sdu_size  = sdu_sizeP;
    RRC_DCCH_DATA_REQ (message_p).sdu_p     = message_buffer;
    RRC_DCCH_DATA_REQ (message_p).mode      = modeP;
    RRC_DCCH_DATA_REQ (message_p).module_id = ctxt_pP->module_id;
    RRC_DCCH_DATA_REQ (message_p).rnti      = ctxt_pP->rnti;
    RRC_DCCH_DATA_REQ (message_p).eNB_index = ctxt_pP->eNB_index;

    itti_send_msg_to_task (
      ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE,
      ctxt_pP->instance,
      message_p);
    return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway.

  }
#else

  //MP:in this case since is called by RRC for sure we have "SRB_FLAG_YES"
  return NB_pdcp_data_req(
           ctxt_pP,
           SRB_FLAG_YES,
           rb_idP,
           muiP,
           confirmP,
           sdu_sizeP,
           buffer_pP,
           modeP);
#endif
}


//we distinguish the SRBs based on the logical channel id and the transmission mode
boolean_t NB_pdcp_data_req(
  protocol_ctxt_t*  ctxt_pP,
  const srb_flag_t     srb_flagP, //SRB_FLAG_YES if called by RRC
  const rb_id_t        rb_idP,
  const mui_t          muiP,
  const confirm_t      confirmP,
  const sdu_size_t     sdu_buffer_sizeP, //the size of message that i should transmit
  unsigned char *const sdu_buffer_pP,
  const pdcp_transmission_mode_t modeP
)
{

  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;
  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?
   *
   * MP: (LTE) The maximum supported size of a PDCP SDU (both data or control) is 8188 octets
   * 	 (NB-IoT) The maximum supported size of a PDCP SDU (both data or control) is 1600 octets
   * 	 MAX_IP_PACKET_SIZE = 1500 (typical MTU for IPv4 packet)
   * 	 MAX_IP_PACKET_SIZE = 1514 for Ethernet (1500 bytes IP packet + 14 bytes ethernet header)
   *	---> i think that the check for the MAX_IP_PACKET_SIZE should be left as it is
   */

  if (sdu_buffer_sizeP > MAX_IP_PACKET_SIZE) {
    LOG_E(PDCP, "Requested SDU size (%d) is bigger than that can be handled by PDCP (%u)!\n",
          sdu_buffer_sizeP, MAX_IP_PACKET_SIZE);
    // XXX What does following call do?
    mac_xface->macphy_exit("PDCP sdu buffer size > MAX_IP_PACKET_SIZE");
  }

  //check for MBMS not needed for NB-IoT*/
  //if (modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT) {
    //AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, NB_RB_MBMS_MAX, ctxt_pP->module_id, ctxt_pP->rnti);
  //} else {

    if (srb_flagP) {
      AssertError (rb_idP < 4 , return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, 3, ctxt_pP->module_id, ctxt_pP->rnti);
    } else {//is a DRB
    	//FIXME: check if correct
      AssertError (rb_idP < 3+ maxDRB_NB_r13, return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, maxDRB_NB_r13, ctxt_pP->module_id, ctxt_pP->rnti);
    }


2073
  key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ENB_FLAG_YES, rb_idP, srb_flagP);
2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190
  h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p);

  if (h_rc != HASH_TABLE_OK) {
	  //if not included in the hashtable means that should be transparent mode
    if (modeP != PDCP_TRANSMISSION_MODE_TRANSPARENT) {
      LOG_W(PDCP, PROTOCOL_CTXT_FMT" Instance is not configured for rb_id %d 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;
  }

  //XXX Start/stop meas are used for measuring the CPU time

  if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
    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 SRB1bis

  //MP: Check may not useful
  if((modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT && rb_idP != 3) || (modeP != PDCP_TRANSMISSION_MODE_TRANSPARENT && rb_idP == 3 ))
	  LOG_E(PDCP, "PDCP_TRANSMISSION_MODE_TRANSPARENT set not for SRB1bis");

  if(modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT && rb_idP == 3 && srb_flagP == SRB_FLAG_YES)
  {
	  LOG_D(PDCP, " [SRB1bis 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 defined(DEBUG_PDCP_PAYLOAD)
	            rlc_util_print_hex_octets(PDCP,
	                                      (unsigned char*)&pdcp_pdu_p->data[0],
	                                      sdu_buffer_sizeP);
	      #endif

	      rlc_status = NB_rlc_data_req(ctxt_pP, srb_flagP, rb_idP, muiP, confirmP, sdu_buffer_sizeP, pdcp_pdu_p);
	      //MP: if all ok rlc_status = RLC_OP_STATUS_OK

	   } else {
	         rlc_status = RLC_OP_STATUS_OUT_OF_RESSOURCES;
	         LOG_W(PDCP,PROTOCOL_CTXT_FMT" PDCP_DATA_REQ SDU for SRB1bis DROPPED, OUT OF MEMORY \n",
	               PROTOCOL_CTXT_ARGS(ctxt_pP));
	   #if defined(STOP_ON_IP_TRAFFIC_OVERLOAD)
	         AssertFatal(0, PROTOCOL_CTXT_FMT"[RB %u] PDCP_DATA_REQ for SRB1bis SDU DROPPED, OUT OF MEMORY \n",
	                     PROTOCOL_CTXT_ARGS(ctxt_pP),
	                     rb_idP);
	   #endif
	   }
  }
  else { //not transparent mode (SRB1 or DRBs)

    // calculate the pdcp header and trailer size

    if (srb_flagP) { //control plane SDU (SRB)
      pdcp_header_len = PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE;
      pdcp_tailer_len = PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE;
    } else { // data PDU (DRBs)
      pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_SHORT_SN_HEADER_SIZE; //Only 7bit SN allowed for NB-IoT
      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) { //MP: Control plane PDCP Data PDU --> 5 bit SN + 3 bit reserved + 4 byte (MAC-I)
        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_NO) {
            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 { //MP: user plane (DRBs) --> NB-IoT use only short SN with 7 bits
    	  pdcp_user_plane_data_pdu_header_with_short_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 ;

2191
        if (pdcp_serialize_user_plane_data_pdu_with_short_sn_buffer((unsigned char*)pdcp_pdu_p->data, &pdu_header) == FALSE) {
2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234
          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_NO) {
            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_NO) {
          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
2235 2236 2237

      //XXX MP: in OAI seems that they not use integrity protection at all --> they padding to 0 all bits

2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253
      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 defined(ENABLE_SECURITY)

      if ((pdcp_p->security_activated != 0) &&
          (((pdcp_p->cipheringAlgorithm) != 0) ||
           ((pdcp_p->integrityProtAlgorithm) != 0))) {

        if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
          start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security);
        } else {
          start_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security);
        }

2254

2255
        NB_pdcp_apply_security(ctxt_pP,
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358
                            pdcp_p,
                            srb_flagP,
                            rb_idP % maxDRB_NB_r13,
                            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);
        }
      }

#endif

      /* 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);
      }

#if defined(STOP_ON_IP_TRAFFIC_OVERLOAD)
      AssertFatal(0, "[FRAME %5u][%s][PDCP][MOD %u/%u][RB %u] PDCP_DATA_REQ SDU DROPPED, OUT OF MEMORY \n",
                  ctxt_pP->frame,
                  (ctxt_pP->enb_flag) ? "eNB" : "UE",
                  ctxt_pP->enb_module_id,
                  ctxt_pP->ue_module_id,
                  rb_idP);
#endif
      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
     */
#ifdef PDCP_MSG_PRINT
    int i=0;
    LOG_F(PDCP,"[MSG] PDCP DL %s PDU on rb_id %d\n", (srb_flagP)? "CONTROL" : "DATA", rb_idP);

    for (i = 0; i < pdcp_pdu_size; i++) {
      LOG_F(PDCP,"%02x ", ((uint8_t*)pdcp_pdu_p->data)[i]);
    }

    LOG_F(PDCP,"\n");
#endif
    rlc_status = NB_rlc_data_req(ctxt_pP, srb_flagP,rb_idP, muiP, confirmP, pdcp_pdu_size, pdcp_pdu_p);

  }

  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;
  }

  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);
  }

  /*
   * Control arrives here only if rlc_data_req() returns RLC_OP_STATUS_OK
   * so we return TRUE afterwards
   */

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT);
  return ret;
}

2359 2360


2361
//defined in L2_interface
2362 2363
//called by the PDCP in the pdcp_data_ind
//mapped to rlc_rrc_data_ind (but maybe no more used for this purpose)
2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392
void NB_rrc_data_ind(
  const protocol_ctxt_t* const ctxt_pP,
  const rb_id_t                Srb_id,
  const sdu_size_t             sdu_sizeP,
  const uint8_t*   const       buffer_pP,
  const srb1bis_flag_t srb1bis_flag
)
//------------------------------------------------------------------------------
{

  rb_id_t    DCCH_index;
  if(srb1bis_flag == SRB1BIS_FLAG_YES)
	  DCCH_index = 3; //SRb1bis (LCID=3) over DCCH0
  else
	  DCCH_index = Srb_id;

  if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
    LOG_N(RRC, "[UE %x] Frame %d: received a DCCH %d message on SRB %d with Size %d from eNB %d\n",
          ctxt_pP->module_id, ctxt_pP->frame, DCCH_index,Srb_id,sdu_sizeP,  ctxt_pP->eNB_index);
  } else {
    LOG_N(RRC, "[eNB %d] Frame %d: received a DCCH %d message on SRB %d with Size %d from UE %x\n",
          ctxt_pP->module_id,
          ctxt_pP->frame,
          DCCH_index,
          Srb_id,
          sdu_sizeP,
          ctxt_pP->rnti);
  }

2393
  //FiXME: MP: we should put out this messages from ITTI ??
2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418
#if defined(ENABLE_ITTI) //From PDCP to RRC
  {
    MessageDef *message_p;
    // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling).
    uint8_t *message_buffer;

    message_buffer = itti_malloc (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, sdu_sizeP);
    memcpy (message_buffer, buffer_pP, sdu_sizeP);

    message_p = itti_alloc_new_message (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, RRC_DCCH_DATA_IND);
    RRC_DCCH_DATA_IND (message_p).frame      = ctxt_pP->frame;
    RRC_DCCH_DATA_IND (message_p).dcch_index = DCCH_index;
    RRC_DCCH_DATA_IND (message_p).sdu_size   = sdu_sizeP;
    RRC_DCCH_DATA_IND (message_p).sdu_p      = message_buffer;
    RRC_DCCH_DATA_IND (message_p).rnti       = ctxt_pP->rnti;
    RRC_DCCH_DATA_IND (message_p).module_id  = ctxt_pP->module_id;
    RRC_DCCH_DATA_IND (message_p).eNB_index  = ctxt_pP->eNB_index;

    itti_send_msg_to_task (ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, ctxt_pP->instance, message_p);
  }
#else

  if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
    rrc_eNB_decode_dcch_NB(
      ctxt_pP,
2419
	  DCCH_index, // becomes the srb_id in decode_dcch
2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476
      buffer_pP,
      sdu_sizeP);
  } else {
//#warning "LG put 0 to arg4 that is eNB index"
    rrc_ue_decode_dcch(
      ctxt_pP,
      DCCH_index,
      buffer_pP,
      0);
  }

#endif
}



/*---------------------------------RRC-RLC-----------------------------------*/

//defined in rlc_rrc.c
rlc_op_status_t NB_rrc_rlc_config_asn1_req (
	const protocol_ctxt_t   * const ctxt_pP,
    const SRB_ToAddModList_NB_r13_t   * const srb2add_listP,
    const DRB_ToAddModList_NB_r13_t   * const drb2add_listP,
    const DRB_ToReleaseList_NB_r13_t  * const drb2release_listP,
	srb1bis_flag_t							srb1bis_flag //may is not so much needed
    )
{
  //-----------------------------------------------------------------------------
  rb_id_t                rb_id           = 0;
  logical_chan_id_t      lc_id           = 0;
  DRB_Identity_t         drb_id          = 0;
  DRB_Identity_t*        pdrb_id         = NULL;
  long int               cnt             = 0;
  const SRB_ToAddMod_NB_r13_t  *srb_toaddmod_p  = NULL;
  const DRB_ToAddMod_NB_r13_t  *drb_toaddmod_p  = NULL;
  rlc_union_t           *rlc_union_p     = NULL;
  hash_key_t             key             = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_rc;

  //no MBMS in NB-IoT( The RLC config for MBMS was UM)

  /* for no gcc warnings */
  (void)rlc_union_p;
  (void)key;
  (void)h_rc;

  LOG_D(RLC, PROTOCOL_CTXT_FMT" CONFIG REQ ASN1 \n",
        PROTOCOL_CTXT_ARGS(ctxt_pP));

#ifdef OAI_EMU

  CHECK_CTXT_ARGS(ctxt_pP)

#endif

  if (srb2add_listP != NULL) {
		if(srb1bis_flag == SRB1BIS_FLAG_YES){
2477
	    	rb_id = DCCH0_NB; //3
2478 2479
		}//srb1bis
	    else{
2480
	    	rb_id = DCCH1_NB; //1
2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525
	    }//srb1

	    lc_id = rb_id;

    for (cnt=0; cnt<srb2add_listP->list.count; cnt++) { //MP: should be only 1 iteration

      LOG_D(RLC, "Adding SRB, rb_id %d\n",rb_id);
      srb_toaddmod_p = srb2add_listP->list.array[cnt];

      if (srb_toaddmod_p->rlc_Config_r13) {
        switch (srb_toaddmod_p->rlc_Config_r13->present) {
        case SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_NOTHING:
          break;

        case SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_explicitValue:
          switch (srb_toaddmod_p->rlc_Config_r13->choice.explicitValue.present) {
          case RLC_Config_NB_r13_PR_NOTHING:
            break;

          case RLC_Config_NB_r13_PR_am:
            if (NB_rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_YES, rb_id, lc_id, RLC_MODE_AM) != NULL) {
              NB_config_req_rlc_am_asn1 (
                ctxt_pP,
                SRB_FLAG_YES,
                &srb_toaddmod_p->rlc_Config_r13->choice.explicitValue.choice.am,
                rb_id,
				lc_id);
            } else {
              LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n",
                    PROTOCOL_CTXT_ARGS(ctxt_pP),
                    rb_id);
            }

            break;

          default:
            LOG_E(RLC, PROTOCOL_CTXT_FMT" UNKNOWN RLC CONFIG %d \n",
                  PROTOCOL_CTXT_ARGS(ctxt_pP),
                  srb_toaddmod_p->rlc_Config_r13->choice.explicitValue.present);
            break;
          }

          break; //RLC explicit value

        case SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_defaultValue:
2526

2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537
          LOG_I(RRC, "RLC SRB1/SRB1bis is default value !!\n");
          struct RLC_Config_NB_r13__am  *  config_am_pP = &srb_toaddmod_p->rlc_Config_r13->choice.explicitValue.choice.am;
          config_am_pP->ul_AM_RLC_r13.t_PollRetransmit_r13     = T_PollRetransmit_NB_r13_ms25000;
          config_am_pP->ul_AM_RLC_r13.maxRetxThreshold_r13 = UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t4;
          config_am_pP->dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 = NULL; //should be disabled

          if (NB_rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_YES, rb_id, lc_id, RLC_MODE_AM) != NULL) {
            NB_config_req_rlc_am_asn1 (
              ctxt_pP,
              SRB_FLAG_YES,
              &srb_toaddmod_p->rlc_Config_r13->choice.explicitValue.choice.am,
2538 2539
              rb_id,
			  lc_id);
2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638
          } else {
            LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n",
                  PROTOCOL_CTXT_ARGS(ctxt_pP),
                  rb_id);
          }
          break;

        default:
          ;
        }
      }
    }
  }

  if (drb2add_listP != NULL) {
    for (cnt=0; cnt<drb2add_listP->list.count; cnt++) {
      drb_toaddmod_p = drb2add_listP->list.array[cnt];

      drb_id = drb_toaddmod_p->drb_Identity_r13;
      if (drb_toaddmod_p->logicalChannelIdentity_r13) {
        lc_id = *drb_toaddmod_p->logicalChannelIdentity_r13;
      } else {
        LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity is missing from drb-ToAddMod information element!\n", PROTOCOL_CTXT_ARGS(ctxt_pP));
        continue;
      }

      if (lc_id == 1 || lc_id == 2 || lc_id == 3) {
        LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity = %d is invalid in RRC message when adding DRB!\n", PROTOCOL_CTXT_ARGS(ctxt_pP), lc_id);
        continue;
      }

      LOG_D(RLC, "Adding DRB %ld, lc_id %d\n",drb_id,lc_id);


      if (drb_toaddmod_p->rlc_Config_r13) {

        switch (drb_toaddmod_p->rlc_Config_r13->present) {
        case RLC_Config_NB_r13_PR_NOTHING:
          break;

        case RLC_Config_NB_r13_PR_am:
          if (NB_rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_NO, drb_id, lc_id, RLC_MODE_AM) != NULL) {
            NB_config_req_rlc_am_asn1 (
              ctxt_pP,
              SRB_FLAG_NO,
              &drb_toaddmod_p->rlc_Config_r13->choice.am,
              drb_id, lc_id);
          }

          break;

        default:
          LOG_W(RLC, PROTOCOL_CTXT_FMT"[RB %ld] unknown drb_toaddmod_p->rlc_Config_r13->present \n",
                PROTOCOL_CTXT_ARGS(ctxt_pP),
                drb_id);
        }
      }
    }
  }

  if (drb2release_listP != NULL) {
    for (cnt=0; cnt<drb2release_listP->list.count; cnt++) {
      pdrb_id = drb2release_listP->list.array[cnt];
      NB_rrc_rlc_remove_rlc(
        ctxt_pP,
        SRB_FLAG_NO,
        *pdrb_id);
    }
  }

//MP: MBMS not in NB-IoT

  LOG_D(RLC, PROTOCOL_CTXT_FMT" CONFIG REQ ASN1 END \n",
        PROTOCOL_CTXT_ARGS(ctxt_pP));
  return RLC_OP_STATUS_OK;
}

//defined in rlc_am.c
//from TS 36.331 V14.2.1
uint32_t pollRetransmit_NB_tab[T_PollRetransmit_NB_r13_spare1] = {250,500,1000,2000,3000,4000,6000,10000,15000,25000,40000,60000,90000,120000,180000};
uint32_t maxRetxThreshold_NB_tab[UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t32 +1] = {1,2,3,4,6,8,16,32};
//-----------------------------------------------------------------------------
void NB_config_req_rlc_am_asn1 (
  const protocol_ctxt_t* const         ctxt_pP,
  const srb_flag_t                     srb_flagP,
  const struct RLC_Config_NB_r13__am  * const config_am_pP, //extracted from the srb_toAddMod
  const rb_id_t                        rb_idP,
  const logical_chan_id_t              chan_idP)
{
  rlc_union_t     *rlc_union_p   = NULL;
  rlc_am_entity_t *l_rlc_p         = NULL;
  hash_key_t       key           = RLC_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(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    l_rlc_p = &rlc_union_p->rlc.am;

2639
    //MP: check if this conditions are correct
2640
    if ((config_am_pP->ul_AM_RLC_r13.maxRetxThreshold_r13 <= UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t32) &&
2641 2642
        (config_am_pP->ul_AM_RLC_r13.t_PollRetransmit_r13 < T_PollRetransmit_NB_r13_spare1)
		&&(config_am_pP->dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 == NULL))
2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659
		{

      MSC_LOG_RX_MESSAGE(
        (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
        (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE,
        NULL,
        0,
        MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ t_PollRetx_NB %u",
        MSC_AS_TIME_ARGS(ctxt_pP),
        PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
        pollRetransmit_NB_tab[config_am_pP->ul_AM_RLC_r13.t_PollRetransmit_r13]);

      LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" CONFIG_REQ (max_retx_threshold_NB = %d t_poll_retransmit_NB = %d \n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p),
            maxRetxThreshold_NB_tab[config_am_pP->ul_AM_RLC_r13.maxRetxThreshold_r13],
            pollRetransmit_NB_tab[config_am_pP->ul_AM_RLC_r13.t_PollRetransmit_r13]);

2660
      //XXX: the following function are ok for NB_IoT??
2661 2662 2663
      rlc_am_init(ctxt_pP, l_rlc_p);
      rlc_am_set_debug_infos(ctxt_pP, l_rlc_p, srb_flagP, rb_idP, chan_idP);
      NB_rlc_am_configure(ctxt_pP,
2664 2665 2666
    		  	  	  	l_rlc_p,
						maxRetxThreshold_NB_tab[config_am_pP->ul_AM_RLC_r13.maxRetxThreshold_r13],
						pollRetransmit_NB_tab[config_am_pP->ul_AM_RLC_r13.t_PollRetransmit_r13],
2667
						(uint32_t*) config_am_pP->dl_AM_RLC_r13.enableStatusReportSN_Gap_r13); //MP:XXX this cast generate problem??
2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697
    } else {
      MSC_LOG_RX_DISCARDED_MESSAGE(
        (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
        (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE,
        NULL,
        0,
        MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ",
        MSC_AS_TIME_ARGS(ctxt_pP),
        PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p));

      LOG_D(RLC,
            PROTOCOL_RLC_AM_CTXT_FMT"ILLEGAL CONFIG_REQ (max_retx_threshold_NB=%ld t_poll_retransmit_NB=%ld), RLC-AM NOT CONFIGURED\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p),
            config_am_pP->ul_AM_RLC_r13.maxRetxThreshold_r13,
            config_am_pP->ul_AM_RLC_r13.t_PollRetransmit_r13);
    }
  } else {
    LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT"CONFIG_REQ --> RLC NOT FOUND\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p));
  }
}

//defined in rlc_am_init.c
//-----------------------------------------------------------------------------
void
NB_rlc_am_configure(
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t *const        rlc_pP,
  const uint16_t                max_retx_thresholdP,
  const uint16_t                t_poll_retransmitP,
2698
  const uint32_t*				enableStatusReportSN_Gap
2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709
  )
{
  if (rlc_pP->configured == TRUE) {
    LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RECONFIGURE] max_retx_threshold_NB %d t_poll_retransmit_NB %d\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
          max_retx_thresholdP,
          t_poll_retransmitP
		  );

    //FIXME: rlc_am_entity_t should be modified??

2710
    rlc_pP->max_retx_threshold_NB = max_retx_thresholdP;
2711
    rlc_pP->protocol_state     = RLC_DATA_TRANSFER_READY_STATE;
2712 2713
    rlc_pP->t_poll_retransmit_NB.ms_duration   = t_poll_retransmitP;
    rlc_pP->enableStatusReportSN_Gap = enableStatusReportSN_Gap;
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723


  } else {
    LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[CONFIGURE] max_retx_threshold_NB %d t_poll_retransmit_NB %d\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
          max_retx_thresholdP,
          t_poll_retransmitP
		  //enableStatusReportSN_Gap
    		);

2724
    rlc_pP->max_retx_threshold_NB = max_retx_thresholdP;
2725
    rlc_pP->protocol_state     = RLC_DATA_TRANSFER_READY_STATE;
2726
    rlc_pP->enableStatusReportSN_Gap = enableStatusReportSN_Gap;
2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750


    rlc_am_init_timer_poll_retransmit(ctxt_pP, rlc_pP, t_poll_retransmitP);

    rlc_pP->configured = TRUE;
  }

}

//defined in rlc_rrc.c
//-----------------------------------------------------------------------------
rlc_union_t* NB_rrc_rlc_add_rlc   (
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t        srb_flagP,
  const rb_id_t           rb_idP,
  const logical_chan_id_t chan_idP,
  const rlc_mode_t        rlc_modeP)
{
  //-----------------------------------------------------------------------------
  hash_key_t             key         = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_rc;
  hash_key_t             key_lcid    = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_lcid_rc;
  rlc_union_t           *rlc_union_p = NULL;
2751

2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906

#ifdef OAI_EMU

  CHECK_CTXT_ARGS(ctxt_pP)

#endif

    AssertFatal (rb_idP < NB_RB_MAX_NB_IOT, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX);
    AssertFatal (chan_idP < RLC_MAX_LC, "LC id is too high (%u/%d)!\n", chan_idP, RLC_MAX_LC);


  {
    key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP);
    key_lcid = RLC_COLL_KEY_LCID_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, srb_flagP);
  }

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    LOG_W(RLC, PROTOCOL_CTXT_FMT"[%s %u] rrc_rlc_add_rlc , already exist %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
    AssertFatal(rlc_union_p->mode == rlc_modeP, "Error rrc_rlc_add_rlc , already exist but RLC mode differ");
    return rlc_union_p;
  } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) {
    rlc_union_p = calloc(1, sizeof(rlc_union_t));
    h_rc = hashtable_insert(rlc_coll_p, key, rlc_union_p);
    h_lcid_rc = hashtable_insert(rlc_coll_p, key_lcid, rlc_union_p);

    if ((h_rc == HASH_TABLE_OK) && (h_lcid_rc == HASH_TABLE_OK)) {

      {
        LOG_I(RLC, PROTOCOL_CTXT_FMT" [%s %u] rrc_rlc_add_rlc  %s\n",
              PROTOCOL_CTXT_ARGS(ctxt_pP),
              (srb_flagP) ? "SRB" : "DRB",
              rb_idP,
              (srb_flagP) ? "SRB" : "DRB");
      }

      rlc_union_p->mode = rlc_modeP;
      return rlc_union_p;
    } else {
      LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] rrc_rlc_add_rlc FAILED %s (add by RB_id=%d; add by LC_id=%d)\n",
            PROTOCOL_CTXT_ARGS(ctxt_pP),
            (srb_flagP) ? "SRB" : "DRB",
            rb_idP,
            (srb_flagP) ? "SRB" : "DRB",
            h_rc, h_lcid_rc);
      free(rlc_union_p);
      rlc_union_p = NULL;
      return NULL;
    }
  } else {
    LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] rrc_rlc_add_rlc , INTERNAL ERROR %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
  }

  return NULL;
}

//defined in rlc_rrc.c
//-----------------------------------------------------------------------------
rlc_op_status_t NB_rrc_rlc_remove_rlc   (
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t  srb_flagP,
  const rb_id_t     rb_idP)
{
  //-----------------------------------------------------------------------------
  logical_chan_id_t      lcid            = 0;
  hash_key_t             key             = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_rc;
  hash_key_t             key_lcid        = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_lcid_rc;
  rlc_union_t           *rlc_union_p = NULL;

#ifdef OAI_EMU
  CHECK_CTXT_ARGS(ctxt_pP)

#endif

  if(rb_idP == 2){
	  LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] NB_rrc_rlc_remove_rlc --> rb_id = 2 (SRB2) should not be used in NB-IoT!\n",
	              PROTOCOL_CTXT_ARGS(ctxt_pP),
	              (srb_flagP) ? "SRB" : "DRB",
	              rb_idP);
  }


  /* for no gcc warnings */
  (void)lcid;

  {
	  //MP: this function know that if i have to search for a DRB the rb_idP that i pass could also be 1,3,... so add something ??
	  //see NB_rrc_rlc_remove_ue
    key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP);
  }

  AssertFatal (rb_idP < NB_RB_MAX_NB_IOT, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX_NB_IOT);

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    // also remove the hash-key created by LC-id
	//MP: UM mode not allowed for NB-IoT
    switch (rlc_union_p->mode) {
    case RLC_MODE_AM:
      lcid = rlc_union_p->rlc.am.channel_id;
      break;
    case RLC_MODE_TM:
      lcid = rlc_union_p->rlc.tm.channel_id;
      break;
    default:
      LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] RLC mode is unknown!\n",
            PROTOCOL_CTXT_ARGS(ctxt_pP),
            (srb_flagP) ? "SRB" : "DRB",
            rb_idP);
    }
    //MP:for lcid
    key_lcid = RLC_COLL_KEY_LCID_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, lcid, srb_flagP);
    h_lcid_rc = hashtable_get(rlc_coll_p, key_lcid, (void**)&rlc_union_p);
  } else {
    h_lcid_rc = HASH_TABLE_KEY_NOT_EXISTS;
  }

  if ((h_rc == HASH_TABLE_OK) && (h_lcid_rc == HASH_TABLE_OK)) {
    h_lcid_rc = hashtable_remove(rlc_coll_p, key_lcid);
    h_rc = hashtable_remove(rlc_coll_p, key);
    LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u LCID %d] RELEASED %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP, lcid,
          (srb_flagP) ? "SRB" : "DRB");
  } else if ((h_rc == HASH_TABLE_KEY_NOT_EXISTS) || (h_lcid_rc == HASH_TABLE_KEY_NOT_EXISTS)) {
    LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u LCID %d] RELEASE : RLC NOT FOUND %s, by RB-ID=%d, by LC-ID=%d\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP, lcid,
          (srb_flagP) ? "SRB" : "DRB",
          h_rc, h_lcid_rc);
  } else {
    LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u LCID %d] RELEASE : INTERNAL ERROR %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP, lcid,
          (srb_flagP) ? "SRB" : "DRB");
  }

  return RLC_OP_STATUS_OK;
}

2907
//defined in rlc_rrc.c
2908
//used only for rrc_t310_expiration --> I don't know if it is used (probably not)
2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931
rlc_op_status_t NB_rrc_rlc_config_req   (
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t      srb_flagP,
  const config_action_t actionP,
  const rb_id_t         rb_idP,
  const rlc_info_t      rlc_infoP)
{
  //-----------------------------------------------------------------------------
  //rlc_op_status_t status;

  LOG_D(RLC, PROTOCOL_CTXT_FMT" CONFIG_REQ for RAB %u\n",
        PROTOCOL_CTXT_ARGS(ctxt_pP),
        rb_idP);

#ifdef OAI_EMU

  CHECK_CTXT_ARGS(ctxt_pP)

#endif
  AssertFatal (rb_idP < NB_RB_MAX_NB_IOT, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX_NB_IOT);

  switch (actionP) {

2932
  //XXX MP:this functuion is not used for adding rlc instance
2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948
  case CONFIG_ACTION_ADD:
    if (NB_rrc_rlc_add_rlc(ctxt_pP, srb_flagP, rb_idP, rb_idP, rlc_infoP.rlc_mode) != NULL) {
      return RLC_OP_STATUS_INTERNAL_ERROR;
    }

    // no break, fall to next case
  case CONFIG_ACTION_MODIFY:
    switch (rlc_infoP.rlc_mode) {
    case RLC_MODE_AM:
      LOG_I(RLC, PROTOCOL_CTXT_FMT"[RB %u] MODIFY RB AM\n",
            PROTOCOL_CTXT_ARGS(ctxt_pP),
            rb_idP);

      NB_config_req_rlc_am(
        ctxt_pP,
        srb_flagP,
2949
        &rlc_infoP.rlc.rlc_am_info_NB, //MP: pass the volatile structure for NB_IoT protocol params in rlc_am_init.h // warning present
2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005
        rb_idP, rb_idP);
      break;

    case RLC_MODE_TM:
      LOG_I(RLC, PROTOCOL_CTXT_FMT"[RB %u] MODIFY RB TM\n",
            PROTOCOL_CTXT_ARGS(ctxt_pP),
            rb_idP);
      NB_config_req_rlc_tm( //MP: TM mode configuration
        ctxt_pP,
        srb_flagP,
        &rlc_infoP.rlc.rlc_tm_info,
        rb_idP,
		rb_idP);
      break;

    default:
      return RLC_OP_STATUS_BAD_PARAMETER;
    }

    break;

  case CONFIG_ACTION_REMOVE:
    return NB_rrc_rlc_remove_rlc(ctxt_pP, srb_flagP, rb_idP);
    break;

  default:
    return RLC_OP_STATUS_BAD_PARAMETER;
  }

  return RLC_OP_STATUS_OK;
}


//defined in rlc_am.c
//-----------------------------------------------------------------------------
void
NB_config_req_rlc_am (
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t             srb_flagP,
  rlc_am_info_NB_t  * const       config_am_pP, //XXX: MP: rlc_am_init.c --> this structure has been modified for NB-IoT
  const rb_id_t                rb_idP,
  const logical_chan_id_t      chan_idP
)
{
  rlc_union_t       *rlc_union_p = NULL;
  rlc_am_entity_t *l_rlc_p         = NULL;
  hash_key_t       key           = RLC_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(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    l_rlc_p = &rlc_union_p->rlc.am;
    LOG_D(RLC,
          PROTOCOL_RLC_AM_CTXT_FMT" CONFIG_REQ (max_retx_threshold=%d t_poll_retransmit=%d)\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p),
3006 3007
          config_am_pP->max_retx_threshold_NB,
          config_am_pP->t_poll_retransmit_NB
3008 3009 3010 3011 3012 3013
		  //enableStatusReportSN_Gap_r13
		  );
    rlc_am_init(ctxt_pP, l_rlc_p);
    rlc_am_set_debug_infos(ctxt_pP, l_rlc_p, srb_flagP, rb_idP, chan_idP);
    NB_rlc_am_configure(ctxt_pP,
    					l_rlc_p,
3014 3015 3016
						config_am_pP->max_retx_threshold_NB,
                    	config_am_pP->t_poll_retransmit_NB,
						config_am_pP->enableStatusReportSN_Gap);
3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080
  } else {
    LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT" CONFIG_REQ RLC NOT FOUND\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p));
  }
}


//defined in rlc_tm_init.c (nothing to be changed)
//-----------------------------------------------------------------------------
void NB_config_req_rlc_tm (
  const protocol_ctxt_t* const  ctxt_pP,
  const srb_flag_t  srb_flagP,
  const rlc_tm_info_t * const config_tmP,
  const rb_id_t rb_idP,
  const logical_chan_id_t chan_idP
)
{
  rlc_union_t     *rlc_union_p  = NULL;
  rlc_tm_entity_t *rlc_p        = NULL;
  hash_key_t       key          = RLC_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(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    rlc_p = &rlc_union_p->rlc.tm;
    LOG_D(RLC, PROTOCOL_RLC_TM_CTXT_FMT" CONFIG_REQ (is_uplink_downlink=%d) RB %u\n",
          PROTOCOL_RLC_TM_CTXT_ARGS(ctxt_pP, rlc_p),
          config_tmP->is_uplink_downlink,
          rb_idP);

    //MP: i think this functions are fine also for NB-IoT
    rlc_tm_init(ctxt_pP, rlc_p);
    rlc_p->protocol_state = RLC_DATA_TRANSFER_READY_STATE;
    rlc_tm_set_debug_infos(ctxt_pP, rlc_p, srb_flagP, rb_idP, chan_idP);
    rlc_tm_configure(ctxt_pP, rlc_p, config_tmP->is_uplink_downlink);
  } else {
    LOG_E(RLC, PROTOCOL_RLC_TM_CTXT_FMT" CONFIG_REQ RB %u RLC NOT FOUND\n",
          PROTOCOL_RLC_TM_CTXT_ARGS(ctxt_pP, rlc_p),
          rb_idP);
  }
}

//defined in rlc_rrc.c
rlc_op_status_t NB_rrc_rlc_remove_ue (
  const protocol_ctxt_t* const ctxt_pP)
{
  //-----------------------------------------------------------------------------
  rb_id_t                rb_id;

  //XXX MP: rb_id = 2 should be not used (SRB2 not defined for NB-IoT)
  for (rb_id = 1; rb_id <= 3; rb_id++) {
    if(rb_id != 2){
    	NB_rrc_rlc_remove_rlc(ctxt_pP,
    						  SRB_FLAG_YES,
						      rb_id);
    }
    else
    {
    	LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] NB_rrc_rlc_remove_ue --> removing an UE with rb_id = 2 in NB_IoT!\n",
    		              PROTOCOL_CTXT_ARGS(ctxt_pP), "SRB", rb_id);
    }
  }

3081 3082
  //XXX possible BUG here???
  for (rb_id = 1; rb_id <= maxDRB_NB_r13 + 3; rb_id++) {
3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096
	  if(rb_id != 2){
		  NB_rrc_rlc_remove_rlc(ctxt_pP,
                       SRB_FLAG_NO,
                       rb_id);
	  }
	  else
	      LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] NB_rrc_rlc_remove_ue --> removing an UE with rb_id = 2 in NB_IoT!\n",
	      		              PROTOCOL_CTXT_ARGS(ctxt_pP), "DRB", rb_id);
  }

  return RLC_OP_STATUS_OK;
}

//defined in rlc_rrc.c --> NO MORE USED PROBABLY
3097 3098 3099 3100 3101 3102 3103 3104 3105
//------------------------------------------------------------------------------
void rrc_rlc_register_rrc_NB (rrc_data_ind_cb_NB_t NB_rrc_data_indP, rrc_data_conf_cb_t rrc_data_confP)
{
	//his function is called by RRC to register its DATA-INDICATE and DATA-CONFIRM handlers to RLC laye
	//map the function pointer to the function in input
	//rlc_rrc_data_ind  and rlc_rrc_data_conf are protected internal functions in the rlc.c file
	 rlc_rrc_data_ind_NB  = NB_rrc_data_indP;
	 rlc_rrc_data_conf = rrc_data_confP;
}
3106 3107

/*--------------------------------------------RLC-PDCP--------------------------------------------------*/
3108 3109
//XXX to be integrated in the flow
//called by rlc_am_send_sdu and rlc_tm_send_sdu
3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166
//defined in rlc.c
//--------------------------------------------
void NB_rlc_data_ind     (
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t  srb_flagP,
  const srb1bis_flag_t srb1bis_flag,
  const rb_id_t     rb_idP,
  const sdu_size_t  sdu_sizeP,
  mem_block_t      *sdu_pP)
{
  //-----------------------------------------------------------------------------


#if defined(TRACE_RLC_PAYLOAD)
  LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u] Display of rlc_data_ind: size %u\n",
        PROTOCOL_CTXT_ARGS(ctxt_pP),
        (srb_flagP) ? "SRB" : "DRB",
        rb_idP,
        sdu_sizeP);

  rlc_util_print_hex_octets(RLC, (unsigned char*)sdu_pP->data, sdu_sizeP);
#endif

#if T_TRACER
  if (ctxt_pP->enb_flag)
    T(T_ENB_RLC_UL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_sizeP));
#endif


  NB_pdcp_data_ind (
    ctxt_pP,
    srb_flagP,
	srb1bis_flag,
    rb_idP,
    sdu_sizeP,
    sdu_pP);
}

//defined in rlc.c
//-----------------------------------------------------------------------------
rlc_op_status_t NB_rlc_data_req     (const protocol_ctxt_t* const ctxt_pP,
                                  const srb_flag_t   srb_flagP,
                                  const rb_id_t      rb_idP,
                                  const mui_t        muiP,
                                  confirm_t    confirmP,
                                  sdu_size_t   sdu_sizeP,
                                  mem_block_t *sdu_pP)
{
  //-----------------------------------------------------------------------------
  mem_block_t           *new_sdu_p    = NULL;
  rlc_mode_t             rlc_mode     = RLC_MODE_NONE;
  rlc_union_t           *rlc_union_p = NULL;
  hash_key_t             key         = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_rc;

#if defined(Rel10) || defined(Rel14)

3167
 //logical_chan_id_t      log_ch_id  = 0;
3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366
#endif
#ifdef DEBUG_RLC_DATA_REQ
  LOG_D(RLC,PROTOCOL_CTXT_FMT"rlc_data_req:  rb_id %u (MAX %d), muip %d, confirmP %d, sdu_sizeP %d, sdu_pP %p\n",
        PROTOCOL_CTXT_ARGS(ctxt_pP),
        rb_idP,
        NB_RAB_MAX, //may to be cha ged for NB-IoT
        muiP,
        confirmP,
        sdu_sizeP,
        sdu_pP);
#endif
#if defined(Rel10) || defined(Rel14)
#else
  //AssertFatal(MBMS_flagP == 0, "MBMS_flagP %u", MBMS_flagP);
#endif
#ifdef OAI_EMU

  CHECK_CTXT_ARGS(ctxt_pP)

#endif

#if T_TRACER
  if (ctxt_pP->enb_flag)
    T(T_ENB_RLC_DL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_sizeP));
#endif

//  if (MBMS_flagP) {
//    AssertFatal (rb_idP < NB_RB_MBMS_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MBMS_MAX);
//  } else {
//    AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX);
//  }

  DevAssert(sdu_pP != NULL);
  DevCheck(sdu_sizeP > 0, sdu_sizeP, 0, 0);

#if !defined(Rel10) && !defined(Rel14)
 // DevCheck(MBMS_flagP == 0, MBMS_flagP, 0, 0);
#endif

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_IN);

#if defined(Rel10) || defined(Rel14)

//  if (MBMS_flagP == TRUE) {
//    if (ctxt_pP->enb_flag) {
//      log_ch_id = rlc_mbms_enb_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP);
//      mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][log_ch_id];
//    } else {
//      log_ch_id = rlc_mbms_ue_get_lcid_by_rb_id(ctxt_pP->rnti,rb_idP);
//      mbms_id_p = &rlc_mbms_lcid2service_session_id_ue[ctxt_pP->rnti][log_ch_id];
//    }
//
//    key = RLC_COLL_KEY_MBMS_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, mbms_id_p->service_id, mbms_id_p->session_id);
//  } else
#endif
  {
    key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP);
  }

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);

  //MP: the RLC entity should be already configured at configuration time
  if (h_rc == HASH_TABLE_OK) {
    rlc_mode = rlc_union_p->mode;
  } else {
    rlc_mode = RLC_MODE_NONE;
    AssertFatal (0 , "RLC not configured key %ju\n", key);
  }

 // if (MBMS_flagP == 0) {

    LOG_D(RLC, PROTOCOL_CTXT_FMT"[RB %u] Display of rlc_data_req:\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          rb_idP);
#if defined(TRACE_RLC_PAYLOAD)
    rlc_util_print_hex_octets(RLC, (unsigned char*)sdu_pP->data, sdu_sizeP);
#endif

#ifdef DEBUG_RLC_DATA_REQ
    LOG_D(RLC,"RLC_TYPE : %d\n", rlc_mode);
#endif

    switch (rlc_mode) {
    case RLC_MODE_NONE:
      free_mem_block(sdu_pP, __func__);
      LOG_E(RLC, PROTOCOL_CTXT_FMT" Received RLC_MODE_NONE as rlc_type for rb_id %u\n",
            PROTOCOL_CTXT_ARGS(ctxt_pP),
            rb_idP);
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
      return RLC_OP_STATUS_BAD_PARAMETER;

    case RLC_MODE_AM:
#ifdef DEBUG_RLC_DATA_REQ
      msg("RLC_MODE_AM\n");
#endif
      new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_am_data_req_alloc), __func__);

      if (new_sdu_p != NULL) {
        // PROCESS OF COMPRESSION HERE:
        memset (new_sdu_p->data, 0, sizeof (struct rlc_am_data_req_alloc));
        memcpy (&new_sdu_p->data[sizeof (struct rlc_am_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP);

        ((struct rlc_am_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP;
        ((struct rlc_am_data_req *) (new_sdu_p->data))->conf = confirmP;
        ((struct rlc_am_data_req *) (new_sdu_p->data))->mui  = muiP;
        ((struct rlc_am_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_am_data_req_alloc);
        free_mem_block(sdu_pP, __func__);
        rlc_am_data_req(ctxt_pP, &rlc_union_p->rlc.am, new_sdu_p);
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
        return RLC_OP_STATUS_OK;
      } else {
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
        return RLC_OP_STATUS_INTERNAL_ERROR;
      }

      break;

//MP: RLC mode UM not defined for NB-IoT

    case RLC_MODE_TM:
      new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_tm_data_req_alloc), __func__);

      if (new_sdu_p != NULL) {
        // PROCESS OF COMPRESSION HERE:
        memset (new_sdu_p->data, 0, sizeof (struct rlc_tm_data_req_alloc));
        memcpy (&new_sdu_p->data[sizeof (struct rlc_tm_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP);

        ((struct rlc_tm_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP;
        ((struct rlc_tm_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_tm_data_req_alloc);
        free_mem_block(sdu_pP, __func__);
        rlc_tm_data_req(ctxt_pP, &rlc_union_p->rlc.tm, new_sdu_p);
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
        return RLC_OP_STATUS_OK;
      } else {
        //handle_event(ERROR,"FILE %s FONCTION rlc_data_req() LINE %s : out of memory\n", __FILE__, __LINE__);
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
        return RLC_OP_STATUS_INTERNAL_ERROR;
      }

      break;

    default:
      free_mem_block(sdu_pP, __func__);
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
      return RLC_OP_STATUS_INTERNAL_ERROR;

    }

    //MBMS not in NB-IoT
//#if defined(Rel10) || defined(Rel14)
//  } else { /* MBMS_flag != 0 */
//    //  LOG_I(RLC,"DUY rlc_data_req: mbms_rb_id in RLC instant is: %d\n", mbms_rb_id);
//    if (sdu_pP != NULL) {
//      if (sdu_sizeP > 0) {
//        LOG_I(RLC,"received a packet with size %d for MBMS \n", sdu_sizeP);
//        new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_um_data_req_alloc), __func__);
//
//        if (new_sdu_p != NULL) {
//          // PROCESS OF COMPRESSION HERE:
//          memset (new_sdu_p->data, 0, sizeof (struct rlc_um_data_req_alloc));
//          memcpy (&new_sdu_p->data[sizeof (struct rlc_um_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP);
//          ((struct rlc_um_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP;
//          ((struct rlc_um_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_um_data_req_alloc);
//          free_mem_block(sdu_pP, __func__);
//          rlc_um_data_req(ctxt_pP, &rlc_union_p->rlc.um, new_sdu_p);
//
//          //free_mem_block(new_sdu, __func__);
//          VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
//          return RLC_OP_STATUS_OK;
//        } else {
//          VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
//          return RLC_OP_STATUS_BAD_PARAMETER;
//        }
//      } else {
//        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
//        return RLC_OP_STATUS_BAD_PARAMETER;
//      }
//    } else {
//      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
//      return RLC_OP_STATUS_BAD_PARAMETER;
//    }
//  }
//
//#else
//  }
//  else  /* MBMS_flag != 0 */
//  {
//    free_mem_block(sdu_pP, __func__);
//    LOG_E(RLC, "MBMS_flag != 0 while Rel10/Rel14 is not defined...\n");
//    //handle_event(ERROR,"FILE %s FONCTION rlc_data_req() LINE %s : parameter module_id out of bounds :%d\n", __FILE__, __LINE__, module_idP);
//    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT);
//    return RLC_OP_STATUS_BAD_PARAMETER;
//  }

//#endif
}


//defined in pdcp.c
3367
//if SRB1bis go transparently through PDCP
3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858
//--------------------------------------------
boolean_t
NB_pdcp_data_ind(
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t   srb_flagP,
  const srb1bis_flag_t srb1bis_flag,
  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;
  list_t      *sdu_list_p      = NULL;
  mem_block_t *new_sdu_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;
#if defined(LINK_ENB_PDCP_TO_GTPV1U)
  MessageDef  *message_p        = NULL;
  uint8_t     *gtpu_buffer_p    = NULL;
#endif


  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_IN);

#ifdef OAI_EMU

  CHECK_CTXT_ARGS(ctxt_pP);

#endif
#ifdef PDCP_MSG_PRINT
  int i=0;
  LOG_F(PDCP,"[MSG] PDCP UL %s PDU on rb_id %d\n", (srb_flagP)? "CONTROL" : "DATA", rb_idP);

  for (i = 0; i < sdu_buffer_sizeP; i++) {
    LOG_F(PDCP,"%02x ", ((uint8_t*)sdu_buffer_pP->data)[i]);
  }

  LOG_F(PDCP,"\n");
#endif

#if T_TRACER
  if (ctxt_pP->enb_flag != ENB_FLAG_NO)
    T(T_ENB_PDCP_UL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_buffer_sizeP));
#endif

  if (srb1bis_flag) { //SRB1bis

	if(rb_id != 3)
	  	  LOG_E(PDCP, "Received SRB1bis but with rb_id = %d", rb_id);

    if (ctxt_pP->enb_flag == ENB_FLAG_NO) {
      LOG_D(PDCP, "SRB1bis Data indication notification for PDCP entity from eNB %u to UE %x "
            "and radio bearer ID %d 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, "SRB1bis Data indication notification for PDCP entity from UE %x to eNB %u "
            "and radio bearer ID %d 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 { //SRB1 or DRBs

    rb_id = rb_idP % maxDRB_NB_r13; //XXX --> rb_id = rb_Idp(1,2not,3,4,5)%2 = 1,0,1,0,

    AssertError (rb_id < maxDRB_NB_r13, return FALSE, "RB id is too high (%u/%d) %u UE %x!\n",
                 rb_id,
				 maxDRB_NB_r13,
                 ctxt_pP->module_id,
                 ctxt_pP->rnti);
    AssertError (rb_id > 0, return FALSE, "RB id is too low (%u/%d) %u UE %x!\n",
                 rb_id,
				 maxDRB_NB_r13,
                 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;
    }
  }

  sdu_list_p = &pdcp_sdu_list; //protected list in pdcp.h file

  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/1bis
      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 == PDCP_SN_7BIT) { //MP: the only allowed for NB-IoT (2^7-1 = 127)
        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 {
        //sequence_number = 128 (2^7);
        LOG_E(PDCP,
              PROTOCOL_PDCP_CTXT_FMT"wrong sequence number  (%d) for this NB-IoT pdcp entity (should be 7 bit) \n",
              PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p),
              pdcp_p->seq_num_size);
      }

    }

    /*
     * 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 (pdcp_is_rx_seq_number_valid(sequence_number, pdcp_p, srb_flagP) == TRUE) {
#if 0
      LOG_T(PDCP, "Incoming PDU has a sequence number (%d) in accordance with RX window\n", sequence_number);
#endif

    } else {
      LOG_W(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
       */
#if 0
      LOG_D(PDCP, "Ignoring PDU...\n");
      free_mem_block(sdu_buffer, __func__);
      return FALSE;
#else
      //LOG_W(PDCP, "Delivering out-of-order SDU to upper layer...\n");
#endif
    }

    // SRB1/SRB1bis: control-plane data
    if (srb_flagP) {

#if defined(ENABLE_SECURITY)

      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);
        }

        pdcp_validate_security(ctxt_pP,
                               pdcp_p,
                               srb_flagP,
                               rb_idP,
                               pdcp_header_len,
                               sequence_number,
                               sdu_buffer_pP->data,
                               sdu_buffer_sizeP - pdcp_tailer_len);

        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);
        }
      }

#endif

  	MSC_LOG_TX_MESSAGE(
  	    (ctxt_pP->enb_flag == ENB_FLAG_NO)? MSC_PDCP_UE:MSC_PDCP_ENB,
        (ctxt_pP->enb_flag == ENB_FLAG_NO)? MSC_RRC_UE:MSC_RRC_ENB,
        NULL,0,
        PROTOCOL_PDCP_CTXT_FMT" DATA-IND len %u",
        PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p),
        sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len);

      NB_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],
					(srb1bis_flag) ? SRB1BIS_FLAG_YES : SRB1BIS_FLAG_NO);

      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;
    }

    /*
     * DRBs
     */
    payload_offset=pdcp_header_len;// PDCP_USER_PLANE_DATA_PDU_SHORT_SN_HEADER_SIZE;
#if defined(ENABLE_SECURITY)

    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);
      }

      pdcp_validate_security(
        ctxt_pP,
        pdcp_p,
        srb_flagP,
        rb_idP,
        pdcp_header_len,
        sequence_number,
        sdu_buffer_pP->data,
        sdu_buffer_sizeP - pdcp_tailer_len);

      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);
      }

    }

#endif
//  } else {
//    payload_offset=0;
//  }

#if defined(USER_MODE) && defined(OAI_EMU)

  if (oai_emulation.info.otg_enabled == 1) {
    //unsigned int dst_instance;
    int    ctime;

    if ((pdcp_p->rlc_mode == RLC_MODE_AM)) { //MP: &&(MBMS_flagP==0)
      pdcp_p->last_submitted_pdcp_rx_sn = sequence_number;
    }

#if defined(DEBUG_PDCP_PAYLOAD)
    rlc_util_print_hex_octets(PDCP,
                              (unsigned char*)&sdu_buffer_pP->data[payload_offset],
                              sdu_buffer_sizeP - payload_offset);
#endif

    ctime = oai_emulation.info.time_ms; // avg current simulation time in ms : we may get the exact time through OCG?
//    if (MBMS_flagP == 0){
//      LOG_D(PDCP,
//	    PROTOCOL_PDCP_CTXT_FMT"Check received buffer :  (dst %d)\n",
//	    PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p),
//	    ctxt_pP->instance);
//    }
    if (otg_rx_pkt(
          ctxt_pP->instance,
          ctime,
          (const char*)(&sdu_buffer_pP->data[payload_offset]),
                   sdu_buffer_sizeP - payload_offset ) == 0 ) {
      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;
    }
  }

#else

  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;
  }

#endif


  // 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)
   *
   *FIXME: to be check if up to know the length of the PDCP packet is ok also for Nb-IoT
   *
   */
#if defined(LINK_ENB_PDCP_TO_GTPV1U)

  if ((TRUE == ctxt_pP->enb_flag) && (FALSE == srb_flagP)) {
    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, 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_GTPV1_U, INSTANCE_DEFAULT, message_p);
    packet_forwarded = TRUE;
  }

#else
  packet_forwarded = FALSE;
#endif

  if (FALSE == packet_forwarded) {
    new_sdu_p = get_free_mem_block(sdu_buffer_sizeP - payload_offset + sizeof (pdcp_data_ind_header_t), __func__);

    if (new_sdu_p) {
      if (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()
       */
      memset(new_sdu_p->data, 0, sizeof (pdcp_data_ind_header_t));
      ((pdcp_data_ind_header_t *) new_sdu_p->data)->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) { //UE
        ((pdcp_data_ind_header_t *) new_sdu_p->data)->rb_id = rb_id;
#if defined(OAI_EMU)
        ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = ctxt_pP->module_id + oai_emulation.info.nb_enb_local - oai_emulation.info.first_ue_local;
#else
#  if defined(ENABLE_USE_MME)
        /* 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
         */
        ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = 1;
#  endif
#endif

      } else { //eNB
        ((pdcp_data_ind_header_t*) new_sdu_p->data)->rb_id = rb_id + (ctxt_pP->module_id * maxDRB_NB_r13);

#if defined(OAI_EMU)
        ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = ctxt_pP->module_id - oai_emulation.info.first_enb_local;
#endif
      }
#ifdef DEBUG_PDCP_FIFO_FLUSH_SDU
      static uint32_t pdcp_inst = 0;
      ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst = pdcp_inst++;
      LOG_D(PDCP, "inst=%d size=%d\n", ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst, ((pdcp_data_ind_header_t *) new_sdu_p->data)->data_size);
#endif

      memcpy(&new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], \
             &sdu_buffer_pP->data[payload_offset], \
             sdu_buffer_sizeP - payload_offset);
      list_add_tail_eurecom (new_sdu_p, sdu_list_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);

      //XXX MP: reactivated this utils for the moment
      LOG_D(PDCP, "HexPrint of the content");
      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
       * XXX Following two actions are identical, is there a merge error?
       */

      /*if (ctxt_pP->enb_flag == 1) {
          Pdcp_stats_rx[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH]++;
          Pdcp_stats_rx_bytes[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH] += sdu_buffer_sizeP;
        } else {
          Pdcp_stats_rx[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH]++;
          Pdcp_stats_rx_bytes[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH] += sdu_buffer_sizeP;
        }*/
    }
  }

#if defined(STOP_ON_IP_TRAFFIC_OVERLOAD)
  else {
    AssertFatal(0, PROTOCOL_PDCP_CTXT_FMT" PDCP_DATA_IND SDU DROPPED, OUT OF MEMORY \n",
                PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p));
  }

#endif

  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;
}

/*-----------------------------------MAC-RLC------------------------------------------*/

//-----------------------------------------------------------------------------
//defined in rlc_mac.c
void NB_mac_rlc_data_ind     (
  const module_id_t         module_idP,
  const rnti_t              rntiP,
  const module_id_t         eNB_index,
  const frame_t             frameP,
  const eNB_flag_t          enb_flagP,
//const MBMS_flag_t         MBMS_flagP,
  const logical_chan_id_t   channel_idP,
  char                     *buffer_pP,
  const tb_size_t           tb_sizeP,
3859
  num_tb_t                  num_tbP, //number of transport block
3860 3861 3862 3863 3864 3865 3866 3867
  crc_t                    *crcs_pP)
{
  //-----------------------------------------------------------------------------
  rlc_mode_t             rlc_mode   = RLC_MODE_NONE;
  rlc_union_t           *rlc_union_p     = NULL;
  hash_key_t             key             = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_rc;
  srb_flag_t             srb_flag        = (channel_idP <= 3) ? SRB_FLAG_YES : SRB_FLAG_NO;
3868
  //srb1bis_flag_t         srb1bis_flag    = (channel_idP == 3) ? SRB1BIS_FLAG_YES : SRB1BIS_FLAG_NO; //may not needed?
3869 3870 3871 3872 3873 3874
  protocol_ctxt_t     ctxt;

  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, enb_flagP, rntiP, frameP, 0, eNB_index);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_DATA_IND,VCD_FUNCTION_IN);

3875 3876 3877 3878
  if(channel_idP == 2)
	  LOG_E(RLC, "NB_mac_rlc_data_ind over srb_id invalid (%d)\n", channel_idP);


3879 3880 3881 3882 3883 3884
#ifdef DEBUG_MAC_INTERFACE

  if (num_tbP) {
    LOG_D(RLC, PROTOCOL_CTXT_FMT" MAC_RLC_DATA_IND on channel %d (%d), rb max %d, Num_tb %d\n",
          PROTOCOL_CTXT_ARGS(&ctxt),
          channel_idP,
3885
          RLC_MAX_LC,
3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913
		  NB_RB_MAX_NB_IOT,
          num_tbP);
  }

#endif // DEBUG_MAC_INTERFACE
#ifdef OAI_EMU


    AssertFatal (channel_idP < NB_RB_MAX_NB_IOT,        "channel id is too high (%u/%d)!\n",
                 channel_idP, NB_RB_MAX_NB_IOT);

  CHECK_CTXT_ARGS(&ctxt);

#endif

#if T_TRACER
  if (enb_flagP)
    T(T_ENB_RLC_MAC_UL, T_INT(module_idP), T_INT(rntiP), T_INT(channel_idP), T_INT(tb_sizeP));
#endif

  //no MBMS flag

  {
    key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag);
  }

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);

3914
  //MP: also for SRB1bis an RLC-AM mode should be configured
3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932
  if (h_rc == HASH_TABLE_OK) {
    rlc_mode = rlc_union_p->mode;
  } else {
    rlc_mode = RLC_MODE_NONE;
    //AssertFatal (0 , "%s RLC not configured rb id %u lcid %u module %u!\n", __FUNCTION__, rb_id, channel_idP, ue_module_idP);
  }

  struct mac_data_ind data_ind = mac_rlc_deserialize_tb(buffer_pP, tb_sizeP, num_tbP, crcs_pP);

  switch (rlc_mode) {
  case RLC_MODE_NONE:
    //handle_event(WARNING,"FILE %s FONCTION mac_rlc_data_ind() LINE %s : no radio bearer configured :%d\n", __FILE__, __LINE__, channel_idP);
    break;

  case RLC_MODE_AM:
    NB_rlc_am_mac_data_indication(&ctxt, &rlc_union_p->rlc.am, data_ind);
    break;

3933
   //MP: no UM mode for NB_IoT
3934 3935 3936 3937 3938 3939

  case RLC_MODE_TM:
    rlc_tm_mac_data_indication(&ctxt, &rlc_union_p->rlc.tm, data_ind);
    break;

  default:
3940
	  LOG_E(RLC,"mac_rlc_data_ind -> RLC mode unknown");
3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193
	break;
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_DATA_IND,VCD_FUNCTION_OUT);

}

//-----------------------------------------------------------------------------
//defined in rlc_am.c
void
NB_rlc_am_mac_data_indication (
  const protocol_ctxt_t* const ctxt_pP,
  void * const                 rlc_pP,
  struct mac_data_ind          data_indP
)
{
  rlc_am_entity_t*           l_rlc_p = (rlc_am_entity_t*) rlc_pP;

#if TRACE_RLC_AM_PDU || MESSAGE_CHART_GENERATOR
  rlc_am_pdu_info_t   pdu_info;
  rlc_am_pdu_sn_10_t *rlc_am_pdu_sn_10_p;
  mem_block_t        *tb_p;
  sdu_size_t          tb_size_in_bytes;
  int                 num_nack;
  char                message_string[7000];
  size_t              message_string_size = 0;
#   if ENABLE_ITTI
  MessageDef         *msg_p;
#   endif
  int                 octet_index, index;
  /* for no gcc warnings */
  (void)num_nack;
  (void)message_string;
  (void)message_string_size;
  (void)octet_index;
  (void)index;
#endif

  (void)l_rlc_p; /* avoid gcc warning "unused variable" */

#if TRACE_RLC_AM_PDU || MESSAGE_CHART_GENERATOR

  if (data_indP.data.nb_elements > 0) {

    tb_p = data_indP.data.head;

    while (tb_p != NULL) {

      rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)((struct mac_tb_ind *) (tb_p->data))->data_ptr;
      tb_size_in_bytes   = ((struct mac_tb_ind *) (tb_p->data))->size;

      if ((((struct mac_tb_ind *) (tb_p->data))->data_ptr[0] & RLC_DC_MASK) == RLC_DC_DATA_PDU ) {
        if (rlc_am_get_data_pdu_infos(ctxt_pP,l_rlc_p,rlc_am_pdu_sn_10_p, tb_size_in_bytes, &pdu_info) >= 0) {
#if MESSAGE_CHART_GENERATOR
          message_string_size = 0;
          message_string_size += sprintf(&message_string[message_string_size],
                                         MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" DATA SN %u size %u RF %u P %u FI %u",
                                         MSC_AS_TIME_ARGS(ctxt_pP),
                                         PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
                                         pdu_info.sn,
                                         tb_size_in_bytes,
                                         pdu_info.rf,
                                         pdu_info.p,
                                         pdu_info.fi);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], " LSF %u\n", pdu_info.lsf);
            message_string_size += sprintf(&message_string[message_string_size], " SO %u\n", pdu_info.so);
          }

          if (pdu_info.e) {
            message_string_size += sprintf(&message_string[message_string_size], "| HE:");

            for (index=0; index < pdu_info.num_li; index++) {
              message_string_size += sprintf(&message_string[message_string_size], " LI %u", pdu_info.li_list[index]);
            }
          }

          MSC_LOG_RX_MESSAGE(
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_UE:MSC_RLC_ENB,
            (char*)rlc_am_pdu_sn_10_p,
            tb_size_in_bytes,
            message_string);

#endif

#   if ENABLE_ITTI && TRACE_RLC_AM_PDU
          message_string_size += sprintf(&message_string[message_string_size], "Bearer      : %u\n", l_rlc_p->rb_id);
          message_string_size += sprintf(&message_string[message_string_size], "PDU size    : %u\n", tb_size_in_bytes);
          message_string_size += sprintf(&message_string[message_string_size], "Header size : %u\n", pdu_info.header_size);
          message_string_size += sprintf(&message_string[message_string_size], "Payload size: %u\n", pdu_info.payload_size);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA IND: AMD PDU segment\n\n");
          } else {
            message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA IND: AMD PDU\n\n");
          }

          message_string_size += sprintf(&message_string[message_string_size], "Header      :\n");
          message_string_size += sprintf(&message_string[message_string_size], "  D/C       : %u\n", pdu_info.d_c);
          message_string_size += sprintf(&message_string[message_string_size], "  RF        : %u\n", pdu_info.rf);
          message_string_size += sprintf(&message_string[message_string_size], "  P         : %u\n", pdu_info.p);
          message_string_size += sprintf(&message_string[message_string_size], "  FI        : %u\n", pdu_info.fi);
          message_string_size += sprintf(&message_string[message_string_size], "  E         : %u\n", pdu_info.e);
          message_string_size += sprintf(&message_string[message_string_size], "  SN        : %u\n", pdu_info.sn);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], "  LSF       : %u\n", pdu_info.lsf);
            message_string_size += sprintf(&message_string[message_string_size], "  SO        : %u\n", pdu_info.so);
          }

          if (pdu_info.e) {
            message_string_size += sprintf(&message_string[message_string_size], "\nHeader extension  : \n");

            for (index=0; index < pdu_info.num_li; index++) {
              message_string_size += sprintf(&message_string[message_string_size], "  LI        : %u\n", pdu_info.li_list[index]);
            }
          }

          message_string_size += sprintf(&message_string[message_string_size], "\nPayload  : \n");
          message_string_size += sprintf(&message_string[message_string_size], "------+-------------------------------------------------|\n");
          message_string_size += sprintf(&message_string[message_string_size], "      |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |\n");
          message_string_size += sprintf(&message_string[message_string_size], "------+-------------------------------------------------|\n");

          for (octet_index = 0; octet_index < pdu_info.payload_size; octet_index++) {
            if ((octet_index % 16) == 0) {
              if (octet_index != 0) {
                message_string_size += sprintf(&message_string[message_string_size], " |\n");
              }

              message_string_size += sprintf(&message_string[message_string_size], " %04d |", octet_index);
            }

            /*
             * Print every single octet in hexadecimal form
             */
            message_string_size += sprintf(&message_string[message_string_size], " %02x", pdu_info.payload[octet_index]);
            /*
             * Align newline and pipes according to the octets in groups of 2
             */
          }

          /*
           * Append enough spaces and put final pipe
           */
          for (index = octet_index; index < 16; ++index) {
            message_string_size += sprintf(&message_string[message_string_size], "   ");
          }

          message_string_size += sprintf(&message_string[message_string_size], " |\n");

          msg_p = itti_alloc_new_message_sized (ctxt_pP->enb_flag > 0 ? TASK_RLC_ENB:TASK_RLC_UE , RLC_AM_DATA_PDU_IND, message_string_size + sizeof (IttiMsgText));
          msg_p->ittiMsg.rlc_am_data_pdu_ind.size = message_string_size;
          memcpy(&msg_p->ittiMsg.rlc_am_data_pdu_ind.text, message_string, message_string_size);

          itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p);

# else
          rlc_am_display_data_pdu_infos(ctxt_pP, l_rlc_p, &pdu_info);
# endif
        }
      } else {
        if (rlc_am_get_control_pdu_infos(rlc_am_pdu_sn_10_p, &tb_size_in_bytes, &l_rlc_p->control_pdu_info) >= 0) {
#if MESSAGE_CHART_GENERATOR
          message_string_size = 0;
          message_string_size += sprintf(&message_string[message_string_size],
                                         MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" STATUS size ACK_SN %u",
                                         MSC_AS_TIME_ARGS(ctxt_pP),
                                         PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
                                         l_rlc_p->control_pdu_info.ack_sn);

          for (num_nack = 0; num_nack < l_rlc_p->control_pdu_info.num_nack; num_nack++) {
            if (l_rlc_p->control_pdu_info.nack_list[num_nack].e2) {
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %u SO START %u SO END %u",
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_start,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_end);

            } else {
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %u",
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn);
            }
          }

          MSC_LOG_RX_MESSAGE(
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_UE:MSC_RLC_ENB,
            (char*)rlc_am_pdu_sn_10_p,
            tb_size_in_bytes,
            message_string);

#endif

#   if ENABLE_ITTI && TRACE_RLC_AM_PDU
          message_string_size = 0;
          message_string_size += sprintf(&message_string[message_string_size], "Bearer      : %u\n", l_rlc_p->rb_id);
          message_string_size += sprintf(&message_string[message_string_size], "PDU size    : %u\n", ((struct mac_tb_ind *) (tb_p->data))->size);
          message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA IND: STATUS PDU\n\n");
          message_string_size += sprintf(&message_string[message_string_size], "Header      :\n");
          message_string_size += sprintf(&message_string[message_string_size], "  D/C       : %u\n", l_rlc_p->control_pdu_info.d_c);
          message_string_size += sprintf(&message_string[message_string_size], "  CPT       : %u\n", l_rlc_p->control_pdu_info.cpt);
          message_string_size += sprintf(&message_string[message_string_size], "  ACK_SN    : %u\n", l_rlc_p->control_pdu_info.ack_sn);
          message_string_size += sprintf(&message_string[message_string_size], "  E1        : %u\n", l_rlc_p->control_pdu_info.e1);

          for (num_nack = 0; num_nack < l_rlc_p->control_pdu_info.num_nack; num_nack++) {
            if (l_rlc_p->control_pdu_info.nack_list[num_nack].e2) {
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %04d SO START %05d SO END %05d",
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_start,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_end);
            } else {
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %04d",  l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn);
            }
          }

          msg_p = itti_alloc_new_message_sized (ctxt_pP->enb_flag > 0 ? TASK_RLC_ENB:TASK_RLC_UE , RLC_AM_STATUS_PDU_IND, message_string_size + sizeof (IttiMsgText));
          msg_p->ittiMsg.rlc_am_status_pdu_ind.size = message_string_size;
          memcpy(&msg_p->ittiMsg.rlc_am_status_pdu_ind.text, message_string, message_string_size);

          itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p);

#   endif
        }
      }

      tb_p = tb_p->next;
    }
  }

#endif
  rlc_am_rx (ctxt_pP, rlc_pP, data_indP);
}

//-----------------------------------------------------------------------------
//defined in rlc_mac.c
//called by the schedule_ue_spec for getting SDU to be transmitted from SRB1/SRB1bis and DRBs
tbs_size_t NB_mac_rlc_data_req_eNB(
  const module_id_t       module_idP,
  const rnti_t            rntiP,
  const eNB_index_t       eNB_index,
  const frame_t           frameP,
  const MBMS_flag_t       MBMS_flagP,
  const logical_chan_id_t channel_idP,
  char             *buffer_pP)
{
  //-----------------------------------------------------------------------------
  struct mac_data_req    data_request;
  rlc_mode_t             rlc_mode        = RLC_MODE_NONE;
  rlc_union_t           *rlc_union_p     = NULL;
  hash_key_t             key             = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_rc;
  srb_flag_t             srb_flag        = (channel_idP <= 3) ? SRB_FLAG_YES : SRB_FLAG_NO;
4194
  //srb1bis_flag_t			srb1bis_flag = (channel_idP == 3) ? SRB1BIS_FLAG_YES : SRB1BIS_FLAG_NO;
4195 4196 4197 4198 4199 4200
  tbs_size_t             ret_tb_size         = 0;
  protocol_ctxt_t     ctxt;

  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, rntiP, frameP, 0,eNB_index);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_DATA_REQ,VCD_FUNCTION_IN);
4201 4202 4203 4204 4205

  if(channel_idP == 2)
  	  LOG_E(RLC, "NB_mac_rlc_data_req_eNB over srb_id invalid (%d)\n", channel_idP);


4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270
#ifdef DEBUG_MAC_INTERFACE
  LOG_D(RLC, PROTOCOL_CTXT_FMT" MAC_RLC_DATA_REQ channel %d (%d) MAX RB %d, Num_tb %d\n",
        PROTOCOL_CTXT_ARGS((&ctxt)),
        channel_idP,
        RLC_MAX_LC,
        NB_RB_MAX);

#endif // DEBUG_MAC_INTERFACE

  { //SRB1 or DRBs
    AssertFatal (channel_idP < NB_RB_MAX_NB_IOT,        "channel id is too high (%u/%d)!\n",     channel_idP, NB_RB_MAX);
  }

#ifdef OAI_EMU
  CHECK_CTXT_ARGS(&ctxt);
  //printf("MBMS_flagP %d, MBMS_FLAG_NO %d \n",MBMS_flagP, MBMS_FLAG_NO);
  //  AssertFatal (MBMS_flagP == MBMS_FLAG_NO ," MBMS FLAG SHOULD NOT BE SET IN mac_rlc_data_req in UE\n");

#endif

  //no MBMS in NB-IoT

  {
    key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, ENB_FLAG_YES, channel_idP, srb_flag);
  }

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    rlc_mode = rlc_union_p->mode;
  } else {
    rlc_mode = RLC_MODE_NONE;
    AssertFatal (0 , "mac_rlc_data req --> RLC not configured lcid %u RNTI %x!\n", channel_idP, rntiP);
  }

  switch (rlc_mode) {
  case RLC_MODE_NONE:
    ret_tb_size =0;
    break;

  case RLC_MODE_AM:
    data_request = rlc_am_mac_data_request(&ctxt, &rlc_union_p->rlc.am, ENB_FLAG_YES);
    ret_tb_size =mac_rlc_serialize_tb(buffer_pP, data_request.data);
    break;

    //UM mode not for NB-IoT

  case RLC_MODE_TM:
    data_request = rlc_tm_mac_data_request(&ctxt, &rlc_union_p->rlc.tm);
    ret_tb_size = mac_rlc_serialize_tb(buffer_pP, data_request.data);
    break;

  default:
    ;
  }

#if T_TRACER
  if (enb_flagP)
    T(T_ENB_RLC_MAC_DL, T_INT(module_idP), T_INT(rntiP), T_INT(channel_idP), T_INT(ret_tb_size));
#endif

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_DATA_REQ,VCD_FUNCTION_OUT);
  return ret_tb_size;
}