Changes in RRC and S1AP to make enb more robust on UE add/rem operations.

* Consolidated functions in S1AP

* Fixed ASAN in some GCC

* Stop quicker the enb

* Minor typo edit

* Fixed mutexing issues in RRC and possibly RLC/PDCP when adding/removing users
master
Ismael Gomez 6 years ago committed by GitHub
parent a75604eb0e
commit 6120f20290
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -324,8 +324,8 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
endif(NOT WIN32)
if (ENABLE_ASAN)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fuse-ld=gold")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fuse-ld=gold")
endif (ENABLE_ASAN)
endif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")

@ -278,9 +278,7 @@ public:
virtual void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec) = 0;
virtual void write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu) = 0;
virtual bool user_exists(uint16_t rnti) = 0;
virtual void user_inactivity(uint16_t rnti) = 0;
virtual void release_eutran(uint16_t rnti) = 0;
virtual bool user_link_lost(uint16_t rnti) = 0;
virtual bool user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio) = 0;
virtual void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res) = 0;
virtual void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res) = 0;
// virtual void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) = 0;

@ -41,7 +41,6 @@ class pdcp : public pdcp_interface_rlc,
public:
void init(rlc_interface_pdcp *rlc_, rrc_interface_pdcp *rrc_, gtpu_interface_pdcp *gtpu_, srslte::log *pdcp_log_);
~pdcp();
void stop();
// pdcp_interface_rlc
@ -104,10 +103,7 @@ private:
user_interface_gtpu gtpu_itf;
user_interface_rrc rrc_itf;
srslte::pdcp *pdcp;
};
// Mutex to protect access to users std::map
pthread_mutex_t mutex;
};
std::map<uint32_t,user_interface> users;

@ -49,7 +49,6 @@ public:
void init(pdcp_interface_rlc *pdcp_, rrc_interface_rlc *rrc_, mac_interface_rlc *mac_,
srslte::mac_interface_timers *mac_timers_, srslte::log *log_h);
~rlc();
void stop();
// rlc_interface_rrc
@ -92,13 +91,11 @@ private:
srsenb::rrc_interface_rlc *rrc;
srslte::rlc *rlc;
srsenb::rlc *parent;
};
// Mutex to protect access to users std::map
pthread_mutex_t mutex;
};
std::map<uint32_t,user_interface> users;
std::vector<mch_service_t> mch_services;
mac_interface_rlc *mac;
pdcp_interface_rlc *pdcp;
rrc_interface_rlc *rrc;

@ -140,9 +140,6 @@ public:
void stop();
void get_metrics(rrc_metrics_t &m);
//rrc_interface_phy
void configure_mbsfn_sibs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13);
// rrc_interface_mac
void rl_failure(uint16_t rnti);
void add_user(uint16_t rnti);
@ -195,7 +192,9 @@ public:
bool is_idle();
bool is_timeout();
void set_activity();
uint32_t rl_failure();
rrc_state_t get_state();
void send_connection_setup(bool is_setup = true);
@ -257,6 +256,7 @@ public:
uint32_t m_tmsi;
uint8_t mmec;
uint32_t rlf_cnt;
uint8_t transaction_id;
rrc_state_t state;
@ -311,9 +311,13 @@ private:
// user connect notifier
connect_notifier *cnotifier;
void process_release_complete(uint16_t rnti);
void process_rl_failure(uint16_t rnti);
void rem_user(uint16_t rnti);
uint32_t generate_sibs();
void config_mac();
void configure_mbsfn_sibs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13);
void config_mac();
void parse_ul_dcch(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu);
void parse_ul_ccch(uint16_t rnti, srslte::byte_buffer_t *pdu);
void configure_security(uint16_t rnti,
@ -344,7 +348,10 @@ private:
srslte::byte_buffer_t* pdu;
}rrc_pdu;
const static uint32_t LCID_REM_USER = 0xffff0001;
const static uint32_t LCID_REM_USER = 0xffff0001;
const static uint32_t LCID_REL_USER = 0xffff0002;
const static uint32_t LCID_RLF_USER = 0xffff0003;
const static uint32_t LCID_ACT_USER = 0xffff0004;
bool running;
static const int RRC_THREAD_PRIO = 65;

