stack lte: create an gtpu-pdcp adapter class that correctly converts lcids to eps bearers and vice-versa

master
Francisco Paisana 3 years ago
parent 4b2f079581
commit 2ade4628ca

@ -49,6 +49,8 @@ public:
struct radio_bearer_t {
srsran::srsran_rat_t rat;
uint32_t lcid;
uint32_t eps_bearer_id;
bool is_valid() const { return rat != srsran_rat_t::nulltype; }
};
/// Single user interface (for UE)
@ -69,6 +71,8 @@ public:
// Stack interface to retrieve active RB
radio_bearer_t get_radio_bearer(uint32_t eps_bearer_id);
radio_bearer_t get_lcid_bearer(uint16_t rnti, uint32_t lcid);
/// Multi-user interface (see comments above)
void add_eps_bearer(uint16_t rnti, uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid);
void remove_eps_bearer(uint16_t rnti, uint8_t eps_bearer_id);
@ -81,10 +85,14 @@ private:
srslog::basic_logger& logger;
typedef std::map<uint32_t, radio_bearer_t> eps_rb_map_t;
std::map<uint16_t, eps_rb_map_t> users_map;
struct user_bearers {
eps_rb_map_t bearers;
std::map<uint32_t, uint32_t> lcid_to_eps_bearer_id;
};
std::map<uint16_t, user_bearers> users_map;
const uint16_t default_key = 0xffff; // dummy RNTI used for public interface without explicit RNTI
radio_bearer_t invalid_rb = {srsran::srsran_rat_t::nulltype, 0};
radio_bearer_t invalid_rb = {srsran::srsran_rat_t::nulltype, 0, 0};
};
} // namespace srsran

@ -31,7 +31,7 @@ struct gtpu_args_t {
class gtpu_interface_pdcp
{
public:
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu(uint16_t rnti, uint32_t bearer_id, srsran::unique_byte_buffer_t pdu) = 0;
};
// GTPU interface for RRC
@ -45,10 +45,13 @@ public:
uint32_t flush_before_teidin = 0;
};
virtual srsran::expected<uint32_t>
add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, const bearer_props* props = nullptr) = 0;
virtual srsran::expected<uint32_t> add_bearer(uint16_t rnti,
uint32_t eps_bearer_id,
uint32_t addr,
uint32_t teid_out,
const bearer_props* props = nullptr) = 0;
virtual void set_tunnel_status(uint32_t teidin, bool dl_active) = 0;
virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0;
virtual void rem_bearer(uint16_t rnti, uint32_t eps_bearer_id) = 0;
virtual void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) = 0;
virtual void rem_user(uint16_t rnti) = 0;
};

