introducing embms support in common upper layer functions

master
yagoda 7 years ago
parent ec918eab76
commit 49c3578f64

@ -213,17 +213,111 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg);
/*********************************************************************
IE Name: PMCH Info List
IE Name: TMGI
Description: Specifies configuration of all PMCHs of an MBSFN area
Description: Temporary Mobile Group Identity (PLMN + MBMS service ID)
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
// Enums
// Structs
typedef struct{
uint16 mcc;
uint16 mnc;
}LIBLTE_RRC_PLMN_IDENTITY_STRUCT;
typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id_r9;
uint8 plmn_index_r9;
bool plmn_id_explicit;
uint32 serviceid_r9;
}LIBLTE_RRC_TMGI_R9_STRUCT;
// Functions
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_tmgi_r9_ie(LIBLTE_RRC_TMGI_R9_STRUCT *tmgi,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_tmgi_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_TMGI_R9_STRUCT *tmgi);
/*********************************************************************
IE Name: MBMS Session Info
Description: Information about an individual MBMS session
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
// Enums
// Structs
typedef struct{
LIBLTE_RRC_TMGI_R9_STRUCT tmgi_r9;
uint8 sessionid_r9;
bool sessionid_r9_present;
uint8 logicalchannelid_r9;
}LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbms_session_info_r9_ie(LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbms_session_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info);
/*********************************************************************
IE Name: PMCH Config
Description: Contains configuration parameters of the sessions
carried by a PMCH
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
// Enums
typedef enum{
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF8 = 0,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF16,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF32,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF64,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF128,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF256,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF512,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF1024,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS,
}LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM;
static const char liblte_rrc_mch_scheduling_period_r9_text[LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS][20] = {"8", "16", "32", "64", "128", "256", "512", "1024"};
static const uint16 liblte_rrc_mch_scheduling_period_r9_num[LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS] = {8, 16, 32, 64, 128, 256, 512, 1024};
// Structs
typedef struct{
uint16 sf_alloc_end_r9;
uint8 datamcs_r9;
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM mch_schedulingperiod_r9;
}LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_config_r9_ie(LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_config_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg);
/*********************************************************************
IE Name: PMCH Info
Description: Specifies configuration of PMCH of an MBSFN area
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
#define LIBLTE_RRC_MAX_SESSION_PER_PMCH 29
// Enums
// Structs
typedef struct{
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT pmch_config_r9;
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT mbms_sessioninfolist_r9[LIBLTE_RRC_MAX_SESSION_PER_PMCH];
uint8 mbms_sessioninfolist_r9_size;
}LIBLTE_RRC_PMCH_INFO_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_info_r9_ie(LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info);
/*********************************************************************
IE Name: C-RNTI
@ -2227,10 +2321,6 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_registration_param_1xrtt_v920_ie(uint8
// Defines
// Enums
// Structs
typedef struct{
uint16 mcc;
uint16 mnc;
}LIBLTE_RRC_PLMN_IDENTITY_STRUCT;
typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id;
uint32 cell_id;
@ -5135,7 +5225,7 @@ typedef struct{
LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT ue_timers_and_constants;
LIBLTE_RRC_ARFCN_VALUE_EUTRA_STRUCT arfcn_value_eutra;
LIBLTE_RRC_UL_BW_STRUCT ul_bw;
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS];
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg_list[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS];
LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer;
uint32 mbsfn_subfr_cnfg_list_size;
uint8 additional_spectrum_emission;
@ -5545,7 +5635,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_9_ie(uint8
// Structs
typedef struct{
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info_list_r9[LIBLTE_RRC_MAX_MBSFN_AREAS];
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbms_notification_config;
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbsfn_notification_config;
uint8 mbsfn_area_info_list_r9_size;
}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT;
// Functions
@ -5771,18 +5861,18 @@ typedef enum{
LIBLTE_RRC_SIB_TYPE_11,
LIBLTE_RRC_SIB_TYPE_12_v920,
LIBLTE_RRC_SIB_TYPE_13_v920,
LIBLTE_RRC_SIB_TYPE_SPARE_5,
LIBLTE_RRC_SIB_TYPE_SPARE_4,
LIBLTE_RRC_SIB_TYPE_SPARE_3,
LIBLTE_RRC_SIB_TYPE_SPARE_2,
LIBLTE_RRC_SIB_TYPE_SPARE_1,
LIBLTE_RRC_SIB_TYPE_14_v1130,
LIBLTE_RRC_SIB_TYPE_15_v1130,
LIBLTE_RRC_SIB_TYPE_16_v1130,
LIBLTE_RRC_SIB_TYPE_17_v1250,
LIBLTE_RRC_SIB_TYPE_18_v1250,
LIBLTE_RRC_SIB_TYPE_N_ITEMS,
}LIBLTE_RRC_SIB_TYPE_ENUM;
static const char liblte_rrc_sib_type_text[LIBLTE_RRC_SIB_TYPE_N_ITEMS][20] = { "3", "4", "5", "6",
"7", "8", "9", "10",
"11", "12", "13", "SPARE",
"SPARE", "SPARE", "SPARE", "SPARE"};
static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0};
"11", "12_v920", "13_v920", "14_v1130",
"15_v1130", "16_v1130", "17_v1250", "18_v1250"};
static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
// Structs
typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT id;
@ -5846,14 +5936,20 @@ typedef enum{
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_11,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_14,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_15,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_16,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_17,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_18,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1, // Intentionally not first
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS,
}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM;
static const char liblte_rrc_sys_info_block_type_text[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS][20] = { "2", "3", "4", "5",
"6", "7", "8", "9",
"10", "11", "12", "13",
"1"};
static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1};
"14", "15", "16", "17",
"18", "1"};
static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1};
// Structs
typedef union{
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
@ -6551,10 +6647,37 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT
Document Reference: 36.331 v10.0.0 Section 6.2.2
*********************************************************************/
// Defines
#define LIBLTE_RRC_MAX_PMCH_PER_MBSFN 15
// Enums
typedef enum{
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF4 = 0,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF8,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF16,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF32,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF64,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF128,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF256,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS,
}LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM;
static const char liblte_rrc_mbsfn_common_sf_alloc_period_r9_text[LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS][20] = {"4", "8", "16", "32",
"64", "128", "256"};
static const uint32 liblte_rrc_mbsfn_common_sf_alloc_period_r9_num[LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS] = {4, 8, 16, 32,
64, 128, 256};
// Structs
typedef struct{
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT commonsf_allocpatternlist_r9[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS];
uint8 commonsf_allocpatternlist_r9_size;
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM commonsf_allocperiod_r9;
LIBLTE_RRC_PMCH_INFO_R9_STRUCT pmch_infolist_r9[LIBLTE_RRC_MAX_PMCH_PER_MBSFN];
uint8 pmch_infolist_r9_size;
}LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT;
// Functions
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg,
LIBLTE_BIT_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *msg,
LIBLTE_RRC_PAGING_STRUCT *mbsfn_area_cnfg);
/*********************************************************************
Message Name: Master Information Block
@ -6783,8 +6906,12 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT
// Defines
// Enums
// Structs
typedef LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT LIBLTE_RRC_MCCH_MSG_STRUCT;
// Functions
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_mcch_msg(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg,
LIBLTE_BIT_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mcch_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg);
/*********************************************************************
Message Name: PCCH Message

@ -57,7 +57,9 @@ public:
void reestablish();
void reset();
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu);
void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void config_security(uint32_t lcid,
uint8_t *k_enc,
uint8_t *k_int,
@ -72,10 +74,12 @@ public:
// RLC interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu);
void write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu);
void write_pdu_bcch_bch(byte_buffer_t *sdu);
void write_pdu_bcch_dlsch(byte_buffer_t *sdu);
void write_pdu_pcch(byte_buffer_t *sdu);
private:
srsue::rlc_interface_pdcp *rlc;
srsue::rrc_interface_pdcp *rrc;
@ -83,10 +87,12 @@ private:
log *pdcp_log;
pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS];
pdcp_entity pdcp_array_mrb[SRSLTE_N_MCH_LCIDS];
uint32_t lcid; // default LCID that is maintained active by PDCP instance
uint8_t direction;
bool valid_lcid(uint32_t lcid);
bool valid_mch_lcid(uint32_t lcid);
};
} // namespace srslte

@ -63,17 +63,21 @@ public:
// PDCP interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu);
bool rb_is_um(uint32_t lcid);
// MAC interface
uint32_t get_buffer_state(uint32_t lcid);
uint32_t get_total_buffer_state(uint32_t lcid);
uint32_t get_total_mch_buffer_state(uint32_t lcid);
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
int read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
int get_increment_sequence_num();
void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
// RRC interface
void reestablish();
@ -81,7 +85,8 @@ public:
void empty_queue();
void add_bearer(uint32_t lcid);
void add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg);
void add_bearer_mrb(uint32_t lcid);
void add_bearer_mrb_enb(uint32_t lcid);
private:
void reset_metrics();
@ -92,13 +97,16 @@ private:
srslte::mac_interface_timers *mac_timers;
srsue::ue_interface *ue;
srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS];
srslte::rlc_um rlc_array_mrb[SRSLTE_N_MCH_LCIDS];
uint32_t default_lcid;
long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS];
long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS];
long dl_tput_bytes_mrb[SRSLTE_N_MCH_LCIDS];
struct timeval metrics_time[3];
bool valid_lcid(uint32_t lcid);
bool valid_lcid_mrb(uint32_t lcid);
};
} // namespace srsue

@ -72,11 +72,13 @@ class rlc_am
public:
rlc_am();
~rlc_am();
void init(log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers);
mac_interface_timers *mac_timers,
bool is_mrb_=false);
void configure(srslte_rlc_config_t cnfg);
void reset();
void reestablish();

@ -155,7 +155,8 @@ public:
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
srslte::mac_interface_timers *mac_timers_) = 0;
srslte::mac_interface_timers *mac_timers_,
bool is_mrb_=false) = 0;
virtual void configure(srslte_rlc_config_t cnfg) = 0;
virtual void reset() = 0;
virtual void stop() = 0;

@ -45,7 +45,8 @@ public:
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers);
mac_interface_timers *mac_timers,
bool is_mrb_=false);
void configure(srslte_rlc_config_t cnfg);
void reset();
void stop();

@ -50,17 +50,19 @@ class rlc_um
{
public:
rlc_um();
~rlc_um();
~rlc_um();
void init(log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers_);
mac_interface_timers *mac_timers_,
bool mrb_=false);
void configure(srslte_rlc_config_t cnfg);
void reset();
void stop();
void empty_queue();
bool is_mrb();
rlc_mode_t get_mode();
uint32_t get_bearer();
@ -73,7 +75,7 @@ public:
uint32_t get_total_buffer_state();
int read_pdu(uint8_t *payload, uint32_t nof_bytes);
void write_pdu(uint8_t *payload, uint32_t nof_bytes);
int get_increment_sequence_num();
// Timeout callback interface
void timer_expired(uint32_t timeout_id);
@ -87,10 +89,12 @@ private:
srsue::pdcp_interface_rlc *pdcp;
srsue::rrc_interface_rlc *rrc;
mac_interface_timers *mac_timers;
bool mrb;
// TX SDU buffers
rlc_tx_queue tx_sdu_queue;
byte_buffer_t *tx_sdu;
byte_buffer_t tx_sdu_temp;
// Rx window
std::map<uint32_t, rlc_umd_pdu_t> rx_window;
@ -133,9 +137,13 @@ private:
int build_data_pdu(uint8_t *payload, uint32_t nof_bytes);
void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes);
int build_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes);
void handle_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes);
void reassemble_rx_sdus();
bool inside_reordering_window(uint16_t sn);
void debug_state();
std::string rb_name();
};
/****************************************************************************

@ -327,13 +327,218 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8
}
/*********************************************************************
IE Name: PMCH Info List
IE Name: TMGI
Description: Specifies configuration of all PMCHs of an MBSFN area
Description: Temporary Mobile Group Identity (PLMN + MBMS service ID)
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_tmgi_r9_ie(LIBLTE_RRC_TMGI_R9_STRUCT *tmgi,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(tmgi != NULL &&
ie_ptr != NULL)
{
liblte_value_2_bits(tmgi->plmn_id_explicit?1:0, ie_ptr, 1);
if(tmgi->plmn_id_explicit){
liblte_rrc_pack_plmn_identity_ie(&tmgi->plmn_id_r9, ie_ptr);
}else{
liblte_value_2_bits(tmgi->plmn_index_r9-1, ie_ptr, 3);
}
liblte_value_2_bits(tmgi->serviceid_r9, ie_ptr, 24);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_tmgi_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_TMGI_R9_STRUCT *tmgi)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
tmgi != NULL)
{
tmgi->plmn_id_explicit = liblte_bits_2_value(ie_ptr, 1);
if(tmgi->plmn_id_explicit){
liblte_rrc_unpack_plmn_identity_ie(ie_ptr, &tmgi->plmn_id_r9);
}else{
tmgi->plmn_index_r9 = liblte_bits_2_value(ie_ptr, 3) + 1;
}
tmgi->serviceid_r9 = liblte_bits_2_value(ie_ptr, 24);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: MBMS Session Info
Description: Information about an individual MBMS session
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbms_session_info_r9_ie(LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(mbms_session_info != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_value_2_bits(mbms_session_info->sessionid_r9_present?1:0, ie_ptr, 1);
liblte_rrc_pack_tmgi_r9_ie(&mbms_session_info->tmgi_r9, ie_ptr);
if(mbms_session_info->sessionid_r9_present){
liblte_value_2_bits(mbms_session_info->sessionid_r9, ie_ptr, 8);
}
liblte_value_2_bits(mbms_session_info->logicalchannelid_r9, ie_ptr, 5);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbms_session_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
mbms_session_info != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
mbms_session_info->sessionid_r9_present = liblte_bits_2_value(ie_ptr, 1);
liblte_rrc_unpack_tmgi_r9_ie(ie_ptr, &mbms_session_info->tmgi_r9);
if(mbms_session_info->sessionid_r9_present){
mbms_session_info->sessionid_r9 = liblte_bits_2_value(ie_ptr, 8);
}
mbms_session_info->logicalchannelid_r9 = liblte_bits_2_value(ie_ptr, 5);
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: PMCH Config
Description: Contains configuration parameters of the sessions
carried by a PMCH
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_config_r9_ie(LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(pmch_cnfg != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_value_2_bits(pmch_cnfg->sf_alloc_end_r9, ie_ptr, 11);
liblte_value_2_bits(pmch_cnfg->datamcs_r9, ie_ptr, 5);
liblte_value_2_bits(pmch_cnfg->mch_schedulingperiod_r9, ie_ptr, 3);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_config_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
pmch_cnfg != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
pmch_cnfg->sf_alloc_end_r9 = liblte_bits_2_value(ie_ptr, 11);
pmch_cnfg->datamcs_r9 = liblte_bits_2_value(ie_ptr, 5);
pmch_cnfg->mch_schedulingperiod_r9 = (LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM)liblte_bits_2_value(ie_ptr, 3);
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: PMCH Info
Description: Specifies configuration of PMCH of an MBSFN area
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_info_r9_ie(LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i;
if(pmch_info != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_rrc_pack_pmch_config_r9_ie(&pmch_info->pmch_config_r9, ie_ptr);
liblte_value_2_bits(pmch_info->mbms_sessioninfolist_r9_size, ie_ptr, 5);
for(i=0; i<pmch_info->mbms_sessioninfolist_r9_size; i++){
liblte_rrc_pack_mbms_session_info_r9_ie(&pmch_info->mbms_sessioninfolist_r9[i], ie_ptr);
}
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i;
if(ie_ptr != NULL &&
pmch_info != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
liblte_rrc_unpack_pmch_config_r9_ie(ie_ptr, &pmch_info->pmch_config_r9);
pmch_info->mbms_sessioninfolist_r9_size = liblte_bits_2_value(ie_ptr, 5);
for(i=0; i<pmch_info->mbms_sessioninfolist_r9_size; i++){
liblte_rrc_unpack_mbms_session_info_r9_ie(ie_ptr, &pmch_info->mbms_sessioninfolist_r9[i]);
}
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: C-RNTI
@ -8896,7 +9101,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_2_ie(LIBLTE_RRC_SYS_INFO_B
liblte_value_2_bits(sib2->mbsfn_subfr_cnfg_list_size - 1, ie_ptr, 3);
for(i=0; i<sib2->mbsfn_subfr_cnfg_list_size; i++)
{
liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg[i], ie_ptr);
liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg_list[i], ie_ptr);
}
}
@ -8994,7 +9199,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_2_ie(uint8
sib2->mbsfn_subfr_cnfg_list_size = liblte_bits_2_value(ie_ptr, 3) + 1;
for(i=0; i<sib2->mbsfn_subfr_cnfg_list_size; i++)
{
liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg[i]);
liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg_list[i]);
}
}else{
sib2->mbsfn_subfr_cnfg_list_size = 0;
@ -10288,7 +10493,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_13_ie(LIBLTE_RRC_SYS_INFO_
{
liblte_rrc_pack_mbsfn_area_info_ie(&sib13->mbsfn_area_info_list_r9[i], ie_ptr);
}
liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbms_notification_config, ie_ptr);
liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbsfn_notification_config, ie_ptr);
err = LIBLTE_SUCCESS;
}
@ -10317,7 +10522,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_13_ie(uint8
{
liblte_rrc_unpack_mbsfn_area_info_ie(ie_ptr, &sib13->mbsfn_area_info_list_r9[i]);
}
liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbms_notification_config);
liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbsfn_notification_config);
liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr);
@ -13003,7 +13208,80 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT
Document Reference: 36.331 v10.0.0 Section 6.2.2
*********************************************************************/
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg,
LIBLTE_BIT_MSG_STRUCT *msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 i;
if(mbsfn_area_cnfg != NULL &&
msg != NULL)
{
// Non-critical extension
liblte_value_2_bits(0, &msg_ptr, 1);
// commonsf_allocpatternlist_r9
liblte_value_2_bits(mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size-1, &msg_ptr, 3);
for(i=0; i<mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size; i++){
liblte_rrc_pack_mbsfn_subframe_config_ie(&mbsfn_area_cnfg->commonsf_allocpatternlist_r9[i], &msg_ptr);
}
// commonsf_allocperiod_r9
liblte_value_2_bits(mbsfn_area_cnfg->commonsf_allocperiod_r9, &msg_ptr, 3);
// pmch_infolist_r9
liblte_value_2_bits(mbsfn_area_cnfg->pmch_infolist_r9_size, &msg_ptr, 4);
for(i=0; i<mbsfn_area_cnfg->pmch_infolist_r9_size; i++){
liblte_rrc_pack_pmch_info_r9_ie(&mbsfn_area_cnfg->pmch_infolist_r9[i], &msg_ptr);
}
// Fill in the number of bits used
msg->N_bits = msg_ptr - msg->msg;
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 i;
bool ext;
if(msg != NULL &&
mbsfn_area_cnfg != NULL)
{
// Non-critical extension
ext = liblte_bits_2_value(&msg_ptr, 1);
liblte_rrc_warning_not_handled(ext, __func__);
// commonsf_allocpatternlist_r9
mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size = liblte_bits_2_value(&msg_ptr, 3) + 1;
for(i=0; i<mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size; i++){
liblte_rrc_unpack_mbsfn_subframe_config_ie(&msg_ptr, &mbsfn_area_cnfg->commonsf_allocpatternlist_r9[i]);
}
// commonsf_allocperiod_r9
mbsfn_area_cnfg->commonsf_allocperiod_r9 = (LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM)liblte_bits_2_value(&msg_ptr, 3);
// pmch_infolist_r9
mbsfn_area_cnfg->pmch_infolist_r9_size = liblte_bits_2_value(&msg_ptr, 4);
for(i=0; i<mbsfn_area_cnfg->pmch_infolist_r9_size; i++){
liblte_rrc_unpack_pmch_info_r9_ie(&msg_ptr, &mbsfn_area_cnfg->pmch_infolist_r9[i]);
}
liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
Message Name: Master Information Block
@ -13104,7 +13382,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_information_transfer_msg(LIBLTE_BIT_MSG_S
liblte_bits_2_value(&msg_ptr, 2);
// Optional indicator
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);;
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);
// Dedicated info type choice
dl_info_transfer->dedicated_info_type = (LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 2);
@ -13373,6 +13651,66 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT
return(err);
}
/*********************************************************************
Message Name: MCCH Message
Description: Contains the set of RRC messages that may be sent
from the E-UTRAN to the UE on the MCCH logical
channel
Document Reference: 36.331 v10.0.0 Section 6.2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_mcch_msg(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg,
LIBLTE_BIT_MSG_STRUCT *msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint8 ext = false;
if(mcch_msg != NULL &&
msg != NULL)
{
// MCCH choice
liblte_value_2_bits(0, &msg_ptr, 1);
err = liblte_rrc_pack_mbsfn_area_configuration_r9_msg(mcch_msg,
&global_msg);
if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 1))
{
memcpy(msg_ptr, global_msg.msg, global_msg.N_bits);
msg->N_bits = global_msg.N_bits + 1;
}else{
msg->N_bits = 0;
err = LIBLTE_ERROR_INVALID_INPUTS;
}
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mcch_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 N_bits_used;
if(msg != NULL &&
mcch_msg != NULL)
{
// MCCH choice
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);;
if((msg->N_bits-(msg_ptr-msg->msg)) <= (LIBLTE_MAX_MSG_SIZE_BITS - 1))
{
memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg));
err = liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(&global_msg,
mcch_msg);
}
}
return(err);
}
/*********************************************************************
Message Name: PCCH Message

@ -100,6 +100,12 @@ void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
}
}
void pdcp::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu)
{
if(valid_mch_lcid(lcid)){
pdcp_array_mrb[lcid].write_sdu(sdu);
}
}
void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
{
if(lcid >= SRSLTE_N_RADIO_BEARERS) {
@ -114,6 +120,21 @@ void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
}
}
void pdcp::add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cfg)
{
if(lcid >= SRSLTE_N_RADIO_BEARERS) {
pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid);
return;
}
if (!pdcp_array_mrb[lcid].is_active()) {
pdcp_array_mrb[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg);
pdcp_log->info("Added bearer %s\n", rrc->get_rb_name(lcid).c_str());
} else {
pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str());
}
}
void pdcp::config_security(uint32_t lcid,
uint8_t *k_enc,
uint8_t *k_int,
@ -175,6 +196,15 @@ void pdcp::write_pdu_pcch(byte_buffer_t *sdu)
rrc->write_pdu_pcch(sdu);
}
void pdcp::write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu)
{
if(0 == lcid) {
rrc->write_pdu_mch(lcid, sdu);
} else {
gw->write_pdu_mch(lcid, sdu);
}
}
/*******************************************************************************
Helpers
*******************************************************************************/
@ -191,4 +221,17 @@ bool pdcp::valid_lcid(uint32_t lcid)
return true;
}
bool pdcp::valid_mch_lcid(uint32_t lcid)
{
if(lcid >= SRSLTE_N_MCH_LCIDS) {
pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid);
return false;
}
if(!pdcp_array_mrb[lcid].is_active()) {
pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid);
return false;
}
return true;
}
} // namespace srsue