@ -76,9 +76,7 @@ public:
void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec);
void write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu);
bool user_exists(uint16_t rnti);
void user_inactivity(uint16_t rnti);
bool user_link_lost(uint16_t rnti);
void release_eutran(uint16_t rnti);
bool user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio);
void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res);
void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res);
//void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps);

@ -234,16 +234,17 @@ void enb::stop()
{
if(started)
{
s1ap.stop();
gtpu.stop();
phy.stop();
mac.stop();
usleep(100000);
usleep(50000);
rlc.stop();
pdcp.stop();
rrc.stop();
usleep(1e5);
usleep(10000);
if(args->pcap.enable)
{
mac_pcap.close();

@ -161,7 +161,7 @@ int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint
return 0;
}
} else {
Error("User rnti=0x%x not found- this\n", rnti);
Error("User rnti=0x%x not found\n", rnti);
return -1;
}
}

@ -420,12 +420,12 @@ int main(int argc, char *argv[])
while (running) {
if (args.expert.print_buffer_state) {
cnt++;
if (cnt==10) {
if (cnt==1000) {
cnt=0;
enb->print_pool();
}
}
sleep(1);
usleep(10000);
}
pthread_cancel(input);
metrics.stop();

@ -355,13 +355,16 @@ void phch_worker::rem_rnti(uint16_t rnti)
void phch_worker::work_imp()
{
bool is_mutexed;
if (!running) {
return;
}
subframe_cfg_t sf_cfg;
phy->get_sf_config(&sf_cfg, tti_tx_dl);// TODO difference between tti_tx_dl and t_tx_dl
pthread_mutex_lock(&mutex);
is_mutexed = true;
mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants;
mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants;
@ -455,7 +458,10 @@ void phch_worker::work_imp()
}
}
}
is_mutexed = false;
pthread_mutex_unlock(&mutex);
// Generate signal and transmit
if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) {
srslte_enb_dl_gen_signal(&enb_dl);
@ -484,7 +490,9 @@ void phch_worker::work_imp()
#endif
unlock:
pthread_mutex_unlock(&mutex);
if (is_mutexed) {
pthread_mutex_unlock(&mutex);
}
}

@ -37,11 +37,6 @@ void pdcp::init(rlc_interface_pdcp* rlc_, rrc_interface_pdcp* rrc_, gtpu_interfa
log_h = pdcp_log_;
pool = srslte::byte_buffer_pool::get_instance();
pthread_mutex_init(&mutex, NULL);
}
pdcp::~pdcp() {
pthread_mutex_destroy(&mutex);
}
void pdcp::stop()
@ -49,14 +44,11 @@ void pdcp::stop()
for(std::map<uint32_t, user_interface>::iterator iter=users.begin(); iter!=users.end(); ++iter) {
rem_user((uint32_t) iter->first);
}
pthread_mutex_lock(&mutex);
users.clear();
pthread_mutex_unlock(&mutex);
}
void pdcp::add_user(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti) == 0) {
srslte::pdcp *obj = new srslte::pdcp;
obj->init(&users[rnti].rlc_itf, &users[rnti].rrc_itf, &users[rnti].gtpu_itf, log_h, RB_ID_SRB0, SECURITY_DIRECTION_DOWNLINK);
@ -69,24 +61,20 @@ void pdcp::add_user(uint16_t rnti)
users[rnti].gtpu_itf.gtpu = gtpu;
users[rnti].pdcp = obj;
}
pthread_mutex_unlock(&mutex);
}
void pdcp::rem_user(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].pdcp->stop();
delete users[rnti].pdcp;
users[rnti].pdcp = NULL;
users.erase(rnti);
}
pthread_mutex_unlock(&mutex);
}
void pdcp::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cfg)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
if(rnti != SRSLTE_MRNTI){
users[rnti].pdcp->add_bearer(lcid, cfg);
@ -94,45 +82,37 @@ void pdcp::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t
users[rnti].pdcp->add_bearer_mrb(lcid, cfg);
}
}
pthread_mutex_unlock(&mutex);
}
void pdcp::reset(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].pdcp->reset();
}
pthread_mutex_unlock(&mutex);
}
void pdcp::config_security(uint16_t rnti, uint32_t lcid, uint8_t* k_rrc_enc_, uint8_t* k_rrc_int_,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].pdcp->config_security(lcid, k_rrc_enc_, k_rrc_int_, cipher_algo_, integ_algo_);
users[rnti].pdcp->enable_integrity(lcid);
users[rnti].pdcp->enable_encryption(lcid);
}
pthread_mutex_unlock(&mutex);
}
void pdcp::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].pdcp->write_pdu(lcid, sdu);
} else {
pool->deallocate(sdu);
}
pthread_mutex_unlock(&mutex);
}
void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
if(rnti != SRSLTE_MRNTI){
users[rnti].pdcp->write_sdu(lcid, sdu);
@ -142,7 +122,6 @@ void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
} else {
pool->deallocate(sdu);
}
pthread_mutex_unlock(&mutex);
}
void pdcp::user_interface_gtpu::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu)