@ -35,16 +35,17 @@ void bearer_manager::add_eps_bearer(uint16_t rnti, uint8_t eps_bearer_id, srsran
auto user_it = users_map.find(rnti);
if (user_it == users_map.end()) {
// add empty bearer map
users_map.emplace(rnti, eps_rb_map_t{});
user_it = users_map.find(rnti);
auto p = users_map.emplace(rnti, user_bearers{});
user_it = p.first;
}
auto bearer_it = user_it->second.find(eps_bearer_id);
if (bearer_it != user_it->second.end()) {
auto bearer_it = user_it->second.bearers.find(eps_bearer_id);
if (bearer_it != user_it->second.bearers.end()) {
logger.error("EPS bearer ID %d already registered", eps_bearer_id);
return;
}
user_it->second.emplace(eps_bearer_id, radio_bearer_t{rat, lcid});
user_it->second.bearers.emplace(eps_bearer_id, radio_bearer_t{rat, lcid, eps_bearer_id});
user_it->second.lcid_to_eps_bearer_id.emplace(lcid, eps_bearer_id);
logger.info("Registered EPS bearer ID %d for lcid=%d over %s-PDCP", eps_bearer_id, lcid, to_string(rat).c_str());
}
@ -63,12 +64,14 @@ void bearer_manager::remove_eps_bearer(uint16_t rnti, uint8_t eps_bearer_id)
return;
}
auto bearer_it = user_it->second.find(eps_bearer_id);
if (bearer_it == user_it->second.end()) {
auto bearer_it = user_it->second.bearers.find(eps_bearer_id);
if (bearer_it == user_it->second.bearers.end()) {
logger.error("Can't remove EPS bearer ID %d", eps_bearer_id);
return;
}
user_it->second.erase(bearer_it);
uint32_t lcid = bearer_it->second.lcid;
user_it->second.bearers.erase(bearer_it);
user_it->second.lcid_to_eps_bearer_id.erase(lcid);
logger.info("Removed mapping for EPS bearer ID %d", eps_bearer_id);
}
@ -87,7 +90,8 @@ void bearer_manager::reset(uint16_t rnti)
return;
}
user_it->second.clear();
user_it->second.lcid_to_eps_bearer_id.clear();
user_it->second.bearers.clear();
logger.info("Reset EPS bearer manager");
}
@ -106,7 +110,7 @@ bool bearer_manager::has_active_radio_bearer(uint16_t rnti, uint32_t eps_bearer_
return false;
}
return user_it->second.find(eps_bearer_id) != user_it->second.end();
return user_it->second.bearers.find(eps_bearer_id) != user_it->second.bearers.end();
}
// Stack interface
@ -115,6 +119,22 @@ bearer_manager::radio_bearer_t bearer_manager::get_radio_bearer(uint32_t eps_bea
return get_radio_bearer(default_key, eps_bearer_id);
}
bearer_manager::radio_bearer_t bearer_manager::get_lcid_bearer(uint16_t rnti, uint32_t lcid)
{
srsran::rwlock_read_guard rw_lock(rwlock);
auto user_it = users_map.find(rnti);
if (user_it == users_map.end()) {
return invalid_rb;
}
auto lcid_it = user_it->second.lcid_to_eps_bearer_id.find(lcid);
if (lcid_it != user_it->second.lcid_to_eps_bearer_id.end()) {
return user_it->second.bearers.at(lcid_it->second);
}
return invalid_rb;
}
bearer_manager::radio_bearer_t bearer_manager::get_radio_bearer(uint16_t rnti, uint32_t eps_bearer_id)
{
srsran::rwlock_read_guard rw_lock(rwlock);
@ -124,10 +144,10 @@ bearer_manager::radio_bearer_t bearer_manager::get_radio_bearer(uint16_t rnti, u
return invalid_rb;
}
if (user_it->second.find(eps_bearer_id) != user_it->second.end()) {
return user_it->second.at(eps_bearer_id);
if (user_it->second.bearers.find(eps_bearer_id) != user_it->second.bearers.end()) {
return user_it->second.bearers.at(eps_bearer_id);
}
return invalid_rb;
}
} // namespace srsue
} // namespace srsran