@ -139,6 +139,12 @@ void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
rlc_array[lcid].write_sdu(sdu);
}
}
void rlc::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu)
{
if(valid_lcid_mrb(lcid)) {
rlc_array_mrb[lcid].write_sdu(sdu);
}
}
bool rlc::rb_is_um(uint32_t lcid) {
return rlc_array[lcid].get_mode()==RLC_MODE_UM;
@ -165,6 +171,15 @@ uint32_t rlc::get_total_buffer_state(uint32_t lcid)
}
}
uint32_t rlc::get_total_mch_buffer_state(uint32_t lcid)
{
if(valid_lcid_mrb(lcid)) {
return rlc_array_mrb[lcid].get_total_buffer_state();
} else {
return 0;
}
}
int rlc::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if(valid_lcid(lcid)) {
@ -174,6 +189,15 @@ int rlc::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
return 0;
}
int rlc::read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if(valid_lcid_mrb(lcid)) {
ul_tput_bytes[lcid] += nof_bytes;
return rlc_array_mrb[lcid].read_pdu(payload, nof_bytes);
}
return 0;
}
void rlc::write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if(valid_lcid(lcid)) {
@ -227,6 +251,14 @@ void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes)
}
}
void rlc::write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if(valid_lcid_mrb(lcid)) {
dl_tput_bytes_mrb[lcid] += nof_bytes;
rlc_array_mrb[lcid].write_pdu(payload, nof_bytes);
}
}
/*******************************************************************************
RRC interface
*******************************************************************************/
@ -287,6 +319,27 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
}
void rlc::add_bearer_mrb(uint32_t lcid)
{
// 36.321 Table 6.2.1-4
if(lcid < 0 || lcid >= SRSLTE_N_MCH_LCIDS) {
rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid);
return;
}
bool is_mrb = true;
rlc_array_mrb[lcid].init(rlc_log, lcid, pdcp, rrc, mac_timers, is_mrb);
}
void rlc::add_bearer_mrb_enb(uint32_t lcid)
{
if(lcid >= SRSLTE_N_MCH_LCIDS) {
rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid);
return;
}
rlc_array_mrb[lcid].init(rlc_log,lcid,pdcp,rrc,mac_timers,true);
}
/*******************************************************************************
Helpers
*******************************************************************************/
@ -301,5 +354,16 @@ bool rlc::valid_lcid(uint32_t lcid)
return true;
}
bool rlc::valid_lcid_mrb(uint32_t lcid)
{
if(lcid < 0 || lcid > 31) {
return false;
}
if(!rlc_array_mrb[lcid].is_mrb()) {
return false;
}
return true;
}
} // namespace srsue

