diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index d4cca957a..cd284619f 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -41,7 +41,7 @@ class pdcp { public: pdcp(); - virtual ~pdcp(){} + virtual ~pdcp(); void init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_, srsue::gw_interface_pdcp *gw_, @@ -78,18 +78,22 @@ public: 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; srsue::gw_interface_pdcp *gw; - 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; + typedef std::map pdcp_map_t; + typedef std::pair pdcp_map_pair_t; + + log *pdcp_log; + pdcp_map_t pdcp_array, pdcp_array_mrb; + pthread_rwlock_t rwlock; + + // default PDCP entity that is maintained active by PDCP instance + srslte_pdcp_config_t default_cnfg; + uint32_t default_lcid; bool valid_lcid(uint32_t lcid); bool valid_mch_lcid(uint32_t lcid); diff --git a/lib/include/srslte/upper/pdcp_entity.h b/lib/include/srslte/upper/pdcp_entity.h index de51ed1de..6586becc0 100644 --- a/lib/include/srslte/upper/pdcp_entity.h +++ b/lib/include/srslte/upper/pdcp_entity.h @@ -33,6 +33,7 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" #include "srslte/common/threads.h" +#include "pdcp_interface.h" namespace srslte { @@ -59,7 +60,7 @@ static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU", * PDCP Entity interface * Common interface for all PDCP entities ***************************************************************************/ -class pdcp_entity +class pdcp_entity : public pdcp_entity_interface { public: pdcp_entity(); diff --git a/lib/include/srslte/upper/pdcp_interface.h b/lib/include/srslte/upper/pdcp_interface.h new file mode 100644 index 000000000..915fbe420 --- /dev/null +++ b/lib/include/srslte/upper/pdcp_interface.h @@ -0,0 +1,73 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_PDCP_INTERFACE_H +#define SRSLTE_PDCP_INTERFACE_H + +#include "srslte/common/buffer_pool.h" +#include "srslte/common/log.h" +#include "srslte/common/common.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/security.h" +#include "srslte/common/threads.h" + + +namespace srslte { + +/**************************************************************************** + * Virtual PDCP interface common for all PDCP entities + ***************************************************************************/ +class pdcp_entity_interface +{ +public: + virtual ~pdcp_entity_interface() {}; + virtual void init(srsue::rlc_interface_pdcp *rlc_, + srsue::rrc_interface_pdcp *rrc_, + srsue::gw_interface_pdcp *gw_, + srslte::log *log_, + uint32_t lcid_, + srslte_pdcp_config_t cfg_) = 0; + virtual void reset() = 0; + virtual void reestablish() = 0; + virtual bool is_active() = 0; + + // RRC interface + virtual void write_sdu(byte_buffer_t *sdu) = 0; + virtual void config_security(uint8_t *k_enc_, + uint8_t *k_int_, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void enable_integrity() = 0; + virtual void enable_encryption() = 0; + + // RLC interface + virtual void write_pdu(byte_buffer_t *pdu) = 0; +}; + +} // namespace srslte + + +#endif // SRSLTE_PDCP_INTERFACE_H diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index e577a12ce..3f934f73d 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -35,47 +35,75 @@ pdcp::pdcp() rrc = NULL; gw = NULL; pdcp_log = NULL; - lcid = 0; - direction = 0; + default_lcid = 0; + pthread_rwlock_init(&rwlock, NULL); +} + +pdcp::~pdcp() +{ + // destroy all remaining entities + pthread_rwlock_wrlock(&rwlock); + for (pdcp_map_t::iterator it = pdcp_array.begin(); it != pdcp_array.end(); ++it) { + delete(it->second); + } + pdcp_array.clear(); + + pthread_rwlock_unlock(&rwlock); + pthread_rwlock_destroy(&rwlock); } void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_, srsue::gw_interface_pdcp *gw_, log *pdcp_log_, uint32_t lcid_, uint8_t direction_) { - rlc = rlc_; - rrc = rrc_; - gw = gw_; - pdcp_log = pdcp_log_; - lcid = lcid_; - direction = direction_; + rlc = rlc_; + rrc = rrc_; + gw = gw_; + pdcp_log = pdcp_log_; + default_lcid = lcid_; // Default config - srslte_pdcp_config_t cnfg; - cnfg.is_control = false; - cnfg.is_data = false; - cnfg.direction = direction_; + default_cnfg.is_control = false; + default_cnfg.is_data = false; + default_cnfg.direction = direction_; - pdcp_array[0].init(rlc, rrc, gw, pdcp_log, lcid, cnfg); + // create default PDCP entity for SRB0 + add_bearer(0, default_cnfg); } void pdcp::stop() { + // destroy default entity + pthread_rwlock_wrlock(&rwlock); + if (valid_lcid(0)) { + pdcp_map_t::iterator it = pdcp_array.find(0); + delete(it->second); + pdcp_array.erase(it); + } + pthread_rwlock_unlock(&rwlock); } void pdcp::reestablish() { - for(uint32_t i=0;ireestablish(); } } + pthread_rwlock_unlock(&rwlock); } void pdcp::reset() { - for(uint32_t i=0;ireset(); + } } - pdcp_array[0].init(rlc, rrc, gw, pdcp_log, lcid, direction); + if (valid_lcid(0)) { + pdcp_array.at(0)->init(rlc, rrc, gw, pdcp_log, default_lcid, default_cnfg); + } + pthread_rwlock_unlock(&rwlock); } /******************************************************************************* @@ -83,56 +111,74 @@ void pdcp::reset() *******************************************************************************/ bool pdcp::is_drb_enabled(uint32_t lcid) { - if(lcid >= SRSLTE_N_RADIO_BEARERS) { + pthread_rwlock_rdlock(&rwlock); + bool ret = false; + + 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 false; + goto unlock_and_exit; } - return pdcp_array[lcid].is_active(); + if (pdcp_array.find(lcid) == pdcp_array.end()) { + goto unlock_and_exit; + } + ret = pdcp_array.at(lcid)->is_active(); + +unlock_and_exit: + pthread_rwlock_unlock(&rwlock); + return ret; } void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { - if(valid_lcid(lcid)) { - pdcp_array[lcid].write_sdu(sdu); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->write_sdu(sdu); } else { pdcp_log->warning("Writing sdu: lcid=%d. Deallocating sdu\n", lcid); byte_buffer_pool::get_instance()->deallocate(sdu); } + pthread_rwlock_unlock(&rwlock); } void pdcp::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu) { - if(valid_mch_lcid(lcid)){ - pdcp_array_mrb[lcid].write_sdu(sdu); + pthread_rwlock_rdlock(&rwlock); + if (valid_mch_lcid(lcid)){ + pdcp_array_mrb.at(lcid)->write_sdu(sdu); } + pthread_rwlock_unlock(&rwlock); } void pdcp::add_bearer(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[lcid].is_active()) { - pdcp_array[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg); + pthread_rwlock_rdlock(&rwlock); + if (not valid_lcid(lcid)) { + if (not pdcp_array.insert(pdcp_map_pair_t(lcid, new pdcp_entity())).second) { + pdcp_log->error("Error inserting PDCP entity in to array\n."); + return; + } + pdcp_array.at(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()); } + pthread_rwlock_unlock(&rwlock); } 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); + pthread_rwlock_rdlock(&rwlock); + if (not valid_mch_lcid(lcid)) { + if (not pdcp_array_mrb.insert(pdcp_map_pair_t(lcid, new pdcp_entity())).second) { + pdcp_log->error("Error inserting PDCP entity in to array\n."); + return; + } + pdcp_array_mrb.at(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()); } + pthread_rwlock_unlock(&rwlock); } void pdcp::config_security(uint32_t lcid, @@ -141,8 +187,11 @@ void pdcp::config_security(uint32_t lcid, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { - if(valid_lcid(lcid)) - pdcp_array[lcid].config_security(k_enc, k_int, cipher_algo, integ_algo); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->config_security(k_enc, k_int, cipher_algo, integ_algo); + } + pthread_rwlock_unlock(&rwlock); } void pdcp::config_security_all(uint8_t *k_enc, @@ -150,23 +199,31 @@ void pdcp::config_security_all(uint8_t *k_enc, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { + pthread_rwlock_rdlock(&rwlock); for(uint32_t i=0;iis_active()) { + pdcp_array.at(i)->config_security(k_enc, k_int, cipher_algo, integ_algo); } } + pthread_rwlock_unlock(&rwlock); } void pdcp::enable_integrity(uint32_t lcid) { - if(valid_lcid(lcid)) - pdcp_array[lcid].enable_integrity(); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->enable_integrity(); + } + pthread_rwlock_unlock(&rwlock); } void pdcp::enable_encryption(uint32_t lcid) { - if(valid_lcid(lcid)) - pdcp_array[lcid].enable_encryption(); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->enable_encryption(); + } + pthread_rwlock_unlock(&rwlock); } /******************************************************************************* @@ -174,18 +231,21 @@ void pdcp::enable_encryption(uint32_t lcid) *******************************************************************************/ void pdcp::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - if(valid_lcid(lcid)) { - pdcp_array[lcid].write_pdu(pdu); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->write_pdu(pdu); } else { pdcp_log->warning("Writing pdu: lcid=%d. Deallocating pdu\n", lcid); byte_buffer_pool::get_instance()->deallocate(pdu); } + pthread_rwlock_unlock(&rwlock); } void pdcp::write_pdu_bcch_bch(byte_buffer_t *sdu) { rrc->write_pdu_bcch_bch(sdu); } + void pdcp::write_pdu_bcch_dlsch(byte_buffer_t *sdu) { rrc->write_pdu_bcch_dlsch(sdu); @@ -198,7 +258,7 @@ void pdcp::write_pdu_pcch(byte_buffer_t *sdu) void pdcp::write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu) { - if(0 == lcid) { + if (0 == lcid) { rrc->write_pdu_mch(lcid, sdu); } else { gw->write_pdu_mch(lcid, sdu); @@ -206,31 +266,35 @@ void pdcp::write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu) } /******************************************************************************* - Helpers + Helpers (Lock must be hold when calling those) *******************************************************************************/ bool pdcp::valid_lcid(uint32_t lcid) { - if(lcid >= SRSLTE_N_RADIO_BEARERS) { + if (lcid >= SRSLTE_N_RADIO_BEARERS) { pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid); return false; } - if(!pdcp_array[lcid].is_active()) { + + if (pdcp_array.find(lcid) == pdcp_array.end()) { pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid); return false; } + return true; } bool pdcp::valid_mch_lcid(uint32_t lcid) { - if(lcid >= SRSLTE_N_MCH_LCIDS) { + 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()) { + + if (pdcp_array_mrb.find(lcid) == pdcp_array_mrb.end()) { pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid); return false; } + return true; } diff --git a/srsenb/hdr/upper/pdcp.h b/srsenb/hdr/upper/pdcp.h index 9624958e4..ce6b01ca6 100644 --- a/srsenb/hdr/upper/pdcp.h +++ b/srsenb/hdr/upper/pdcp.h @@ -39,7 +39,7 @@ class pdcp : public pdcp_interface_rlc, public pdcp_interface_rrc { public: - + virtual ~pdcp() {}; void init(rlc_interface_pdcp *rlc_, rrc_interface_pdcp *rrc_, gtpu_interface_pdcp *gtpu_, srslte::log *pdcp_log_); void stop(); diff --git a/srsenb/src/upper/pdcp.cc b/srsenb/src/upper/pdcp.cc index 6f07e4ece..7f62477f9 100644 --- a/srsenb/src/upper/pdcp.cc +++ b/srsenb/src/upper/pdcp.cc @@ -56,7 +56,7 @@ void pdcp::add_user(uint16_t rnti) { pthread_rwlock_rdlock(&rwlock); if (users.count(rnti) == 0) { - srslte::pdcp *obj = new srslte::pdcp; + 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); users[rnti].rlc_itf.rnti = rnti; users[rnti].gtpu_itf.rnti = rnti;