@ -40,11 +40,6 @@ void rlc::init(pdcp_interface_rlc* pdcp_, rrc_interface_rlc* rrc_, mac_interface
pool = srslte::byte_buffer_pool::get_instance();
pthread_mutex_init(&mutex, NULL);
}
rlc::~rlc() {
pthread_mutex_destroy(&mutex);
}
void rlc::stop()
@ -52,15 +47,12 @@ void rlc::stop()
for(std::map<uint32_t, user_interface>::iterator iter=users.begin(); iter!=users.end(); ++iter) {
rem_user((uint32_t) iter->first);
}
pthread_mutex_lock(&mutex);
users.clear();
pthread_mutex_unlock(&mutex);
}
void rlc::add_user(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti) == 0) {
if (users.count(rnti) == 0) {
srslte::rlc *obj = new srslte::rlc;
obj->init(&users[rnti], &users[rnti], &users[rnti], log_h, mac_timers, RB_ID_SRB0);
users[rnti].rnti = rnti;
@ -69,33 +61,27 @@ void rlc::add_user(uint16_t rnti)
users[rnti].rlc = obj;
users[rnti].parent = this;
}
pthread_mutex_unlock(&mutex);
}
void rlc::rem_user(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].rlc->stop();
delete users[rnti].rlc;
users[rnti].rlc = NULL;
users.erase(rnti);
}
pthread_mutex_unlock(&mutex);
}
void rlc::reset(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].rlc->reset();
}
pthread_mutex_unlock(&mutex);
}
void rlc::clear_buffer(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].rlc->empty_queue();
for (int i=0;i<SRSLTE_N_RADIO_BEARERS;i++) {
@ -103,34 +89,27 @@ void rlc::clear_buffer(uint16_t rnti)
}
log_h->info("Cleared buffer rnti=0x%x\n", rnti);
}
pthread_mutex_unlock(&mutex);
}
void rlc::add_bearer(uint16_t rnti, uint32_t lcid)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].rlc->add_bearer(lcid);
}
pthread_mutex_unlock(&mutex);
}
void rlc::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].rlc->add_bearer(lcid, cnfg);
}
pthread_mutex_unlock(&mutex);
}
void rlc::add_bearer_mrb(uint16_t rnti, uint32_t lcid)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].rlc->add_bearer_mrb_enb(lcid);
}
pthread_mutex_unlock(&mutex);
}
void rlc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
@ -140,14 +119,13 @@ void rlc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
int rlc::read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes)
{
pthread_mutex_lock(&mutex);
int ret;
uint32_t tx_queue;
if (users.count(rnti)) {
if (rnti != SRSLTE_MRNTI) {
if(users.count(rnti)){
if(rnti != SRSLTE_MRNTI){
ret = users[rnti].rlc->read_pdu(lcid, payload, nof_bytes);
tx_queue = users[rnti].rlc->get_total_buffer_state(lcid);
} else {
}else{
ret = users[rnti].rlc->read_pdu_mch(lcid, payload, nof_bytes);
tx_queue = users[rnti].rlc->get_total_mch_buffer_state(lcid);
}
@ -157,14 +135,15 @@ int rlc::read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_b
uint32_t retx_queue = 0;
log_h->debug("Buffer state PDCP: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue);
mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue);
return ret;
}else{
return SRSLTE_ERROR;
}
pthread_mutex_unlock(&mutex);
return ret;
}
void rlc::write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes)
{
pthread_mutex_lock(&mutex);
if (users.count(rnti)) {
users[rnti].rlc->write_pdu(lcid, payload, nof_bytes);
@ -175,7 +154,6 @@ void rlc::write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof
log_h->debug("Buffer state PDCP: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue);
mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue);
}
pthread_mutex_unlock(&mutex);
}
void rlc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t *payload)
@ -186,8 +164,7 @@ void rlc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t *payload)
void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
{
pthread_mutex_lock(&mutex);
uint32_t tx_queue;
if (users.count(rnti)) {
if(rnti != SRSLTE_MRNTI){
@ -206,7 +183,6 @@ void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
} else {
pool->deallocate(sdu);
}
pthread_mutex_unlock(&mutex);
}
bool rlc::rb_is_um(uint16_t rnti, uint32_t lcid) {

@ -75,69 +75,7 @@ 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)
void rrc::set_connect_notifer(connect_notifier *cnotifier)
{
this->cnotifier = cnotifier;
}
@ -150,104 +88,40 @@ 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);
}
void rrc::get_metrics(rrc_metrics_t &m)
{
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) {
ue *u = (ue*) &iter->second;
if(iter->first != SRSLTE_MRNTI){
m.ues[m.n_ues++].state = u->get_state();
}
}
pthread_mutex_unlock(&user_mutex);
}
/*******************************************************************************
Public functions
All public functions must be mutexed.
*******************************************************************************/
uint32_t rrc::generate_sibs()
void rrc::get_metrics(rrc_metrics_t &m)
{
// 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));
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) {
ue *u = (ue*) &iter->second;
if(iter->first != SRSLTE_MRNTI){
m.ues[m.n_ues++].state = u->get_state();
}
}
pthread_mutex_unlock(&user_mutex);
}
// 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::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);
}
/*******************************************************************************
MAC interface
Those functions that shall be called from a phch_worker should push the command
to the queue and process later
*******************************************************************************/
void rrc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t* payload)
{
@ -257,123 +131,87 @@ void rrc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t* payload)
}
void rrc::rl_failure(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);
}
{
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::rem_user_thread(uint16_t rnti)
{
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)
{
}
// This function is called from PRACH worker (can wait)
void rrc::add_user(uint16_t rnti)
{
pthread_mutex_lock(&user_mutex);
if (users.count(rnti) == 0) {
users[rnti].parent = this;
users[rnti].rnti = rnti;
users[rnti].parent = this;
users[rnti].rnti = rnti;
rlc->add_user(rnti);
pdcp->add_user(rnti);
pdcp->add_user(rnti);
rrc_log->info("Added new user rnti=0x%x\n", rnti);
} else {
rrc_log->error("Adding user rnti=0x%x (already exists)\n", rnti);
}
if(rnti == SRSLTE_MRNTI){
srslte::srslte_pdcp_config_t cfg;
cfg.is_control = false;
cfg.is_data = true;
cfg.direction = SECURITY_DIRECTION_DOWNLINK;
uint32_t teid_in = 1;
for(uint32_t i = 0; i <mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size; i++) {
uint32_t lcid = mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[i].logicalchannelid_r9;
rlc->add_bearer_mrb(SRSLTE_MRNTI,lcid);
pdcp->add_bearer(SRSLTE_MRNTI,lcid,cfg);
gtpu->add_bearer(SRSLTE_MRNTI,lcid, 1, 1, &teid_in);
}
}
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
*/
mac->ue_rem(rnti); // MAC handles PHY
gtpu->rem_user(rnti);
if(rnti == SRSLTE_MRNTI){
srslte::srslte_pdcp_config_t cfg;
cfg.is_control = false;
cfg.is_data = true;
cfg.direction = SECURITY_DIRECTION_DOWNLINK;
uint32_t teid_in = 1;
// 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);
for(uint32_t i = 0; i <mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size; i++) {
uint32_t lcid = mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[i].logicalchannelid_r9;
rlc->add_bearer_mrb(SRSLTE_MRNTI,lcid);
pdcp->add_bearer(SRSLTE_MRNTI,lcid,cfg);
gtpu->add_bearer(SRSLTE_MRNTI,lcid, 1, 1, &teid_in);
}
}
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)
/* 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)
*/
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);
} else {
users[old_rnti].send_connection_release();
}
}
}
void rrc::set_activity_user(uint16_t rnti)
{
if (users.count(rnti) == 1) {
users[rnti].set_activity();
}
pthread_mutex_unlock(&user_mutex);
}
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,63 +809,72 @@ 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)
while(running)
{
usleep(10000);
pthread_mutex_lock(&parent->user_mutex);
uint16_t rem_rnti = 0;
uint16_t rem_rnti = 0;
for(std::map<uint16_t, ue>::iterator iter=parent->users.begin(); rem_rnti == 0 && iter!=parent->users.end(); ++iter) {
if(iter->first != SRSLTE_MRNTI){
ue *u = (ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
uint16_t rnti = (uint16_t) iter->first;
if (parent->cnotifier && u->is_connected() && !u->connect_notified) {
parent->cnotifier->user_connected(rnti);
u->connect_notified = true;
u->connect_notified = true;
}
if (u->is_timeout()) {
parent->rrc_log->info("User rnti=0x%x timed out. Exists in s1ap=%s\n", rnti, parent->s1ap->user_exists(rnti)?"yes":"no");
rem_rnti = rnti;
}
}
rem_rnti = rnti;
}
}
}
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);
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;
@ -1692,7 +1776,7 @@ void rrc::ue::send_dl_ccch(LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg)
}
}
void rrc::ue::send_dl_dcch(LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg, byte_buffer_t *pdu)
void rrc::ue::send_dl_dcch(LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg, byte_buffer_t *pdu)
{
if (!pdu) {
pdu = pool_allocate;
@ -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;
}
}