@ -81,12 +81,12 @@ rlc_am::~rlc_am()
pool->deallocate(tx_sdu);
}
}
void rlc_am::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
srslte::mac_interface_timers *mac_timers)
srslte::mac_interface_timers *mac_timers,
bool is_mrb)
{
log = log_;
lcid = lcid_;

@ -42,7 +42,8 @@ void rlc_tm::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers)
mac_interface_timers *mac_timers,
bool is_mrb)
{
log = log_;
lcid = lcid_;

@ -26,6 +26,7 @@
#include "srslte/upper/rlc_um.h"
#include <sstream>
#define RX_MOD_BASE(x) (x-vr_uh-cfg.rx_window_size)%cfg.rx_mod
@ -55,6 +56,7 @@ rlc_um::rlc_um() : tx_sdu_queue(32)
vr_ur_in_rx_sdu = 0;
mac_timers = NULL;
mrb = false;
pdu_lost = false;
}
@ -63,24 +65,42 @@ rlc_um::~rlc_um()
{
stop();
}
void rlc_um::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
srslte::mac_interface_timers *mac_timers_)
srslte::mac_interface_timers *mac_timers_,
bool mrb_)
{
log = log_;
lcid = lcid_;
pdcp = pdcp_;
rrc = rrc_;
mac_timers = mac_timers_;
mrb = mrb_;
reordering_timer_id = mac_timers->timer_get_unique_id();
reordering_timer = mac_timers->timer_get(reordering_timer_id);
if(mrb) {
cfg.t_reordering = 0;
cfg.rx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS;
cfg.rx_window_size = 0;
cfg.rx_mod = 32;
cfg.tx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS;
cfg.tx_mod = 32;
log->info("MRB%d configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits\n",
lcid, liblte_rrc_rlc_mode_text[LIBLTE_RRC_RLC_MODE_UM_UNI_DL],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
}
}
void rlc_um::configure(srslte_rlc_config_t cnfg_)
{
if(mrb) {
return; // Default configured in init()
}
cfg = cnfg_.um;
switch(cnfg_.rlc_mode)
@ -88,18 +108,19 @@ void rlc_um::configure(srslte_rlc_config_t cnfg_)
case LIBLTE_RRC_RLC_MODE_UM_BI:
log->warning("%s configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
log->warning("%s configured in %s mode: tx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
log->warning("%s configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break;
default:
@ -116,6 +137,11 @@ void rlc_um::empty_queue() {
}
}
bool rlc_um::is_mrb()
{
return mrb;
}
void rlc_um::stop()
{
reset();
@ -197,7 +223,7 @@ uint32_t rlc_um::get_buffer_state()
// Room needed for fixed header?
if(n_bytes > 0)
n_bytes += 3;
n_bytes += (mrb)?2:3;
return n_bytes;
}
@ -209,9 +235,14 @@ uint32_t rlc_um::get_total_buffer_state()
int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes)
{
int r;
log->debug("MAC opportunity - %d bytes\n", nof_bytes);
pthread_mutex_lock(&mutex);
int r = build_data_pdu(payload, nof_bytes);
if(mrb){
r = build_mch_data_pdu(payload, nof_bytes);
} else{
r = build_data_pdu(payload, nof_bytes);
}
pthread_mutex_unlock(&mutex);
return r;
}
@ -219,7 +250,11 @@ int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes)
void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes)
{
pthread_mutex_lock(&mutex);
if(mrb) {
handle_mch_data_pdu(payload, nof_bytes);
} else {
handle_data_pdu(payload, nof_bytes);
}
pthread_mutex_unlock(&mutex);
}
@ -235,7 +270,7 @@ void rlc_um::timer_expired(uint32_t timeout_id)
// 36.322 v10 Section 5.1.2.2.4
log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n",
rrc->get_rb_name(lcid).c_str());
rb_name().c_str());
log->warning("Lost PDU SN: %d\n", vr_ur);
pdu_lost = true;
@ -269,6 +304,130 @@ bool rlc_um::reordering_timeout_running()
* Helpers
***************************************************************************/
int rlc_um::build_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
if(!tx_sdu && tx_sdu_queue.size() == 0)
{
log->info("No data available to be sent\n");
return 0;
}
byte_buffer_t *pdu = pool_allocate;
if(!pdu || pdu->N_bytes != 0)
{
log->error("Failed to allocate PDU buffer\n");
return 0;
}
rlc_umd_pdu_header_t header;
header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED;
header.sn = vt_us;
header.N_li = 0;
header.sn_size = RLC_UMD_SN_SIZE_5_BITS; //cfg.tx_sn_field_length;
uint32_t to_move = 0;
uint32_t last_li = 0;
uint8_t *pdu_ptr = pdu->msg;
int head_len = rlc_um_packed_length(&header);
int pdu_space = nof_bytes;
if(pdu_space <= head_len + 1)
{
pool->deallocate(pdu);
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
rb_name().c_str(), nof_bytes, head_len);
return 0;
}
// Check for SDU segment
if(tx_sdu)
{
uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
rb_name().c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move;
pdu_ptr += to_move;
pdu->N_bytes += to_move;
tx_sdu->N_bytes -= to_move;
tx_sdu->msg += to_move;
if(tx_sdu->N_bytes == 0)
{
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu);
tx_sdu = NULL;
}
pdu_space -= to_move;
header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU
}
// Pull SDUs from queue
while(pdu_space > head_len + 1 && tx_sdu_queue.size() > 0)
{
log->debug("pdu_space=%d, head_len=%d\n", pdu_space, head_len);
if(last_li > 0)
header.li[header.N_li++] = last_li;
head_len = rlc_um_packed_length(&header);
tx_sdu_queue.read(&tx_sdu);
uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
rb_name().c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move;
pdu_ptr += to_move;
pdu->N_bytes += to_move;
tx_sdu->N_bytes -= to_move;
tx_sdu->msg += to_move;
if(tx_sdu->N_bytes == 0)
{
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu);
tx_sdu = NULL;
}
pdu_space -= to_move;
}
if(tx_sdu)
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
// Set SN
header.sn = vt_us;
vt_us = (vt_us + 1)%cfg.tx_mod;
// Add header and TX
log->debug("%s packing PDU with length %d\n", rb_name().c_str(), pdu->N_bytes);
if(pdu_space > 0 && tx_sdu == NULL){
//header.li[header.N_li++] = last_li;
header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED;
}
rlc_um_write_data_pdu_header(&header, pdu);
memcpy(payload, pdu->msg, pdu->N_bytes);
uint32_t ret = pdu->N_bytes;
log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
pool->deallocate(pdu);
debug_state();
return ret;
}
int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
if(!tx_sdu && tx_sdu_queue.size() == 0)
@ -300,7 +459,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
pool->deallocate(pdu);
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len);
rb_name().c_str(), nof_bytes, head_len);
return 0;
}
@ -310,7 +469,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes);
rb_name().c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move;
pdu_ptr += to_move;
@ -339,7 +498,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes);
rb_name().c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move;
pdu_ptr += to_move;
@ -360,14 +519,16 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
// Set SN
header.sn = vt_us;
vt_us = (vt_us + 1)%cfg.tx_mod;
// Add header and TX
log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
log->debug("%s packing PDU with length %d\n", rb_name().c_str(), pdu->N_bytes);
rlc_um_write_data_pdu_header(&header, pdu);
memcpy(payload, pdu->msg, pdu->N_bytes);
uint32_t ret = pdu->N_bytes;
log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
pool->deallocate(pdu);
@ -375,6 +536,63 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
return ret;
}
void rlc_um::handle_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
if(!rx_sdu) {
rx_sdu = pool_allocate;
}
rlc_umd_pdu_header_t header;
rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header);
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
rb_name().c_str(), header.sn);
//Strip header from PDU
int header_len = rlc_um_packed_length(&header);
payload += header_len;
nof_bytes -= header_len;
if(0 == header.sn) {
vr_uh = 0;
}
// Handle SDU segments
for(uint32_t i=0; i<header.N_li; i++) {
int len = header.li[i];
if(vr_uh != header.sn) {
rx_sdu->reset();
vr_uh = header.sn;
if(!rlc_um_start_aligned(header.fi)) {
payload += len;
nof_bytes -= len;
}
} else {
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], payload, len);
log->debug("Concatenating %d bytes in to current length %d.\n", len, rx_sdu->N_bytes);
rx_sdu->N_bytes += len;
payload += len;
nof_bytes -= len;
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU i=%d", rb_name().c_str(), i);
rx_sdu->set_timestamp();
pdcp->write_pdu_mch(lcid, rx_sdu);
rx_sdu = pool_allocate;
}
}
// Handle last segment
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], payload, nof_bytes);
rx_sdu->N_bytes += nof_bytes;
log->debug("Writing last segment in SDU buffer. Buffer size=%d, segment size=%d\n",
rx_sdu->N_bytes, nof_bytes);
if(rlc_um_end_aligned(header.fi)) {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rb_name().c_str());
rx_sdu->set_timestamp();
pdcp->write_pdu_mch(lcid, rx_sdu);
rx_sdu = pool_allocate;
}
vr_uh = (header.sn + 1);
}
void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
std::map<uint32_t, rlc_umd_pdu_t>::iterator it;
@ -382,20 +600,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header);
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
rrc->get_rb_name(lcid).c_str(), header.sn);
rb_name().c_str(), header.sn);
if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur))
{
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh);
rb_name().c_str(), header.sn, vr_ur, vr_uh);
return;
}
it = rx_window.find(header.sn);
if(rx_window.end() != it)
{
log->info("%s Discarding duplicate SN: %d\n",
rrc->get_rb_name(lcid).c_str(), header.sn);
rb_name().c_str(), header.sn);
return;
}
@ -486,7 +704,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
rx_sdu->reset();
} else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i);
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rb_name().c_str(), vr_ur, i);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
@ -562,7 +780,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
rx_sdu->reset();
} else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i);
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rb_name().c_str(), vr_ur, i);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
@ -601,7 +819,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n");
rx_sdu->reset();
} else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur);
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rb_name().c_str(), vr_ur);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
@ -625,6 +843,9 @@ clean_up_rx_window:
bool rlc_um::inside_reordering_window(uint16_t sn)
{
if(cfg.rx_window_size == 0) {
return true;
}
if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh))
{
@ -637,8 +858,18 @@ bool rlc_um::inside_reordering_window(uint16_t sn)
void rlc_um::debug_state()
{
log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n",
rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh);
rb_name().c_str(), vt_us, vr_ur, vr_ux, vr_uh);
}
std::string rlc_um::rb_name() {
if(mrb) {
std::stringstream ss;
ss << "MRB" << lcid;
return ss.str();
} else {
return rrc->get_rb_name(lcid);
}
}
/****************************************************************************

Loading…
Cancel
Save