|
|
|
@ -24,14 +24,14 @@
|
|
|
|
|
#include "srslte/common/bcd_helpers.h"
|
|
|
|
|
#include "srslte/common/int_helpers.h"
|
|
|
|
|
|
|
|
|
|
#include <arpa/inet.h> //for inet_ntop()
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <netinet/sctp.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h> //for close(), sleep()
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <netinet/sctp.h>
|
|
|
|
|
#include <arpa/inet.h> //for inet_ntop()
|
|
|
|
|
#include <unistd.h> //for close(), sleep()
|
|
|
|
|
|
|
|
|
|
using srslte::s1ap_mccmnc_to_plmn;
|
|
|
|
|
using srslte::uint32_to_uint8;
|
|
|
|
@ -82,52 +82,129 @@ void s1ap::ue::ho_prep_proc_t::then(const srslte::proc_state_t& result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************************************************
|
|
|
|
|
* S1AP class
|
|
|
|
|
* MME Connection
|
|
|
|
|
*********************************************************/
|
|
|
|
|
|
|
|
|
|
s1ap::s1ap() :
|
|
|
|
|
thread("S1AP"),
|
|
|
|
|
rrc(nullptr),
|
|
|
|
|
s1ap_log(nullptr),
|
|
|
|
|
pool(nullptr),
|
|
|
|
|
mme_connected(false),
|
|
|
|
|
running(false),
|
|
|
|
|
next_eNB_UE_S1AP_ID(1),
|
|
|
|
|
next_ue_stream_id(1)
|
|
|
|
|
srslte::proc_outcome_t s1ap::s1_setup_proc_t::init()
|
|
|
|
|
{
|
|
|
|
|
procInfo("Starting new MME connection.\n");
|
|
|
|
|
|
|
|
|
|
return start_mme_connection();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srslte::proc_outcome_t s1ap::s1_setup_proc_t::start_mme_connection()
|
|
|
|
|
{
|
|
|
|
|
if (not s1ap_ptr->running) {
|
|
|
|
|
procInfo("S1AP is not running anymore.\n");
|
|
|
|
|
return srslte::proc_outcome_t::error;
|
|
|
|
|
}
|
|
|
|
|
if (s1ap_ptr->mme_connected) {
|
|
|
|
|
procInfo("eNB S1AP is already connected to MME\n");
|
|
|
|
|
return srslte::proc_outcome_t::success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (not s1ap_ptr->connect_mme()) {
|
|
|
|
|
procError("Failed to initiate SCTP socket. Attempting reconnection in %d seconds\n",
|
|
|
|
|
s1ap_ptr->mme_connect_timer.duration() / 1000);
|
|
|
|
|
s1ap_ptr->s1ap_log->console("Failed to initiate SCTP socket. Attempting reconnection in %d seconds\n",
|
|
|
|
|
s1ap_ptr->mme_connect_timer.duration() / 1000);
|
|
|
|
|
s1ap_ptr->mme_connect_timer.run();
|
|
|
|
|
return srslte::proc_outcome_t::error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (not s1ap_ptr->setup_s1()) {
|
|
|
|
|
procError("S1 setup failed. Exiting...\n");
|
|
|
|
|
s1ap_ptr->s1ap_log->console("S1 setup failed\n");
|
|
|
|
|
s1ap_ptr->running = false;
|
|
|
|
|
return srslte::proc_outcome_t::error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::init(s1ap_args_t args_, rrc_interface_s1ap* rrc_, srslte::log* s1ap_log_, srslte::timer_handler* timers_)
|
|
|
|
|
s1ap_ptr->s1setup_timeout.run();
|
|
|
|
|
procInfo("S1SetupRequest sent. Waiting for response...\n");
|
|
|
|
|
return srslte::proc_outcome_t::yield;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srslte::proc_outcome_t s1ap::s1_setup_proc_t::react(const srsenb::s1ap::s1_setup_proc_t::s1setupresult& event)
|
|
|
|
|
{
|
|
|
|
|
if (s1ap_ptr->s1setup_timeout.is_running()) {
|
|
|
|
|
s1ap_ptr->s1setup_timeout.stop();
|
|
|
|
|
}
|
|
|
|
|
if (event.success) {
|
|
|
|
|
procInfo("S1Setup procedure completed successfully\n");
|
|
|
|
|
return srslte::proc_outcome_t::success;
|
|
|
|
|
}
|
|
|
|
|
procError("S1Setup failed. Exiting...\n");
|
|
|
|
|
s1ap_ptr->s1ap_log->console("S1setup failed\n");
|
|
|
|
|
return srslte::proc_outcome_t::error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void s1ap::s1_setup_proc_t::then(const srslte::proc_state_t& result) const
|
|
|
|
|
{
|
|
|
|
|
if (result.is_error()) {
|
|
|
|
|
// If a connection to the MME was created, it has to be erased again
|
|
|
|
|
// if (s1ap_ptr->s1ap_socket.is_init()) {
|
|
|
|
|
// s1ap_ptr->stack->remove_mme_socket(s1ap_ptr->s1ap_socket.fd());
|
|
|
|
|
// }
|
|
|
|
|
s1ap_ptr->s1ap_socket.reset();
|
|
|
|
|
procInfo("S1AP socket closed.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************************************************
|
|
|
|
|
* S1AP class
|
|
|
|
|
*********************************************************/
|
|
|
|
|
|
|
|
|
|
s1ap::s1ap() : s1setup_proc(this) {}
|
|
|
|
|
|
|
|
|
|
bool s1ap::init(s1ap_args_t args_,
|
|
|
|
|
rrc_interface_s1ap* rrc_,
|
|
|
|
|
srslte::log* s1ap_log_,
|
|
|
|
|
srslte::timer_handler* timers_,
|
|
|
|
|
srsenb::stack_interface_s1ap_lte* stack_)
|
|
|
|
|
{
|
|
|
|
|
rrc = rrc_;
|
|
|
|
|
args = args_;
|
|
|
|
|
s1ap_log = s1ap_log_;
|
|
|
|
|
timers = timers_;
|
|
|
|
|
|
|
|
|
|
stack = stack_;
|
|
|
|
|
pool = srslte::byte_buffer_pool::get_instance();
|
|
|
|
|
mme_connected = false;
|
|
|
|
|
running = false;
|
|
|
|
|
next_eNB_UE_S1AP_ID = 1;
|
|
|
|
|
next_ue_stream_id = 1;
|
|
|
|
|
|
|
|
|
|
build_tai_cgi();
|
|
|
|
|
|
|
|
|
|
start(S1AP_THREAD_PRIO);
|
|
|
|
|
// Setup MME reconnection timer
|
|
|
|
|
mme_connect_timer = timers->get_unique_timer();
|
|
|
|
|
auto mme_connect_run = [this](uint32_t tid) {
|
|
|
|
|
if (not s1setup_proc.launch()) {
|
|
|
|
|
s1ap_log->error("Failed to initiate S1Setup procedure.\n");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
mme_connect_timer.set(10000, mme_connect_run);
|
|
|
|
|
// Setup S1Setup timeout
|
|
|
|
|
s1setup_timeout = timers->get_unique_timer();
|
|
|
|
|
uint32_t s1setup_timeout_val = 1000;
|
|
|
|
|
s1setup_timeout.set(s1setup_timeout_val, [this](uint32_t tid) {
|
|
|
|
|
s1_setup_proc_t::s1setupresult res;
|
|
|
|
|
res.success = false;
|
|
|
|
|
res.cause = s1_setup_proc_t::s1setupresult::cause_t::timeout;
|
|
|
|
|
s1setup_proc.trigger(res);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
running = true;
|
|
|
|
|
// starting MME connection
|
|
|
|
|
if (not s1setup_proc.launch()) {
|
|
|
|
|
s1ap_log->error("Failed to initiate S1Setup procedure.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void s1ap::stop()
|
|
|
|
|
{
|
|
|
|
|
if(running) {
|
|
|
|
|
running = false;
|
|
|
|
|
thread_cancel();
|
|
|
|
|
wait_thread_finish();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(close(socket_fd) == -1) {
|
|
|
|
|
s1ap_log->error("Failed to close SCTP socket\n");
|
|
|
|
|
}
|
|
|
|
|
s1ap_socket.reset();
|
|
|
|
|
// if (s1ap_socket.is_init()) {
|
|
|
|
|
// stack->remove_mme_socket(s1ap_socket.fd());
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void s1ap::get_metrics(s1ap_metrics_t& m)
|
|
|
|
@ -143,58 +220,6 @@ void s1ap::get_metrics(s1ap_metrics_t &m)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void s1ap::run_thread()
|
|
|
|
|
{
|
|
|
|
|
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool, "s1ap::run_thread");
|
|
|
|
|
if (!pdu) {
|
|
|
|
|
s1ap_log->error("Fatal Error: Couldn't allocate buffer in s1ap::run_thread().\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t sz = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET;
|
|
|
|
|
running = true;
|
|
|
|
|
|
|
|
|
|
// Connect to MME
|
|
|
|
|
while(running && !connect_mme()) {
|
|
|
|
|
s1ap_log->error("Failed to connect to MME - retrying in 10 seconds\n");
|
|
|
|
|
s1ap_log->console("Failed to connect to MME - retrying in 10 seconds\n");
|
|
|
|
|
sleep(10);
|
|
|
|
|
}
|
|
|
|
|
if(!setup_s1()) {
|
|
|
|
|
s1ap_log->error("S1 setup failed\n");
|
|
|
|
|
s1ap_log->console("S1 setup failed\n");
|
|
|
|
|
running = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// S1AP rx loop
|
|
|
|
|
while(running) {
|
|
|
|
|
pdu->clear();
|
|
|
|
|
ssize_t n_recv = recv(socket_fd, pdu->msg, sz, 0);
|
|
|
|
|
if (n_recv <= 0) {
|
|
|
|
|
mme_connected = false;
|
|
|
|
|
do {
|
|
|
|
|
s1ap_log->error("Disconnected - attempting reconnection in 10 seconds\n");
|
|
|
|
|
s1ap_log->console("Disconnected - attempting reconnection in 10 seconds\n");
|
|
|
|
|
sleep(10);
|
|
|
|
|
} while(running && !connect_mme());
|
|
|
|
|
|
|
|
|
|
if(!setup_s1()) {
|
|
|
|
|
s1ap_log->error("S1 setup failed\n");
|
|
|
|
|
s1ap_log->console("S1 setup failed\n");
|
|
|
|
|
running = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pdu->N_bytes = static_cast<uint32_t>(n_recv);
|
|
|
|
|
|
|
|
|
|
s1ap_log->info_hex(pdu->msg, pdu->N_bytes, "Received S1AP PDU");
|
|
|
|
|
handle_s1ap_rx_pdu(pdu.get());
|
|
|
|
|
}
|
|
|
|
|
printf("%s ended\n", __PRETTY_FUNCTION__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate common S1AP protocol IEs from config args
|
|
|
|
|
void s1ap::build_tai_cgi()
|
|
|
|
|
{
|
|
|
|
@ -227,7 +252,9 @@ void s1ap::build_tai_cgi()
|
|
|
|
|
liblte_unpack((uint8_t*)&tmp32, 4, enb_id_bits);
|
|
|
|
|
uint8_t cell_id_bits[1 * 8];
|
|
|
|
|
liblte_unpack(&args.cell_id, 1, cell_id_bits);
|
|
|
|
|
memcpy(eutran_cgi.cell_ID.buffer, &enb_id_bits[32-LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
|
|
|
|
|
memcpy(eutran_cgi.cell_ID.buffer,
|
|
|
|
|
&enb_id_bits[32 - LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN],
|
|
|
|
|
LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
|
|
|
|
|
memcpy(&eutran_cgi.cell_ID.buffer[LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], cell_id_bits, 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -320,42 +347,21 @@ bool s1ap::is_mme_connected()
|
|
|
|
|
|
|
|
|
|
bool s1ap::connect_mme()
|
|
|
|
|
{
|
|
|
|
|
socket_fd = 0;
|
|
|
|
|
|
|
|
|
|
s1ap_log->info("Connecting to MME %s:%d\n", args.mme_addr.c_str(), MME_PORT);
|
|
|
|
|
|
|
|
|
|
if((socket_fd = socket(ADDR_FAMILY, SOCK_TYPE, PROTO)) == -1) {
|
|
|
|
|
s1ap_log->error("Failed to create S1AP socket\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Bind to the local address
|
|
|
|
|
struct sockaddr_in local_addr;
|
|
|
|
|
memset(&local_addr, 0, sizeof(struct sockaddr_in));
|
|
|
|
|
local_addr.sin_family = ADDR_FAMILY;
|
|
|
|
|
local_addr.sin_port = 0; // Any local port will do
|
|
|
|
|
if(inet_pton(AF_INET, args.s1c_bind_addr.c_str(), &(local_addr.sin_addr)) != 1) {
|
|
|
|
|
s1ap_log->error("Error converting IP address (%s) to sockaddr_in structure\n", args.s1c_bind_addr.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (bind(socket_fd, (struct sockaddr *)&local_addr, sizeof(local_addr)) != 0) {
|
|
|
|
|
s1ap_log->error("Failed to bind on S1-C address %s: %s errno %d\n", args.s1c_bind_addr.c_str(), strerror(errno), errno);
|
|
|
|
|
// Init SCTP socket and bind it
|
|
|
|
|
if (not srslte::net_utils::sctp_init_client(
|
|
|
|
|
&s1ap_socket, srslte::net_utils::socket_type::seqpacket, args.s1c_bind_addr.c_str(), s1ap_log)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Connect to the MME address
|
|
|
|
|
memset(&mme_addr, 0, sizeof(struct sockaddr_in));
|
|
|
|
|
mme_addr.sin_family = ADDR_FAMILY;
|
|
|
|
|
mme_addr.sin_port = htons(MME_PORT);
|
|
|
|
|
if(inet_pton(AF_INET, args.mme_addr.c_str(), &(mme_addr.sin_addr)) != 1) {
|
|
|
|
|
s1ap_log->error("Error converting IP address (%s) to sockaddr_in structure\n", args.mme_addr.c_str());
|
|
|
|
|
if (not s1ap_socket.connect_to(args.mme_addr.c_str(), MME_PORT, &mme_addr, s1ap_log)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(connect(socket_fd, (struct sockaddr*)&mme_addr, sizeof(mme_addr)) == -1) {
|
|
|
|
|
s1ap_log->error("Failed to establish socket connection to MME\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Assign a handler to rx MME packets (going to run in a different thread)
|
|
|
|
|
stack->add_mme_socket(s1ap_socket.fd());
|
|
|
|
|
|
|
|
|
|
s1ap_log->info("SCTP socket established with MME\n");
|
|
|
|
|
return true;
|
|
|
|
@ -395,7 +401,9 @@ bool s1ap::setup_s1()
|
|
|
|
|
tmp32 = htonl(args.enb_id);
|
|
|
|
|
uint8_t enb_id_bits[4 * 8];
|
|
|
|
|
liblte_unpack((uint8_t*)&tmp32, 4, enb_id_bits);
|
|
|
|
|
memcpy(s1setup->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer, &enb_id_bits[32-LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
|
|
|
|
|
memcpy(s1setup->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer,
|
|
|
|
|
&enb_id_bits[32 - LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN],
|
|
|
|
|
LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
|
|
|
|
|
|
|
|
|
|
s1setup->eNBname_present = true;
|
|
|
|
|
s1setup->eNBname.ext = false;
|
|
|
|
@ -419,24 +427,47 @@ bool s1ap::setup_s1()
|
|
|
|
|
s1setup->DefaultPagingDRX.ext = false;
|
|
|
|
|
s1setup->DefaultPagingDRX.e = LIBLTE_S1AP_PAGINGDRX_V128; // Todo: add to args, config file
|
|
|
|
|
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
|
|
|
|
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending s1SetupRequest");
|
|
|
|
|
return sctp_send_s1ap_pdu(&pdu, 0, "s1SetupRequest");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID), 0, NONUE_STREAM_ID, 0, 0);
|
|
|
|
|
if(n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send s1SetupRequest\n");
|
|
|
|
|
/*******************************************************************************
|
|
|
|
|
/* S1AP message handlers
|
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
|
|
|
|
bool s1ap::handle_mme_rx_msg(srslte::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;
|
|
|
|
|
s1ap_log->debug("SCTP Notification %d\n", notification->sn_header.sn_type);
|
|
|
|
|
if (notification->sn_header.sn_type == SCTP_SHUTDOWN_EVENT) {
|
|
|
|
|
s1ap_log->info("SCTP Association Shutdown. Association: %d\n", sri.sinfo_assoc_id);
|
|
|
|
|
s1ap_log->console("SCTP Association Shutdown. Association: %d\n", sri.sinfo_assoc_id);
|
|
|
|
|
s1ap_socket.reset();
|
|
|
|
|
}
|
|
|
|
|
} else if (pdu->N_bytes == 0) {
|
|
|
|
|
s1ap_log->error("SCTP return 0 bytes. Closing socket\n");
|
|
|
|
|
s1ap_socket.reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restart MME connection procedure if we lost connection
|
|
|
|
|
if (not s1ap_socket.is_init()) {
|
|
|
|
|
mme_connected = false;
|
|
|
|
|
if (not s1setup_proc.launch()) {
|
|
|
|
|
s1ap_log->error("Failed to initiate MME connection procedure.\n");
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s1ap_log->info_hex(pdu->msg, pdu->N_bytes, "Received S1AP PDU");
|
|
|
|
|
handle_s1ap_rx_pdu(pdu.get());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
|
/* S1AP message handlers
|
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
|
|
|
|
bool s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t* pdu)
|
|
|
|
|
{
|
|
|
|
|
LIBLTE_S1AP_S1AP_PDU_STRUCT rx_pdu;
|
|
|
|
@ -488,7 +519,8 @@ bool s1ap::handle_successfuloutcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
|
|
|
|
|
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE:
|
|
|
|
|
return handle_s1setupresponse(&msg->choice.S1SetupResponse);
|
|
|
|
|
default:
|
|
|
|
|
s1ap_log->error("Unhandled successful outcome message: %s\n", liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]);
|
|
|
|
|
s1ap_log->error("Unhandled successful outcome message: %s\n",
|
|
|
|
|
liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
@ -512,6 +544,9 @@ bool s1ap::handle_s1setupresponse(LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT *ms
|
|
|
|
|
s1ap_log->info("Received S1SetupResponse\n");
|
|
|
|
|
s1setupresponse = *msg;
|
|
|
|
|
mme_connected = true;
|
|
|
|
|
s1_setup_proc_t::s1setupresult res;
|
|
|
|
|
res.success = true;
|
|
|
|
|
s1setup_proc.trigger(res);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -723,7 +758,8 @@ bool s1ap::handle_uectxtreleasecommand(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMA
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::handle_s1setupfailure(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *msg) {
|
|
|
|
|
bool s1ap::handle_s1setupfailure(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT* msg)
|
|
|
|
|
{
|
|
|
|
|
std::string cause = get_cause(&msg->Cause);
|
|
|
|
|
s1ap_log->error("S1 Setup Failure. Cause: %s\n", cause.c_str());
|
|
|
|
|
s1ap_log->console("S1 Setup Failure. Cause: %s\n", cause.c_str());
|
|
|
|
@ -807,22 +843,7 @@ bool s1ap::send_initialuemessage(uint16_t rnti,
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
|
|
|
|
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending InitialUEMessage for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
msg.msg,
|
|
|
|
|
msg.N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send InitialUEMessage for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "InitialUEMessage");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::send_ulnastransport(uint16_t rnti, srslte::unique_byte_buffer_t pdu)
|
|
|
|
@ -864,22 +885,7 @@ bool s1ap::send_ulnastransport(uint16_t rnti, srslte::unique_byte_buffer_t pdu)
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
|
|
|
|
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UplinkNASTransport for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
msg.msg,
|
|
|
|
|
msg.N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "UplinkNASTransport");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::send_uectxtreleaserequest(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT* cause)
|
|
|
|
@ -912,22 +918,7 @@ bool s1ap::send_uectxtreleaserequest(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT *ca
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
|
|
|
|
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UEContextReleaseRequest for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
msg.msg,
|
|
|
|
|
msg.N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send UEContextReleaseRequest for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "UEContextReleaseRequest");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::send_uectxtreleasecomplete(uint16_t rnti, uint32_t mme_ue_id, uint32_t enb_ue_id)
|
|
|
|
@ -953,25 +944,7 @@ bool s1ap::send_uectxtreleasecomplete(uint16_t rnti, uint32_t mme_ue_id, uint32_
|
|
|
|
|
comp->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = enb_ue_id;
|
|
|
|
|
comp->MME_UE_S1AP_ID.MME_UE_S1AP_ID = mme_ue_id;
|
|
|
|
|
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
|
|
|
|
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UEContextReleaseComplete for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
msg.msg,
|
|
|
|
|
msg.N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send UEContextReleaseComplete for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "UEContextReleaseComplete");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::send_initial_ctxt_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT* res_)
|
|
|
|
@ -1011,26 +984,7 @@ bool s1ap::send_initial_ctxt_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_I
|
|
|
|
|
res->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
|
|
|
|
res->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
|
|
|
|
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
|
|
|
|
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending InitialContextSetupResponse for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
buf->msg,
|
|
|
|
|
buf->N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send InitialContextSetupResponse for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "InitialContextSetupResponse");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::send_erab_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT* res_)
|
|
|
|
@ -1070,26 +1024,7 @@ bool s1ap::send_erab_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETU
|
|
|
|
|
res->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
|
|
|
|
res->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
|
|
|
|
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
|
|
|
|
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending E_RABSetupResponse for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
buf->msg,
|
|
|
|
|
buf->N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send E_RABSetupResponse for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "E_RABSetupResponse");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::send_initial_ctxt_setup_failure(uint16_t rnti)
|
|
|
|
@ -1123,26 +1058,7 @@ bool s1ap::send_initial_ctxt_setup_failure(uint16_t rnti)
|
|
|
|
|
fail->Cause.choice.radioNetwork.ext = false;
|
|
|
|
|
fail->Cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_UNSPECIFIED;
|
|
|
|
|
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
|
|
|
|
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending InitialContextSetupFailure for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
buf->msg,
|
|
|
|
|
buf->N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "InitialContextSetupFailure");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::send_uectxmodifyresp(uint16_t rnti)
|
|
|
|
@ -1174,23 +1090,7 @@ bool s1ap::send_uectxmodifyresp(uint16_t rnti)
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
|
|
|
|
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending ContextModificationFailure for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
buf->msg,
|
|
|
|
|
buf->N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send ContextModificationFailure for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "ContextModificationFailure");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool s1ap::send_uectxmodifyfailure(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT* cause)
|
|
|
|
@ -1221,26 +1121,7 @@ bool s1ap::send_uectxmodifyfailure(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT* caus
|
|
|
|
|
|
|
|
|
|
memcpy(&fail->Cause, cause, sizeof(LIBLTE_S1AP_CAUSE_STRUCT));
|
|
|
|
|
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
|
|
|
|
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending UEContextModificationFailure for RNTI:0x%x", rnti);
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
buf->msg,
|
|
|
|
|
buf->N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
s1ap_log->error("Failed to send UEContextModificationFailure for RNTI:0x%x\n", rnti);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "UEContextModificationFailure");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************
|
|
|
|
@ -1314,19 +1195,29 @@ bool s1ap::sctp_send_s1ap_pdu(LIBLTE_S1AP_S1AP_PDU_STRUCT* tx_pdu, uint32_t rnti
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
liblte_s1ap_pack_s1ap_pdu(tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
|
|
|
|
if (rnti > 0) {
|
|
|
|
|
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending %s for rnti=0x%x", procedure_name, rnti);
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
|
|
|
|
} else {
|
|
|
|
|
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending %s to MME", procedure_name);
|
|
|
|
|
}
|
|
|
|
|
uint16_t streamid = rnti == 0 ? NONUE_STREAM_ID : get_user_ctxt(rnti)->stream_id;
|
|
|
|
|
|
|
|
|
|
ssize_t n_sent = sctp_sendmsg(s1ap_socket.fd(),
|
|
|
|
|
buf->msg,
|
|
|
|
|
buf->N_bytes,
|
|
|
|
|
(struct sockaddr*)&mme_addr,
|
|
|
|
|
sizeof(struct sockaddr_in),
|
|
|
|
|
htonl(PPID),
|
|
|
|
|
0,
|
|
|
|
|
get_user_ctxt(rnti)->stream_id,
|
|
|
|
|
streamid,
|
|
|
|
|
0,
|
|
|
|
|
0);
|
|
|
|
|
if (n_sent == -1) {
|
|
|
|
|
if (rnti > 0) {
|
|
|
|
|
s1ap_log->error("Failed to send %s for rnti=0x%x\n", procedure_name, rnti);
|
|
|
|
|
} else {
|
|
|
|
|
s1ap_log->error("Failed to send %s\n", procedure_name);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|