@ -204,54 +204,30 @@ void s1ap::write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu)
send_ulnastransport(rnti, pdu);
}
void s1ap::user_inactivity(uint16_t rnti)
bool s1ap::user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio)
{
s1ap_log->info("User inactivity - RNTI:0x%x\n", rnti);
if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) {
s1ap_log->warning("User RNTI:0x%x context not found\n", rnti);
return;
return false;
}
if(ue_ctxt_map[rnti].release_requested) {
s1ap_log->warning("UE context for RNTI:0x%x is in zombie state. Releasing...\n", rnti);
ue_ctxt_map.erase(rnti);
rrc->release_complete(rnti);
return;
}
LIBLTE_S1AP_CAUSE_STRUCT cause;
cause.ext = false;
cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK;
cause.choice.radioNetwork.ext = false;
cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_USER_INACTIVITY;
ue_ctxt_map[rnti].release_requested = true;
send_uectxtreleaserequest(rnti, &cause);
}
void s1ap::release_eutran(uint16_t rnti)
{
s1ap_log->info("Release by EUTRAN - RNTI:0x%x\n", rnti);
if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) {
s1ap_log->warning("User RNTI:0x%x context not found\n", rnti);
return;
}
if(ue_ctxt_map[rnti].release_requested) {
return;
return false;
}
LIBLTE_S1AP_CAUSE_STRUCT cause;
cause.ext = false;
cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK;
cause.choice.radioNetwork.ext = false;
cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_RELEASE_DUE_TO_EUTRAN_GENERATED_REASON;
cause.choice.radioNetwork.e = cause_radio;
ue_ctxt_map[rnti].release_requested = true;
send_uectxtreleaserequest(rnti, &cause);
return send_uectxtreleaserequest(rnti, &cause);
}
bool s1ap::user_exists(uint16_t rnti)
@ -259,29 +235,6 @@ bool s1ap::user_exists(uint16_t rnti)
return ue_ctxt_map.end() != ue_ctxt_map.find(rnti);
}
bool s1ap::user_link_lost(uint16_t rnti)
{
s1ap_log->info("User link lost - RNTI:0x%x\n", rnti);
if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) {
s1ap_log->warning("User RNTI:0x%x context not found\n", rnti);
return false;
}
if(ue_ctxt_map[rnti].release_requested) {
return false;
}
LIBLTE_S1AP_CAUSE_STRUCT cause;
cause.ext = false;
cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK;
cause.choice.radioNetwork.ext = false;
cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_RADIO_CONNECTION_WITH_UE_LOST;
ue_ctxt_map[rnti].release_requested = true;
return send_uectxtreleaserequest(rnti, &cause);
}
void s1ap::ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res)
{
if(res->E_RABSetupListCtxtSURes.len > 0) {

@ -529,7 +529,7 @@ void nas::cipher_decrypt(byte_buffer_t *pdu)
memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6);
break;
default:
nas_log->error("Ciphering algorithmus not known\n");
nas_log->error("Ciphering algorithms not known\n");
break;
}
}

Loading…
Cancel
Save