Commit 6dd054cf authored by gauthier's avatar gauthier

sgwc

parent 339f4777
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgwc_app.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "conversions.hpp"
#include "itti.hpp"
#include "logger.hpp"
#if SGW_AUTOTEST
#include "mme_s11.hpp"
#include "enb_s1u.hpp"
#endif
#include "sgwc_app.hpp"
#include "sgwc_config.hpp"
#include "sgwc_s5s8.hpp"
#include "sgwc_s11.hpp"
#include <stdexcept>
using namespace oai::cn::proto::gtpv2c;
using namespace oai::cn::proto::pfcp;
using namespace oai::cn::core;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::sgwc;
using namespace std;
// C includes
#if SGW_AUTOTEST
using namespace oai::cn::nf::spgwu;
mme_s11 *mme_s11_inst = nullptr;
enb_s1u *enb_s1u_inst = nullptr;
#endif
sgw_s11 *sgw_s11_inst = nullptr;
sgw_s5s8 *sgw_s5s8_inst = nullptr;
extern itti_mw *itti_inst;
extern sgwc_app *sgwc_app_inst;
extern sgwc_config sgwc_cfg;
void sgwc_app_task (void*);
//------------------------------------------------------------------------------
teid_t sgwc_app::generate_s11_cp_teid() {
teid_t loop_detect_teid = teid_s11_cp;
teid_t teid = ++teid_s11_cp;
while ((is_s11c_teid_exist(teid)) || (teid == UNASSIGNED_TEID)) {
teid = ++teid_s11_cp;
if (loop_detect_teid == teid) return UNASSIGNED_TEID;
}
return teid;
}
//------------------------------------------------------------------------------
teid_t sgwc_app::generate_s5s8_cp_teid() {
teid_t loop_detect_teid = teid_s5s8_cp;
teid_t teid = ++teid_s5s8_cp;
while ((is_s5s8c_teid_exist(teid)) || (teid == UNASSIGNED_TEID)) {
teid = ++teid_s5s8_cp;
if (loop_detect_teid == teid) return UNASSIGNED_TEID;
}
return teid;
}
//------------------------------------------------------------------------------
bool sgwc_app::is_s11c_teid_exist(const teid_t& teid_s11_cp) const
{
return bool{s11lteid2sgw_eps_bearer_context.count(teid_s11_cp) > 0};
}
//------------------------------------------------------------------------------
bool sgwc_app::is_s5s8c_teid_exist(const teid_t& teid_s5s8_cp) const
{
return bool{s5s8lteid2sgw_contexts.count(teid_s5s8_cp) > 0};
}
//------------------------------------------------------------------------------
fteid_t sgwc_app::generate_s11_cp_fteid(const struct in_addr ipv4_address) {
fteid_t fteid = {};
fteid.interface_type = S11_S4_SGW_GTP_C;
fteid.v4 = 1;
fteid.ipv4_address = ipv4_address;
fteid.v6 = 0;
fteid.ipv6_address = in6addr_any;
fteid.teid_gre_key = generate_s11_cp_teid();
return fteid;
}
//------------------------------------------------------------------------------
fteid_t sgwc_app::generate_s5s8_cp_fteid(const struct in_addr ipv4_address) {
fteid_t fteid = {};
fteid.interface_type = S5_S8_SGW_GTP_C;
fteid.v4 = 1;
fteid.ipv4_address = ipv4_address;
fteid.v6 = 0;
fteid.ipv6_address = in6addr_any;
fteid.teid_gre_key = generate_s5s8_cp_teid();
return fteid;
}
//------------------------------------------------------------------------------
bool sgwc_app::is_s5s8sgw_teid_2_sgw_contexts(const teid_t& sgw_teid) const
{
return bool{s5s8lteid2sgw_contexts.count(sgw_teid) > 0};
}
//------------------------------------------------------------------------------
bool sgwc_app::is_s11sgw_teid_2_sgw_eps_bearer_context(const teid_t& sgw_teid) const
{
return bool{s11lteid2sgw_eps_bearer_context.count(sgw_teid) > 0};
}
//------------------------------------------------------------------------------
std::pair<std::shared_ptr<sgw_eps_bearer_context>, std::shared_ptr<sgw_pdn_connection>> sgwc_app::s5s8sgw_teid_2_sgw_contexts(const teid_t& sgw_teid) const
{
return s5s8lteid2sgw_contexts.at(sgw_teid);
}
//------------------------------------------------------------------------------
shared_ptr<sgw_eps_bearer_context> sgwc_app::s11sgw_teid_2_sgw_eps_bearer_context(const teid_t& sgw_teid) const
{
return s11lteid2sgw_eps_bearer_context.at(sgw_teid);
}
//------------------------------------------------------------------------------
void sgwc_app::set_s5s8sgw_teid_2_sgw_contexts(const teid_t& sgw_teid, shared_ptr<sgw_eps_bearer_context> sebc, std::shared_ptr<sgw_pdn_connection> spc)
{
s5s8lteid2sgw_contexts[sgw_teid] = std::make_pair(sebc, spc);
}
//------------------------------------------------------------------------------
void sgwc_app::set_s11sgw_teid_2_sgw_eps_bearer_context(const teid_t& sgw_teid, shared_ptr<sgw_eps_bearer_context> sebc)
{
s11lteid2sgw_eps_bearer_context[sgw_teid] = sebc;
}
//------------------------------------------------------------------------------
bool sgwc_app::is_imsi64_2_sgw_eps_bearer_context(const imsi64_t& imsi64) const
{
return bool{imsi2sgw_eps_bearer_context.count(imsi64) > 0};
}
//------------------------------------------------------------------------------
shared_ptr<sgw_eps_bearer_context> sgwc_app::imsi64_2_sgw_eps_bearer_context(const imsi64_t& imsi64) const
{
return imsi2sgw_eps_bearer_context.at(imsi64);
}
//------------------------------------------------------------------------------
void sgwc_app::set_imsi64_2_sgw_eps_bearer_context(const imsi64_t& imsi64, shared_ptr<sgw_eps_bearer_context> sebc)
{
imsi2sgw_eps_bearer_context[imsi64] = sebc;
}
//------------------------------------------------------------------------------
void sgwc_app::delete_sgw_eps_bearer_context(std::shared_ptr<sgw_eps_bearer_context> sebc)
{
if (sebc.get()) {
imsi64_t imsi64 = imsi_to_imsi64(&sebc->imsi);
Logger::sgwc_app().debug("Delete SGW EPS BEARER CONTEXT IMSI " IMSI_64_FMT " ", imsi64);
imsi2sgw_eps_bearer_context.erase(imsi64);
s11lteid2sgw_eps_bearer_context.erase(sebc->sgw_fteid_s11_s4_cp.teid_gre_key);
}
}
//------------------------------------------------------------------------------
void sgwc_app_task (void *args_p)
{
const task_id_t task_id = TASK_SGWC_APP;
itti_inst->notify_task_ready(task_id);
do {
std::shared_ptr<itti_msg> shared_msg = itti_inst->receive_msg(task_id);
auto *msg = shared_msg.get();
switch (msg->msg_type) {
case S11_CREATE_SESSION_REQUEST:
/*
* We received a create session request from MME (with GTP abstraction here)
* procedures might be:
* E-UTRAN Initial Attach
* UE requests PDN connectivity
*/
if (itti_s11_create_session_request* m = dynamic_cast<itti_s11_create_session_request*>(msg)) {
sgwc_app_inst->handle_itti_msg(ref(*m));
}
break;
case S5S8_CREATE_SESSION_RESPONSE:
if (itti_s5s8_create_session_response* m = dynamic_cast<itti_s5s8_create_session_response*>(msg)) {
sgwc_app_inst->handle_itti_msg(ref(*m));
}
break;
case S5S8_MODIFY_BEARER_RESPONSE:
if (itti_s5s8_modify_bearer_response* m = dynamic_cast<itti_s5s8_modify_bearer_response*>(msg)) {
sgwc_app_inst->handle_itti_msg(ref(*m));
}
break;
case S5S8_RELEASE_ACCESS_BEARERS_RESPONSE:
if (itti_s5s8_release_access_bearers_response* m = dynamic_cast<itti_s5s8_release_access_bearers_response*>(msg)) {
sgwc_app_inst->handle_itti_msg(ref(*m));
}
break;
case S11_DELETE_SESSION_REQUEST:
if (itti_s11_delete_session_request* m = dynamic_cast<itti_s11_delete_session_request*>(msg)) {
sgwc_app_inst->handle_itti_msg(ref(*m));
}
break;
case S5S8_DELETE_SESSION_RESPONSE:
if (itti_s5s8_delete_session_response* m = dynamic_cast<itti_s5s8_delete_session_response*>(msg)) {
sgwc_app_inst->handle_itti_msg(ref(*m));
}
break;
case S11_MODIFY_BEARER_REQUEST:
if (itti_s11_modify_bearer_request* m = dynamic_cast<itti_s11_modify_bearer_request*>(msg)) {
sgwc_app_inst->handle_itti_msg(ref(*m));
}
break;
case S11_RELEASE_ACCESS_BEARERS_REQUEST:
if (itti_s11_release_access_bearers_request* m = dynamic_cast<itti_s11_release_access_bearers_request*>(msg)) {
sgwc_app_inst->handle_itti_msg(ref(*m));
}
break;
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
Logger::sgwc_app().info( "TIME-OUT event timer id %d", to->timer_id);
}
break;
case TERMINATE:
if (itti_msg_terminate *terminate = dynamic_cast<itti_msg_terminate*>(msg)) {
Logger::sgwc_app().info( "Received terminate message");
return;
}
break;
default:
Logger::sgwc_app().info( "no handler for ITTI msg type %d", msg->msg_type);
}
} while (true);
}
//------------------------------------------------------------------------------
sgwc_app::sgwc_app (const std::string& config_file) : s11lteid2sgw_eps_bearer_context()
{
Logger::sgwc_app().startup("Starting...");
sgwc_cfg.load(config_file);
sgwc_cfg.execute();
sgwc_cfg.display();
teid_s11_cp = 0;
teid_s5s8_cp = 0;
imsi2sgw_eps_bearer_context = {};
s11lteid2sgw_eps_bearer_context = {};
s5s8lteid2sgw_contexts = {};
try {
sgw_s5s8_inst = new sgw_s5s8();
sgw_s11_inst = new sgw_s11();
#if SGW_AUTOTEST
mme_s11_inst = new mme_s11();
enb_s1u_inst = new enb_s1u();
#endif
} catch (std::exception& e) {
Logger::sgwc_app().error( "Cannot create SGW_APP: %s", e.what() );
throw e;
}
if (itti_inst->create_task(TASK_SGWC_APP, sgwc_app_task, nullptr) ) {
Logger::sgwc_app().error( "Cannot create task TASK_SGWC_APP" );
throw std::runtime_error( "Cannot create task TASK_SGWC_APP" );
}
}
//------------------------------------------------------------------------------
sgwc_app::~sgwc_app()
{
if (sgw_s5s8_inst) delete sgw_s5s8_inst;
if (sgw_s11_inst) delete sgw_s11_inst;
#if SGW_AUTOTEST
if (mme_s11_inst) delete mme_s11_inst;
if (enb_s1u_inst) delete enb_s1u_inst;
#endif
}
//------------------------------------------------------------------------------
void sgwc_app::handle_itti_msg (itti_s11_create_session_request& csreq)
{
// mme_sgw_tunnel_t *new_endpoint_p = NULL;
// s_plus_p_gw_eps_bearer_context_information_t *s_plus_p_gw_eps_bearer_ctxt_info_p = NULL;
// sgw_eps_bearer_ctxt_t *eps_bearer_ctxt_p = NULL;
Logger::sgwc_app().debug("Received S11 CREATE_SESSION_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", csreq.teid, csreq.gtpc_tx_id);
/*
* Upon reception of create session request from MME,
* S-GW should create UE, eNB and MME contexts and forward message to P-GW.
*/
if (csreq.gtp_ies.rat_type.rat_type < RAT_TYPE_E_EUTRAN_WB_EUTRAN) {
Logger::sgwc_app().warn("Received S11 CSReq with RAT < RAT_TYPE_E_EUTRAN_WB_EUTRAN: type %d", csreq.gtp_ies.rat_type.rat_type);
}
/*
* As we are abstracting GTP-C transport, FTeid ip address is useless.
* We just use the teid to identify MME tunnel. Normally we received either:
* - ipv4 address if ipv4 flag is set
* - ipv6 address if ipv6 flag is set
* - ipv4 and ipv6 if both flags are set
* Communication between MME and S-GW involves S11 interface so we are expecting
* S11_MME_GTP_C (11) as interface_type.
*/
if (csreq.gtp_ies.sender_fteid_for_cp.interface_type != S11_MME_GTP_C) {
Logger::sgwc_app().warn("Received S11 CSReq with sender_fteid_for_cp != S11_MME_GTP_C %d, ignore CSreq", csreq.gtp_ies.sender_fteid_for_cp.interface_type);
return;
}
if (csreq.gtp_ies.sender_fteid_for_cp.teid_gre_key == 0) {
// MME sent request with teid = 0. This is not valid...
Logger::sgwc_app().warn("Received S11 CSReq with sender_fteid_for_cp.teid = 0, ignore CSR");
return;
}
if ((csreq.teid) && (not sgwc_app_inst->is_s11c_teid_exist(csreq.teid))) {
Logger::sgwc_app().warn("Received S11 CSReq with dest teid " TEID_FMT " unknown, ignore CSreq", csreq.teid);
return;
}
shared_ptr<sgw_eps_bearer_context> ebc;
core::imsi_t imsi = {};
if (csreq.gtp_ies.get(imsi)) {
// imsi not authenticated
core::indication_t indication = {};
if ((csreq.gtp_ies.get(indication)) && (indication.uimsi)){
Logger::sgwc_app().debug("TODO S11 CREATE_SESSION_REQUEST (no AUTHENTICATED IMSI) sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", csreq.teid, csreq.gtpc_tx_id);
return;
} else {
imsi64_t imsi64 = imsi_to_imsi64(&imsi);
if (is_imsi64_2_sgw_eps_bearer_context(imsi64)) {
ebc = imsi64_2_sgw_eps_bearer_context(imsi64);
} else {
ebc = std::shared_ptr<sgw_eps_bearer_context>(new sgw_eps_bearer_context());
set_imsi64_2_sgw_eps_bearer_context(imsi64, ebc);
}
}
} else {
if (csreq.teid) {
if (is_s11sgw_teid_2_sgw_eps_bearer_context(csreq.teid)) {
ebc = s11sgw_teid_2_sgw_eps_bearer_context(csreq.teid);
} else {
Logger::sgwc_app().debug("Discarding S11 CREATE_SESSION_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64", invalid teid", csreq.teid, csreq.gtpc_tx_id);
return;
}
} else {
// TODO
Logger::sgwc_app().debug("TODO S11 CREATE_SESSION_REQUEST (no IMSI) sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", csreq.teid, csreq.gtpc_tx_id);
return;
}
}
ebc->handle_itti_msg(csreq);
Logger::sgwc_app().debug("sgw_eps_bearer_context: %s!", ebc->toString().c_str());
}
//------------------------------------------------------------------------------
void sgwc_app::handle_itti_msg (itti_s11_delete_session_request& m)
{
Logger::sgwc_app().debug("Received S11 DELETE_SESSION_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", m.teid, m.gtpc_tx_id);
if (m.teid) {
if (is_s11sgw_teid_2_sgw_eps_bearer_context(m.teid)) {
shared_ptr<sgw_eps_bearer_context> ebc = s11sgw_teid_2_sgw_eps_bearer_context(m.teid);
ebc->handle_itti_msg(m);
Logger::sgwc_app().debug("sgw_eps_bearer_context: %s!", ebc->toString().c_str());
} else {
Logger::sgwc_app().debug("Discarding S11 CREATE_SESSION_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64", invalid teid", m.teid, m.gtpc_tx_id);
return;
}
} else {
// TODO
Logger::sgwc_app().debug("Discarding S11 DELETE_SESSION_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", m.teid, m.gtpc_tx_id);
return;
}
}
//------------------------------------------------------------------------------
void sgwc_app::handle_itti_msg (itti_s11_modify_bearer_request& m)
{
Logger::sgwc_app().debug("Received S11 MODIFY_BEARER_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", m.teid, m.gtpc_tx_id);
if (m.teid) {
if (is_s11sgw_teid_2_sgw_eps_bearer_context(m.teid)) {
shared_ptr<sgw_eps_bearer_context> ebc = s11sgw_teid_2_sgw_eps_bearer_context(m.teid);
ebc->handle_itti_msg(m);
Logger::sgwc_app().debug("sgw_eps_bearer_context: %s!", ebc->toString().c_str());
} else {
Logger::sgwc_app().debug("Discarding S11 MODIFY_BEARER_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64", invalid teid", m.teid, m.gtpc_tx_id);
return;
}
} else {
// TODO
Logger::sgwc_app().debug("Discarding S11 MODIFY_BEARER_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64", invalid teid", m.teid, m.gtpc_tx_id);
return;
}
}
//------------------------------------------------------------------------------
void sgwc_app::handle_itti_msg (itti_s11_release_access_bearers_request& m)
{
Logger::sgwc_app().debug("Received S11 RELEASE_ACCESS_BEARERS_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", m.teid, m.gtpc_tx_id);
if (m.teid) {
if (is_s11sgw_teid_2_sgw_eps_bearer_context(m.teid)) {
shared_ptr<sgw_eps_bearer_context> ebc = s11sgw_teid_2_sgw_eps_bearer_context(m.teid);
ebc->handle_itti_msg(m);
Logger::sgwc_app().debug("sgw_eps_bearer_context: %s!", ebc->toString().c_str());
} else {
Logger::sgwc_app().debug("Discarding S11 RELEASE_ACCESS_BEARERS_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64", invalid teid", m.teid, m.gtpc_tx_id);
return;
}
} else {
// TODO
Logger::sgwc_app().debug("Discarding S11 RELEASE_ACCESS_BEARERS_REQUEST sender teid " TEID_FMT " gtpc_tx_id %" PRIX64", invalid teid", m.teid, m.gtpc_tx_id);
return;
}
}
//------------------------------------------------------------------------------
void sgwc_app::handle_itti_msg (itti_s5s8_create_session_response& m)
{
Logger::sgwc_app().debug("Received S5S8 CREATE_SESSION_RESPONSE sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", m.teid, m.gtpc_tx_id);
if (m.gtp_ies.s5_s8_pgw_fteid.second.interface_type != S5_S8_PGW_GTP_C) {
Logger::sgwc_app().warn("Received S5S8 CREATE_SESSION_RESPONSE with s5_s8_pgw_fteid.interface_type != S5_S8_PGW_GTP_C %d, ignore CSResp", m.gtp_ies.sender_fteid_for_cp.second.interface_type);
return;
}
if (m.gtp_ies.s5_s8_pgw_fteid.second.teid_gre_key == 0) {
// MME sent request with teid = 0. This is not valid...
Logger::sgwc_app().warn("Received S5S8 CREATE_SESSION_RESPONSE with s5_s8_pgw_fteid.teid = 0, ignore CSResp");
return;
}
if (is_s5s8sgw_teid_2_sgw_contexts(m.teid)) {
std::pair<std::shared_ptr<sgw_eps_bearer_context>, std::shared_ptr<sgw_pdn_connection>> p = s5s8sgw_teid_2_sgw_contexts(m.teid);
if ((p.first.get()) && (p.second.get())) {
p.first->handle_itti_msg(m, p.second);
Logger::sgwc_app().debug("sgw_eps_bearer_context: %s!", p.first->toString().c_str());
} else {
Logger::sgwc_app().debug("Received S5S8 CREATE_SESSION_RESPONSE with dest teid " TEID_FMT ", SGW contexts not found, ignore CSResp", m.teid);
}
} else {
Logger::sgwc_app().debug("Received S5S8 CREATE_SESSION_RESPONSE with dest teid " TEID_FMT " unknown, ignore CSResp", m.teid);
}
}
//------------------------------------------------------------------------------
void sgwc_app::handle_itti_msg (itti_s5s8_delete_session_response& m)
{
if (is_s5s8sgw_teid_2_sgw_contexts(m.teid)) {
std::pair<std::shared_ptr<sgw_eps_bearer_context>, std::shared_ptr<sgw_pdn_connection>> p = s5s8sgw_teid_2_sgw_contexts(m.teid);
if ((p.first.get()) && (p.second.get())) {
p.first->handle_itti_msg(m, p.second);
// cleanup
if (0 == p.first->get_num_pdn_connections()) {
delete_sgw_eps_bearer_context(p.first);
} else {
Logger::sgwc_app().debug("get_num_pdn_connections() = %d", p.first->get_num_pdn_connections());
}
Logger::sgwc_app().debug("sgw_eps_bearer_context: %s!", p.first->toString().c_str());
} else {
Logger::sgwc_app().debug("Received S5S8 DELETE_SESSION_RESPONSE with dest teid " TEID_FMT ", SGW contexts not found, ignore DSResp", m.teid);
}
} else {
Logger::sgwc_app().debug("Received S5S8 DELETE_SESSION_RESPONSE with dest teid " TEID_FMT " unknown, ignore DSResp", m.teid);
}
}
//------------------------------------------------------------------------------
void sgwc_app::handle_itti_msg (itti_s5s8_modify_bearer_response& m)
{
Logger::sgwc_app().debug("Received S5S8 MODIFY_BEARER_RESPONSE sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", m.teid, m.gtpc_tx_id);
if (is_s5s8sgw_teid_2_sgw_contexts(m.teid)) {
std::pair<std::shared_ptr<sgw_eps_bearer_context>, std::shared_ptr<sgw_pdn_connection>> p = s5s8sgw_teid_2_sgw_contexts(m.teid);
if ((p.first.get()) && (p.second.get())) {
p.first->handle_itti_msg(m, p.second);
Logger::sgwc_app().debug("sgw_eps_bearer_context: %s!", p.first->toString().c_str());
} else {
Logger::sgwc_app().debug("Received S5S8 MODIFY_BEARER_RESPONSE with dest teid " TEID_FMT ", SGW contexts not found, ignore CSResp", m.teid);
}
} else {
Logger::sgwc_app().debug("Received S5S8 MODIFY_BEARER_RESPONSE with dest teid " TEID_FMT " unknown, ignore CSResp", m.teid);
}
}
//------------------------------------------------------------------------------
void sgwc_app::handle_itti_msg (itti_s5s8_release_access_bearers_response& m)
{
Logger::sgwc_app().debug("Received S5S8 RELEASE_ACCESS_BEARERS_RESPONSE sender teid " TEID_FMT " gtpc_tx_id %" PRIX64" ", m.teid, m.gtpc_tx_id);
if (is_s5s8sgw_teid_2_sgw_contexts(m.teid)) {
std::pair<std::shared_ptr<sgw_eps_bearer_context>, std::shared_ptr<sgw_pdn_connection>> p = s5s8sgw_teid_2_sgw_contexts(m.teid);
if ((p.first.get()) && (p.second.get())) {
p.first->handle_itti_msg(m, p.second);
Logger::sgwc_app().debug("sgw_eps_bearer_context: %s!", p.first->toString().c_str());
} else {
Logger::sgwc_app().debug("Received S5S8 RELEASE_ACCESS_BEARERS_RESPONSE with dest teid " TEID_FMT ", SGW contexts not found, ignore CSResp", m.teid);
}
} else {
Logger::sgwc_app().debug("Received S5S8 RELEASE_ACCESS_BEARERS_RESPONSE with dest teid " TEID_FMT " unknown, ignore CSResp", m.teid);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgwc_app.hpp
\author Lionel GAUTHIER
\date 2018
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SGWC_APP_HPP_SEEN
#define FILE_SGWC_APP_HPP_SEEN
#include "common_root_types.h"
#include "itti_msg_s11.hpp"
#include "itti_msg_s5s8.hpp"
#include "sgwc_eps_bearer_context.hpp"
#include <boost/atomic.hpp>
#include <map>
#include <string>
#include <thread>
#include <memory>
#include <map>
#include <set>
namespace oai::cn::nf::sgwc {
class sgwc_app {
private:
std::thread::id thread_id;
std::thread thread;
// teid generators (linear)
boost::atomic<teid_t> teid_s11_cp;
boost::atomic<teid_t> teid_s5s8_cp;
/* There shall be only one pair of TEID-C per UE over the S11 and the S4 interfaces. The same tunnel shall be
shared for the control messages related to the same UE operation. A TEID-C on the S11/S4 interface shall be
released after all its associated EPS bearers are deleted.*/
std::map<imsi64_t, std::shared_ptr<sgw_eps_bearer_context>> imsi2sgw_eps_bearer_context;
std::map<teid_t, std::shared_ptr<sgw_eps_bearer_context>> s11lteid2sgw_eps_bearer_context;
std::map<teid_t, std::pair<std::shared_ptr<sgw_eps_bearer_context>, std::shared_ptr<sgw_pdn_connection>>> s5s8lteid2sgw_contexts;
teid_t generate_s11_cp_teid();
bool is_s11c_teid_exist(const teid_t& teid_s11_cp) const;
bool is_s5s8sgw_teid_2_sgw_contexts(const teid_t& sgw_teid) const;
// s11lteid2sgw_eps_bearer_context collection
bool is_s11sgw_teid_2_sgw_eps_bearer_context(const teid_t& sgw_teid) const;
bool is_imsi64_2_sgw_eps_bearer_context(const imsi64_t& imsi64) const;
void set_imsi64_2_sgw_eps_bearer_context(const imsi64_t& imsi64, std::shared_ptr<sgw_eps_bearer_context> sebc);
teid_t generate_s5s8_cp_teid();
bool is_s5s8c_teid_exist(const teid_t& teid_s5s8_cp)const;
bool is_s5s8u_teid_exist(const teid_t& teid_s5s8_up) const;
public:
// key is S11 S-GW local teid, value is S11 tunnel id pair
// map<teid_t, int> s11teid2mme_hashtable;
// key is paa, value is S11 s-gw local teid
//obj_hash_table_uint64_t *ip2s11teid;
// key is S1-U S-GW local teid
////hash_table_t *s1uteid2enb_hashtable;
// the key of this hashtable is the S11 s-gw local teid.
//hash_table_ts_t *s11_bearer_context_information_hashtable;
/* The TEID-C shall be unique per PDN-Connection on GTP based S2a, S2b, S5 and S8 interfaces. The same
tunnel shall be shared for the control messages related to all bearers associated to
the PDN-Connection. A TEID-C on the S2a/S2b/S5/S8 interface shall be released after all its associated EPS bearers are deleted. */
//gtpv1u_data_t gtpv1u_data;
sgwc_app(const std::string& config_file);
~sgwc_app();
sgwc_app(sgwc_app const&) = delete;
void operator=(sgwc_app const&) = delete;
core::fteid_t generate_s5s8_cp_fteid(const struct in_addr ipv4_address);
core::fteid_t generate_s11_cp_fteid(const struct in_addr ipv4_address);
std::pair<std::shared_ptr<sgw_eps_bearer_context>, std::shared_ptr<sgw_pdn_connection>> s5s8sgw_teid_2_sgw_contexts(const teid_t& sgw_teid) const;
std::shared_ptr<sgw_eps_bearer_context> s11sgw_teid_2_sgw_eps_bearer_context(const teid_t& sgw_teid) const;
void set_s11sgw_teid_2_sgw_eps_bearer_context(const teid_t& sgw_teid, std::shared_ptr<sgw_eps_bearer_context> sebc);
void delete_sgw_eps_bearer_context(std::shared_ptr<sgw_eps_bearer_context> sebc);
std::shared_ptr<sgw_eps_bearer_context> imsi64_2_sgw_eps_bearer_context(const imsi64_t& imsi64) const;
void set_s5s8sgw_teid_2_sgw_contexts(const teid_t& sgw_teid, std::shared_ptr<sgw_eps_bearer_context> sebc, std::shared_ptr<sgw_pdn_connection> spc);
void handle_itti_msg (core::itti::itti_s11_create_session_request& m);
void handle_itti_msg (core::itti::itti_s11_delete_session_request& m);
void handle_itti_msg (core::itti::itti_s11_modify_bearer_request& m);
void handle_itti_msg (core::itti::itti_s11_release_access_bearers_request& m);
void handle_itti_msg (core::itti::itti_s5s8_create_session_response& m);
void handle_itti_msg (core::itti::itti_s5s8_delete_session_response& m);
void handle_itti_msg (core::itti::itti_s5s8_modify_bearer_response& m);
void handle_itti_msg (core::itti::itti_s5s8_release_access_bearers_response& m);
};
}
#endif /* FILE_SGWC_APP_HPP_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sSGW_CONFIG.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "async_shell_cmd.hpp"
#include "common_defs.h"
#include "if.hpp"
#include "logger.hpp"
#include "sgwc_config.hpp"
#include "string.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <cstdlib>
#include <iomanip>
#include <iostream>
using namespace std;
using namespace libconfig;
using namespace oai::cn::nf::sgwc;
// C includes
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
//------------------------------------------------------------------------------
int sgwc_config::execute ()
{
return RETURNok;
}
//------------------------------------------------------------------------------
int sgwc_config::load_interface(const Setting& if_cfg, interface_cfg_t& cfg)
{
if_cfg.lookupValue(SGWC_CONFIG_STRING_INTERFACE_NAME, cfg.if_name);
util::trim(cfg.if_name);
if (not boost::iequals(cfg.if_name, "none")) {
std::string address = {};
if_cfg.lookupValue(SGWC_CONFIG_STRING_IPV4_ADDRESS, address);
util::trim(address);
if (boost::iequals(address, "read")) {
if (get_inet_addr_infos_from_iface(cfg.if_name, cfg.addr4, cfg.network4, cfg.mtu)) {
Logger::sgwc_app().error("Could not read %s network interface configuration", cfg.if_name);
return RETURNerror;
}
} else {
std::vector<std::string> words;
boost::split(words, address, boost::is_any_of("/"), boost::token_compress_on);
if (words.size() != 2) {
Logger::sgwc_app().error("Bad value " SGWC_CONFIG_STRING_IPV4_ADDRESS " = %s in config file", address.c_str());
return RETURNerror;
}
unsigned char buf_in_addr[sizeof(struct in6_addr)]; // you never know...
if (inet_pton (AF_INET, util::trim(words.at(0)).c_str(), buf_in_addr) == 1) {
memcpy (&cfg.addr4, buf_in_addr, sizeof (struct in_addr));
} else {
Logger::sgwc_app().error("In conversion: Bad value " SGWC_CONFIG_STRING_IPV4_ADDRESS " = %s in config file", util::trim(words.at(0)).c_str());
return RETURNerror;
}
cfg.network4.s_addr = htons(ntohs(cfg.addr4.s_addr) & 0xFFFFFFFF << (32 - std::stoi (util::trim(words.at(1)))));
}
if_cfg.lookupValue(SGWC_CONFIG_STRING_PORT, cfg.port);
}
return RETURNok;
}
//------------------------------------------------------------------------------
int sgwc_config::load(const string& config_file)
{
Config cfg;
// Read the file. If there is an error, report it and exit.
try
{
cfg.readFile(config_file.c_str());
}
catch(const FileIOException &fioex)
{
Logger::sgwc_app().error("I/O error while reading file %s - %s", config_file.c_str(), fioex.what());
throw fioex;
}
catch(const ParseException &pex)
{
Logger::sgwc_app().error("Parse error at %s:%d - %s", pex.getFile(), pex.getLine(), pex.getError());
throw pex;
}
const Setting& root = cfg.getRoot();
try
{
const Setting& sgw_cfg = root[SGWC_CONFIG_STRING_SGW_CONFIG];
sgw_cfg.lookupValue(SGWC_CONFIG_STRING_INSTANCE, instance);
sgw_cfg.lookupValue(SGWC_CONFIG_STRING_PID_DIRECTORY, pid_dir);
util::trim(pid_dir);
const Setting& nw_if_cfg = sgw_cfg[SGWC_CONFIG_STRING_INTERFACES];
const Setting& s11_cp_cfg = nw_if_cfg[SGWC_CONFIG_STRING_INTERFACE_S11_CP];
load_interface(s11_cp_cfg, s11_cp);
const Setting& s5s8_cp_cfg = nw_if_cfg[SGWC_CONFIG_STRING_INTERFACE_S5_S8_CP];
load_interface(s5s8_cp_cfg, s5s8_cp);
}
catch(const SettingNotFoundException &nfex)
{
Logger::sgwc_app().error("%s : %s", nfex.what(), nfex.getPath());
return RETURNerror;
}
return RETURNok;
}
//------------------------------------------------------------------------------
void sgwc_config::display ()
{
Logger::sgwc_app().info("==== EURECOM %s v%s ====", PACKAGE_NAME, PACKAGE_VERSION);
Logger::sgwc_app().info( "Configuration:");
//Logger::sgwc_app().info( "- Instance ..............: %s", instance);
//Logger::sgwc_app().info( "- PID dir ...............: %s", pid_dir.c_str());
Logger::sgwc_app().info( "- S5_S8-C:");
Logger::sgwc_app().info( " iface ............: %s", s5s8_cp.if_name.c_str());
Logger::sgwc_app().info( " ipv4.addr ........: %s", inet_ntoa (s5s8_cp.addr4));
Logger::sgwc_app().info( " ipv4.mask ........: %s", inet_ntoa (s5s8_cp.network4));
Logger::sgwc_app().info( " port .............: %d", s5s8_cp.port);
Logger::sgwc_app().info( "- S11-C:");
Logger::sgwc_app().info( " iface ............: %s", s11_cp.if_name.c_str());
Logger::sgwc_app().info( " ipv4.addr ........: %s", inet_ntoa (s11_cp.addr4));
Logger::sgwc_app().info( " ipv4.mask ........: %s", inet_ntoa (s11_cp.network4));
Logger::sgwc_app().info( " port .............: %u", s11_cp.port);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgwc_config.hpp
* \brief
* \author Lionel Gauthier
* \company Eurecom
* \email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SGWC_CONFIG_HPP_SEEN
#define FILE_SGWC_CONFIG_HPP_SEEN
#include <libconfig.h++>
#include <mutex>
#include <netinet/in.h>
#include <stdint.h>
#include <stdbool.h>
namespace oai::cn::nf::sgwc {
#define SGWC_CONFIG_STRING_SGW_CONFIG "S-GW"
#define SGWC_CONFIG_STRING_PID_DIRECTORY "PID_DIRECTORY"
#define SGWC_CONFIG_STRING_INSTANCE "INSTANCE"
#define SGWC_CONFIG_STRING_INTERFACES "INTERFACES"
#define SGWC_CONFIG_STRING_INTERFACE_NAME "INTERFACE_NAME"
#define SGWC_CONFIG_STRING_IPV4_ADDRESS "IPV4_ADDRESS"
#define SGWC_CONFIG_STRING_PORT "PORT"
#define SGWC_CONFIG_STRING_INTERFACE_S11_CP "S11_CP"
#define SGWC_CONFIG_STRING_INTERFACE_S11_UP "S11_UP"
#define SGWC_CONFIG_STRING_INTERFACE_S5_S8_CP "S5_S8_CP"
#define SPGW_ABORT_ON_ERROR true
#define SPGW_WARN_ON_ERROR false
typedef struct interface_cfg_s {
std::string if_name;
struct in_addr addr4;
struct in_addr network4;
struct in6_addr addr6;
unsigned int mtu;
unsigned int port;
} interface_cfg_t;
class sgwc_config {
private:
int load_interface(const libconfig::Setting& if_cfg, interface_cfg_t& cfg);
public:
/* Reader/writer lock for this configuration */
std::mutex m_rw_lock;
std::string pid_dir;
unsigned int instance;
interface_cfg_t s11_cp;
interface_cfg_t s11_up;
interface_cfg_t s5s8_cp;
//interface_cfg_t sxa;
bool local_to_eNB;
sgwc_config() : m_rw_lock(), pid_dir(), instance(0), s11_cp(), s11_up(), s5s8_cp(), local_to_eNB(false) {};
void lock() {m_rw_lock.lock();};
void unlock() {m_rw_lock.unlock();};
int load(const std::string& config_file);
int execute();
void display();
};
} // namespace sgw
#endif /* FILE_SGWC_CONFIG_HPP_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgw_eps_bearer_context.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "sgwc_app.hpp"
#include "sgwc_eps_bearer_context.hpp"
#include "sgwc_config.hpp"
#include "3gpp_29.274.h"
#include <algorithm>
using namespace oai::cn::core;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::sgwc;
using namespace std;
extern sgwc_app *sgwc_app_inst;
extern sgwc_config sgwc_cfg;
//------------------------------------------------------------------------------
std::string sgw_eps_bearer::toString() const
{
std::string s = {};
s.append("EPS BEARER:\n");
s.append("\tEBI:\t\t\t\t").append(std::to_string(ebi.ebi)).append("\n");
s.append("\tTFT:\t\t\t\tTODO tft").append("\n");
s.append("\tPGW FTEID S5S8 UP:\t\t").append(oai::cn::core::toString(pgw_fteid_s5_s8_up)).append("\n");
s.append("\tSGW FTEID S5S8 UP:\t\t").append(oai::cn::core::toString(sgw_fteid_s5_s8_up)).append("\n");
s.append("\tSGW FTEID S1S12S4 UP:\t\t").append(oai::cn::core::toString(sgw_fteid_s1u_s12_s4u_s11u)).append("\n");
s.append("\tSGW FTEID S11 UP:\t\t").append(oai::cn::core::toString(sgw_fteid_s11u)).append("\n");
s.append("\tMME FTEID S11 UP:\t\t").append(oai::cn::core::toString(mme_fteid_s11u)).append("\n");
s.append("\teNB FTEID S1 UP:\t\t").append(oai::cn::core::toString(enb_fteid_s1u)).append("\n");
s.append("\tBearer QOS:\t\t\t").append(oai::cn::core::toString(eps_bearer_qos)).append("\n");
return s;
}
//------------------------------------------------------------------------------
void sgw_eps_bearer::deallocate_ressources()
{
// Logger::sgwc_app().info( "TODO remove_eps_bearer(%d) OpenFlow", ebi.ebi);
// if (not is_fteid_zero(sgw_fteid_s5_s8_up))
// sgwc_app_inst->free_s5s8_up_fteid(sgw_fteid_s5_s8_up);
//if (not is_fteid_zero(sgw_fteid_s1u_s12_s4u_s11u))
// sgwc_app_inst->free_s1s12s4s11_up_fteid(sgw_fteid_s1u_s12_s4u_s11u);
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::erase_pdn_connection(std::shared_ptr<sgw_pdn_connection> spc)
{
kpdn_t k = std::make_pair<std::string,uint8_t>(std::string(spc.get()->apn_in_use), (uint8_t)spc.get()->pdn_type.pdn_type);
std::size_t size = pdn_connections.erase(k);
Logger::sgwc_app().trace( "erase_pdn_connection(%s,%d) %d erased", spc.get()->apn_in_use.c_str(), spc.get()->pdn_type.pdn_type, size);
}
//------------------------------------------------------------------------------
shared_ptr<sgw_pdn_connection> sgw_eps_bearer_context::insert_pdn_connection(sgw_pdn_connection* p)
{
kpdn_t k(p->apn_in_use, (uint8_t)p->pdn_type.pdn_type);
shared_ptr<sgw_pdn_connection> s = shared_ptr<sgw_pdn_connection>(p);
std::pair<std::map<kpdn_t, shared_ptr<sgw_pdn_connection>>::iterator,bool> ret;
ret = pdn_connections.insert(std::pair<kpdn_t, shared_ptr<sgw_pdn_connection>>(k, s));
if (ret.second==false) {
Logger::sgwc_app().error( "insert_pdn_connection(%s,%d) failed", ret.first->first.first.c_str(), (int)ret.first->first.second);
} else {
Logger::sgwc_app().trace( "insert_pdn_connection(%s,%d) succeed key(%s,%d)",
ret.first->first.first.c_str(), (int)ret.first->first.second,k.first.c_str(), (int)k.second);
}
return s;
}
//------------------------------------------------------------------------------
bool sgw_eps_bearer_context::find_pdn_connection(const std::string& apn, const pdn_type_t pdn_type, std::shared_ptr<sgw_pdn_connection> &sp)
{
kpdn_t k(apn, pdn_type.pdn_type);
std::map<kpdn_t,shared_ptr<sgw_pdn_connection>>::iterator it;
it = pdn_connections.find(k);
if (it != pdn_connections.end()) {
sp = it->second;
return true;
}
sp = {};
return false;
}
//------------------------------------------------------------------------------
bool sgw_eps_bearer_context::find_pdn_connection(const core::ebi_t& ebi, std::shared_ptr<sgw_pdn_connection> &sp)
{
for (auto it=pdn_connections.begin(); it!=pdn_connections.end(); ++it) {
if (it->second.get()->default_bearer.ebi == ebi.ebi) {
sp = it->second;
return true;
}
std::shared_ptr<sgw_eps_bearer> seb;
if (it->second.get()->get_eps_bearer(ebi, seb)) {
if (seb.get()) {
sp = it->second;
return true;
}
}
}
sp = {};
return false;
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::create_procedure(itti_s11_create_session_request& csreq)
{
create_session_request_procedure* p = new create_session_request_procedure(csreq);
insert_procedure(p);
if (p->run(sgwc_app_inst->s11sgw_teid_2_sgw_eps_bearer_context(this->sgw_fteid_s11_s4_cp.teid_gre_key))) {
// TODO handle error code
Logger::sgwc_app().info( "S11 CREATE_SESSION_REQUEST procedure failed");
remove_procedure(p);
} else {
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::create_procedure(itti_s11_modify_bearer_request& mbreq)
{
//Assuming actually that only one pdn_connection per modify bearer request
if (mbreq.gtp_ies.has_bearer_context_to_be_modified() || mbreq.gtp_ies.has_bearer_context_to_be_removed()) {
modify_bearer_request_procedure* p = new modify_bearer_request_procedure(mbreq);
insert_procedure(p);
int rc = p->run(sgwc_app_inst->s11sgw_teid_2_sgw_eps_bearer_context(this->sgw_fteid_s11_s4_cp.teid_gre_key));
switch (rc) {
case RETURNerror:
// TODO handle error code
Logger::sgwc_app().info( "S11 MODIFY_BEARER_REQUEST procedure failed");
case RETURNclear:
remove_procedure(p);
break;
case RETURNok:
default:;
}
} else {
Logger::sgwc_app().error("S11 MODIFY_BEARER_REQUEST not bearer context to be modified or to be removed found, should be handled by GTPV2-C stack, silently discarded!");
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::create_procedure(itti_s11_release_access_bearers_request& rabreq)
{
//Assuming actually that only one pdn_connection per modify bearer request
release_access_bearers_request_procedure* p = new release_access_bearers_request_procedure(rabreq);
insert_procedure(p);
int rc = p->run(sgwc_app_inst->s11sgw_teid_2_sgw_eps_bearer_context(this->sgw_fteid_s11_s4_cp.teid_gre_key));
switch (rc) {
case RETURNerror:
// TODO handle error code
Logger::sgwc_app().info( "S11 RELEASE_ACCESS_BEARERS_REQUEST procedure failed");
case RETURNclear:
remove_procedure(p);
break;
case RETURNok:
default:;
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::create_procedure(itti_s11_delete_session_request& dsreq)
{
std::vector<shared_ptr<sgw_pdn_connection>> to_delete = {}; // list of PDN connections to delete
core::ebi_t default_bearer = {};
if (dsreq.gtp_ies.get(default_bearer)) {
shared_ptr<sgw_pdn_connection> pdn;
if (find_pdn_connection(default_bearer, pdn)) {
if (pdn.get()) {
to_delete.push_back(pdn);
} else {
// TODO return error
Logger::sgwc_app().info("S11 DELETE_SESSION_REQUEST PDN connection null, discarded!");
}
} else {
Logger::sgwc_app().info("S11 DELETE_SESSION_REQUEST PDN connection not found, discarded!");
}
} else {
// Normally should be only one PDN connection
// TODO decide what todo (reject request, delete all, ?)
for (auto it=pdn_connections.begin(); it!=pdn_connections.end(); ++it) {
to_delete.push_back(it->second);
}
}
for (auto it=to_delete.begin(); it!=to_delete.end(); ++it) {
delete_session_request_procedure* p = new delete_session_request_procedure(dsreq, *it);
insert_procedure(p);
if (p->run(shared_from_this())) {
Logger::sgwc_app().info( "S11 DELETE_SESSION_REQUEST procedure failed");
// TODO handle error code
remove_procedure(p);
}
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::insert_procedure(sebc_procedure* proc)
{
pending_procedures.push_back(shared_ptr<sebc_procedure>(proc));
}
//------------------------------------------------------------------------------
shared_ptr<sebc_procedure> sgw_eps_bearer_context::find_procedure(const uint64_t& gtpc_tx_id)
{
auto found = std::find_if(pending_procedures.begin(), pending_procedures.end(), [gtpc_tx_id](std::shared_ptr<sebc_procedure> const& i) -> bool { return i.get()->has_trxn_id(gtpc_tx_id);});
if (found != pending_procedures.end()) {
return *found;
}
return shared_ptr<sebc_procedure>(nullptr);
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::remove_procedure(sebc_procedure* proc)
{
auto found = std::find_if(pending_procedures.begin(), pending_procedures.end(), [proc](std::shared_ptr<sebc_procedure> const& i) {
return i.get() == proc;
});
if (found != pending_procedures.end()) {
pending_procedures.erase(found);
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::delete_pdn_connection(std::shared_ptr<sgw_pdn_connection> spc)
{
if (spc.get()) {
Logger::sgwc_app().debug("sgw_eps_bearer_context::delete_pdn_connection() OK doing it");
erase_pdn_connection(spc);
spc.get()->deallocate_ressources();
spc.get()->delete_bearers();
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::handle_itti_msg (itti_s11_create_session_request& csreq)
{
if (sgw_fteid_s11_s4_cp.teid_gre_key == UNASSIGNED_TEID) {
sgw_fteid_s11_s4_cp = sgwc_app_inst->generate_s11_cp_fteid(sgwc_cfg.s11_cp.addr4);
sgwc_app_inst->set_s11sgw_teid_2_sgw_eps_bearer_context(sgw_fteid_s11_s4_cp.teid_gre_key, shared_from_this());
mme_fteid_s11 = csreq.gtp_ies.sender_fteid_for_cp;
imsi = csreq.gtp_ies.imsi;
} else {
if (not is_fteid_equal(mme_fteid_s11, csreq.gtp_ies.sender_fteid_for_cp)) {
Logger::sgwc_app().debug("S11 CREATE_SESSION_REQUEST MME S11 FTEID changed");
mme_fteid_s11 = csreq.gtp_ies.sender_fteid_for_cp;
}
}
create_procedure(csreq);
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::handle_itti_msg (itti_s11_modify_bearer_request& mbreq)
{
shared_ptr<sebc_procedure> sp = find_procedure(mbreq.gtpc_tx_id);
if (sp.get()) {
Logger::sgwc_app().error("S11 MODIFY_BEARER_REQUEST ignored, existing procedure found gtpc_tx_id %d!", mbreq.gtpc_tx_id);
return;
} else {
create_procedure(mbreq);
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::handle_itti_msg (itti_s11_release_access_bearers_request& rabreq)
{
shared_ptr<sebc_procedure> sp = find_procedure(rabreq.gtpc_tx_id);
if (sp.get()) {
Logger::sgwc_app().error("S11 RELEASE_ACCESS_BEARERS_REQUEST ignored, existing procedure found gtpc_tx_id %d!", rabreq.gtpc_tx_id);
return;
} else {
create_procedure(rabreq);
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::handle_itti_msg (itti_s11_delete_session_request& dsreq)
{
shared_ptr<sebc_procedure> sp = find_procedure(dsreq.gtpc_tx_id);
if (sp.get()) {
Logger::sgwc_app().error("S11 DELETE_SESSION_REQUEST ignored, existing procedure found gtpc_tx_id %d!", dsreq.gtpc_tx_id);
return;
} else {
core::indication_t indication = {};
if (dsreq.gtp_ies.get(indication)) {
if (indication.oi) {
create_procedure(dsreq);
return;
}
} else {
Logger::sgwc_app().trace("S11 DELETE_SESSION_REQUEST indication.u1.b = %d");
}
// TODO DELETE SESSION locally
Logger::sgwc_app().info("S11 DELETE_SESSION_REQUEST TODO delete session locally");
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::handle_itti_msg (itti_s5s8_create_session_response& csresp, std::shared_ptr<sgw_pdn_connection> spc)
{
shared_ptr<sebc_procedure> sp = find_procedure(csresp.gtpc_tx_id);
if (sp.get()) {
sp.get()->handle_itti_msg(csresp, shared_from_this(), spc);
if (sp.get()->marked_for_removal) {
remove_procedure(sp.get());
}
} else {
Logger::sgwc_app().debug("S5S8 CREATE_SESSION_RESPONSE ignored, no procedure found gtpc_tx_id %d!", csresp.gtpc_tx_id);
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::handle_itti_msg (itti_s5s8_modify_bearer_response& resp, std::shared_ptr<sgw_pdn_connection> spc)
{
shared_ptr<sebc_procedure> sp = find_procedure(resp.gtpc_tx_id);
if (sp.get()) {
sp.get()->handle_itti_msg(resp, shared_from_this(), spc);
if (sp.get()->marked_for_removal) {
remove_procedure(sp.get());
}
} else {
Logger::sgwc_app().debug("S5S8 MODIFY_BEARER_RESPONSE ignored, no procedure found gtpc_tx_id %d!", resp.gtpc_tx_id);
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::handle_itti_msg (itti_s5s8_release_access_bearers_response& resp, std::shared_ptr<sgw_pdn_connection> spc)
{
shared_ptr<sebc_procedure> sp = find_procedure(resp.gtpc_tx_id);
if (sp.get()) {
sp.get()->handle_itti_msg(resp, shared_from_this(), spc);
if (sp.get()->marked_for_removal) {
remove_procedure(sp.get());
}
} else {
Logger::sgwc_app().debug("S5S8 RELEASE_ACCESS_BEARERS_RESPONSE ignored, no procedure found gtpc_tx_id %d!", resp.gtpc_tx_id);
}
}
//------------------------------------------------------------------------------
void sgw_eps_bearer_context::handle_itti_msg (itti_s5s8_delete_session_response& dsresp, std::shared_ptr<sgw_pdn_connection> spc)
{
shared_ptr<sebc_procedure> sp = find_procedure(dsresp.gtpc_tx_id);
if (sp.get()) {
sp.get()->handle_itti_msg(dsresp, shared_from_this(), spc);
if (sp.get()->marked_for_removal) {
remove_procedure(sp.get());
}
} else {
Logger::sgwc_app().debug("S5S8 CREATE_SESSION_RESPONSE ignored, no procedure found gtpc_tx_id %d!", dsresp.gtpc_tx_id);
}
}
//------------------------------------------------------------------------------
std::string sgw_eps_bearer_context::toString() const
{
std::string s = {};
s.append("SGW EPS BEARER CONTEXT:\n");
s.append("\tIMSI:\t\t\t").append(oai::cn::core::toString(imsi)).append("\n");
s.append("\tIMSI UNAUTHENTICATED:\t").append(std::to_string(imsi_unauthenticated_indicator)).append("\n");
s.append("\tMME FTEID S11 CP:\t").append(oai::cn::core::toString(mme_fteid_s11)).append("\n");
s.append("\tSGW FTEID S11 CP:\t").append(oai::cn::core::toString(sgw_fteid_s11_s4_cp)).append("\n");
//s.append("\tSGSN FTEID S4 CP:\t").append(oai::cn::core::toString(sgsn_fteid_s4_cp)).append("\n");
s.append("\tLAST KNOWN CELL ID:\t").append(oai::cn::core::toString(last_known_cell_Id)).append("\n");
for (auto it : pdn_connections) {
s.append(it.second.get()->toString());
}
return s;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgwc_eps_bearer_context.hpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SGWC_EPS_BEARER_CONTEXT_HPP_SEEN
#define FILE_SGWC_EPS_BEARER_CONTEXT_HPP_SEEN
#include "3gpp_29.274.h"
#include "itti_msg_s11.hpp"
#include "itti_msg_s5s8.hpp"
#include "sgwc_procedure.hpp"
#include <map>
#include <memory>
#include <vector>
namespace oai::cn::nf::sgwc {
class sgw_eps_bearer {
public:
sgw_eps_bearer() {
ebi.ebi = EPS_BEARER_IDENTITY_UNASSIGNED;
tft = {};
pgw_fteid_s5_s8_up = {};
sgw_fteid_s5_s8_up = {};
sgw_fteid_s1u_s12_s4u_s11u = {};
sgw_fteid_s11u = {};
mme_fteid_s11u = {};
enb_fteid_s1u = {};
eps_bearer_qos = {};
}
sgw_eps_bearer(const sgw_eps_bearer& b) {
ebi.ebi = b.ebi.ebi;
tft = b.tft;
pgw_fteid_s5_s8_up = b.pgw_fteid_s5_s8_up;
sgw_fteid_s5_s8_up = b.sgw_fteid_s5_s8_up;
sgw_fteid_s1u_s12_s4u_s11u = b.sgw_fteid_s1u_s12_s4u_s11u;
sgw_fteid_s11u = b.sgw_fteid_s11u;
mme_fteid_s11u = b.mme_fteid_s11u;
enb_fteid_s1u = b.enb_fteid_s1u;
eps_bearer_qos = b.eps_bearer_qos;
}
void clear() {
ebi.ebi = EPS_BEARER_IDENTITY_UNASSIGNED;
tft = {};
pgw_fteid_s5_s8_up = {};
sgw_fteid_s5_s8_up = {};
sgw_fteid_s1u_s12_s4u_s11u = {};
sgw_fteid_s11u = {};
mme_fteid_s11u = {};
enb_fteid_s1u = {};
eps_bearer_qos = {};
}
bool update(const oai::cn::proto::gtpv2c::bearer_context_modified_within_modify_bearer_response& b) {
core::ebi_t check_ebi = {};
if ((b.get(check_ebi)) && (check_ebi.ebi == ebi.ebi)) {
b.get_s1_u_sgw_fteid(sgw_fteid_s1u_s12_s4u_s11u);
return true;
}
return false;
}
sgw_eps_bearer(sgw_eps_bearer&& b) = delete;
void deallocate_ressources();
std::string toString() const;
core::ebi_t ebi; //EPS Bearer Id //An EPS bearer identity uniquely identifies an EPS bearer for one UE accessing via E-UTRAN.
core::traffic_flow_template_t tft; // Traffic Flow Template
//core::ip_address_t pgw_address_in_use_up; // The IP address of the P-GW currently used for sending user plane traffic. (For GTP-based S5/S8 only).
//teid_t pgw_teid_s5_s8_up; // P-GW Tunnel Endpoint Identifier for the S5/S8 interface for the user plane. (For GTP-based S5/S8 only).
// replaced by
core::fteid_t pgw_fteid_s5_s8_up; // P-GW FTEID for the S5/S8 interface for the user plane. (For GTP-based S5/S8 only).
//ip_address_t s_gw_ip_address_s5_s8_up; // S-GW IP address for user plane data received from PDN GW. (For GTP-based S5/S8 only).
//teid_t s_gw_teid_s5_s8_up; // S-GW Tunnel Endpoint Identifier for the S5/S8 interface for the user plane. (For GTP-based S5/S8 only).
// replaced by
core::fteid_t sgw_fteid_s5_s8_up; // S-GW FTEID for the S5/S8 interface for the user plane. (For GTP-based S5/S8 only).
//ip_address_t s_gw_ip_address_s1u_s12_s4u_s11u;// S-GW IP address for the S1-u interface (used by the eNodeB), for the S12 interface (used by the RNC) and for the S4
// interface (used by the SGSN). Also S-GW IP address for the S11-u interface (used by the MME) if no separation of S1-U
// and S11-U is required. The S11-u interface is used for Control Plane CIoT EPS Optimisation.
//teid_t sgw_teid_s1u_s12_s4u_s11u; // S-GW Tunnel Endpoint Identifier for the S1-u interface, for the S12 interface (used by the RNC) and for the S4 interface (used by the SGSN). Also S-GW Tunnel Endpoint Identifier for the
// S11-u interface (used by the MME) if no separation of S1-U and S11-U is required. The S11-u interface is used for Control Plane CIoT EPS Optimisation.
// replaced by
core::fteid_t sgw_fteid_s1u_s12_s4u_s11u;
//ip_address_t sgw_ip_address_s11u; // S-GW IP address for the S11-u interface (used by the MME). if S11-u is separated from S1-u. The S11-u interface is used for Control Plane CIoT EPS Optimisation.
//teid_t sgw_teid_s11u; // S-GW Tunnel Endpoint Identifier for the S11-u interface (used by the MME) if S11-u is separated from S1-u. The S11-u interface is used for Control Plane CIoT EPS Optimisation.
// replaced by
core::fteid_t sgw_fteid_s11u;
//ip_address_t mme_ip_address_s11u; // MME IP address for the S11-u interface (Used by the S-GW). The S11-u interface is used for Control Plane CIoT EPS Optimisation.
//teid_t mme_teid_s11u; // MME Tunnel Endpoint Identifier for the S11-u interface (Used by the S-GW). The S11-u interface is used for Control Plane CIoT EPS Optimisation.
// replaced by
core::fteid_t mme_fteid_s11u; // MME FTEID for the S11-u interface (Used by the S-GW). The S11-u interface is used for Control Plane CIoT EPS Optimisation.
//ip_address_t enb_ip_address_s1u; // eNodeB IP address for the S1-u interface (Used by the S-GW).
//teid_t enb_teid_s1u; // eNodeB Tunnel Endpoint Identifier for the S1-u interface.
// replaced by
core::fteid_t enb_fteid_s1u; // eNodeB FTEID for the S1-u interface.
// RNC IP address for S12 // RNC IP address for the S12 interface (Used by the S-GW).
// RNC TEID for S12 // RNC Tunnel Endpoint Identifier for the S12 interface.
// SGSN IP address for S4 (user plane) // SGSN IP address for the S4 interface (Used by the S-GW).
// SGSN TEID for S4 (user plane) // SGSN Tunnel Endpoint Identifier for the S4 interface.
core::bearer_qos_t eps_bearer_qos; ///< ARP, GBR, MBR, QCI.
// NOT NEEDED charging_id ///< Charging identifier, identifies charging records generated by S-GW and PDN GW.
};
class sgw_pdn_connection {
public:
sgw_pdn_connection() : apn_in_use(), pdn_type(), pgw_fteid_s5_s8_cp(), pgw_address_in_use_up(),
sgw_fteid_s5_s8_cp(), is_dl_up_tunnels_released(false), sgw_eps_bearers() {
default_bearer.ebi = EPS_BEARER_IDENTITY_UNASSIGNED;
}
sgw_pdn_connection(sgw_pdn_connection& b) = delete;
bool get_eps_bearer(const core::ebi_t& ebi, std::shared_ptr<sgw_eps_bearer>& b);
void add_eps_bearer(std::shared_ptr<sgw_eps_bearer> eps_bearer);
bool update_eps_bearer(const oai::cn::proto::gtpv2c::bearer_context_modified_within_modify_bearer_response& b);
void remove_eps_bearer(const core::ebi_t& ebi);
void remove_eps_bearer(std::shared_ptr<sgw_eps_bearer> bearer);
void delete_bearers();
bool is_released() {return is_dl_up_tunnels_released;}
//core::fteid_t generate_s5s8_up_fteid(const struct in_addr ipv4_address, const core::bearer_qos_t& bearer_qos);
void deallocate_ressources();
std::string toString() const;
std::string apn_in_use; ///< The APN currently used, as received from the MME or S4 SGSN.
//PDN Type // IPv4, IPv6, IPv4v6 or Non-IP. (This information is needed by the SGW in order to determine whether to perform Paging Policy Differentiation).
core::pdn_type_t pdn_type;
//EPS PDN Charging Characteristics ///< The charging characteristics of this PDN connection, e.g.normal, prepaid, flat-rate and/or hot billing.
//ip_address_t pgw_address_in_use_cp; ///< The IP address of the P-GW currently used for sending control plane signalling.
// The TEID-C shall be unique per PDN-Connection on GTP based S2a, S2b, S5 and S8 interfaces. The same
// tunnel shall be shared for the control messages related to all bearers associated to the PDN-Connection.
// A TEID-C on the S2a/S2b/S5/S8 interface shall be released after all its associated EPS bearers are deleted.
//teid_t pgw_teid_s5_s8_cp; ///< P-GW Tunnel Endpoint Identifier for the S5/S8 interface for the control plane. (For GTP-based S5/S8 only).
// replaced by
core::fteid_t pgw_fteid_s5_s8_cp;
// NOT IMPLEMENTED NOW
core::ip_address_t pgw_address_in_use_up; ///< The IP address of the P-GW currently used for sending user plane traffic. (For PMIP-based S5/S8 only)
// NOT NEEDED p_gw_gre_key_for_uplink_traffic_up ///< PDN GW assigned GRE Key for the S5/S8 interface for the user plane for uplink traffic. (For PMIP-based S5/S8 only)
//ip_address_t sgw_ip_address_s5_s8_cp; ///< S-GW IP address for the S5/S8 for the control plane signalling.
//teid_t sgw_teid_s5_s8_cp; ///< S-GW Tunnel Endpoint Identifier for the S5/S8 control plane interface. (For GTP-based S5/S8 only).
// replaced by (seems PMIP wont be used)
core::fteid_t sgw_fteid_s5_s8_cp;
//ip_address_t sgw_address_in_use_up; ///< The IP address of the S-GW currently used for sending user plane traffic. (For PMIP-based S5/S8 only)
// NOT NEEDED s_gw_gre_key_for_dl_traffic_up ///< user plane for downlink traffic. (For PMIP-based S5/S8 only)
core::ebi_t default_bearer; ///< Identifies the default bearer within the PDN connection by its EPS Bearer Id. (For PMIP based S5/S8.)
// eps bearers
bool is_dl_up_tunnels_released;
std::map<uint8_t,std::shared_ptr<sgw_eps_bearer>> sgw_eps_bearers;
};
// pair apn,pdn_type
typedef std::pair<std::string,uint8_t> kpdn_t;
//struct keypdncmp {
// bool operator()(const kpdn_t & a, const kpdn_t & b) const {
// return a.second < b.first;
// }
//};
//
//template<typename S, typename T>
//bool operator<(const std::pair<S, T> & a, const std::pair<S, T> & b)
//{
// return (a.first < b.first) || (a.first == b.first && a.second < b.second);
//}
class sgw_eps_bearer_context : public std::enable_shared_from_this<sgw_eps_bearer_context> {
private:
void erase_pdn_connection(std::shared_ptr<sgw_pdn_connection> spc);
public:
sgw_eps_bearer_context(): imsi(), imsi_unauthenticated_indicator(false), msisdn(), mme_fteid_s11(),
sgw_fteid_s11_s4_cp(), sgsn_fteid_s4_cp(),last_known_cell_Id(), pending_procedures(), pdn_connections() {}
void create_procedure(core::itti::itti_s11_create_session_request& );
void create_procedure(core::itti::itti_s11_modify_bearer_request& );
void create_procedure(core::itti::itti_s11_delete_session_request& );
void create_procedure(core::itti::itti_s11_release_access_bearers_request& );
void insert_procedure(sebc_procedure* proc);
std::shared_ptr<sebc_procedure> find_procedure(const uint64_t& gtpc_tx_id);
void remove_procedure(sebc_procedure* proc);
std::shared_ptr<sgw_pdn_connection> insert_pdn_connection(sgw_pdn_connection* p);
bool find_pdn_connection(const std::string& apn, const core::pdn_type_t pdn_type, std::shared_ptr<sgw_pdn_connection> &sp);
bool find_pdn_connection(const core::ebi_t& ebi, std::shared_ptr<sgw_pdn_connection> &sp);
void delete_pdn_connection(std::shared_ptr<sgw_pdn_connection> spc);
int get_num_pdn_connections() {return pdn_connections.size();};
sgw_eps_bearer_context(sgw_eps_bearer_context& b) = delete;
void handle_itti_msg (core::itti::itti_s11_create_session_request& m);
void handle_itti_msg (core::itti::itti_s11_modify_bearer_request& m);
void handle_itti_msg (core::itti::itti_s11_release_access_bearers_request& m);
void handle_itti_msg (core::itti::itti_s11_delete_session_request& m);
void handle_itti_msg (core::itti::itti_s5s8_create_session_response& m, std::shared_ptr<sgw_pdn_connection> spc);
void handle_itti_msg (core::itti::itti_s5s8_delete_session_response& m, std::shared_ptr<sgw_pdn_connection> spc);
void handle_itti_msg (core::itti::itti_s5s8_modify_bearer_response& m, std::shared_ptr<sgw_pdn_connection> spc);
void handle_itti_msg (core::itti::itti_s5s8_release_access_bearers_response& m, std::shared_ptr<sgw_pdn_connection> spc);
std::string toString() const;
core::imsi_t imsi; // IMSI (International Mobile Subscriber Identity) is the subscriber permanent identity.
bool imsi_unauthenticated_indicator; // This is an IMSI indicator to show the IMSI is unauthenticated.
// TO BE CHECKED me_identity_t me_identity; // Mobile Equipment Identity (e.g. IMEI/IMEISV).
core::msisdn_t msisdn; // The basic MSISDN of the UE. The presence is dictated by its storage in the HSS.
// selected_cn_operator_id // Selected core network operator identity (to support networksharing as defined in TS 23.251
// LTE-M Indication // Information used by the core network to differentiate traffic from category M UEs for charging purposes, where different values of M (e.g. M1, M2) are defined in TS 36.306 [82].
//teid_t mme_teid_s11; // MME Tunnel Endpoint Identifier for the S11 interface
//ip_address_t mme_ip_address_s11; // MME IP address the S11 interface.
// replaced by
core::fteid_t mme_fteid_s11;
//teid_t sgw_teid_s11_s4_cp; // S-GW Tunnel Endpoint Identifier for the S11 Interface and the S4 Interface (control plane)
//ip_address_t sgw_ip_address_s11_s4_cp; // S-GW IP address for the S11 interface and the S4 Interface (control plane).
// replaced by
core::fteid_t sgw_fteid_s11_s4_cp;
//ip_address_t sgsn_ip_address_for_S4_cp; // S-GW IP address for the S11 interface and the S4 Interface (control plane).
//teid_t sgsn_teid_s4_cp; // S-GW Tunnel Endpoint Identifier for the S11 Interface and the S4 Interface (control plane)
// replaced by
core::fteid_t sgsn_fteid_s4_cp;
// NOT NEEDED Trace reference // Identifies a record or a collection of records for a particular trace.
// NOT NEEDED Trace type // Indicates the type of trace
// NOT NEEDED Trigger id // Identifies the entity that initiated the trace
// NOT NEEDED OMC identity // Identifies the OMC that shall receive the trace record(s).
core::ecgi_field_t last_known_cell_Id; // This is the last location of the UE known by the network
// NOT NEEDED NOW Last known Cell Id age // This is the age of the above UE location information
// DL Data Buffer Expiration Time // The time until the Serving GW buffers DL data, when the MME has requested extended buffering in an DDN Ack (e.g. when a UE is in PSM).
// Serving PLMN-Rate-Control // For inclusion on Serving GW CDR to allow post processing of CDRs and permit detection of abusive UEs.
std::map<kpdn_t, std::shared_ptr<sgw_pdn_connection>> pdn_connections;
//--------------------------------------------
// internals
std::vector<std::shared_ptr<sebc_procedure>> pending_procedures;
};
}
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgw_pdn_connection.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "sgwc_app.hpp"
#include "sgwc_eps_bearer_context.hpp"
#include "sgwc_config.hpp"
#include <algorithm>
using namespace oai::cn::core;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::sgwc;
using namespace std;
extern sgwc_app *sgwc_app_inst;
////------------------------------------------------------------------------------
//fteid_t sgw_pdn_connection::generate_s5s8_up_fteid(const struct in_addr ipv4_address, const bearer_qos_t& bearer_qos) {
// fteid_t fteid = {};
// fteid.interface_type = S5_S8_SGW_GTP_U;
// fteid.v4 = 1;
// fteid.ipv4_address = ipv4_address;
// fteid.v6 = 0;
// fteid.ipv6_address = in6addr_any;
// for (auto it : sgw_eps_bearers) {
// if (it.second->sgw_fteid_s5_s8_up.v4) {
// if (it.second->eps_bearer_qos.is_arp_equals(bearer_qos)) {
// fteid.teid_gre_key = it.second->sgw_fteid_s5_s8_up.teid_gre_key;
// return fteid;
// }
// }
// }
// fteid.teid_gre_key = sgwc_app_inst->generate_s5s8_up_teid();
// return fteid;
//}
//------------------------------------------------------------------------------
void sgw_pdn_connection::add_eps_bearer(std::shared_ptr<sgw_eps_bearer> sb)
{
if (sb.get()) {
if ((sb->ebi.ebi >= EPS_BEARER_IDENTITY_FIRST) and (sb->ebi.ebi <= EPS_BEARER_IDENTITY_LAST)) {
sgw_eps_bearers.insert(std::pair<uint8_t,std::shared_ptr<sgw_eps_bearer>>(sb->ebi.ebi, sb));
Logger::sgwc_app().trace( "sgw_pdn_connection::add_eps_bearer(%d) success", sb->ebi.ebi);
} else {
Logger::sgwc_app().error( "sgw_pdn_connection::add_eps_bearer(%d) failed, invalid EBI", sb->ebi.ebi);
}
}
}
//------------------------------------------------------------------------------
bool sgw_pdn_connection::get_eps_bearer(const core::ebi_t& ebi, std::shared_ptr<sgw_eps_bearer>& b)
{
if (sgw_eps_bearers.count(ebi.ebi)) {
b = sgw_eps_bearers.at(ebi.ebi);
return true;
}
b = {};
return false;
}
//------------------------------------------------------------------------------
bool sgw_pdn_connection::update_eps_bearer(const oai::cn::proto::gtpv2c::bearer_context_modified_within_modify_bearer_response& b)
{
core::ebi_t ebi = {};
if (b.get(ebi)) {
std::shared_ptr<sgw_eps_bearer> sb = {};
if (get_eps_bearer(ebi, sb)) {
return sb->update(b);
}
}
return false;
}
//------------------------------------------------------------------------------
void sgw_pdn_connection::remove_eps_bearer(const core::ebi_t& ebi)
{
std::shared_ptr<sgw_eps_bearer> sb = {};
if (get_eps_bearer(ebi, sb)) {
if (sb.get()) {
sb->deallocate_ressources();
sgw_eps_bearers.erase(ebi.ebi);
}
}
}
//------------------------------------------------------------------------------
void sgw_pdn_connection::remove_eps_bearer(std::shared_ptr<sgw_eps_bearer> sb)
{
if (sb.get()) {
core::ebi_t ebi = {.ebi = sb->ebi.ebi};
sb->deallocate_ressources();
sgw_eps_bearers.erase(ebi.ebi);
}
}
//------------------------------------------------------------------------------
void sgw_pdn_connection::delete_bearers()
{
sgw_eps_bearers.clear();
}
//------------------------------------------------------------------------------
void sgw_pdn_connection::deallocate_ressources()
{
Logger::sgwc_app().error( "TODO sgw_pdn_connection::deallocate_ressources()");
for (auto it : sgw_eps_bearers) {
it.second->deallocate_ressources();
}
}
//------------------------------------------------------------------------------
std::string sgw_pdn_connection::toString() const
{
std::string s = {};
s.reserve(300);
s.append("PDN CONNECTION:\n");
s.append("\tAPN IN USE:\t\t").append(apn_in_use).append("\n");
s.append("\tPDN TYPE:\t\t").append(oai::cn::core::toString(pdn_type)).append("\n");
s.append("\tPGW FTEID S5S8 CP:\t").append(oai::cn::core::toString(pgw_fteid_s5_s8_cp)).append("\n");
//s.append("\tPGW ADDRESS IN USE UP:\t").append(oai::cn::core::toString(pgw_address_in_use_up)).append("\n");
s.append("\tSGW FTEID S5S8 CP:\t").append(oai::cn::core::toString(sgw_fteid_s5_s8_cp)).append("\n");
s.append("\tDEFAULT BEARER:\t\t").append(std::to_string(default_bearer.ebi)).append("\n");
for (auto it : sgw_eps_bearers) {
s.append(it.second->toString());
}
return s;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "common_defs.h"
#include "itti.hpp"
#include "itti_msg_s11.hpp"
#include "itti_msg_s5s8.hpp"
#include "logger.hpp"
#include "pgw_config.hpp"
#include "sgwc_app.hpp"
#include "sgwc_config.hpp"
#include "sgwc_procedure.hpp"
#include "sgwc_eps_bearer_context.hpp"
using namespace oai::cn::core;
using namespace oai::cn::core::itti;
using namespace oai::cn::proto::gtpv2c;
using namespace oai::cn::nf::sgwc;
using namespace std;
extern oai::cn::nf::pgwc::pgw_config pgw_cfg;
extern itti_mw *itti_inst;
extern sgwc_app *sgwc_app_inst;
extern sgwc_config sgwc_cfg;
//------------------------------------------------------------------------------
int create_session_request_procedure::run(shared_ptr<sgw_eps_bearer_context> c)
{
// TODO check if compatible with ongoing procedures if any
//for (auto p : pending_procedures) {
// if (p) {
//
// }
//}
std::shared_ptr<sgw_pdn_connection> pdn = {};
if (c->find_pdn_connection(msg.gtp_ies.apn.access_point_name, msg.gtp_ies.pdn_type, pdn)) {
return RETURNerror;
}
ebc = c;
sgw_pdn_connection* p = new sgw_pdn_connection();
p->apn_in_use = msg.gtp_ies.apn.access_point_name;
p->pdn_type = msg.gtp_ies.pdn_type;
std::shared_ptr<sgw_pdn_connection> spc = ebc->insert_pdn_connection(p);
// TODO : default_bearer
p->default_bearer = msg.gtp_ies.bearer_contexts_to_be_created.at(0).eps_bearer_id;
p->sgw_fteid_s5_s8_cp = sgwc_app_inst->generate_s5s8_cp_fteid(sgwc_cfg.s5s8_cp.addr4);
sgwc_app_inst->set_s5s8sgw_teid_2_sgw_contexts(p->sgw_fteid_s5_s8_cp.teid_gre_key, c, spc);
// Forward to P-GW (temp use ITTI instead of ITTI/GTPv2-C/UDP)
itti_s5s8_create_session_request *s5s8_csr = new itti_s5s8_create_session_request(TASK_SGWC_APP, TASK_SGWC_S5S8);
s5s8_csr->gtpc_tx_id = get_trxn_id();
// transfer IEs from S11 msg to S5 msg
// Mandatory imsi
imsi_t imsi = {}; if (msg.gtp_ies.get(imsi)) s5s8_csr->gtp_ies.set(imsi);
// The IE shall be included for the case of a UE Requested PDN Connectivity, if the MME has it stored for that UE.
// It shall be included when used on the S5/S8 interfaces if provided by the MME/SGSN:
msisdn_t msisdn = {}; if (msg.gtp_ies.get(msisdn)) s5s8_csr->gtp_ies.set(msisdn);
// If the SGW receives this IE, it shall forward it to the PGW on the S5/S8 interface:
mei_t mei = {}; if (msg.gtp_ies.get(mei)) s5s8_csr->gtp_ies.set(mei);
// The SGW shall include this IE on S5/S8 if it receives the ULI from MME/SGSN.
uli_t uli = {}; if (msg.gtp_ies.get(uli)) s5s8_csr->gtp_ies.set(uli);
// No Serving Network
// Mandatory rat_type
rat_type_t rat_type = {}; if (msg.gtp_ies.get(rat_type)) s5s8_csr->gtp_ies.set(rat_type);
// Conditional. tweak this later
indication_t indication = {}; if (msg.gtp_ies.get(indication)) s5s8_csr->gtp_ies.set(indication);
// Mandatory
s5s8_csr->gtp_ies.set_sender_fteid_for_cp(p->sgw_fteid_s5_s8_cp);
// Conditional
fteid_t fteid = {}; if (msg.gtp_ies.get_pgw_s5s8_address_for_cp(fteid)) s5s8_csr->gtp_ies.set_pgw_s5s8_address_for_cp(fteid);
// Mandatory
apn_t apn = {}; if (msg.gtp_ies.get(apn)) s5s8_csr->gtp_ies.set(apn);
// Conditional
selection_mode_t selection_mode = {}; if (msg.gtp_ies.get(selection_mode)) s5s8_csr->gtp_ies.set(selection_mode);
// Conditional
pdn_type_t pdn_type = {}; if (msg.gtp_ies.get(pdn_type)) s5s8_csr->gtp_ies.set(pdn_type);
// Conditional
paa_t paa = {}; if (msg.gtp_ies.get(paa)) s5s8_csr->gtp_ies.set(paa);
// Conditional
apn_restriction_t apn_restriction = {}; if (msg.gtp_ies.get(apn_restriction)) s5s8_csr->gtp_ies.set(apn_restriction);
// Conditional
ambr_t ambr = {}; if (msg.gtp_ies.get(ambr)) s5s8_csr->gtp_ies.set(ambr);
// Conditional
protocol_configuration_options_t protocol_configuration_options = {}; if (msg.gtp_ies.get(protocol_configuration_options)) s5s8_csr->gtp_ies.set(protocol_configuration_options);
if (msg.gtp_ies.has_bearer_context_to_be_created()) {
for (auto i : msg.gtp_ies.bearer_contexts_to_be_created) {
bearer_context_to_be_created_within_create_session_request b = {};
ebi_t ebi = {}; if (i.get(ebi)) b.set(ebi);
bearer_qos_t bearer_qos = {}; if (i.get(bearer_qos)) b.set(bearer_qos);
// get_s5_s8_u_sgw_fteid
// Wrong FTEID
fteid_t s5s8_up_fteid = {};
if (i.get(s5s8_up_fteid)) b.set_s5_s8_u_sgw_fteid(s5s8_up_fteid);;
s5s8_csr->gtp_ies.add_bearer_context_to_be_created(b);
core::ebi_t cebi = {.ebi = ebi};
sgw_eps_bearer* eps_bearer = new sgw_eps_bearer();
eps_bearer->ebi = cebi;
//eps_bearer->sgw_fteid_s5_s8_up = s5s8_up_fteid;
eps_bearer->eps_bearer_qos = bearer_qos;
spc->add_eps_bearer(std::shared_ptr<sgw_eps_bearer>(eps_bearer));
}
}
if (msg.gtp_ies.has_bearer_context_to_be_removed()) {
for (auto i : msg.gtp_ies.bearer_contexts_to_be_removed) {
bearer_context_to_be_removed_within_create_session_request b = {};
ebi_t ebi = {}; if (i.get(ebi)) b.set(ebi);
s5s8_csr->gtp_ies.add_bearer_context_to_be_removed(b);
core::ebi_t cebi = {.ebi = ebi};
std::shared_ptr<sgw_eps_bearer> seb = {};
if (spc->get_eps_bearer(cebi, seb)) {
seb->deallocate_ressources();
// TODO check when have to remove the bearer
spc->remove_eps_bearer(seb);
}
}
}
//s5s8_csr->gtp_ies = msg.gtp_ies;
//s5s8_csr->l_endpoint = {};
s5s8_csr->r_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(ntohl(pgw_cfg.s5s8_cp.addr4.s_addr)), sgwc_cfg.s5s8_cp.port);
std::shared_ptr<itti_s5s8_create_session_request> msg = std::shared_ptr<itti_s5s8_create_session_request>(s5s8_csr);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S5S8", s5s8_csr->get_msg_name());
return RETURNerror;
}
return RETURNok;
}
//------------------------------------------------------------------------------
void create_session_request_procedure::handle_itti_msg (core::itti::itti_s5s8_create_session_response& csresp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> pdn)
{
marked_for_removal = true;
//TODO Get PDN connection and fill the field
if (nullptr == pdn.get()) {
Logger::sgwc_app().error( "create_session_request_procedure handling CREATE_SESSION_RESPONSE, Could not get sgw_pdn_connection object, discarding");
return;
}
itti_s11_create_session_response *s11_csresp = new itti_s11_create_session_response(TASK_SGWC_APP, TASK_SGWC_S11);
s11_csresp->gtpc_tx_id = get_trxn_id();
s11_csresp->r_endpoint = this->msg.r_endpoint;
s11_csresp->teid = this->msg.gtp_ies.sender_fteid_for_cp.teid_gre_key;
// transfer IEs from S5 msg to S11 msg
// Mandatory imsi
core::cause_t cause = {}; if (csresp.gtp_ies.get(cause)) s11_csresp->gtp_ies.set(cause);
csresp.gtp_ies.get_s5_s8_pgw_fteid(pdn->pgw_fteid_s5_s8_cp);
s11_csresp->gtp_ies.set_sender_fteid_for_cp(ebc->sgw_fteid_s11_s4_cp);
paa_t paa = {}; if (csresp.gtp_ies.get(paa)) s11_csresp->gtp_ies.set(paa);
apn_restriction_t apn_restriction = {}; if (csresp.gtp_ies.get(apn_restriction)) s11_csresp->gtp_ies.set(apn_restriction);
ambr_t ambr = {}; if (csresp.gtp_ies.get(ambr)) s11_csresp->gtp_ies.set(ambr);
//ebi_t ebi = {}; if (msg.gtp_ies.get(ebi)) s11_csresp->gtp_ies.set(ebi);
core::protocol_configuration_options_t pco = {}; if (csresp.gtp_ies.get(pco)) s11_csresp->gtp_ies.set(pco);
fq_csid_t fq_csid = {}; if (msg.gtp_ies.get(fq_csid,0)) s11_csresp->gtp_ies.set(fq_csid,0);
// TODO FQCSID instance 1
// local_distinguished_name_t ldn = {}; if (msg.gtp_ies.get(ldn,1)) ;
epc_timer_t pgw_back_off_time = {}; if (csresp.gtp_ies.get(pgw_back_off_time)) s11_csresp->gtp_ies.set(pgw_back_off_time);
indication_t indication = {}; if (csresp.gtp_ies.get(indication)) s11_csresp->gtp_ies.set(indication);
if (csresp.gtp_ies.has_bearer_context_created()) {
for (auto i : csresp.gtp_ies.bearer_contexts_created.second) {
bearer_context_created_within_create_session_response b = {};
cause_t cause = {}; if (i.get(cause)) b.set(cause);
core::ebi_t ebi = {}; if (i.get(ebi)) b.set(ebi);
if (cause.cause_value == REQUEST_ACCEPTED) {
core::ebi_t cebi = {.ebi = ebi};
std::shared_ptr<sgw_eps_bearer> seb = {};
if (pdn->get_eps_bearer(cebi, seb)) {
seb->ebi = cebi;
i.get(seb->eps_bearer_qos);
i.get(seb->pgw_fteid_s5_s8_up, 2);
#define SPGW_PLIT 0
#if !SPGW_SPLIT
seb->sgw_fteid_s1u_s12_s4u_s11u = seb->pgw_fteid_s5_s8_up;
seb->sgw_fteid_s1u_s12_s4u_s11u.interface_type = S1_U_SGW_GTP_U;
#else
// TODO
#endif
if (not is_fteid_zero(seb->sgw_fteid_s1u_s12_s4u_s11u)) b.set_s1_u_sgw_fteid(seb->sgw_fteid_s1u_s12_s4u_s11u);
core::bearer_qos_t bearer_qos = {};
if (i.get(bearer_qos)) {
b.set(bearer_qos);
}
}
}
s11_csresp->gtp_ies.add_bearer_context_created(b);
}
}
if (csresp.gtp_ies.has_bearer_context_marked_for_removal()) {
for (auto i : csresp.gtp_ies.bearer_contexts_marked_for_removal.second) {
bearer_context_marked_for_removal_within_create_session_response b = {};
core::cause_t cause = {}; if (i.get(cause)) b.set(cause);
core::ebi_t ebi = {}; if (i.get(ebi)) b.set(ebi);
s11_csresp->gtp_ies.add_bearer_context_marked_for_removal(b);
core::ebi_t cebi = {.ebi = ebi};
std::shared_ptr<sgw_eps_bearer> seb = {};
if (pdn->get_eps_bearer(cebi, seb)) {
if (seb.get()) {
seb->clear();
}
}
}
}
std::shared_ptr<itti_s11_create_session_response> msg_send = std::shared_ptr<itti_s11_create_session_response>(s11_csresp);
int ret = itti_inst->send_msg(msg_send);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGW_11", s11_csresp->get_msg_name());
}
}
//------------------------------------------------------------------------------
int delete_session_request_procedure::run(shared_ptr<sgw_eps_bearer_context> c)
{
if (nullptr == c.get()) {
return RETURNerror;
} else {
ebc = c;
core::indication_t indication = {};
bool oi_set = false;
if (msg.gtp_ies.get(indication)) {
if (indication.oi) {
oi_set = true;
}
}
// Forward to P-GW (temp use ITTI instead of ITTI/GTPv2-C/UDP)
itti_s5s8_delete_session_request *s5s8_dsr = new itti_s5s8_delete_session_request(TASK_SGWC_APP, TASK_SGWC_S5S8);
s5s8_dsr->gtpc_tx_id = get_trxn_id();
s5s8_dsr->teid = pdn_connection->pgw_fteid_s5_s8_cp.teid_gre_key;
s5s8_dsr->r_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(ntohl(pgw_cfg.s5s8_cp.addr4.s_addr)), sgwc_cfg.s5s8_cp.port);
// transfer IEs from S11 msg to S5 msg
// The SGW shall include this IE on S5/S8 if it receives the Cause from the MME/SGSN.
core::cause_t cause = {}; if (msg.gtp_ies.get(cause)) s5s8_dsr->gtp_ies.set(cause);
// This IE shall be included on the S4/S11, S5/S8 and S2a/S2b interfaces to indicate the default bearer
// associated with the PDN being disconnected unless in the handover/TAU/RAU with SGW relocation procedures.
core::ebi_t ebi = {};
if (msg.gtp_ies.get(ebi)) {
s5s8_dsr->gtp_ies.set(ebi);
} else {
s5s8_dsr->gtp_ies.set(pdn_connection->default_bearer);
}
// The MME/SGSN shall include this IE on the S4/S11 interface for the Detach procedure. The MME shall include
// ECGI, SGSN shall include CGI/SAI. The SGW shall include this IE on S5/S8 if it receives the ULI from MME/SGSN.
core::uli_t uli = {}; if (msg.gtp_ies.get(uli)) s5s8_dsr->gtp_ies.set(uli);
// If the UE includes the PCO IE, then the MME/SGSN shall Configuration Options copy the content of this IE transparently from the PCO IE
// (PCO) included by the UE. If SGW receives the PCO IE, SGW shall forward it to PGW.
core::protocol_configuration_options_t pco = {}; if (msg.gtp_ies.get(pco)) s5s8_dsr->gtp_ies.set(pco);
// C This IE may be included on the S5/S8 and S2a/S2b interfaces.
// If the Sender F-TEID for Control Plane is received by the PGW, the PGW shall only accept the Delete Session
// Request message when the Sender F-TEID for Control Plane in this message is the same as the Sender F-TEID
// for Control Plane that was last received in either the Create Session Request message or the Modify Bearer Request
// message on the given interface. See NOTE 6.
// CO The SGW shall include this IE on the S5/S8 interface if the Delete Session Request is sent to clean up a hanging PDN
// connection context in the PGW, i.e. as a result of receiving a Create Session Request at the SGW colliding with an
// existing PDN connection context (see subclause 7.2.1).
s5s8_dsr->gtp_ies.set_sender_fteid_for_cp(pdn_connection->sgw_fteid_s5_s8_cp);
if (oi_set) {
// The SGW shall forward this IE on the S5/S8 interface if the SGW receives it from the MME/SGSN, and if the Operation
// Indication bit received from the MME/SGSN is set to 1.
core::ue_time_zone_t ue_time_zone = {}; if (msg.gtp_ies.get(ue_time_zone)) s5s8_dsr->gtp_ies.set(ue_time_zone);
// The MME shall include this IE on the S11 interface to indicate the NAS release cause to release the PDN
// connection, if available and this information is permitted to be sent to the PGW operator according to MME operator's policy.
// The SGW shall include this IE on the S5/S8 interface if it receives it from the MME and if the Operation Indication bit
// received from the MME is set to 1.
core::ran_nas_cause_t ran_nas_cause = {}; if (msg.gtp_ies.get(ran_nas_cause)) s5s8_dsr->gtp_ies.set(ran_nas_cause);
}
// If the UE includes the ePCO IE, then the MME shall copy the content of this IE transparently from the ePCO IE included by the UE.
// If the SGW receives the ePCO IE, the SGW shall forward it to the PGW.
core::extended_protocol_configuration_options_t epco = {}; if (msg.gtp_ies.get(epco)) s5s8_dsr->gtp_ies.set(epco);
std::shared_ptr<itti_s5s8_delete_session_request> msg = std::shared_ptr<itti_s5s8_delete_session_request>(s5s8_dsr);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S5S8", s5s8_dsr->get_msg_name());
return RETURNerror;
}
return RETURNok;
}
}
//------------------------------------------------------------------------------
void delete_session_request_procedure::handle_itti_msg (core::itti::itti_s5s8_delete_session_response& dsresp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection>& pdn)
{
itti_s11_delete_session_response *s11_dsresp = new itti_s11_delete_session_response(TASK_SGWC_APP, TASK_SGWC_S11);
s11_dsresp->gtpc_tx_id = get_trxn_id();
s11_dsresp->r_endpoint = this->msg.r_endpoint;
s11_dsresp->teid = this->ebc->mme_fteid_s11.teid_gre_key;
marked_for_removal = true;
// transfer IEs from S5 msg to S11 msg
core::cause_t cause = {};
if (dsresp.gtp_ies.get(cause)) {
s11_dsresp->gtp_ies.set(cause);
} else {
Logger::sgwc_app().error( "Could not get CAUSE in S5S8 DELETE_SESSION_RESPONSE");
}
//TODO Get PDN connection and fill the field
if (nullptr == pdn.get()) {
Logger::sgwc_app().error( "Could not get sgw_pdn_connection object");
return;
}
// Delete PDN connection even if s5s8 cause is not success
ebc->delete_pdn_connection(pdn);
std::shared_ptr<itti_s11_delete_session_response> msg = std::shared_ptr<itti_s11_delete_session_response>(s11_dsresp);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S11", s11_dsresp->get_msg_name());
}
}
//------------------------------------------------------------------------------
int modify_bearer_request_procedure::run(shared_ptr<sgw_eps_bearer_context> c)
{
// Since SGW is not completely split with PGW, we have to always fw this req to PGW
if (nullptr == c.get()) {
return RETURNerror;
} else {
ebc = c;
bool report_error = false;
if (msg.gtp_ies.has_bearer_context_to_be_modified()) {
for (auto it : msg.gtp_ies.bearer_contexts_to_be_modified) {
std::shared_ptr<sgw_pdn_connection> pdn = {};
std::shared_ptr<sgw_eps_bearer> sb = {};
// bearer_context_to_be_modified_within_modify_bearer_request
if (not ebc->find_pdn_connection(it.eps_bearer_id, pdn)) {
bearer_context_modified_within_modify_bearer_response bm = {};
bm.set(it.eps_bearer_id);
core::cause_t cause = {};
cause.cause_value = CONTEXT_NOT_FOUND;
bm.set(cause);
bearer_contexts_modified.push_back(bm);
} else {
// not necessary now, but should be later if S/P split
bearer_context_to_be_modified_within_modify_bearer_request bm(it);
bool pdn_registered = false;
// Should always be true since find_pdn_connection() returne true
core::fteid_t v = {};
if (it.get_s1_u_enb_fteid(v)) {
if (pdn->sgw_pdn_connection::get_eps_bearer(it.eps_bearer_id, sb)) {
if (is_fteid_equal(v, sb->enb_fteid_s1u)) {
Logger::pgwc_app().debug( "modify_bearer_procedure: ebi %d enb_fteid_s1u unchanged", it.eps_bearer_id.ebi);
bearer_context_modified_within_modify_bearer_response bm = {};
bm.set(it.eps_bearer_id);
core::cause_t cause = {};
cause.cause_value = REQUEST_ACCEPTED;
bm.set(cause);
bearer_contexts_modified.push_back(bm);
} else {
for (std::vector<std::shared_ptr<pdn_bearers_to_be_xied>>::iterator it_pdns = pdn_bearers.begin() ; it_pdns != pdn_bearers.end(); ++it_pdns) {
pdn_bearers_to_be_xied *px = it_pdns->get();
if (px->pdn == pdn) {
pdn_registered = true;
px->bearer_contexts_to_be_modified.push_back(bm);
}
}
if (not pdn_registered) {
pdn_bearers_to_be_xied *px = new (pdn_bearers_to_be_xied);
px->pdn = pdn;
px->bearer_contexts_to_be_modified.push_back(bm);
pdn_bearers.push_back(std::shared_ptr<pdn_bearers_to_be_xied>(px));
}
}
}
}
}
}
}
if (msg.gtp_ies.has_bearer_context_to_be_removed()) {
for (auto it : msg.gtp_ies.bearer_contexts_to_be_removed) {
std::shared_ptr<sgw_pdn_connection> pdn = {};
std::shared_ptr<sgw_eps_bearer> sb = {};
if (not c->find_pdn_connection(it.eps_bearer_id, pdn)) {
bearer_context_marked_for_removal_within_modify_bearer_response bm = {};
bm.set(it.eps_bearer_id);
core::cause_t cause = {};
cause.cause_value = CONTEXT_NOT_FOUND;
bm.set(cause);
bearer_contexts_marked_for_removal.push_back(bm);
} else {
// not necessary now, but should be later if S/P split
bearer_context_to_be_removed_within_modify_bearer_request bm(it);
bool pdn_registered = false;
for (std::vector<std::shared_ptr<pdn_bearers_to_be_xied>>::iterator it_pdns = pdn_bearers.begin() ; it_pdns != pdn_bearers.end(); ++it_pdns) {
pdn_bearers_to_be_xied *px = it_pdns->get();
if (px->pdn == pdn) {
pdn_registered = true;
//pdn_bearers.erase(it_pdns);
px->bearer_contexts_to_be_removed.push_back(bm);
break;
}
}
if (not pdn_registered) {
pdn_bearers_to_be_xied *px = new (pdn_bearers_to_be_xied);
px->pdn = pdn;
px->bearer_contexts_to_be_removed.push_back(bm);
pdn_bearers.push_back(std::shared_ptr<pdn_bearers_to_be_xied>(px));
}
}
}
}
if (pdn_bearers.empty()) {
itti_s11_modify_bearer_response *s11_mbresp = new itti_s11_modify_bearer_response(TASK_SGWC_APP, TASK_SGWC_S11);
s11_mbresp->gtpc_tx_id = get_trxn_id();
s11_mbresp->r_endpoint = this->msg.r_endpoint;
s11_mbresp->teid = ebc->mme_fteid_s11.teid_gre_key;
core::cause_t cause = {};
cause.cause_value = CONTEXT_NOT_FOUND;
s11_mbresp->gtp_ies.set(cause);
for (auto it_mod: bearer_contexts_modified) {
s11_mbresp->gtp_ies.add_bearer_context_modified(it_mod);
}
for (auto it_rem: bearer_contexts_marked_for_removal) {
s11_mbresp->gtp_ies.add_bearer_context_marked_for_removal(it_rem);
}
std::shared_ptr<itti_s11_modify_bearer_response> msg_send = std::shared_ptr<itti_s11_modify_bearer_response>(s11_mbresp);
int ret = itti_inst->send_msg(msg_send);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S11", s11_mbresp->get_msg_name());
return RETURNerror;
}
return RETURNclear;
} else {
// Now we can send X modify bearer request to X GTPV2-C tunnels
for (auto it_pdns : pdn_bearers) {
pdn_bearers_to_be_xied *px = it_pdns.get();
itti_s5s8_modify_bearer_request *s5s8_mbr = new itti_s5s8_modify_bearer_request(TASK_SGWC_APP, TASK_SGWC_S5S8);
std::shared_ptr<itti_s5s8_modify_bearer_request> msg_s5s8 = std::shared_ptr<itti_s5s8_modify_bearer_request>(s5s8_mbr);
// New gtpc_tx_id
px->gtpc_tx_id = oai::cn::util::uint_uid_generator<uint64_t>::get_instance().get_uid();
s5s8_mbr->gtpc_tx_id = px->gtpc_tx_id;
s5s8_mbr->teid = px->pdn->pgw_fteid_s5_s8_cp.teid_gre_key;
s5s8_mbr->r_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(ntohl(pgw_cfg.s5s8_cp.addr4.s_addr)), sgwc_cfg.s5s8_cp.port);
core::mei_t mei;
if (msg.gtp_ies.get(mei)) {
msg_s5s8->gtp_ies.set(mei);
}
core::serving_network_t serving_network;
if (msg.gtp_ies.get(serving_network)) {
msg_s5s8->gtp_ies.set(serving_network);
}
core::ue_time_zone_t ue_time_zone;
if (msg.gtp_ies.get(ue_time_zone)) {
s5s8_mbr->gtp_ies.set(ue_time_zone);
}
for (auto it_mod: px->bearer_contexts_to_be_modified) {
std::shared_ptr<sgw_eps_bearer> b = {};
if (px->pdn->get_eps_bearer(it_mod.eps_bearer_id, b)) {
if(it_mod.get_s1_u_enb_fteid(b->enb_fteid_s1u)) {
s5s8_mbr->gtp_ies.add_bearer_context_to_be_modified(it_mod);
}
}
}
for (auto it_rem: px->bearer_contexts_to_be_removed) {
s5s8_mbr->gtp_ies.add_bearer_context_to_be_removed(it_rem);
}
int ret = itti_inst->send_msg(msg_s5s8);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S5S8", s5s8_mbr->get_msg_name());
}
}
}
return RETURNok;
}
}
//------------------------------------------------------------------------------
void modify_bearer_request_procedure::handle_itti_msg (core::itti::itti_s5s8_modify_bearer_response& s5resp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> pdn)
{
itti_s11_modify_bearer_response *s11_resp = new itti_s11_modify_bearer_response(TASK_SGWC_APP, TASK_SGWC_S11);
s11_resp->gtpc_tx_id = get_trxn_id();
s11_resp->r_endpoint = this->msg.r_endpoint;
s11_resp->teid = this->ebc->mme_fteid_s11.teid_gre_key;
// transfer IEs from S5 msg to S11 msg
core::cause_t cause = {};
if (s5resp.gtp_ies.get(cause)) {
s11_resp->gtp_ies.set(cause);
} else {
Logger::sgwc_app().error( "Could not get CAUSE in S5S8 MODIFY_BEARER_RESPONSE");
marked_for_removal = true;
}
//TODO Get PDN connection and fill the field
if (nullptr == pdn.get()) {
Logger::sgwc_app().error( "Could not get sgw_pdn_connection object");
return;
marked_for_removal = true;
}
for (std::vector<std::shared_ptr<pdn_bearers_to_be_xied>>::iterator it_bearer = pdn_bearers.begin(); it_bearer != pdn_bearers.end(); ++it_bearer) {
pdn_bearers_to_be_xied *px = it_bearer->get();
if (px->gtpc_tx_id == s5resp.gtpc_tx_id) {
if (s5resp.gtp_ies.has_bearer_context_modified()) {
for (auto it_modified : s5resp.gtp_ies.bearer_contexts_modified.second) {
for (std::vector<proto::gtpv2c::bearer_context_to_be_modified_within_modify_bearer_request>::iterator it_to_be_modified = px->bearer_contexts_to_be_modified.begin()
; it_to_be_modified != px->bearer_contexts_to_be_modified.end(); ++it_to_be_modified) {
if (it_to_be_modified->eps_bearer_id.ebi == it_modified.eps_bearer_id.second.ebi) {
#define SPGW_PLIT 0
#if !SPGW_SPLIT
it_modified.s1_u_sgw_fteid.second.interface_type = S1_U_SGW_GTP_U;
#endif
bearer_contexts_modified.push_back(it_modified);
px->bearer_contexts_to_be_modified.erase(it_to_be_modified);
break;
}
}
}
}
if (s5resp.gtp_ies.has_bearer_context_marked_for_removal()) {
for (auto it_marked : s5resp.gtp_ies.bearer_contexts_marked_for_removal.second) {
for (std::vector<proto::gtpv2c::bearer_context_to_be_removed_within_modify_bearer_request>::iterator it_to_be_removed = px->bearer_contexts_to_be_removed.begin()
; it_to_be_removed != px->bearer_contexts_to_be_removed.end(); ++it_to_be_removed) {
if (it_to_be_removed->eps_bearer_id.ebi == it_marked.eps_bearer_id.second.ebi) {
bearer_contexts_marked_for_removal.push_back(it_marked);
px->bearer_contexts_to_be_removed.erase(it_to_be_removed);
break;
}
}
}
}
std::shared_ptr<sgw_pdn_connection> pdn = px->pdn;
pdn_bearers.erase(it_bearer);
if (pdn_bearers.empty()) {
// Send modify bearer response
core::cause_t global_cause = {};
global_cause.cause_value = SYSTEM_FAILURE;
marked_for_removal = true;
for (auto it_to_be_modified : msg.gtp_ies.bearer_contexts_to_be_modified) {
bool bearer_found = false;
for (auto it_modified : bearer_contexts_modified) {
if (it_modified.eps_bearer_id.second.ebi == it_to_be_modified.eps_bearer_id.ebi) {
pdn->update_eps_bearer(it_modified);
s11_resp->gtp_ies.add_bearer_context_modified(it_modified);
bearer_found = true;
if (global_cause.cause_value != REQUEST_ACCEPTED_PARTIALLY) {
global_cause.cause_value = REQUEST_ACCEPTED;
}
break;
}
}
if (not bearer_found) {
bearer_context_modified_within_modify_bearer_response b = {};
b.set(it_to_be_modified.eps_bearer_id);
cause = {};
cause.cause_value = CONTEXT_NOT_FOUND;
b.set(cause);
s11_resp->gtp_ies.add_bearer_context_modified(b);
if (global_cause.cause_value == REQUEST_ACCEPTED) {
global_cause.cause_value = REQUEST_ACCEPTED_PARTIALLY;
}
}
}
for (auto it_to_be_removed : msg.gtp_ies.bearer_contexts_to_be_removed) {
bool bearer_found = false;
for (auto it_marked : bearer_contexts_marked_for_removal) {
if (it_marked.eps_bearer_id.second.ebi == it_to_be_removed.eps_bearer_id.ebi) {
pdn->remove_eps_bearer(it_marked.eps_bearer_id.second);
s11_resp->gtp_ies.add_bearer_context_marked_for_removal(it_marked);
bearer_found = true;
if (global_cause.cause_value != REQUEST_ACCEPTED_PARTIALLY) {
global_cause.cause_value = REQUEST_ACCEPTED;
}
break;
}
}
if (not bearer_found) {
bearer_context_marked_for_removal_within_modify_bearer_response b = {};
b.set(it_to_be_removed.eps_bearer_id);
cause = {};
cause.cause_value = CONTEXT_NOT_FOUND;
b.set(cause);
s11_resp->gtp_ies.add_bearer_context_marked_for_removal(b);
}
}
s11_resp->gtp_ies.set(global_cause);
std::shared_ptr<itti_s11_modify_bearer_response> msg = std::shared_ptr<itti_s11_modify_bearer_response>(s11_resp);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S11", s11_resp->get_msg_name());
}
}
break;
}
}
}
//------------------------------------------------------------------------------
bool modify_bearer_request_procedure::has_trxn_id(const uint64_t trxn_id)
{
if (sebc_procedure::has_trxn_id(trxn_id)) {
//Logger::sgwc_app().error( "modify_bearer_request_procedure::has_trxn_id(%d) -> true", trxn_id);
return true;
}
for (auto it_pdns : pdn_bearers) {
//Logger::sgwc_app().error( "modify_bearer_request_procedure::has_trxn_id(%d) -> check with %d", trxn_id, it_pdns->gtpc_tx_id);
if (it_pdns->gtpc_tx_id == trxn_id) {
//Logger::sgwc_app().error( "modify_bearer_request_procedure::has_trxn_id(%d) -> true", trxn_id);
return true;
}
}
//Logger::sgwc_app().error( "modify_bearer_request_procedure::has_trxn_id(%d) -> false (is %d)", trxn_id, get_trxn_id());
return false;
}
//------------------------------------------------------------------------------
bool release_access_bearers_request_procedure::has_trxn_id(const uint64_t trxn_id)
{
if (sebc_procedure::has_trxn_id(trxn_id)) {
//Logger::sgwc_app().error( "release_access_bearers_request_procedure::has_trxn_id(%d) -> true", trxn_id);
return true;
}
for (auto it : bearers) {
//Logger::sgwc_app().error( "release_access_bearers_request_procedure::has_trxn_id(%d) -> check with %d", trxn_id, it_pdns->gtpc_tx_id);
if (it->gtpc_tx_id == trxn_id) {
//Logger::sgwc_app().error( "release_access_bearers_request_procedure::has_trxn_id(%d) -> true", trxn_id);
return true;
}
}
//Logger::sgwc_app().error( "release_access_bearers_request_procedure::has_trxn_id(%d) -> false (is %d)", trxn_id, get_trxn_id());
return false;
}
//------------------------------------------------------------------------------
int release_access_bearers_request_procedure::run(shared_ptr<sgw_eps_bearer_context> c)
{
// Since SGW is not completely split with PGW, we have to always fw this req to PGW
if (nullptr == c.get()) {
Logger::sgwc_app().error( "release_access_bearers_request_procedure Could not get sgw_eps_bearer_context");
return RETURNerror;
} else {
ebc = c;
for (std::map<kpdn_t, std::shared_ptr<sgw_pdn_connection>>::const_iterator it_pdn = ebc->pdn_connections.begin(); it_pdn != ebc->pdn_connections.end(); ++it_pdn) {
if (not it_pdn->second->is_released()) {
bearers_to_be_released *breal = new bearers_to_be_released();
breal->pdn = it_pdn->second;
breal->gtpc_tx_id = get_trxn_id();
bearers.push_back(std::shared_ptr<bearers_to_be_released>(breal));
itti_s5s8_release_access_bearers_request *s5s8 = new itti_s5s8_release_access_bearers_request(TASK_SGWC_APP, TASK_SGWC_S5S8);
s5s8->gtpc_tx_id = breal->gtpc_tx_id;
s5s8->teid = it_pdn->second->pgw_fteid_s5_s8_cp.teid_gre_key;
s5s8->r_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(ntohl(it_pdn->second->pgw_fteid_s5_s8_cp.ipv4_address.s_addr)), pgw_cfg.s5s8_cp.port);
std::shared_ptr<itti_s5s8_release_access_bearers_request> msg = std::shared_ptr<itti_s5s8_release_access_bearers_request>(s5s8);
//breal->msg = msg;
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S5S8", s5s8->get_msg_name());
}
}
}
if (bearers.empty()) {
Logger::sgwc_app().error( "release_access_bearers_request_procedure all pdn connections already released");
itti_s11_release_access_bearers_response *s11 = new itti_s11_release_access_bearers_response(TASK_SGWC_APP, TASK_SGWC_S11);
s11->gtpc_tx_id = get_trxn_id();
s11->r_endpoint = this->msg.r_endpoint;
s11->teid = ebc->mme_fteid_s11.teid_gre_key;
core::cause_t cause = {};
cause.cause_value = REQUEST_ACCEPTED;
s11->gtp_ies.set(cause);
std::shared_ptr<itti_s11_release_access_bearers_response> msg_send = std::shared_ptr<itti_s11_release_access_bearers_response>(s11);
int ret = itti_inst->send_msg(msg_send);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S11", s11->get_msg_name());
return RETURNerror;
}
return RETURNclear;
}
return RETURNok;
}
}
//------------------------------------------------------------------------------
void release_access_bearers_request_procedure::handle_itti_msg (core::itti::itti_s5s8_release_access_bearers_response& s5resp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> pdn)
{
itti_s11_release_access_bearers_response *s11_resp = new itti_s11_release_access_bearers_response(TASK_SGWC_APP, TASK_SGWC_S11);
s11_resp->gtpc_tx_id = get_trxn_id();
s11_resp->r_endpoint = this->msg.r_endpoint;
s11_resp->teid = this->ebc->mme_fteid_s11.teid_gre_key;
// transfer IEs from S5 msg to S11 msg
//TODO Get PDN connection and fill the field
if (nullptr == pdn.get()) {
Logger::sgwc_app().error( "Could not get sgw_pdn_connection object");
return;
}
for (std::vector<std::shared_ptr<bearers_to_be_released>>::iterator it_bearer = bearers.begin(); it_bearer != bearers.end(); ++it_bearer) {
bearers_to_be_released *px = it_bearer->get();
if (px->gtpc_tx_id == s5resp.gtpc_tx_id) {
if (cause.cause_value == 0) {
if (not s5resp.gtp_ies.get(cause)) {
Logger::sgwc_app().info( "Could not get CAUSE in S5S8 RELEASE_ACCESS_BEARERS_RESPONSE");
// TODO ?
cause.cause_value = REQUEST_ACCEPTED;
}
} else {
core::cause_t get_cause = {};
if (s5resp.gtp_ies.get(get_cause)) {
switch (get_cause.cause_value) {
case REQUEST_ACCEPTED:
if (cause.cause_value == CONTEXT_NOT_FOUND) {
cause.cause_value = REQUEST_ACCEPTED_PARTIALLY;
}
break;
case REQUEST_ACCEPTED_PARTIALLY:
cause.cause_value = REQUEST_ACCEPTED_PARTIALLY;
break;
case CONTEXT_NOT_FOUND:
default:
if (cause.cause_value == REQUEST_ACCEPTED) {
cause.cause_value = REQUEST_ACCEPTED_PARTIALLY;
}
break;
}
s11_resp->gtp_ies.set(cause);
} else {
cause.cause_value = REQUEST_ACCEPTED;
}
}
s11_resp->gtp_ies.set(cause);
std::shared_ptr<sgw_pdn_connection> pdn = px->pdn;
bearers.erase(it_bearer);
if (bearers.empty()) {
// Send response
std::shared_ptr<itti_s11_release_access_bearers_response> msg = std::shared_ptr<itti_s11_release_access_bearers_response>(s11_resp);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::sgwc_app().error( "Could not send ITTI message %s to task TASK_SGWC_S11", s11_resp->get_msg_name());
}
}
break;
}
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef FILE_SGWC_PROCEDURE_HPP_SEEN
#define FILE_SGWC_PROCEDURE_HPP_SEEN
/*! \file sgwc_procedure.hpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "itti_msg_s11.hpp"
#include "msg_gtpv2c.hpp"
#include "uint_generator.hpp"
#include <memory>
#include <list>
namespace oai::cn::nf::sgwc {
class sgw_eps_bearer_context;
class sgw_pdn_connection;
class sebc_procedure {
private:
static uint64_t generate_trxn_id() {
return oai::cn::util::uint_uid_generator<uint64_t>::get_instance().get_uid();
}
uint64_t gtpc_tx_id;
public:
bool marked_for_removal;
sebc_procedure(){gtpc_tx_id = generate_trxn_id();marked_for_removal = false;}
sebc_procedure(uint64_t tx_id){gtpc_tx_id = tx_id;marked_for_removal = false;}
virtual ~sebc_procedure(){}
virtual core::itti::itti_msg_type_t get_procedure_type(){return core::itti::ITTI_MSG_TYPE_NONE;}
virtual bool has_trxn_id(const uint64_t trxn_id) {return (trxn_id == gtpc_tx_id);}
virtual uint64_t get_trxn_id() {return gtpc_tx_id;}
virtual int run(std::shared_ptr<sgw_eps_bearer_context> ebc) {return RETURNerror;}
virtual void handle_itti_msg (core::itti::itti_s5s8_create_session_response& csresp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> spc) {}
virtual void handle_itti_msg (core::itti::itti_s5s8_delete_session_response& dsresp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> spc) {}
virtual void handle_itti_msg (core::itti::itti_s5s8_modify_bearer_response& dsresp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> spc) {}
virtual void handle_itti_msg (core::itti::itti_s5s8_release_access_bearers_response& dsresp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> spc) {}
};
//------------------------------------------------------------------------------
class sgw_eps_bearer_context;
class sgw_pdn_connection;
class create_session_request_procedure : public sebc_procedure {
public:
create_session_request_procedure(core::itti::itti_s11_create_session_request& msg) : sebc_procedure(msg.gtpc_tx_id), msg(msg), ebc(nullptr) {}
int run(std::shared_ptr<sgw_eps_bearer_context> ebc);
void handle_itti_msg (core::itti::itti_s5s8_create_session_response& csresp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> spc);
core::itti::itti_s11_create_session_request msg;
std::shared_ptr<sgw_eps_bearer_context> ebc;
};
//------------------------------------------------------------------------------
class pdn_bearers_to_be_xied {
public:
pdn_bearers_to_be_xied() : pdn(), bearer_contexts_to_be_modified(), bearer_contexts_to_be_removed(), msg(), gtpc_tx_id() {}
pdn_bearers_to_be_xied(const pdn_bearers_to_be_xied& p) : pdn(p.pdn), bearer_contexts_to_be_modified(p.bearer_contexts_to_be_modified),
bearer_contexts_to_be_removed(p.bearer_contexts_to_be_removed), msg(p.msg), gtpc_tx_id(p.gtpc_tx_id) {}
std::shared_ptr<sgw_pdn_connection> pdn;
std::vector<oai::cn::proto::gtpv2c::bearer_context_to_be_modified_within_modify_bearer_request> bearer_contexts_to_be_modified;
// Still there because of not complete S/P GW split
std::vector<oai::cn::proto::gtpv2c::bearer_context_to_be_removed_within_modify_bearer_request> bearer_contexts_to_be_removed;
std::shared_ptr<core::itti::itti_s5s8_modify_bearer_request> msg;
uint64_t gtpc_tx_id;
};
class modify_bearer_request_procedure : public sebc_procedure {
public:
modify_bearer_request_procedure(core::itti::itti_s11_modify_bearer_request& msg) : sebc_procedure(msg.gtpc_tx_id), msg(msg),
pdn_bearers(), null_pdn_bearers(), ebc(), bearer_contexts_modified(), bearer_contexts_marked_for_removal() {}
bool has_trxn_id(const uint64_t trxn_id);
int run(std::shared_ptr<sgw_eps_bearer_context> ebc);
void handle_itti_msg (core::itti::itti_s5s8_modify_bearer_response& s5resp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> pdn);
core::itti::itti_s11_modify_bearer_request msg;
std::vector<std::shared_ptr<pdn_bearers_to_be_xied>> pdn_bearers;
pdn_bearers_to_be_xied null_pdn_bearers;
std::vector<oai::cn::proto::gtpv2c::bearer_context_modified_within_modify_bearer_response> bearer_contexts_modified;
std::vector<oai::cn::proto::gtpv2c::bearer_context_marked_for_removal_within_modify_bearer_response> bearer_contexts_marked_for_removal;
std::shared_ptr<sgw_eps_bearer_context> ebc;
};
//------------------------------------------------------------------------------
class bearers_to_be_released {
public:
bearers_to_be_released(): pdn(), gtpc_tx_id() {}
bearers_to_be_released(const bearers_to_be_released& p): pdn(p.pdn), gtpc_tx_id(p.gtpc_tx_id) {}
std::shared_ptr<sgw_pdn_connection> pdn;
// Still there because of not complete S/P GW split
//std::shared_ptr<core::itti::itti_s5s8_release_access_bearers_request> msg;
uint64_t gtpc_tx_id;
};
class release_access_bearers_request_procedure : public sebc_procedure {
public:
release_access_bearers_request_procedure(core::itti::itti_s11_release_access_bearers_request& msg) : sebc_procedure(msg.gtpc_tx_id), msg(msg),
bearers(), ebc(), cause() {}
bool has_trxn_id(const uint64_t trxn_id);
int run(std::shared_ptr<sgw_eps_bearer_context> ebc);
void handle_itti_msg (core::itti::itti_s5s8_release_access_bearers_response& s5resp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection> pdn);
core::itti::itti_s11_release_access_bearers_request msg;
std::vector<std::shared_ptr<bearers_to_be_released>> bearers;
std::shared_ptr<sgw_eps_bearer_context> ebc;
core::cause_t cause;
};
//------------------------------------------------------------------------------
class delete_session_request_procedure : public sebc_procedure {
public:
delete_session_request_procedure(core::itti::itti_s11_delete_session_request& msg, std::shared_ptr<sgw_pdn_connection>& pdn) : sebc_procedure(msg.gtpc_tx_id), msg(msg), pdn_connection(pdn), ebc(nullptr) {}
int run(std::shared_ptr<sgw_eps_bearer_context> ebc);
void handle_itti_msg (core::itti::itti_s5s8_delete_session_response& dsresp, std::shared_ptr<sgw_eps_bearer_context> ebc, std::shared_ptr<sgw_pdn_connection>& spc);
core::itti::itti_s11_delete_session_request msg;
std::shared_ptr<sgw_eps_bearer_context> ebc;
std::shared_ptr<sgw_pdn_connection> pdn_connection;
};
}
#include "sgwc_eps_bearer_context.hpp"
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgw_s11.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "common_defs.h"
#include "itti.hpp"
#include "logger.hpp"
#include "sgwc_config.hpp"
#include "sgwc_s11.hpp"
#include <stdexcept>
using namespace oai::cn::core;
using namespace oai::cn::proto::gtpv2c;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::sgwc;
using namespace std;
extern itti_mw *itti_inst;
extern sgwc_config sgwc_cfg;
extern sgw_s11 *sgw_s11_inst;
void sgw_s11_task (void*);
static std::string string_to_hex(const char * const input, const std::size_t bytes_transferred)
{
static const char* const lut = "0123456789ABCDEF";
size_t len = bytes_transferred;
std::string output;
output.reserve(2 * len);
for (size_t i = 0; i < len; ++i)
{
const unsigned char c = input[i];
output.push_back(lut[c >> 4]);
output.push_back(lut[c & 15]);
}
return output;
}
//------------------------------------------------------------------------------
void sgw_s11_task (void *args_p)
{
const task_id_t task_id = TASK_SGWC_S11;
itti_inst->notify_task_ready(task_id);
do {
std::shared_ptr<itti_msg> shared_msg = itti_inst->receive_msg(task_id);
auto *msg = shared_msg.get();
switch (msg->msg_type) {
case S11_CREATE_SESSION_RESPONSE:
if (itti_s11_create_session_response* m = dynamic_cast<itti_s11_create_session_response*>(msg)) {
sgw_s11_inst->send_msg(ref(*m));
}
break;
case S11_DELETE_SESSION_RESPONSE:
if (itti_s11_delete_session_response* m = dynamic_cast<itti_s11_delete_session_response*>(msg)) {
sgw_s11_inst->send_msg(ref(*m));
}
break;
case S11_MODIFY_BEARER_RESPONSE:
if (itti_s11_modify_bearer_response* m = dynamic_cast<itti_s11_modify_bearer_response*>(msg)) {
sgw_s11_inst->send_msg(ref(*m));
}
break;
case S11_RELEASE_ACCESS_BEARERS_RESPONSE:
if (itti_s11_release_access_bearers_response* m = dynamic_cast<itti_s11_release_access_bearers_response*>(msg)) {
sgw_s11_inst->send_msg(ref(*m));
}
break;
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
Logger::sgwc_s11().debug( "TIME-OUT event timer id %d", to->timer_id);
sgw_s11_inst->time_out_itti_event(to->timer_id);
}
break;
case TERMINATE:
if (itti_msg_terminate *terminate = dynamic_cast<itti_msg_terminate*>(msg)) {
Logger::sgwc_s11().info( "Received terminate message");
return;
}
break;
default:
Logger::sgwc_s11().info( "no handler for msg type %d", msg->msg_type);
}
} while (true);
}
//------------------------------------------------------------------------------
sgw_s11::sgw_s11 () : gtpv2c_stack(string(inet_ntoa(sgwc_cfg.s11_cp.addr4)), sgwc_cfg.s11_cp.port)
{
Logger::sgwc_s11().startup("Starting...");
if (itti_inst->create_task(TASK_SGWC_S11, sgw_s11_task, nullptr) ) {
Logger::sgwc_s11().error( "Cannot create task TASK_SGWC_S11" );
throw std::runtime_error( "Cannot create task TASK_SGWC_S11" );
}
Logger::sgwc_s11().startup( "Started" );
}
//------------------------------------------------------------------------------
void sgw_s11::send_msg(itti_s11_create_session_response& i)
{
send_triggered_message(i.r_endpoint, i.teid, i.gtp_ies, i.gtpc_tx_id);
}
//------------------------------------------------------------------------------
void sgw_s11::send_msg(itti_s11_delete_session_response& i)
{
send_triggered_message(i.r_endpoint, i.teid, i.gtp_ies, i.gtpc_tx_id);
}
//------------------------------------------------------------------------------
void sgw_s11::send_msg(itti_s11_modify_bearer_response& i)
{
send_triggered_message(i.r_endpoint, i.teid, i.gtp_ies, i.gtpc_tx_id);
}
//------------------------------------------------------------------------------
void sgw_s11::send_msg(itti_s11_release_access_bearers_response& i)
{
send_triggered_message(i.r_endpoint, i.teid, i.gtp_ies, i.gtpc_tx_id);
}
//------------------------------------------------------------------------------
void sgw_s11::handle_receive_create_session_request(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_create_session_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S11, error, gtpc_tx_id);
if (!error) {
itti_s11_create_session_request *itti_msg = new itti_s11_create_session_request(TASK_SGWC_S11, TASK_SGWC_APP);
itti_msg->gtp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->gtpc_tx_id = gtpc_tx_id;
itti_msg->teid = msg.get_teid();
std::shared_ptr<itti_s11_create_session_request> i = std::shared_ptr<itti_s11_create_session_request>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::sgwc_s11().error( "Could not send ITTI message %s to task TASK_SGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void sgw_s11::handle_receive_delete_session_request(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_delete_session_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S11, error, gtpc_tx_id);
if (!error) {
itti_s11_delete_session_request *itti_msg = new itti_s11_delete_session_request(TASK_SGWC_S11, TASK_SGWC_APP);
itti_msg->gtp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->gtpc_tx_id = gtpc_tx_id;
itti_msg->teid = msg.get_teid();
std::shared_ptr<itti_s11_delete_session_request> i = std::shared_ptr<itti_s11_delete_session_request>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::sgwc_s11().error( "Could not send ITTI message %s to task TASK_SGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void sgw_s11::handle_receive_modify_bearer_request(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_modify_bearer_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S11, error, gtpc_tx_id);
if (!error) {
itti_s11_modify_bearer_request *itti_msg = new itti_s11_modify_bearer_request(TASK_SGWC_S11, TASK_SGWC_APP);
itti_msg->gtp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->gtpc_tx_id = gtpc_tx_id;
itti_msg->teid = msg.get_teid();
std::shared_ptr<itti_s11_modify_bearer_request> i = std::shared_ptr<itti_s11_modify_bearer_request>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::sgwc_s11().error( "Could not send ITTI message %s to task TASK_SGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void sgw_s11::handle_receive_release_access_bearers_request(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_release_access_bearers_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S11, error, gtpc_tx_id);
if (!error) {
itti_s11_release_access_bearers_request *itti_msg = new itti_s11_release_access_bearers_request(TASK_SGWC_S11, TASK_SGWC_APP);
itti_msg->gtp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->gtpc_tx_id = gtpc_tx_id;
itti_msg->teid = msg.get_teid();
std::shared_ptr<itti_s11_release_access_bearers_request> i = std::shared_ptr<itti_s11_release_access_bearers_request>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::sgwc_s11().error( "Could not send ITTI message %s to task TASK_SGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void sgw_s11::handle_receive_echo_request(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_echo_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S11, error, gtpc_tx_id);
if (!error) {
if (not msg_ies_container.recovery_restart_counter.first) {
// Should be detected by lower layers
Logger::sgwc_s11().warn("Received S11 ECHO REQUEST without recovery restart counter IE!, ignore message");
return;
}
Logger::sgwc_s11().info("Received S11 ECHO REQUEST");
send_echo_response(remote_endpoint, gtpc_tx_id);
}
}
//------------------------------------------------------------------------------
void sgw_s11::handle_receive_echo_response(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_echo_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S11, error, gtpc_tx_id);
if (!error) {
if (not msg_ies_container.recovery_restart_counter.first) {
// Should be detected by lower layers
Logger::sgwc_s11().warn("Received S11 ECHO RESPONSE without recovery restart counter IE!, ignore message");
return;
}
Logger::sgwc_s11().info("Received S11 ECHO RESPONSE");
// TODO
}
}
//------------------------------------------------------------------------------
void sgw_s11::send_echo_response(const boost::asio::ip::udp::endpoint& r_endpoint, const uint64_t trxn_id)
{
gtpv2c_echo_response h = {};
recovery_t r = {.restart_counter = 0};
h.set(r);
send_triggered_message(r_endpoint, h, trxn_id);
}
//------------------------------------------------------------------------------
void sgw_s11::handle_receive_gtpv2c_msg(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
//Logger::sgwc_s11().trace( "handle_receive_gtpv2c_msg msg type %d length %d", msg.get_message_type(), msg.get_message_length());
switch (msg.get_message_type()) {
case GTP_CREATE_SESSION_REQUEST: {
handle_receive_create_session_request(msg, remote_endpoint);
}
break;
case GTP_MODIFY_BEARER_REQUEST: {
handle_receive_modify_bearer_request(msg, remote_endpoint);
}
break;
case GTP_DELETE_SESSION_REQUEST: {
handle_receive_delete_session_request(msg, remote_endpoint);
}
break;
case GTP_RELEASE_ACCESS_BEARERS_REQUEST: {
handle_receive_release_access_bearers_request(msg, remote_endpoint);
}
break;
case GTP_ECHO_REQUEST: {
handle_receive_echo_request(msg, remote_endpoint);
}
break;
case GTP_ECHO_RESPONSE: {
handle_receive_echo_response(msg, remote_endpoint);
}
break;
case GTP_VERSION_NOT_SUPPORTED_INDICATION:
case GTP_CREATE_SESSION_RESPONSE:
case GTP_MODIFY_BEARER_RESPONSE:
case GTP_DELETE_SESSION_RESPONSE:
case GTP_CHANGE_NOTIFICATION_REQUEST:
case GTP_CHANGE_NOTIFICATION_RESPONSE:
case GTP_REMOTE_UE_REPORT_NOTIFICATION:
case GTP_REMOTE_UE_REPORT_ACKNOWLEDGE:
case GTP_MODIFY_BEARER_COMMAND:
case GTP_MODIFY_BEARER_FAILURE_INDICATION:
case GTP_DELETE_BEARER_COMMAND:
case GTP_DELETE_BEARER_FAILURE_INDICATION:
case GTP_BEARER_RESOURCE_COMMAND:
case GTP_BEARER_RESOURCE_FAILURE_INDICATION:
case GTP_DOWNLINK_DATA_NOTIFICATION_FAILURE_INDICATION:
case GTP_TRACE_SESSION_ACTIVATION:
case GTP_TRACE_SESSION_DEACTIVATION:
case GTP_STOP_PAGING_INDICATION:
case GTP_CREATE_BEARER_REQUEST:
case GTP_CREATE_BEARER_RESPONSE:
case GTP_UPDATE_BEARER_REQUEST:
case GTP_UPDATE_BEARER_RESPONSE:
case GTP_DELETE_BEARER_REQUEST:
case GTP_DELETE_BEARER_RESPONSE:
case GTP_DELETE_PDN_CONNECTION_SET_REQUEST:
case GTP_DELETE_PDN_CONNECTION_SET_RESPONSE:
case GTP_PGW_DOWNLINK_TRIGGERING_NOTIFICATION:
case GTP_PGW_DOWNLINK_TRIGGERING_ACKNOWLEDGE:
case GTP_IDENTIFICATION_REQUEST:
case GTP_IDENTIFICATION_RESPONSE:
case GTP_CONTEXT_REQUEST:
case GTP_CONTEXT_RESPONSE:
case GTP_CONTEXT_ACKNOWLEDGE:
case GTP_FORWARD_RELOCATION_REQUEST:
case GTP_FORWARD_RELOCATION_RESPONSE:
case GTP_FORWARD_RELOCATION_COMPLETE_NOTIFICATION:
case GTP_FORWARD_RELOCATION_COMPLETE_ACKNOWLEDGE:
case GTP_FORWARD_ACCESS_CONTEXT_NOTIFICATION:
case GTP_FORWARD_ACCESS_CONTEXT_ACKNOWLEDGE:
case GTP_RELOCATION_CANCEL_REQUEST:
case GTP_RELOCATION_CANCEL_RESPONSE:
case GTP_CONFIGURATION_TRANSFER_TUNNEL_MESSAGE:
case GTP_DETACH_NOTIFICATION:
case GTP_DETACH_ACKNOWLEDGE:
case GTP_CS_PAGING_INDICATION:
case GTP_RAN_INFORMATION_RELAY:
case GTP_ALERT_MME_NOTIFICATION:
case GTP_ALERT_MME_ACKNOWLEDGE:
case GTP_UE_ACTIVITY_NOTIFICATION:
case GTP_UE_ACTIVITY_ACKNOWLEDGE:
case GTP_ISR_STATUS_INDICATION:
case GTP_UE_REGISTRATION_QUERY_REQUEST:
case GTP_UE_REGISTRATION_QUERY_RESPONSE:
case GTP_CREATE_FORWARDING_TUNNEL_REQUEST:
case GTP_CREATE_FORWARDING_TUNNEL_RESPONSE:
case GTP_SUSPEND_NOTIFICATION:
case GTP_SUSPEND_ACKNOWLEDGE:
case GTP_RESUME_NOTIFICATION:
case GTP_RESUME_ACKNOWLEDGE:
case GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST:
case GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE:
case GTP_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST:
case GTP_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE:
case GTP_RELEASE_ACCESS_BEARERS_RESPONSE:
case GTP_DOWNLINK_DATA_NOTIFICATION:
case GTP_DOWNLINK_DATA_NOTIFICATION_ACKNOWLEDGE:
case GTP_PGW_RESTART_NOTIFICATION:
case GTP_PGW_RESTART_NOTIFICATION_ACKNOWLEDGE:
case GTP_UPDATE_PDN_CONNECTION_SET_REQUEST:
case GTP_UPDATE_PDN_CONNECTION_SET_RESPONSE:
case GTP_MODIFY_ACCESS_BEARERS_REQUEST:
case GTP_MODIFY_ACCESS_BEARERS_RESPONSE:
case GTP_MBMS_SESSION_START_REQUEST:
case GTP_MBMS_SESSION_START_RESPONSE:
case GTP_MBMS_SESSION_UPDATE_REQUEST:
case GTP_MBMS_SESSION_UPDATE_RESPONSE:
case GTP_MBMS_SESSION_STOP_RESPONSE:
break;
default:
Logger::sgwc_s11().error( "handle_receive_gtpv2c_msg msg length %d", msg.get_message_length());
}
}
//------------------------------------------------------------------------------
void sgw_s11::handle_receive(char* recv_buffer, const std::size_t bytes_transferred, boost::asio::ip::udp::endpoint& remote_endpoint)
{
//Logger::sgwc_s11().info( "handle_receive(%d bytes)", bytes_transferred);
//std::cout << string_to_hex(recv_buffer, bytes_transferred) << std::endl;
std::istringstream iss(std::istringstream::binary);
iss.rdbuf()->pubsetbuf(recv_buffer,bytes_transferred);
gtpv2c_msg msg = {};
msg.remote_port = remote_endpoint.port();
try {
msg.load_from(iss);
handle_receive_gtpv2c_msg(msg, remote_endpoint);
} catch (gtpc_exception& e) {
Logger::sgwc_s11().info( "handle_receive exception %s", e.what());
}
}
//------------------------------------------------------------------------------
void sgw_s11::time_out_itti_event(const uint32_t timer_id)
{
bool handled = false;
time_out_event(timer_id, TASK_SGWC_S11, handled);
if (!handled) {
Logger::sgwc_s11().warn( "Timer %d not Found", timer_id);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgwc_s11.hpp
\author Lionel GAUTHIER
\date 2018
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SGWC_S11_HPP_SEEN
#define FILE_SGWC_S11_HPP_SEEN
#include "gtpv2c.hpp"
#include "itti_msg_s11.hpp"
#include <thread>
namespace oai::cn::nf::sgwc {
class sgw_s11 : public proto::gtpv2c::gtpv2c_stack {
private:
std::thread::id thread_id;
std::thread thread;
void handle_receive_gtpv2c_msg(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_echo_request(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint );
void handle_receive_echo_response(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint );
void handle_receive_create_session_request(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint );
void handle_receive_delete_session_request(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_modify_bearer_request(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_release_access_bearers_request(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
public:
sgw_s11();
sgw_s11(sgw_s11 const&) = delete;
void operator=(sgw_s11 const&) = delete;
void handle_receive(char* recv_buffer, const std::size_t bytes_transferred, boost::asio::ip::udp::endpoint& remote_endpoint);
void send_msg(core::itti::itti_s11_create_session_response& m);
void send_msg(core::itti::itti_s11_delete_session_response& m);
void send_msg(core::itti::itti_s11_modify_bearer_response& m);
void send_msg(core::itti::itti_s11_release_access_bearers_response& m);
void send_echo_response(const boost::asio::ip::udp::endpoint& r_endpoint, const uint64_t trxn_id);
void time_out_itti_event(const uint32_t timer_id);
};
}
#endif /* FILE_SGWC_S11_HPP_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgw_s5s8.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "common_defs.h"
#include "itti.hpp"
#include "logger.hpp"
#include "sgwc_config.hpp"
#include "sgwc_s5s8.hpp"
#include <stdexcept>
using namespace oai::cn::core;
using namespace oai::cn::proto::gtpv2c;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::sgwc;
using namespace std;
extern itti_mw *itti_inst;
extern sgwc_config sgwc_cfg;
extern sgw_s5s8 *sgw_s5s8_inst;
void sgw_s5s8_task (void*);
//------------------------------------------------------------------------------
void sgw_s5s8_task (void *args_p)
{
const task_id_t task_id = TASK_SGWC_S5S8;
itti_inst->notify_task_ready(task_id);
do {
std::shared_ptr<itti_msg> shared_msg = itti_inst->receive_msg(task_id);
auto *msg = shared_msg.get();
switch (msg->msg_type) {
case S5S8_CREATE_SESSION_REQUEST:
if (itti_s5s8_create_session_request* m = dynamic_cast<itti_s5s8_create_session_request*>(msg)) {
sgw_s5s8_inst->send_msg(ref(*m));
}
break;
case S5S8_MODIFY_BEARER_REQUEST:
if (itti_s5s8_modify_bearer_request* m = dynamic_cast<itti_s5s8_modify_bearer_request*>(msg)) {
sgw_s5s8_inst->send_msg(ref(*m));
}
break;
case S5S8_RELEASE_ACCESS_BEARERS_REQUEST:
if (itti_s5s8_release_access_bearers_request* m = dynamic_cast<itti_s5s8_release_access_bearers_request*>(msg)) {
sgw_s5s8_inst->send_msg(ref(*m));
}
break;
case S5S8_DELETE_SESSION_REQUEST:
if (itti_s5s8_delete_session_request* m = dynamic_cast<itti_s5s8_delete_session_request*>(msg)) {
sgw_s5s8_inst->send_msg(ref(*m));
}
break;
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
Logger::sgwc_s5s8().debug( "TIME-OUT event timer id %d", to->timer_id);
sgw_s5s8_inst->time_out_itti_event(to->timer_id);
}
break;
case TERMINATE:
if (itti_msg_terminate *terminate = dynamic_cast<itti_msg_terminate*>(msg)) {
Logger::sgwc_s5s8().info( "Received terminate message");
return;
}
break;
default:
Logger::sgwc_s5s8().info( "no handler for msg type %d", msg->msg_type);
}
} while (true);
}
//------------------------------------------------------------------------------
sgw_s5s8::sgw_s5s8 () : gtpv2c_stack(string(inet_ntoa(sgwc_cfg.s5s8_cp.addr4)), sgwc_cfg.s5s8_cp.port)
{
Logger::sgwc_s5s8().startup("Starting...");
if (itti_inst->create_task(TASK_SGWC_S5S8, sgw_s5s8_task, nullptr) ) {
Logger::sgwc_s5s8().error( "Cannot create task TASK_SGWC_S5S8" );
throw std::runtime_error( "Cannot create task TASK_SGWC_S5S8" );
}
Logger::sgwc_s5s8().startup( "Started" );
}
//------------------------------------------------------------------------------
void sgw_s5s8::send_msg(itti_s5s8_create_session_request& i)
{
send_initial_message(i.r_endpoint, i.teid, i.gtp_ies, TASK_SGWC_S5S8, i.gtpc_tx_id);
}
//------------------------------------------------------------------------------
void sgw_s5s8::send_msg(itti_s5s8_delete_session_request& i)
{
send_initial_message(i.r_endpoint, i.teid, i.gtp_ies, TASK_SGWC_S5S8, i.gtpc_tx_id);
}
//------------------------------------------------------------------------------
void sgw_s5s8::send_msg(itti_s5s8_modify_bearer_request& i)
{
send_initial_message(i.r_endpoint, i.teid, i.gtp_ies, TASK_SGWC_S5S8, i.gtpc_tx_id);
}
//------------------------------------------------------------------------------
void sgw_s5s8::send_msg(itti_s5s8_release_access_bearers_request& i)
{
send_initial_message(i.r_endpoint, i.teid, i.gtp_ies, TASK_SGWC_S5S8, i.gtpc_tx_id);
}
//------------------------------------------------------------------------------
void sgw_s5s8::handle_receive_create_session_response(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_create_session_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S5S8, error, gtpc_tx_id);
if (!error) {
itti_s5s8_create_session_response *itti_msg = new itti_s5s8_create_session_response(TASK_SGWC_S5S8, TASK_SGWC_APP);
itti_msg->gtp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->gtpc_tx_id = gtpc_tx_id;
itti_msg->teid = msg.get_teid();
std::shared_ptr<itti_s5s8_create_session_response> i = std::shared_ptr<itti_s5s8_create_session_response>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::sgwc_s5s8().error( "Could not send ITTI message %s to task TASK_SGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void sgw_s5s8::handle_receive_modify_bearer_response(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_modify_bearer_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S5S8, error, gtpc_tx_id);
if (!error) {
itti_s5s8_modify_bearer_response *itti_msg = new itti_s5s8_modify_bearer_response(TASK_SGWC_S5S8, TASK_SGWC_APP);
itti_msg->gtp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->gtpc_tx_id = gtpc_tx_id;
itti_msg->teid = msg.get_teid();
std::shared_ptr<itti_s5s8_modify_bearer_response> i = std::shared_ptr<itti_s5s8_modify_bearer_response>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::sgwc_s5s8().error( "Could not send ITTI message %s to task TASK_SGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void sgw_s5s8::handle_receive_release_access_bearers_response(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_release_access_bearers_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S5S8, error, gtpc_tx_id);
if (!error) {
itti_s5s8_release_access_bearers_response *itti_msg = new itti_s5s8_release_access_bearers_response(TASK_SGWC_S5S8, TASK_SGWC_APP);
itti_msg->gtp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->gtpc_tx_id = gtpc_tx_id;
itti_msg->teid = msg.get_teid();
std::shared_ptr<itti_s5s8_release_access_bearers_response> i = std::shared_ptr<itti_s5s8_release_access_bearers_response>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::sgwc_s5s8().error( "Could not send ITTI message %s to task TASK_SGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void sgw_s5s8::handle_receive_delete_session_response(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t gtpc_tx_id = 0;
gtpv2c_delete_session_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SGWC_S5S8, error, gtpc_tx_id);
if (!error) {
itti_s5s8_delete_session_response *itti_msg = new itti_s5s8_delete_session_response(TASK_SGWC_S5S8, TASK_SGWC_APP);
itti_msg->gtp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->gtpc_tx_id = gtpc_tx_id;
itti_msg->teid = msg.get_teid();
std::shared_ptr<itti_s5s8_delete_session_response> i = std::shared_ptr<itti_s5s8_delete_session_response>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::sgwc_s5s8().error( "Could not send ITTI message %s to task TASK_SGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void sgw_s5s8::handle_receive_gtpv2c_msg(gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
//Logger::sgwc_s5s8().trace( "handle_receive_gtpv2c_msg msg type %d length %d", msg.get_message_type(), msg.get_message_length());
switch (msg.get_message_type()) {
case GTP_CREATE_SESSION_REQUEST: {
}
break;
case GTP_ECHO_REQUEST:
case GTP_ECHO_RESPONSE:
case GTP_VERSION_NOT_SUPPORTED_INDICATION:
case GTP_CREATE_SESSION_RESPONSE:
handle_receive_create_session_response(msg, remote_endpoint);
break;
case GTP_MODIFY_BEARER_REQUEST: {
}
break;
case GTP_MODIFY_BEARER_RESPONSE:
handle_receive_modify_bearer_response(msg, remote_endpoint);
break;
case GTP_DELETE_SESSION_REQUEST: {
//handle_receive_delete_session_request(msg, remote_endpoint);
}
break;
case GTP_DELETE_SESSION_RESPONSE: {
handle_receive_delete_session_response(msg, remote_endpoint);
}
break;
case GTP_RELEASE_ACCESS_BEARERS_RESPONSE: {
handle_receive_release_access_bearers_response(msg, remote_endpoint);
}
break;
case GTP_CHANGE_NOTIFICATION_REQUEST:
case GTP_CHANGE_NOTIFICATION_RESPONSE:
case GTP_REMOTE_UE_REPORT_NOTIFICATION:
case GTP_REMOTE_UE_REPORT_ACKNOWLEDGE:
case GTP_MODIFY_BEARER_COMMAND:
case GTP_MODIFY_BEARER_FAILURE_INDICATION:
case GTP_DELETE_BEARER_COMMAND:
case GTP_DELETE_BEARER_FAILURE_INDICATION:
case GTP_BEARER_RESOURCE_COMMAND:
case GTP_BEARER_RESOURCE_FAILURE_INDICATION:
case GTP_DOWNLINK_DATA_NOTIFICATION_FAILURE_INDICATION:
case GTP_TRACE_SESSION_ACTIVATION:
case GTP_TRACE_SESSION_DEACTIVATION:
case GTP_STOP_PAGING_INDICATION:
case GTP_CREATE_BEARER_REQUEST:
case GTP_CREATE_BEARER_RESPONSE:
case GTP_UPDATE_BEARER_REQUEST:
case GTP_UPDATE_BEARER_RESPONSE:
case GTP_DELETE_BEARER_REQUEST:
case GTP_DELETE_BEARER_RESPONSE:
case GTP_DELETE_PDN_CONNECTION_SET_REQUEST:
case GTP_DELETE_PDN_CONNECTION_SET_RESPONSE:
case GTP_PGW_DOWNLINK_TRIGGERING_NOTIFICATION:
case GTP_PGW_DOWNLINK_TRIGGERING_ACKNOWLEDGE:
case GTP_IDENTIFICATION_REQUEST:
case GTP_IDENTIFICATION_RESPONSE:
case GTP_CONTEXT_REQUEST:
case GTP_CONTEXT_RESPONSE:
case GTP_CONTEXT_ACKNOWLEDGE:
case GTP_FORWARD_RELOCATION_REQUEST:
case GTP_FORWARD_RELOCATION_RESPONSE:
case GTP_FORWARD_RELOCATION_COMPLETE_NOTIFICATION:
case GTP_FORWARD_RELOCATION_COMPLETE_ACKNOWLEDGE:
case GTP_FORWARD_ACCESS_CONTEXT_NOTIFICATION:
case GTP_FORWARD_ACCESS_CONTEXT_ACKNOWLEDGE:
case GTP_RELOCATION_CANCEL_REQUEST:
case GTP_RELOCATION_CANCEL_RESPONSE:
case GTP_CONFIGURATION_TRANSFER_TUNNEL_MESSAGE:
case GTP_DETACH_NOTIFICATION:
case GTP_DETACH_ACKNOWLEDGE:
case GTP_CS_PAGING_INDICATION:
case GTP_RAN_INFORMATION_RELAY:
case GTP_ALERT_MME_NOTIFICATION:
case GTP_ALERT_MME_ACKNOWLEDGE:
case GTP_UE_ACTIVITY_NOTIFICATION:
case GTP_UE_ACTIVITY_ACKNOWLEDGE:
case GTP_ISR_STATUS_INDICATION:
case GTP_UE_REGISTRATION_QUERY_REQUEST:
case GTP_UE_REGISTRATION_QUERY_RESPONSE:
case GTP_CREATE_FORWARDING_TUNNEL_REQUEST:
case GTP_CREATE_FORWARDING_TUNNEL_RESPONSE:
case GTP_SUSPEND_NOTIFICATION:
case GTP_SUSPEND_ACKNOWLEDGE:
case GTP_RESUME_NOTIFICATION:
case GTP_RESUME_ACKNOWLEDGE:
case GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST:
case GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE:
case GTP_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST:
case GTP_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE:
case GTP_RELEASE_ACCESS_BEARERS_REQUEST:
case GTP_DOWNLINK_DATA_NOTIFICATION:
case GTP_DOWNLINK_DATA_NOTIFICATION_ACKNOWLEDGE:
case GTP_PGW_RESTART_NOTIFICATION:
case GTP_PGW_RESTART_NOTIFICATION_ACKNOWLEDGE:
case GTP_UPDATE_PDN_CONNECTION_SET_REQUEST:
case GTP_UPDATE_PDN_CONNECTION_SET_RESPONSE:
case GTP_MODIFY_ACCESS_BEARERS_REQUEST:
case GTP_MODIFY_ACCESS_BEARERS_RESPONSE:
case GTP_MBMS_SESSION_START_REQUEST:
case GTP_MBMS_SESSION_START_RESPONSE:
case GTP_MBMS_SESSION_UPDATE_REQUEST:
case GTP_MBMS_SESSION_UPDATE_RESPONSE:
case GTP_MBMS_SESSION_STOP_RESPONSE:
break;
default:
Logger::sgwc_s5s8().error( "handle_receive_gtpv2c_msg msg length %d", msg.get_message_length());
}
}
//------------------------------------------------------------------------------
void sgw_s5s8::handle_receive(char* recv_buffer, const std::size_t bytes_transferred, boost::asio::ip::udp::endpoint& remote_endpoint)
{
//Logger::sgwc_s5s8().info( "handle_receive(%d bytes)", bytes_transferred);
//std::cout << string_to_hex(recv_buffer, bytes_transferred) << std::endl;
std::istringstream iss(std::istringstream::binary);
iss.rdbuf()->pubsetbuf(recv_buffer,bytes_transferred);
gtpv2c_msg msg = {};
msg.remote_port = remote_endpoint.port();
try {
msg.load_from(iss);
handle_receive_gtpv2c_msg(msg, remote_endpoint);
} catch (gtpc_exception& e) {
Logger::sgwc_s5s8().info( "handle_receive exception %s", e.what());
}
}
//------------------------------------------------------------------------------
void sgw_s5s8::time_out_itti_event(const uint32_t timer_id)
{
bool handled = false;
time_out_event(timer_id, TASK_SGWC_S5S8, handled);
if (!handled) {
Logger::sgwc_s5s8().warn( "Timer %d not Found", timer_id);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file sgwc_s5s8.hpp
\author Lionel GAUTHIER
\date 2018
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SGWC_S5S8_HPP_SEEN
#define FILE_SGWC_S5S8_HPP_SEEN
#include "gtpv2c.hpp"
#include "itti_msg_s5s8.hpp"
#include <thread>
namespace oai::cn::nf::sgwc {
class sgw_s5s8 : public proto::gtpv2c::gtpv2c_stack {
private:
std::thread::id thread_id;
std::thread thread;
void handle_receive_gtpv2c_msg(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_create_session_response(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint );
void handle_receive_delete_session_response(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_modify_bearer_response(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_release_access_bearers_response(proto::gtpv2c::gtpv2c_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
public:
sgw_s5s8();
sgw_s5s8(sgw_s5s8 const&) = delete;
void operator=(sgw_s5s8 const&) = delete;
void handle_receive(char* recv_buffer, const std::size_t bytes_transferred, boost::asio::ip::udp::endpoint& remote_endpoint);
void send_msg(core::itti::itti_s5s8_create_session_request& m);
void send_msg(core::itti::itti_s5s8_delete_session_request& m);
void send_msg(core::itti::itti_s5s8_modify_bearer_request& m);
void send_msg(core::itti::itti_s5s8_release_access_bearers_request& m);
void time_out_itti_event(const uint32_t timer_id);
};
}
#endif /* FILE_SGWC_S5S8_HPP_SEEN */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment