mirror of https://github.com/pvnis/srsRAN_4G.git
Initial commit for ngap in enb
parent
3284143b39
commit
c117b563c9
@ -0,0 +1,31 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_NGAP_UTILS_H
|
||||
#define SRSRAN_NGAP_UTILS_H
|
||||
|
||||
#include "asn1_utils.h"
|
||||
#include "ngap.h"
|
||||
/************************
|
||||
* Forward declarations
|
||||
***********************/
|
||||
|
||||
namespace asn1 {
|
||||
namespace ngap_nr {
|
||||
struct rrcestablishment_cause_opts;
|
||||
struct cause_radio_network_opts;
|
||||
using rrcestablishment_cause_e = enumerated<rrcestablishment_cause_opts, true, 1>;
|
||||
using cause_radio_network_e = enumerated<cause_radio_network_opts, true, 2>;
|
||||
} // namespace ngap
|
||||
} // namespace asn1
|
||||
|
||||
#endif // SRSRAN_NGAP_UTILS_H
|
@ -0,0 +1,60 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_GNB_NGAP_INTERFACES_H
|
||||
#define SRSRAN_GNB_NGAP_INTERFACES_H
|
||||
|
||||
#include "srsran/asn1/ngap_utils.h"
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
struct ngap_args_t {
|
||||
uint32_t gnb_id; // 20-bit id (lsb bits)
|
||||
uint8_t cell_id; // 8-bit cell id
|
||||
uint16_t tac; // 16-bit tac
|
||||
uint16_t mcc; // BCD-coded with 0xF filler
|
||||
uint16_t mnc; // BCD-coded with 0xF filler
|
||||
std::string amf_addr;
|
||||
std::string gtp_bind_addr;
|
||||
std::string gtp_advertise_addr;
|
||||
std::string ngc_bind_addr;
|
||||
std::string gnb_name;
|
||||
};
|
||||
|
||||
// NGAP interface for RRC
|
||||
class ngap_interface_rrc_nr
|
||||
{
|
||||
public:
|
||||
virtual void initial_ue(uint16_t rnti,
|
||||
uint32_t gnb_cc_idx,
|
||||
asn1::ngap_nr::rrcestablishment_cause_e cause,
|
||||
srsran::unique_byte_buffer_t pdu) = 0;
|
||||
virtual void initial_ue(uint16_t rnti,
|
||||
uint32_t gnb_cc_idx,
|
||||
asn1::ngap_nr::rrcestablishment_cause_e cause,
|
||||
srsran::unique_byte_buffer_t pdu,
|
||||
uint32_t m_tmsi,
|
||||
uint8_t mmec) = 0;
|
||||
|
||||
virtual void write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu) = 0;
|
||||
virtual bool user_exists(uint16_t rnti) = 0;
|
||||
virtual void user_mod(uint16_t old_rnti, uint16_t new_rnti) = 0;
|
||||
virtual bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) = 0;
|
||||
virtual bool is_amf_connected() = 0;
|
||||
|
||||
/// TS 36.413, 8.3.1 - Initial Context Setup
|
||||
virtual void ue_ctxt_setup_complete(uint16_t rnti) = 0;
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSRAN_GNB_NGAP_INTERFACES_H
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
#ifndef SRSRAN_GNB_RRC_NR_INTERFACES_H
|
||||
#define SRSRAN_GNB_RRC_NR_INTERFACES_H
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
class rrc_interface_ngap_nr
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSRAN_GNB_RRC_NR_INTERFACES_H
|
@ -0,0 +1,134 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
#ifndef SRSENB_NGAP_H
|
||||
#define SRSENB_NGAP_H
|
||||
|
||||
#include "srsenb/hdr/common/common_enb.h"
|
||||
#include "srsran/adt/circular_map.h"
|
||||
#include "srsran/asn1/asn1_utils.h"
|
||||
#include "srsran/asn1/ngap.h"
|
||||
#include "srsran/common/bcd_helpers.h"
|
||||
#include "srsran/common/buffer_pool.h"
|
||||
#include "srsran/common/common.h"
|
||||
#include "srsran/common/network_utils.h"
|
||||
#include "srsran/common/stack_procedure.h"
|
||||
#include "srsran/common/standard_streams.h"
|
||||
#include "srsran/common/task_scheduler.h"
|
||||
#include "srsran/common/threads.h"
|
||||
#include "srsran/interfaces/gnb_ngap_interfaces.h"
|
||||
#include "srsran/interfaces/gnb_rrc_nr_interfaces.h"
|
||||
#include "srsran/srslog/srslog.h"
|
||||
|
||||
namespace srsenb {
|
||||
class ngap : public ngap_interface_rrc_nr
|
||||
{
|
||||
public:
|
||||
ngap(srsran::task_sched_handle task_sched_,
|
||||
srslog::basic_logger& logger,
|
||||
srsran::socket_manager_itf* rx_socket_handler);
|
||||
int init(ngap_args_t args_, rrc_interface_ngap_nr* rrc_);
|
||||
void stop();
|
||||
|
||||
// RRC NR interface
|
||||
void initial_ue(uint16_t rnti,
|
||||
uint32_t gnb_cc_idx,
|
||||
asn1::ngap_nr::rrcestablishment_cause_e cause,
|
||||
srsran::unique_byte_buffer_t pdu){};
|
||||
void initial_ue(uint16_t rnti,
|
||||
uint32_t gnb_cc_idx,
|
||||
asn1::ngap_nr::rrcestablishment_cause_e cause,
|
||||
srsran::unique_byte_buffer_t pdu,
|
||||
uint32_t m_tmsi,
|
||||
uint8_t mmec){};
|
||||
void write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu){};
|
||||
bool user_exists(uint16_t rnti) { return true; };
|
||||
void user_mod(uint16_t old_rnti, uint16_t new_rnti){};
|
||||
bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) { return true; };
|
||||
bool is_amf_connected();
|
||||
|
||||
/// TS 36.413, 8.3.1 - Initial Context Setup
|
||||
void ue_ctxt_setup_complete(uint16_t rnti){};
|
||||
|
||||
// Stack interface
|
||||
bool
|
||||
handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags);
|
||||
|
||||
private:
|
||||
static const int AMF_PORT = 38412;
|
||||
static const int ADDR_FAMILY = AF_INET;
|
||||
static const int SOCK_TYPE = SOCK_STREAM;
|
||||
static const int PROTO = IPPROTO_SCTP;
|
||||
static const int PPID = 60;
|
||||
static const int NONUE_STREAM_ID = 0;
|
||||
|
||||
// args
|
||||
rrc_interface_ngap_nr* rrc = nullptr;
|
||||
ngap_args_t args;
|
||||
srslog::basic_logger& logger;
|
||||
srsran::task_sched_handle task_sched;
|
||||
srsran::task_queue_handle amf_task_queue;
|
||||
srsran::socket_manager_itf* rx_socket_handler;
|
||||
|
||||
srsran::unique_socket amf_socket;
|
||||
struct sockaddr_in amf_addr = {}; // AMF address
|
||||
bool amf_connected = false;
|
||||
bool running = false;
|
||||
uint32_t next_enb_ue_ngap_id = 1; // Next ENB-side UE identifier
|
||||
uint16_t next_ue_stream_id = 1; // Next UE SCTP stream identifier
|
||||
srsran::unique_timer amf_connect_timer, ngsetup_timeout;
|
||||
|
||||
// Protocol IEs sent with every UL NGAP message
|
||||
asn1::ngap_nr::tai_s tai;
|
||||
asn1::ngap_nr::nr_cgi_s nr_cgi;
|
||||
|
||||
asn1::ngap_nr::ng_setup_resp_s ngsetupresponse;
|
||||
|
||||
// procedures
|
||||
class ng_setup_proc_t
|
||||
{
|
||||
public:
|
||||
struct ngsetupresult {
|
||||
bool success = false;
|
||||
enum class cause_t { timeout, failure } cause;
|
||||
};
|
||||
|
||||
explicit ng_setup_proc_t(ngap* ngap_) : ngap_ptr(ngap_) {}
|
||||
srsran::proc_outcome_t init();
|
||||
srsran::proc_outcome_t step() { return srsran::proc_outcome_t::yield; }
|
||||
srsran::proc_outcome_t react(const ngsetupresult& event);
|
||||
void then(const srsran::proc_state_t& result) const;
|
||||
const char* name() const { return "AMF Connection"; }
|
||||
|
||||
private:
|
||||
srsran::proc_outcome_t start_amf_connection();
|
||||
|
||||
ngap* ngap_ptr = nullptr;
|
||||
};
|
||||
|
||||
void build_tai_cgi();
|
||||
bool connect_amf();
|
||||
bool setup_ng();
|
||||
bool sctp_send_ngap_pdu(const asn1::ngap_nr::ngap_pdu_c& tx_pdu, uint32_t rnti, const char* procedure_name);
|
||||
|
||||
bool handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu);
|
||||
bool handle_successfuloutcome(const asn1::ngap_nr::successful_outcome_s& msg);
|
||||
|
||||
bool handle_ngsetupresponse(const asn1::ngap_nr::ng_setup_resp_s& msg);
|
||||
|
||||
srsran::proc_t<ng_setup_proc_t> ngsetup_proc;
|
||||
|
||||
std::string get_cause(const asn1::ngap_nr::cause_c& c);
|
||||
void log_ngap_msg(const asn1::ngap_nr::ngap_pdu_c& msg, srsran::const_span<uint8_t> sdu, bool is_rx);
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
#endif
|
@ -0,0 +1,405 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsenb/hdr/stack/upper/ngap.h"
|
||||
|
||||
#define procError(fmt, ...) ngap_ptr->logger.error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
|
||||
#define procWarning(fmt, ...) ngap_ptr->logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
|
||||
#define procInfo(fmt, ...) ngap_ptr->logger.info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
|
||||
|
||||
using namespace asn1::ngap_nr;
|
||||
|
||||
namespace srsenb {
|
||||
/*********************************************************
|
||||
* AMF Connection
|
||||
*********************************************************/
|
||||
|
||||
srsran::proc_outcome_t ngap::ng_setup_proc_t::init()
|
||||
{
|
||||
procInfo("Starting new AMF connection.");
|
||||
return start_amf_connection();
|
||||
}
|
||||
|
||||
srsran::proc_outcome_t ngap::ng_setup_proc_t::start_amf_connection()
|
||||
{
|
||||
if (not ngap_ptr->running) {
|
||||
procInfo("NGAP is not running anymore.");
|
||||
return srsran::proc_outcome_t::error;
|
||||
}
|
||||
if (ngap_ptr->amf_connected) {
|
||||
procInfo("gNB NGAP is already connected to AMF");
|
||||
return srsran::proc_outcome_t::success;
|
||||
}
|
||||
|
||||
if (not ngap_ptr->connect_amf()) {
|
||||
procInfo("Could not connect to AMF");
|
||||
return srsran::proc_outcome_t::error;
|
||||
}
|
||||
|
||||
if (not ngap_ptr->setup_ng()) {
|
||||
procError("NG setup failed. Exiting...");
|
||||
srsran::console("NG setup failed\n");
|
||||
ngap_ptr->running = false;
|
||||
return srsran::proc_outcome_t::error;
|
||||
}
|
||||
|
||||
ngap_ptr->ngsetup_timeout.run();
|
||||
procInfo("NGSetupRequest sent. Waiting for response...");
|
||||
return srsran::proc_outcome_t::yield;
|
||||
}
|
||||
|
||||
srsran::proc_outcome_t ngap::ng_setup_proc_t::react(const srsenb::ngap::ng_setup_proc_t::ngsetupresult& event)
|
||||
{
|
||||
if (ngap_ptr->ngsetup_timeout.is_running()) {
|
||||
ngap_ptr->ngsetup_timeout.stop();
|
||||
}
|
||||
if (event.success) {
|
||||
procInfo("NGSetup procedure completed successfully");
|
||||
return srsran::proc_outcome_t::success;
|
||||
}
|
||||
procError("NGSetup failed.");
|
||||
srsran::console("NGsetup failed\n");
|
||||
return srsran::proc_outcome_t::error;
|
||||
}
|
||||
|
||||
void ngap::ng_setup_proc_t::then(const srsran::proc_state_t& result) const
|
||||
{
|
||||
if (result.is_error()) {
|
||||
procInfo("Failed to initiate NG connection. Attempting reconnection in %d seconds",
|
||||
ngap_ptr->amf_connect_timer.duration() / 1000);
|
||||
srsran::console("Failed to initiate NG connection. Attempting reconnection in %d seconds\n",
|
||||
ngap_ptr->amf_connect_timer.duration() / 1000);
|
||||
ngap_ptr->rx_socket_handler->remove_socket(ngap_ptr->amf_socket.get_socket());
|
||||
ngap_ptr->amf_socket.close();
|
||||
procInfo("NGAP socket closed.");
|
||||
ngap_ptr->amf_connect_timer.run();
|
||||
// Try again with in 10 seconds
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* NGAP class
|
||||
*********************************************************/
|
||||
|
||||
ngap::ngap(srsran::task_sched_handle task_sched_,
|
||||
srslog::basic_logger& logger,
|
||||
srsran::socket_manager_itf* rx_socket_handler_) :
|
||||
ngsetup_proc(this), logger(logger), task_sched(task_sched_), rx_socket_handler(rx_socket_handler_)
|
||||
{
|
||||
amf_task_queue = task_sched.make_task_queue();
|
||||
}
|
||||
|
||||
int ngap::init(ngap_args_t args_, rrc_interface_ngap_nr* rrc_)
|
||||
{
|
||||
rrc = rrc_;
|
||||
args = args_;
|
||||
|
||||
build_tai_cgi();
|
||||
|
||||
// Setup AMF reconnection timer
|
||||
amf_connect_timer = task_sched.get_unique_timer();
|
||||
auto amf_connect_run = [this](uint32_t tid) {
|
||||
if (ngsetup_proc.is_busy()) {
|
||||
logger.error("Failed to initiate NGSetup procedure.");
|
||||
}
|
||||
ngsetup_proc.launch();
|
||||
};
|
||||
amf_connect_timer.set(10000, amf_connect_run);
|
||||
// Setup NGSetup timeout
|
||||
ngsetup_timeout = task_sched.get_unique_timer();
|
||||
uint32_t ngsetup_timeout_val = 5000;
|
||||
ngsetup_timeout.set(ngsetup_timeout_val, [this](uint32_t tid) {
|
||||
ng_setup_proc_t::ngsetupresult res;
|
||||
res.success = false;
|
||||
res.cause = ng_setup_proc_t::ngsetupresult::cause_t::timeout;
|
||||
ngsetup_proc.trigger(res);
|
||||
});
|
||||
|
||||
running = true;
|
||||
// starting AMF connection
|
||||
if (not ngsetup_proc.launch()) {
|
||||
logger.error("Failed to initiate NGSetup procedure.");
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
void ngap::stop()
|
||||
{
|
||||
running = false;
|
||||
amf_socket.close();
|
||||
}
|
||||
|
||||
bool ngap::is_amf_connected()
|
||||
{
|
||||
return amf_connected;
|
||||
}
|
||||
|
||||
// Generate common NGAP protocol IEs from config args
|
||||
void ngap::build_tai_cgi()
|
||||
{
|
||||
uint32_t plmn;
|
||||
|
||||
// TAI
|
||||
srsran::s1ap_mccmnc_to_plmn(args.mcc, args.mnc, &plmn);
|
||||
tai.plmn_id.from_number(plmn);
|
||||
|
||||
tai.tac.from_number(args.tac);
|
||||
|
||||
// nr_cgi
|
||||
nr_cgi.plmn_id.from_number(plmn);
|
||||
// TODO Check how to build nr cell id
|
||||
nr_cgi.nrcell_id.from_number((uint32_t)(args.gnb_id << 8) | args.cell_id);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
/* NGAP message handlers
|
||||
********************************************************************************/
|
||||
bool ngap::handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu,
|
||||
const sockaddr_in& from,
|
||||
const sctp_sndrcvinfo& sri,
|
||||
int flags)
|
||||
{
|
||||
// Handle Notification Case
|
||||
if (flags & MSG_NOTIFICATION) {
|
||||
// Received notification
|
||||
union sctp_notification* notification = (union sctp_notification*)pdu->msg;
|
||||
logger.debug("SCTP Notification %d", notification->sn_header.sn_type);
|
||||
if (notification->sn_header.sn_type == SCTP_SHUTDOWN_EVENT) {
|
||||
logger.info("SCTP Association Shutdown. Association: %d", sri.sinfo_assoc_id);
|
||||
srsran::console("SCTP Association Shutdown. Association: %d\n", sri.sinfo_assoc_id);
|
||||
rx_socket_handler->remove_socket(amf_socket.get_socket());
|
||||
amf_socket.close();
|
||||
} else if (notification->sn_header.sn_type == SCTP_PEER_ADDR_CHANGE &&
|
||||
notification->sn_paddr_change.spc_state == SCTP_ADDR_UNREACHABLE) {
|
||||
logger.info("SCTP peer addres unreachable. Association: %d", sri.sinfo_assoc_id);
|
||||
srsran::console("SCTP peer address unreachable. Association: %d\n", sri.sinfo_assoc_id);
|
||||
rx_socket_handler->remove_socket(amf_socket.get_socket());
|
||||
amf_socket.close();
|
||||
}
|
||||
} else if (pdu->N_bytes == 0) {
|
||||
logger.error("SCTP return 0 bytes. Closing socket");
|
||||
amf_socket.close();
|
||||
}
|
||||
|
||||
// Restart MME connection procedure if we lost connection
|
||||
if (not amf_socket.is_open()) {
|
||||
amf_connected = false;
|
||||
if (ngsetup_proc.is_busy()) {
|
||||
logger.error("Failed to initiate MME connection procedure, as it is already running.");
|
||||
return false;
|
||||
}
|
||||
ngsetup_proc.launch();
|
||||
return false;
|
||||
}
|
||||
|
||||
handle_ngap_rx_pdu(pdu.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ngap::handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu)
|
||||
{
|
||||
// Save message to PCAP
|
||||
// if (pcap != nullptr) {
|
||||
// pcap->write_ngap(pdu->msg, pdu->N_bytes);
|
||||
// }
|
||||
|
||||
ngap_pdu_c rx_pdu;
|
||||
asn1::cbit_ref bref(pdu->msg, pdu->N_bytes);
|
||||
|
||||
if (rx_pdu.unpack(bref) != asn1::SRSASN_SUCCESS) {
|
||||
logger.error(pdu->msg, pdu->N_bytes, "Failed to unpack received PDU");
|
||||
cause_c cause;
|
||||
cause.set_protocol().value = cause_protocol_opts::transfer_syntax_error;
|
||||
// send_error_indication(cause);
|
||||
return false;
|
||||
}
|
||||
// log_ngap_msg(rx_pdu, srsran::make_span(*pdu), true);
|
||||
|
||||
switch (rx_pdu.type().value) {
|
||||
// case ngap_pdu_c::types_opts::init_msg:
|
||||
// return handle_initiatingmessage(rx_pdu.init_msg());
|
||||
case ngap_pdu_c::types_opts::successful_outcome:
|
||||
return handle_successfuloutcome(rx_pdu.successful_outcome());
|
||||
// case ngap_pdu_c::types_opts::unsuccessful_outcome:
|
||||
// return handle_unsuccessfuloutcome(rx_pdu.unsuccessful_outcome());
|
||||
default:
|
||||
logger.error("Unhandled PDU type %d", rx_pdu.type().value);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ngap::handle_successfuloutcome(const successful_outcome_s& msg)
|
||||
{
|
||||
switch (msg.value.type().value) {
|
||||
case ngap_elem_procs_o::successful_outcome_c::types_opts::ng_setup_resp:
|
||||
return handle_ngsetupresponse(msg.value.ng_setup_resp());
|
||||
default:
|
||||
logger.error("Unhandled successful outcome message: %s", msg.value.type().to_string());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ngap::handle_ngsetupresponse(const asn1::ngap_nr::ng_setup_resp_s& msg)
|
||||
{
|
||||
ngsetupresponse = msg;
|
||||
amf_connected = true;
|
||||
ng_setup_proc_t::ngsetupresult res;
|
||||
res.success = true;
|
||||
ngsetup_proc.trigger(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
/* NGAP connection helpers
|
||||
********************************************************************************/
|
||||
|
||||
bool ngap::connect_amf()
|
||||
{
|
||||
using namespace srsran::net_utils;
|
||||
logger.info("Connecting to AMF %s:%d", args.amf_addr.c_str(), int(AMF_PORT));
|
||||
|
||||
// Init SCTP socket and bind it
|
||||
if (not sctp_init_client(&amf_socket, socket_type::seqpacket, args.ngc_bind_addr.c_str())) {
|
||||
return false;
|
||||
}
|
||||
logger.info("SCTP socket opened. fd=%d", amf_socket.fd());
|
||||
|
||||
// Connect to the AMF address
|
||||
if (not amf_socket.connect_to(args.amf_addr.c_str(), AMF_PORT, &amf_addr)) {
|
||||
return false;
|
||||
}
|
||||
logger.info("SCTP socket connected with AMF. fd=%d", amf_socket.fd());
|
||||
|
||||
// Assign a handler to rx AMF packets
|
||||
auto rx_callback =
|
||||
[this](srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags) {
|
||||
// Defer the handling of AMF packet to eNB stack main thread
|
||||
handle_amf_rx_msg(std::move(pdu), from, sri, flags);
|
||||
};
|
||||
rx_socket_handler->add_socket_handler(amf_socket.fd(),
|
||||
srsran::make_sctp_sdu_handler(logger, amf_task_queue, rx_callback));
|
||||
|
||||
logger.info("SCTP socket established with AMF");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ngap::setup_ng()
|
||||
{
|
||||
uint32_t tmp32;
|
||||
uint16_t tmp16;
|
||||
|
||||
uint32_t plmn;
|
||||
srsran::s1ap_mccmnc_to_plmn(args.mcc, args.mnc, &plmn);
|
||||
plmn = htonl(plmn);
|
||||
|
||||
ngap_pdu_c pdu;
|
||||
pdu.set_init_msg().load_info_obj(ASN1_NGAP_NR_ID_NG_SETUP);
|
||||
ng_setup_request_ies_container& container = pdu.init_msg().value.ng_setup_request().protocol_ies;
|
||||
global_gnb_id_s& global_gnb_id = container.global_ran_node_id.value.set_global_gnb_id();
|
||||
global_gnb_id.plmn_id = tai.plmn_id;
|
||||
// TODO: when ASN1 is fixed
|
||||
// global_gnb_id.gnb_id.set_gnb_id().from_number(args.gnb_id);
|
||||
|
||||
// container.ran_node_name_present = true;
|
||||
// container.ran_node_name.value.from_string(args.gnb_name);
|
||||
|
||||
asn1::bounded_bitstring<22, 32, false, true>& gnb_str = global_gnb_id.gnb_id.set_gnb_id();
|
||||
gnb_str.resize(32);
|
||||
uint8_t buffer[4];
|
||||
asn1::bit_ref bref(&buffer[0], sizeof(buffer));
|
||||
bref.pack(args.gnb_id, 8);
|
||||
memcpy(gnb_str.data(), &buffer[0], bref.distance_bytes());
|
||||
|
||||
// .from_number(args.gnb_id);
|
||||
|
||||
container.ran_node_name_present = true;
|
||||
if (args.gnb_name.length() >= 150) {
|
||||
args.gnb_name.resize(150);
|
||||
}
|
||||
// container.ran_node_name.value.from_string(args.enb_name);
|
||||
container.ran_node_name.value.resize(args.gnb_name.size());
|
||||
memcpy(&container.ran_node_name.value[0], &args.gnb_name[0], args.gnb_name.size());
|
||||
|
||||
container.supported_ta_list.value.resize(1);
|
||||
container.supported_ta_list.value[0].tac = tai.tac;
|
||||
container.supported_ta_list.value[0].broadcast_plmn_list.resize(1);
|
||||
container.supported_ta_list.value[0].broadcast_plmn_list[0].plmn_id = tai.plmn_id;
|
||||
container.supported_ta_list.value[0].broadcast_plmn_list[0].tai_slice_support_list.resize(1);
|
||||
container.supported_ta_list.value[0].broadcast_plmn_list[0].tai_slice_support_list[0].s_nssai.sst.from_number(1);
|
||||
|
||||
container.default_paging_drx.value.value = asn1::ngap_nr::paging_drx_opts::v256; // Todo: add to args, config file
|
||||
|
||||
return sctp_send_ngap_pdu(pdu, 0, "ngSetupRequest");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
/* General helpers
|
||||
********************************************************************************/
|
||||
|
||||
bool ngap::sctp_send_ngap_pdu(const asn1::ngap_nr::ngap_pdu_c& tx_pdu, uint32_t rnti, const char* procedure_name)
|
||||
{
|
||||
if (not amf_connected and rnti != SRSRAN_INVALID_RNTI) {
|
||||
logger.error("Aborting %s for rnti=0x%x. Cause: AMF is not connected.", procedure_name, rnti);
|
||||
return false;
|
||||
}
|
||||
|
||||
srsran::unique_byte_buffer_t buf = srsran::make_byte_buffer();
|
||||
if (buf == nullptr) {
|
||||
logger.error("Fatal Error: Couldn't allocate buffer for %s.", procedure_name);
|
||||
return false;
|
||||
}
|
||||
asn1::bit_ref bref(buf->msg, buf->get_tailroom());
|
||||
if (tx_pdu.pack(bref) != asn1::SRSASN_SUCCESS) {
|
||||
logger.error("Failed to pack TX PDU %s", procedure_name);
|
||||
return false;
|
||||
}
|
||||
buf->N_bytes = bref.distance_bytes();
|
||||
|
||||
// TODO: when we got pcap support
|
||||
// Save message to PCAP
|
||||
// if (pcap != nullptr) {
|
||||
// pcap->write_s1ap(buf->msg, buf->N_bytes);
|
||||
// }
|
||||
|
||||
if (rnti != SRSRAN_INVALID_RNTI) {
|
||||
logger.info(buf->msg, buf->N_bytes, "Tx S1AP SDU, %s, rnti=0x%x", procedure_name, rnti);
|
||||
} else {
|
||||
logger.info(buf->msg, buf->N_bytes, "Tx S1AP SDU, %s", procedure_name);
|
||||
}
|
||||
// TODO: when user list is ready
|
||||
// uint16_t streamid = rnti == SRSRAN_INVALID_RNTI ? NONUE_STREAM_ID : users.find_ue_rnti(rnti)->stream_id;
|
||||
uint16_t streamid = 0;
|
||||
ssize_t n_sent = sctp_sendmsg(amf_socket.fd(),
|
||||
buf->msg,
|
||||
buf->N_bytes,
|
||||
(struct sockaddr*)&amf_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
streamid,
|
||||
0,
|
||||
0);
|
||||
if (n_sent == -1) {
|
||||
if (rnti != SRSRAN_INVALID_RNTI) {
|
||||
logger.error("Error: Failure at Tx S1AP SDU, %s, rnti=0x%x", procedure_name, rnti);
|
||||
} else {
|
||||
logger.error("Error: Failure at Tx S1AP SDU, %s", procedure_name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace srsenb
|
Loading…
Reference in New Issue