@ -36,6 +36,8 @@
namespace srsenb {
class gtpu_pdcp_adapter;
class enb_stack_lte final : public enb_stack_base,
public stack_interface_phy_lte,
public stack_interface_phy_nr,
@ -178,6 +180,10 @@ private:
srsran::task_scheduler task_sched;
srsran::task_queue_handle enb_task_queue, sync_task_queue, metrics_task_queue;
// bearer management
srsran::bearer_manager bearers; // helper to manage mapping between EPS and radio bearers
std::unique_ptr<gtpu_pdcp_adapter> gtpu_adapter;
srsenb::mac mac;
srsenb::rlc rlc;
srsenb::pdcp pdcp;
@ -191,8 +197,6 @@ private:
srsenb::pdcp pdcp_nr;
srsenb::rrc_nr rrc_nr;
srsran::bearer_manager bearers; // helper to manage mapping between EPS and radio bearers
// RAT-specific interfaces
phy_interface_stack_lte* phy = nullptr;
phy_interface_stack_nr* phy_nr = nullptr;

@ -22,6 +22,23 @@ using namespace srsran;
namespace srsenb {
class gtpu_pdcp_adapter : public gtpu_interface_pdcp
{
public:
gtpu_pdcp_adapter(gtpu* gtpu_, srsran::bearer_manager& bearers_) : gtpu_obj(gtpu_), bearers(&bearers_) {}
/// Converts LCID to EPS-BearerID and sends corresponding PDU to GTPU
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu)
{
auto bearer = bearers->get_lcid_bearer(rnti, lcid);
gtpu_obj->write_pdu(rnti, bearer.eps_bearer_id, std::move(pdu));
}
private:
gtpu* gtpu_obj = nullptr;
srsran::bearer_manager* bearers = nullptr;
};
enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) :
thread("STACK"),
mac_logger(srslog::fetch_basic_logger("MAC", log_sink)),
@ -145,13 +162,16 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_)
// add sync queue
sync_task_queue = task_sched.make_task_queue(args.sync_queue_size);
// setup bearer managers
gtpu_adapter.reset(new gtpu_pdcp_adapter(&gtpu, bearers));
// Init all LTE layers
if (!mac.init(args.mac, rrc_cfg.cell_list, phy, &rlc, &rrc)) {
stack_logger.error("Couldn't initialize MAC");
return SRSRAN_ERROR;
}
rlc.init(&pdcp, &rrc, &mac, task_sched.get_timer_handler());
pdcp.init(&rlc, &rrc, &gtpu);
pdcp.init(&rlc, &rrc, gtpu_adapter.get());
if (rrc.init(rrc_cfg, phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &rrc_nr) != SRSRAN_SUCCESS) {
stack_logger.error("Couldn't initialize RRC");
return SRSRAN_ERROR;
@ -281,7 +301,6 @@ void enb_stack_lte::run_thread()
void enb_stack_lte::write_sdu(uint16_t rnti, uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu, int pdcp_sn)
{
auto bearer = bearers.get_radio_bearer(rnti, eps_bearer_id);
auto task = [this, rnti, eps_bearer_id, bearer, pdcp_sn](srsran::unique_byte_buffer_t& sdu) {
// route SDU to PDCP entity
if (bearer.rat == srsran_rat_t::lte) {
pdcp.write_sdu(rnti, bearer.lcid, std::move(sdu), pdcp_sn);
@ -290,7 +309,6 @@ void enb_stack_lte::write_sdu(uint16_t rnti, uint32_t eps_bearer_id, srsran::uni
} else {
stack_logger.warning("Can't deliver SDU for EPS bearer %d. Dropping it.", eps_bearer_id);
}
};
}
std::map<uint32_t, srsran::unique_byte_buffer_t> enb_stack_lte::get_buffered_pdus(uint16_t rnti, uint32_t lcid)

@ -394,7 +394,7 @@ srsran::expected<uint32_t> bearer_cfg_handler::add_gtpu_bearer(uint32_t
erab_t::gtpu_tunnel bearer;
bearer.teid_out = teid_out;
bearer.addr = addr;
srsran::expected<uint32_t> teidin = gtpu->add_bearer(rnti, erab.lcid, addr, teid_out, props);
srsran::expected<uint32_t> teidin = gtpu->add_bearer(rnti, erab.id, addr, teid_out, props);
if (teidin.is_error()) {
logger->error("Adding erab_id=%d to GTPU", erab_id);
return srsran::default_error_t();
@ -411,7 +411,7 @@ void bearer_cfg_handler::rem_gtpu_bearer(uint32_t erab_id)
logger->warning("Removing erab_id=%d from GTPU", erab_id);
return;
}
gtpu->rem_bearer(rnti, it->second.lcid);
gtpu->rem_bearer(rnti, it->second.id);
}
void bearer_cfg_handler::fill_pending_nas_info(asn1::rrc::rrc_conn_recfg_r8_ies_s* msg)

@ -29,19 +29,19 @@ static const size_t PDU_HEADER_SIZE = 20;
class pdcp_tester : public pdcp_dummy
{
public:
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn) override
void write_sdu(uint16_t rnti, uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu, int pdcp_sn) override
{
last_sdu = std::move(sdu);
last_pdcp_sn = pdcp_sn;
last_rnti = rnti;
last_lcid = lcid;
last_eps_bearer_id = eps_bearer_id;
}
std::map<uint32_t, srsran::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t lcid) override
std::map<uint32_t, srsran::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t eps_bearer_id) override
{
return std::move(buffered_pdus);
}
void send_status_report(uint16_t rnti) override {}
void send_status_report(uint16_t rnti, uint32_t lcid) override {}
void send_status_report(uint16_t rnti, uint32_t eps_bearer_id) override {}
void push_buffered_pdu(uint32_t sn, srsran::unique_byte_buffer_t pdu) { buffered_pdus[sn] = std::move(pdu); }
@ -49,7 +49,7 @@ public:
{
last_sdu = nullptr;
last_pdcp_sn = -1;
last_lcid = 0;
last_eps_bearer_id = 0;
last_rnti = SRSRAN_INVALID_RNTI;
}
@ -57,7 +57,7 @@ public:
srsran::unique_byte_buffer_t last_sdu;
int last_pdcp_sn = -1;
uint16_t last_rnti = SRSRAN_INVALID_RNTI;
uint32_t last_lcid = 0;
uint32_t last_eps_bearer_id = 0;
};
struct dummy_socket_manager : public srsran::socket_manager_itf {
@ -154,43 +154,43 @@ void test_gtpu_tunnel_manager()
struct sockaddr_in sgw_sockaddr = {};
srsran::net_utils::set_sockaddr(&sgw_sockaddr, sgw_addr_str, GTPU_PORT);
uint32_t sgw_addr = ntohl(sgw_sockaddr.sin_addr.s_addr);
const uint32_t drb1_lcid = 3;
const uint32_t drb1_eps_bearer_id = 5;
srsran::task_scheduler task_sched;
gtpu_args_t gtpu_args = {};
gtpu_tunnel_manager tunnels(&task_sched, srslog::fetch_basic_logger("GTPU"));
tunnels.init(gtpu_args, nullptr);
TESTASSERT(tunnels.find_tunnel(0) == nullptr);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_lcid).empty());
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_eps_bearer_id).empty());
TESTASSERT(tunnels.find_rnti_tunnels(0x46) == nullptr);
// Creation of tunnels for different users and lcids
const gtpu_tunnel* tun = tunnels.add_tunnel(0x46, drb1_lcid, 5, sgw_addr);
// Creation of tunnels for different users and bearers
const gtpu_tunnel* tun = tunnels.add_tunnel(0x46, drb1_eps_bearer_id, 5, sgw_addr);
TESTASSERT(tun != nullptr);
TESTASSERT(tunnels.find_tunnel(tun->teid_in) == tun);
const gtpu_tunnel* tun2 = tunnels.add_tunnel(0x47, drb1_lcid, 6, sgw_addr);
const gtpu_tunnel* tun2 = tunnels.add_tunnel(0x47, drb1_eps_bearer_id, 6, sgw_addr);
TESTASSERT(tun2 != nullptr);
TESTASSERT(tunnels.find_tunnel(tun2->teid_in) == tun2);
tun2 = tunnels.add_tunnel(0x47, drb1_lcid + 1, 7, sgw_addr);
tun2 = tunnels.add_tunnel(0x47, drb1_eps_bearer_id + 1, 7, sgw_addr);
TESTASSERT(tun2 != nullptr);
TESTASSERT(tunnels.find_tunnel(tun2->teid_in) == tun2);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_lcid).size() == 1);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x47, drb1_lcid).size() == 1);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x47, drb1_lcid + 1).size() == 1);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_eps_bearer_id).size() == 1);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x47, drb1_eps_bearer_id).size() == 1);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x47, drb1_eps_bearer_id + 1).size() == 1);
// TEST: Creation/Removal of indirect tunnel
const gtpu_tunnel* fwd_tun = tunnels.add_tunnel(0x46, drb1_lcid, 8, sgw_addr);
const gtpu_tunnel* fwd_tun = tunnels.add_tunnel(0x46, drb1_eps_bearer_id, 8, sgw_addr);
TESTASSERT(fwd_tun != nullptr);
TESTASSERT(tunnels.find_tunnel(fwd_tun->teid_in) == fwd_tun);
tunnels.setup_forwarding(tun->teid_in, fwd_tun->teid_in);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_lcid).size() == 2);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_eps_bearer_id).size() == 2);
// Removing a tunnel also clears any associated forwarding tunnel
TESTASSERT(tunnels.remove_tunnel(tun->teid_in));
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_lcid).empty());
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_eps_bearer_id).empty());
// TEST: Prioritization of one TEID over another
const gtpu_tunnel* before_tun = tunnels.add_tunnel(0x46, drb1_lcid, 7, sgw_addr);
const gtpu_tunnel* after_tun = tunnels.add_tunnel(0x46, drb1_lcid, 8, sgw_addr);
const gtpu_tunnel* before_tun = tunnels.add_tunnel(0x46, drb1_eps_bearer_id, 7, sgw_addr);
const gtpu_tunnel* after_tun = tunnels.add_tunnel(0x46, drb1_eps_bearer_id, 8, sgw_addr);
TESTASSERT(before_tun != nullptr and after_tun != nullptr);
tunnels.set_tunnel_priority(before_tun->teid_in, after_tun->teid_in);
for (uint32_t i = 0; i < 1000; ++i) {
@ -200,9 +200,9 @@ void test_gtpu_tunnel_manager()
tunnels.handle_rx_pdcp_sdu(before_tun->teid_in);
}
// Removing active TEID, will automatically switch TEID paths
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_lcid).size() == 2);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_eps_bearer_id).size() == 2);
tunnels.remove_tunnel(before_tun->teid_in);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_lcid).size() == 1);
TESTASSERT(tunnels.find_rnti_bearer_tunnels(0x46, drb1_eps_bearer_id).size() == 1);
TESTASSERT(after_tun->state == gtpu_tunnel_manager::tunnel_state::pdcp_active);
}
@ -215,7 +215,7 @@ int test_gtpu_direct_tunneling(tunnel_test_event event)
srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST");
logger.info("\n\n**** Test GTPU Direct Tunneling ****\n");
uint16_t rnti = 0x46, rnti2 = 0x50;
uint32_t drb1 = 3;
uint32_t drb1_bearer_id = 5;
uint32_t sgw_teidout1 = 1, sgw_teidout2 = 2;
const char * sgw_addr_str = "127.0.0.1", *senb_addr_str = "127.0.1.1", *tenb_addr_str = "127.0.1.2";
struct sockaddr_in senb_sockaddr = {}, sgw_sockaddr = {}, tenb_sockaddr = {};
@ -246,8 +246,8 @@ int test_gtpu_direct_tunneling(tunnel_test_event event)
tenb_gtpu.init(gtpu_args, &tenb_pdcp);
// create tunnels MME-SeNB and MME-TeNB
uint32_t senb_teid_in = senb_gtpu.add_bearer(rnti, drb1, sgw_addr, sgw_teidout1).value();
uint32_t tenb_teid_in = tenb_gtpu.add_bearer(rnti2, drb1, sgw_addr, sgw_teidout2).value();
uint32_t senb_teid_in = senb_gtpu.add_bearer(rnti, drb1_bearer_id, sgw_addr, sgw_teidout1).value();
uint32_t tenb_teid_in = tenb_gtpu.add_bearer(rnti2, drb1_bearer_id, sgw_addr, sgw_teidout2).value();
// Buffer PDUs in SeNB PDCP
for (size_t sn = 6; sn < 10; ++sn) {
@ -260,11 +260,11 @@ int test_gtpu_direct_tunneling(tunnel_test_event event)
gtpu::bearer_props props;
props.flush_before_teidin_present = true;
props.flush_before_teidin = tenb_teid_in;
uint32_t dl_tenb_teid_in = tenb_gtpu.add_bearer(rnti2, drb1, senb_addr, 0, &props).value();
uint32_t dl_tenb_teid_in = tenb_gtpu.add_bearer(rnti2, drb1_bearer_id, senb_addr, 0, &props).value();
props = {};
props.forward_from_teidin_present = true;
props.forward_from_teidin = senb_teid_in;
senb_gtpu.add_bearer(rnti, drb1, tenb_addr, dl_tenb_teid_in, &props);
senb_gtpu.add_bearer(rnti, drb1_bearer_id, tenb_addr, dl_tenb_teid_in, &props);
std::vector<uint8_t> data_vec(10);
std::iota(data_vec.begin(), data_vec.end(), 0);
@ -280,7 +280,7 @@ int test_gtpu_direct_tunneling(tunnel_test_event event)
pdu_view = srsran::make_span(tenb_pdcp.last_sdu);
TESTASSERT(std::count(pdu_view.begin() + PDU_HEADER_SIZE, pdu_view.end(), 7) == 10);
TESTASSERT(tenb_pdcp.last_rnti == rnti2);
TESTASSERT(tenb_pdcp.last_lcid == drb1);
TESTASSERT(tenb_pdcp.last_eps_bearer_id == drb1_bearer_id);
TESTASSERT(tenb_pdcp.last_pdcp_sn == (int)7);
// TEST: verify that PDCP buffered SNs have been forwarded through SeNB->TeNB tunnel
@ -289,7 +289,7 @@ int test_gtpu_direct_tunneling(tunnel_test_event event)
pdu_view = srsran::make_span(tenb_pdcp.last_sdu);
TESTASSERT(std::count(pdu_view.begin() + PDU_HEADER_SIZE, pdu_view.end(), sn) == 10);
TESTASSERT(tenb_pdcp.last_rnti == rnti2);
TESTASSERT(tenb_pdcp.last_lcid == drb1);
TESTASSERT(tenb_pdcp.last_eps_bearer_id == drb1_bearer_id);
TESTASSERT(tenb_pdcp.last_pdcp_sn == (int)sn);
}
@ -302,7 +302,7 @@ int test_gtpu_direct_tunneling(tunnel_test_event event)
pdu_view = srsran::make_span(tenb_pdcp.last_sdu);
TESTASSERT(pdu_view.size() == encoded_data.size() and
std::equal(pdu_view.begin(), pdu_view.end(), encoded_data.begin()));
TESTASSERT(tenb_pdcp.last_rnti == rnti2 and tenb_pdcp.last_lcid == drb1);
TESTASSERT(tenb_pdcp.last_rnti == rnti2 and tenb_pdcp.last_eps_bearer_id == drb1_bearer_id);
// TEST: verify that MME->TeNB packets are buffered until SeNB->TeNB tunnel is closed
tenb_pdcp.clear();
@ -361,7 +361,7 @@ int test_gtpu_direct_tunneling(tunnel_test_event event)
if (event != tunnel_test_event::ue_removal_no_marker) {
// The User is removed in SeNB in case it hasn't and there was no reestablishment
if (std::uniform_int_distribution<uint32_t>{0, 1}(g) > 0) {
senb_gtpu.rem_bearer(0x46, 3);
senb_gtpu.rem_bearer(0x46, drb1_bearer_id);
}
senb_gtpu.rem_user(0x46);
}

Loading…
Cancel
Save