@ -75,68 +75,6 @@ void rrc::init(rrc_cfg_t *cfg_,
start ( RRC_THREAD_PRIO ) ;
}
void rrc : : configure_mbsfn_sibs ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT * sib2 , LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT * sib13 )
{
// Temp assignment of MCCH, this will eventually come from a cfg file
mcch . pmch_infolist_r9_size = 1 ;
mcch . commonsf_allocpatternlist_r9_size = 1 ;
mcch . commonsf_allocperiod_r9 = LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF64 ;
mcch . commonsf_allocpatternlist_r9 [ 0 ] . radio_fr_alloc_offset = 0 ;
mcch . commonsf_allocpatternlist_r9 [ 0 ] . radio_fr_alloc_period = LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N1 ;
mcch . commonsf_allocpatternlist_r9 [ 0 ] . subfr_alloc = 32 + 31 ;
mcch . commonsf_allocpatternlist_r9 [ 0 ] . subfr_alloc_num_frames = LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9_size = 1 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . logicalchannelid_r9 = 1 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . sessionid_r9 = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . sessionid_r9_present = true ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . plmn_id_explicit = true ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . plmn_id_r9 . mcc = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . plmn_id_r9 . mnc = 3 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . plmn_index_r9 = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . serviceid_r9 = 0 ;
if ( mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9_size > 1 ) {
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . logicalchannelid_r9 = 2 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . sessionid_r9 = 1 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . sessionid_r9_present = true ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . plmn_id_explicit = true ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . plmn_id_r9 . mcc = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . plmn_id_r9 . mnc = 3 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . plmn_index_r9 = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . serviceid_r9 = 1 ;
}
mcch . pmch_infolist_r9 [ 0 ] . pmch_config_r9 . datamcs_r9 = 10 ;
mcch . pmch_infolist_r9 [ 0 ] . pmch_config_r9 . mch_schedulingperiod_r9 = LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF64 ;
mcch . pmch_infolist_r9 [ 0 ] . pmch_config_r9 . sf_alloc_end_r9 = 64 * 6 ;
phy - > configure_mbsfn ( sib2 , sib13 , mcch ) ;
mac - > write_mcch ( sib2 , sib13 , & mcch ) ;
}
rrc : : activity_monitor : : activity_monitor ( rrc * parent_ )
{
running = true ;
parent = parent_ ;
}
void rrc : : activity_monitor : : stop ( )
{
if ( running ) {
running = false ;
thread_cancel ( ) ;
wait_thread_finish ( ) ;
}
}
void rrc : : set_connect_notifer ( connect_notifier * cnotifier )
{
this - > cnotifier = cnotifier ;
@ -150,13 +88,22 @@ void rrc::stop()
wait_thread_finish ( ) ;
}
act_monitor . stop ( ) ;
pthread_mutex_lock ( & user_mutex ) ;
users . clear ( ) ;
pthread_mutex_unlock ( & user_mutex ) ;
pthread_mutex_destroy ( & user_mutex ) ;
pthread_mutex_destroy ( & paging_mutex ) ;
}
/*******************************************************************************
Public functions
All public functions must be mutexed .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void rrc : : get_metrics ( rrc_metrics_t & m )
{
if ( running ) {
pthread_mutex_lock ( & user_mutex ) ;
m . n_ues = 0 ;
for ( std : : map < uint16_t , ue > : : iterator iter = users . begin ( ) ; m . n_ues < ENB_METRICS_MAX_USERS & & iter ! = users . end ( ) ; + + iter ) {
@ -166,110 +113,51 @@ void rrc::get_metrics(rrc_metrics_t &m)
}
}
pthread_mutex_unlock ( & user_mutex ) ;
}
}
/*******************************************************************************
MAC interface
uint32_t rrc : : generate_sibs ( )
{
// nof_messages includes SIB2 by default, plus all configured SIBs
uint32_t nof_messages = 1 + cfg . sibs [ 0 ] . sib . sib1 . N_sched_info ;
LIBLTE_RRC_SCHEDULING_INFO_STRUCT * sched_info = cfg . sibs [ 0 ] . sib . sib1 . sched_info ;
// msg is array of SI messages, each SI message msg[i] may contain multiple SIBs
// all SIBs in a SI message msg[i] share the same periodicity
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT * msg = ( LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT * ) calloc ( nof_messages + 1 , sizeof ( LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT ) ) ;
// Copy SIB1 to first SI message
msg [ 0 ] . N_sibs = 1 ;
memcpy ( & msg [ 0 ] . sibs [ 0 ] , & cfg . sibs [ 0 ] , sizeof ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT ) ) ;
// Copy rest of SIBs
for ( uint32_t sched_info_elem = 0 ; sched_info_elem < nof_messages ; sched_info_elem + + ) {
uint32_t msg_index = sched_info_elem + 1 ; // first msg is SIB1, therefore start with second
uint32_t current_msg_element_offset = 0 ;
msg [ msg_index ] . N_sibs = 0 ;
// SIB2 always in second SI message
if ( msg_index = = 1 ) {
msg [ msg_index ] . N_sibs + + ;
memcpy ( & msg [ msg_index ] . sibs [ 0 ] , & cfg . sibs [ 1 ] , sizeof ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT ) ) ;
current_msg_element_offset = 1 ; // make sure "other SIBs" do not overwrite this SIB2
// Save SIB2
memcpy ( & sib2 , & cfg . sibs [ 1 ] . sib . sib2 , sizeof ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT ) ) ;
} else {
current_msg_element_offset = 0 ; // no SIB2, no offset
}
// Add other SIBs to this message, if any
for ( uint32_t mapping = 0 ; mapping < sched_info [ sched_info_elem ] . N_sib_mapping_info ; mapping + + ) {
msg [ msg_index ] . N_sibs + + ;
// current_msg_element_offset skips SIB2 if necessary
memcpy ( & msg [ msg_index ] . sibs [ mapping + current_msg_element_offset ] ,
& cfg . sibs [ ( int ) sched_info [ sched_info_elem ] . sib_mapping_info [ mapping ] . sib_type + 2 ] ,
sizeof ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT ) ) ;
}
}
Those functions that shall be called from a phch_worker should push the command
to the queue and process later
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Pack payload for all messages
for ( uint32_t msg_index = 0 ; msg_index < nof_messages ; msg_index + + ) {
LIBLTE_BIT_MSG_STRUCT bitbuffer ;
liblte_rrc_pack_bcch_dlsch_msg ( & msg [ msg_index ] , & bitbuffer ) ;
srslte_bit_pack_vector ( bitbuffer . msg , sib_buffer [ msg_index ] . msg , bitbuffer . N_bits ) ;
sib_buffer [ msg_index ] . N_bytes = ( bitbuffer . N_bits - 1 ) / 8 + 1 ;
void rrc : : read_pdu_bcch_dlsch ( uint32_t sib_index , uint8_t * payload )
{
if ( sib_index < LIBLTE_RRC_MAX_SIB ) {
memcpy ( payload , sib_buffer [ sib_index ] . msg , sib_buffer [ sib_index ] . N_bytes ) ;
}
free ( msg ) ;
return nof_messages ;
}
void rrc : : config_mac( )
void rrc : : rl_failure ( uint16_t rnti )
{
// Fill MAC scheduler configuration for SIBs
sched_interface : : cell_cfg_t sched_cfg ;
bzero ( & sched_cfg , sizeof ( sched_interface : : cell_cfg_t ) ) ;
for ( uint32_t i = 0 ; i < nof_si_messages ; i + + ) {
sched_cfg . sibs [ i ] . len = sib_buffer [ i ] . N_bytes ;
if ( i = = 0 ) {
sched_cfg . sibs [ i ] . period_rf = 8 ; // SIB1 is always 8 rf
} else {
sched_cfg . sibs [ i ] . period_rf = liblte_rrc_si_periodicity_num [ cfg . sibs [ 0 ] . sib . sib1 . sched_info [ i - 1 ] . si_periodicity ] ;
}
}
sched_cfg . si_window_ms = liblte_rrc_si_window_length_num [ cfg . sibs [ 0 ] . sib . sib1 . si_window_length ] ;
sched_cfg . prach_rar_window = liblte_rrc_ra_response_window_size_num [ cfg . sibs [ 1 ] . sib . sib2 . rr_config_common_sib . rach_cnfg . ra_resp_win_size ] ;
sched_cfg . maxharq_msg3tx = cfg . sibs [ 1 ] . sib . sib2 . rr_config_common_sib . rach_cnfg . max_harq_msg3_tx ;
// Copy Cell configuration
memcpy ( & sched_cfg . cell , & cfg . cell , sizeof ( srslte_cell_t ) ) ;
// Configure MAC scheduler
mac - > cell_cfg ( & sched_cfg ) ;
rrc_pdu p = { rnti , LCID_RLF_USER , NULL } ;
rx_pdu_queue . push ( p ) ;
}
void rrc : : set_activity_user ( uint16_t rnti )
{
rrc_pdu p = { rnti , LCID_ACT_USER , NULL } ;
rx_pdu_queue . push ( p ) ;
}
void rrc : : read_pdu_bcch_dlsch ( uint32_t sib_index , uint8_t * payload )
void rrc : : rem_user_thread ( uint16_t rnti )
{
if ( sib_index < LIBLTE_RRC_MAX_SIB ) {
memcpy ( payload , sib_buffer [ sib_index ] . msg , sib_buffer [ sib_index ] . N_bytes ) ;
}
rrc_pdu p = { rnti , LCID_REM_USER , NULL } ;
rx_pdu_queue . push ( p ) ;
}
void rrc : : rl_failure ( uint16_t rnti )
uint32_t rrc : : get_nof_users ( ) {
return users . size ( ) ;
}
void rrc : : max_retx_attempted ( uint16_t rnti )
{
rrc_log - > info ( " Radio-Link failure detected rnti=0x%x \n " , rnti ) ;
if ( s1ap - > user_exists ( rnti ) ) {
if ( ! s1ap - > user_link_lost ( rnti ) ) {
rrc_log - > info ( " Removing rnti=0x%x \n " , rnti ) ;
rem_user_thread ( rnti ) ;
}
} else {
rrc_log - > warning ( " User rnti=0x%x context not existing in S1AP. Removing user \n " , rnti ) ;
rem_user_thread ( rnti ) ;
}
}
// This function is called from PRACH worker (can wait)
void rrc : : add_user ( uint16_t rnti )
{
pthread_mutex_lock ( & user_mutex ) ;
@ -302,46 +190,17 @@ void rrc::add_user(uint16_t rnti)
pthread_mutex_unlock ( & user_mutex ) ;
}
void rrc : : rem_user ( uint16_t rnti )
{
pthread_mutex_lock ( & user_mutex ) ;
if ( users . count ( rnti ) = = 1 ) {
rrc_log - > console ( " Disconnecting rnti=0x%x. \n " , rnti ) ;
rrc_log - > info ( " Disconnecting rnti=0x%x. \n " , rnti ) ;
/* First remove MAC and GTPU to stop processing DL/UL traffic for this user
/* Function called by MAC after the reception of a C-RNTI CE indicating that the UE still has a
* valid RNTI .
* Called by MAC reader thread ( can wait to process )
*/
mac - > ue_rem ( rnti ) ; // MAC handles PHY
gtpu - > rem_user ( rnti ) ;
// Wait enough time
pthread_mutex_unlock ( & user_mutex ) ;
usleep ( 50000 ) ;
pthread_mutex_lock ( & user_mutex ) ;
// Now remove RLC and PDCP
rlc - > rem_user ( rnti ) ;
pdcp - > rem_user ( rnti ) ;
// And deallocate resources from RRC
users [ rnti ] . sr_free ( ) ;
users [ rnti ] . cqi_free ( ) ;
users . erase ( rnti ) ;
rrc_log - > info ( " Removed user rnti=0x%x \n " , rnti ) ;
} else {
rrc_log - > error ( " Removing user rnti=0x%x (does not exist) \n " , rnti ) ;
}
pthread_mutex_unlock ( & user_mutex ) ;
}
// Function called by MAC after the reception of a C-RNTI CE indicating that the UE still has a
// valid RNTI
void rrc : : upd_user ( uint16_t new_rnti , uint16_t old_rnti )
{
// Remove new_rnti
rem_user_thread ( new_rnti ) ;
// Send Reconfiguration to old_rnti if is RRC_CONNECT or RRC Release if already released here
pthread_mutex_lock ( & user_mutex ) ;
if ( users . count ( old_rnti ) = = 1 ) {
if ( users [ old_rnti ] . is_connected ( ) ) {
users [ old_rnti ] . send_connection_reconf_upd ( pool_allocate ) ;
@ -349,31 +208,10 @@ void rrc::upd_user(uint16_t new_rnti, uint16_t old_rnti)
users [ old_rnti ] . send_connection_release ( ) ;
}
}
pthread_mutex_unlock ( & user_mutex ) ;
}
void rrc : : set_activity_user ( uint16_t rnti )
{
if ( users . count ( rnti ) = = 1 ) {
users [ rnti ] . set_activity ( ) ;
}
}
void rrc : : rem_user_thread ( uint16_t rnti )
{
if ( users . count ( rnti ) = = 1 ) {
rrc_pdu p = { rnti , LCID_REM_USER , NULL } ;
rx_pdu_queue . push ( p ) ;
}
}
uint32_t rrc : : get_nof_users ( ) {
return users . size ( ) ;
}
void rrc : : max_retx_attempted ( uint16_t rnti )
{
}
/*******************************************************************************
PDCP interface
@ -392,6 +230,8 @@ void rrc::write_dl_info(uint16_t rnti, byte_buffer_t* sdu)
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg ;
bzero ( & dl_dcch_msg , sizeof ( LIBLTE_RRC_DL_DCCH_MSG_STRUCT ) ) ;
pthread_mutex_lock ( & user_mutex ) ;
if ( users . count ( rnti ) = = 1 ) {
dl_dcch_msg . msg_type = LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER ;
memcpy ( dl_dcch_msg . msg . dl_info_transfer . dedicated_info . msg , sdu - > msg , sdu - > N_bytes ) ;
@ -404,30 +244,24 @@ void rrc::write_dl_info(uint16_t rnti, byte_buffer_t* sdu)
} else {
rrc_log - > error ( " Rx SDU for unknown rnti=0x%x \n " , rnti ) ;
}
pthread_mutex_unlock ( & user_mutex ) ;
}
void rrc : : release_complete ( uint16_t rnti )
{
rrc_log - > info ( " Received Release Complete rnti=0x%x \n " , rnti ) ;
if ( users . count ( rnti ) = = 1 ) {
if ( ! users [ rnti ] . is_idle ( ) ) {
rlc - > clear_buffer ( rnti ) ;
users [ rnti ] . send_connection_release ( ) ;
// There is no RRCReleaseComplete message from UE thus wait ~100 subframes for tx
usleep ( 100000 ) ;
}
rem_user ( rnti ) ;
} else {
rrc_log - > error ( " Received ReleaseComplete for unknown rnti=0x%x \n " , rnti ) ;
}
void rrc : : release_complete ( uint16_t rnti ) {
rrc_pdu p = { rnti , LCID_REL_USER , NULL } ;
rx_pdu_queue . push ( p ) ;
}
bool rrc : : setup_ue_ctxt ( uint16_t rnti , LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT * msg )
{
pthread_mutex_lock ( & user_mutex ) ;
rrc_log - > info ( " Adding initial context for 0x%x \n " , rnti ) ;
if ( users . count ( rnti ) = = 0 ) {
rrc_log - > warning ( " Unrecognised rnti: 0x%x \n " , rnti ) ;
pthread_mutex_unlock ( & user_mutex ) ;
return false ;
}
@ -488,15 +322,20 @@ bool rrc::setup_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRE
// Setup E-RABs
users [ rnti ] . setup_erabs ( & msg - > E_RABToBeSetupListCtxtSUReq ) ;
pthread_mutex_unlock ( & user_mutex ) ;
return true ;
}
bool rrc : : setup_ue_erabs ( uint16_t rnti , LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT * msg )
{
pthread_mutex_lock ( & user_mutex ) ;
rrc_log - > info ( " Setting up erab(s) for 0x%x \n " , rnti ) ;
if ( users . count ( rnti ) = = 0 ) {
rrc_log - > warning ( " Unrecognised rnti: 0x%x \n " , rnti ) ;
pthread_mutex_unlock ( & user_mutex ) ;
return false ;
}
@ -508,21 +347,35 @@ bool rrc::setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_ST
// Setup E-RABs
users [ rnti ] . setup_erabs ( & msg - > E_RABToBeSetupListBearerSUReq ) ;
pthread_mutex_unlock ( & user_mutex ) ;
return true ;
}
bool rrc : : release_erabs ( uint32_t rnti )
{
pthread_mutex_lock ( & user_mutex ) ;
rrc_log - > info ( " Releasing E-RABs for 0x%x \n " , rnti ) ;
if ( users . count ( rnti ) = = 0 ) {
rrc_log - > warning ( " Unrecognised rnti: 0x%x \n " , rnti ) ;
pthread_mutex_unlock ( & user_mutex ) ;
return false ;
}
return users [ rnti ] . release_erabs ( ) ;
bool ret = users [ rnti ] . release_erabs ( ) ;
pthread_mutex_unlock ( & user_mutex ) ;
return ret ;
}
/*******************************************************************************
Paging functions
These functions use a different mutex because access different shared variables
than user map
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void rrc : : add_paging_id ( uint32_t ueid , LIBLTE_S1AP_UEPAGINGID_STRUCT UEPagingID )
{
pthread_mutex_lock ( & paging_mutex ) ;
@ -615,17 +468,21 @@ bool rrc::is_paging_opportunity(uint32_t tti, uint32_t *payload_len)
return false ;
}
void rrc : : read_pdu_pcch ( uint8_t * payload , uint32_t buffer_size )
{
pthread_mutex_lock ( & paging_mutex ) ;
uint32_t N_bytes = ( bit_buf_paging . N_bits - 1 ) / 8 + 1 ;
if ( N_bytes < = buffer_size ) {
srslte_bit_pack_vector ( bit_buf_paging . msg , payload , bit_buf_paging . N_bits ) ;
}
pthread_mutex_unlock ( & paging_mutex ) ;
}
/*******************************************************************************
Parsers
Private functions
All private functions are not mutexed and must be called from a mutexed enviornment
from either a public function or the internal thread
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void rrc : : parse_ul_ccch ( uint16_t rnti , byte_buffer_t * pdu )
@ -664,12 +521,13 @@ void rrc::parse_ul_ccch(uint16_t rnti, byte_buffer_t *pdu)
if ( users . count ( old_rnti ) ) {
rrc_log - > error ( " Not supported: ConnectionReestablishment for rnti=0x%x. Sending Connection Reject \n " , old_rnti ) ;
users [ rnti ] . send_connection_reest_rej ( ) ;
rem_user_thread( old_rnti ) ;
s1ap- > user_release ( old_rnti , LIBLTE_S1AP_CAUSERADIONETWORK_RELEASE_DUE_TO_EUTRAN_GENERATED_REASON ) ;
} else {
rrc_log - > error ( " Received ConnectionReestablishment for rnti=0x%x without context \n " , old_rnti ) ;
users [ rnti ] . send_connection_reest_rej ( ) ;
}
// remove temporal rnti
rrc_log - > warning ( " Received ConnectionReestablishment for rnti=0x%x. Removing temporal rnti=0x%x \n " , old_rnti , rnti ) ;
rem_user_thread ( rnti ) ;
} else {
rrc_log - > error ( " Received ReestablishmentRequest from an rnti=0x%x not in IDLE \n " , rnti ) ;
@ -695,6 +553,210 @@ void rrc::parse_ul_dcch(uint16_t rnti, uint32_t lcid, byte_buffer_t *pdu)
}
}
void rrc : : process_rl_failure ( uint16_t rnti )
{
if ( users . count ( rnti ) = = 0 ) {
uint32_t n_rfl = users [ rnti ] . rl_failure ( ) ;
if ( n_rfl = = 1 ) {
rrc_log - > info ( " Radio-Link failure detected rnti=0x%x \n " , rnti ) ;
if ( s1ap - > user_exists ( rnti ) ) {
if ( ! s1ap - > user_release ( rnti , LIBLTE_S1AP_CAUSERADIONETWORK_RADIO_CONNECTION_WITH_UE_LOST ) ) {
rrc_log - > info ( " Removing rnti=0x%x \n " , rnti ) ;
}
} else {
rrc_log - > warning ( " User rnti=0x%x context not existing in S1AP. Removing user \n " , rnti ) ;
// Remove user from separate thread to wait to close all resources
rem_user_thread ( rnti ) ;
}
} else {
rrc_log - > info ( " %d Radio-Link failure detected rnti=0x%x \n " , n_rfl , rnti ) ;
}
}
}
void rrc : : process_release_complete ( uint16_t rnti )
{
rrc_log - > info ( " Received Release Complete rnti=0x%x \n " , rnti ) ;
if ( users . count ( rnti ) = = 1 ) {
if ( ! users [ rnti ] . is_idle ( ) ) {
rlc - > clear_buffer ( rnti ) ;
users [ rnti ] . send_connection_release ( ) ;
// There is no RRCReleaseComplete message from UE thus wait ~50 subframes for tx
usleep ( 50000 ) ;
}
// Save to call rem_user() directly without thread, because calling from private function
rem_user ( rnti ) ;
} else {
rrc_log - > error ( " Received ReleaseComplete for unknown rnti=0x%x \n " , rnti ) ;
}
}
void rrc : : rem_user ( uint16_t rnti )
{
if ( users . count ( rnti ) = = 1 ) {
rrc_log - > console ( " Disconnecting rnti=0x%x. \n " , rnti ) ;
rrc_log - > info ( " Disconnecting rnti=0x%x. \n " , rnti ) ;
/* First remove MAC and GTPU to stop processing DL/UL traffic for this user
*/
mac - > ue_rem ( rnti ) ; // MAC handles PHY
gtpu - > rem_user ( rnti ) ;
// Wait enough time
pthread_mutex_unlock ( & user_mutex ) ;
usleep ( 50000 ) ;
pthread_mutex_lock ( & user_mutex ) ;
// Now remove RLC and PDCP
rlc - > rem_user ( rnti ) ;
pdcp - > rem_user ( rnti ) ;
// And deallocate resources from RRC
users [ rnti ] . sr_free ( ) ;
users [ rnti ] . cqi_free ( ) ;
users . erase ( rnti ) ;
rrc_log - > info ( " Removed user rnti=0x%x \n " , rnti ) ;
} else {
rrc_log - > error ( " Removing user rnti=0x%x (does not exist) \n " , rnti ) ;
}
}
void rrc : : config_mac ( )
{
// Fill MAC scheduler configuration for SIBs
sched_interface : : cell_cfg_t sched_cfg ;
bzero ( & sched_cfg , sizeof ( sched_interface : : cell_cfg_t ) ) ;
for ( uint32_t i = 0 ; i < nof_si_messages ; i + + ) {
sched_cfg . sibs [ i ] . len = sib_buffer [ i ] . N_bytes ;
if ( i = = 0 ) {
sched_cfg . sibs [ i ] . period_rf = 8 ; // SIB1 is always 8 rf
} else {
sched_cfg . sibs [ i ] . period_rf = liblte_rrc_si_periodicity_num [ cfg . sibs [ 0 ] . sib . sib1 . sched_info [ i - 1 ] . si_periodicity ] ;
}
}
sched_cfg . si_window_ms = liblte_rrc_si_window_length_num [ cfg . sibs [ 0 ] . sib . sib1 . si_window_length ] ;
sched_cfg . prach_rar_window = liblte_rrc_ra_response_window_size_num [ cfg . sibs [ 1 ] . sib . sib2 . rr_config_common_sib . rach_cnfg . ra_resp_win_size ] ;
sched_cfg . maxharq_msg3tx = cfg . sibs [ 1 ] . sib . sib2 . rr_config_common_sib . rach_cnfg . max_harq_msg3_tx ;
// Copy Cell configuration
memcpy ( & sched_cfg . cell , & cfg . cell , sizeof ( srslte_cell_t ) ) ;
// Configure MAC scheduler
mac - > cell_cfg ( & sched_cfg ) ;
}
uint32_t rrc : : generate_sibs ( )
{
// nof_messages includes SIB2 by default, plus all configured SIBs
uint32_t nof_messages = 1 + cfg . sibs [ 0 ] . sib . sib1 . N_sched_info ;
LIBLTE_RRC_SCHEDULING_INFO_STRUCT * sched_info = cfg . sibs [ 0 ] . sib . sib1 . sched_info ;
// msg is array of SI messages, each SI message msg[i] may contain multiple SIBs
// all SIBs in a SI message msg[i] share the same periodicity
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT * msg = ( LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT * ) calloc ( nof_messages + 1 , sizeof ( LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT ) ) ;
// Copy SIB1 to first SI message
msg [ 0 ] . N_sibs = 1 ;
memcpy ( & msg [ 0 ] . sibs [ 0 ] , & cfg . sibs [ 0 ] , sizeof ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT ) ) ;
// Copy rest of SIBs
for ( uint32_t sched_info_elem = 0 ; sched_info_elem < nof_messages ; sched_info_elem + + ) {
uint32_t msg_index = sched_info_elem + 1 ; // first msg is SIB1, therefore start with second
uint32_t current_msg_element_offset = 0 ;
msg [ msg_index ] . N_sibs = 0 ;
// SIB2 always in second SI message
if ( msg_index = = 1 ) {
msg [ msg_index ] . N_sibs + + ;
memcpy ( & msg [ msg_index ] . sibs [ 0 ] , & cfg . sibs [ 1 ] , sizeof ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT ) ) ;
current_msg_element_offset = 1 ; // make sure "other SIBs" do not overwrite this SIB2
// Save SIB2
memcpy ( & sib2 , & cfg . sibs [ 1 ] . sib . sib2 , sizeof ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT ) ) ;
} else {
current_msg_element_offset = 0 ; // no SIB2, no offset
}
// Add other SIBs to this message, if any
for ( uint32_t mapping = 0 ; mapping < sched_info [ sched_info_elem ] . N_sib_mapping_info ; mapping + + ) {
msg [ msg_index ] . N_sibs + + ;
// current_msg_element_offset skips SIB2 if necessary
memcpy ( & msg [ msg_index ] . sibs [ mapping + current_msg_element_offset ] ,
& cfg . sibs [ ( int ) sched_info [ sched_info_elem ] . sib_mapping_info [ mapping ] . sib_type + 2 ] ,
sizeof ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT ) ) ;
}
}
// Pack payload for all messages
for ( uint32_t msg_index = 0 ; msg_index < nof_messages ; msg_index + + ) {
LIBLTE_BIT_MSG_STRUCT bitbuffer ;
liblte_rrc_pack_bcch_dlsch_msg ( & msg [ msg_index ] , & bitbuffer ) ;
srslte_bit_pack_vector ( bitbuffer . msg , sib_buffer [ msg_index ] . msg , bitbuffer . N_bits ) ;
sib_buffer [ msg_index ] . N_bytes = ( bitbuffer . N_bits - 1 ) / 8 + 1 ;
}
free ( msg ) ;
return nof_messages ;
}
void rrc : : configure_mbsfn_sibs ( LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT * sib2 , LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT * sib13 )
{
// Temp assignment of MCCH, this will eventually come from a cfg file
mcch . pmch_infolist_r9_size = 1 ;
mcch . commonsf_allocpatternlist_r9_size = 1 ;
mcch . commonsf_allocperiod_r9 = LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF64 ;
mcch . commonsf_allocpatternlist_r9 [ 0 ] . radio_fr_alloc_offset = 0 ;
mcch . commonsf_allocpatternlist_r9 [ 0 ] . radio_fr_alloc_period = LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N1 ;
mcch . commonsf_allocpatternlist_r9 [ 0 ] . subfr_alloc = 32 + 31 ;
mcch . commonsf_allocpatternlist_r9 [ 0 ] . subfr_alloc_num_frames = LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9_size = 1 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . logicalchannelid_r9 = 1 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . sessionid_r9 = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . sessionid_r9_present = true ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . plmn_id_explicit = true ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . plmn_id_r9 . mcc = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . plmn_id_r9 . mnc = 3 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . plmn_index_r9 = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 0 ] . tmgi_r9 . serviceid_r9 = 0 ;
if ( mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9_size > 1 ) {
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . logicalchannelid_r9 = 2 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . sessionid_r9 = 1 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . sessionid_r9_present = true ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . plmn_id_explicit = true ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . plmn_id_r9 . mcc = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . plmn_id_r9 . mnc = 3 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . plmn_index_r9 = 0 ;
mcch . pmch_infolist_r9 [ 0 ] . mbms_sessioninfolist_r9 [ 1 ] . tmgi_r9 . serviceid_r9 = 1 ;
}
mcch . pmch_infolist_r9 [ 0 ] . pmch_config_r9 . datamcs_r9 = 10 ;
mcch . pmch_infolist_r9 [ 0 ] . pmch_config_r9 . mch_schedulingperiod_r9 = LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF64 ;
mcch . pmch_infolist_r9 [ 0 ] . pmch_config_r9 . sf_alloc_end_r9 = 64 * 6 ;
phy - > configure_mbsfn ( sib2 , sib13 , mcch ) ;
mac - > write_mcch ( sib2 , sib13 , & mcch ) ;
}
void rrc : : configure_security ( uint16_t rnti ,
uint32_t lcid ,
uint8_t * k_rrc_enc ,
uint8_t * k_rrc_int ,
uint8_t * k_up_enc ,
uint8_t * k_up_int ,
srslte : : CIPHERING_ALGORITHM_ID_ENUM cipher_algo ,
srslte : : INTEGRITY_ALGORITHM_ID_ENUM integ_algo )
{
// TODO: add k_up_enc, k_up_int support to PDCP
pdcp - > config_security ( rnti , lcid , k_rrc_enc , k_rrc_int , cipher_algo , integ_algo ) ;
}
/*******************************************************************************
RRC thread
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@ -709,6 +771,8 @@ void rrc::run_thread()
if ( p . pdu ) {
rrc_log - > info_hex ( p . pdu - > msg , p . pdu - > N_bytes , " Rx %s PDU " , rb_id_text [ p . lcid ] ) ;
}
// Mutex these calls even though it's a private function
pthread_mutex_lock ( & user_mutex ) ;
if ( users . count ( p . rnti ) = = 1 ) {
switch ( p . lcid )
@ -721,10 +785,18 @@ void rrc::run_thread()
parse_ul_dcch ( p . rnti , p . lcid , p . pdu ) ;
break ;
case LCID_REM_USER :
pthread_mutex_unlock ( & user_mutex ) ;
usleep ( 10000 ) ;
rem_user ( p . rnti ) ;
pthread_mutex_lock ( & user_mutex ) ;
break ;
case LCID_REL_USER :
process_release_complete ( p . rnti ) ;
break ;
case LCID_RLF_USER :
process_rl_failure ( p . rnti ) ;
break ;
case LCID_ACT_USER :
if ( users . count ( p . rnti ) = = 1 ) {
users [ p . rnti ] . set_activity ( ) ;
}
break ;
default :
rrc_log - > error ( " Rx PDU with invalid bearer id: %d " , p . lcid ) ;
@ -737,6 +809,28 @@ void rrc::run_thread()
pthread_mutex_unlock ( & user_mutex ) ;
}
}
/*******************************************************************************
Activity monitor class
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
rrc : : activity_monitor : : activity_monitor ( rrc * parent_ )
{
running = true ;
parent = parent_ ;
}
void rrc : : activity_monitor : : stop ( )
{
if ( running ) {
running = false ;
thread_cancel ( ) ;
wait_thread_finish ( ) ;
}
}
void rrc : : activity_monitor : : run_thread ( )
{
while ( running )
@ -760,40 +854,27 @@ void rrc::activity_monitor::run_thread()
}
}
}
pthread_mutex_unlock ( & parent - > user_mutex ) ;
if ( rem_rnti ) {
if ( parent - > s1ap - > user_exists ( rem_rnti ) ) {
parent - > s1ap - > user_ inactivity( rem_rnti ) ;
parent - > s1ap - > user_ release( rem_rnti , LIBLTE_S1AP_CAUSERADIONETWORK_USER_INACTIVITY ) ;
} else {
if ( rem_rnti ! = SRSLTE_MRNTI )
parent - > rem_user ( rem_rnti ) ;
}
}
pthread_mutex_unlock ( & parent - > user_mutex ) ;
}
}
/*******************************************************************************
RRC : : UE Helpers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void rrc : : configure_security ( uint16_t rnti ,
uint32_t lcid ,
uint8_t * k_rrc_enc ,
uint8_t * k_rrc_int ,
uint8_t * k_up_enc ,
uint8_t * k_up_int ,
srslte : : CIPHERING_ALGORITHM_ID_ENUM cipher_algo ,
srslte : : INTEGRITY_ALGORITHM_ID_ENUM integ_algo )
{
// TODO: add k_up_enc, k_up_int support to PDCP
pdcp - > config_security ( rnti , lcid , k_rrc_enc , k_rrc_int , cipher_algo , integ_algo ) ;
}
/*******************************************************************************
UE class
Every function in UE class is called from a mutex environment thus does not
need extra protection .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
rrc : : ue : : ue ( )
{
@ -812,6 +893,7 @@ rrc::ue::ue()
cqi_idx = 0 ;
cqi_sched_sf_idx = 0 ;
cqi_sched_prb_idx = 0 ;
rlf_cnt = 0 ;
state = RRC_STATE_IDLE ;
pool = srslte : : byte_buffer_pool : : get_instance ( ) ;
}
@ -821,6 +903,11 @@ rrc_state_t rrc::ue::get_state()
return state ;
}
uint32_t rrc : : ue : : rl_failure ( ) {
rlf_cnt + + ;
return rlf_cnt ;
}
void rrc : : ue : : set_activity ( )
{
gettimeofday ( & t_last_activity , NULL ) ;
@ -1222,7 +1309,6 @@ void rrc::ue::send_connection_setup(bool is_setup)
rr_cfg = & dl_ccch_msg . msg . rrc_con_reest . rr_cnfg ;
}
// Add SRB1 to cfg
rr_cfg - > srb_to_add_mod_list_size = 1 ;
rr_cfg - > srb_to_add_mod_list [ 0 ] . srb_id = 1 ;
@ -1349,13 +1435,11 @@ void rrc::ue::send_connection_setup(bool is_setup)
send_dl_ccch ( & dl_ccch_msg ) ;
}
void rrc : : ue : : send_connection_reest ( )
{
send_connection_setup ( false ) ;
}
void rrc : : ue : : send_connection_release ( )
{
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg ;
@ -1793,7 +1877,6 @@ int rrc::ue::sr_allocate(uint32_t period, uint32_t *I_sr, uint32_t *N_pucch_sr)
return 0 ;
}
int rrc : : ue : : cqi_free ( )
{
if ( cqi_allocated ) {
@ -1885,7 +1968,4 @@ int rrc::ue::cqi_allocate(uint32_t period, uint32_t *pmi_idx, uint32_t *n_pucch)
return 0 ;
}
}