|
|
|
@ -35,6 +35,7 @@
|
|
|
|
|
#include <linux/if_tun.h>
|
|
|
|
|
#include "spgw/spgw.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace srsepc{
|
|
|
|
|
|
|
|
|
|
spgw* spgw::m_instance = NULL;
|
|
|
|
@ -128,61 +129,6 @@ spgw::stop()
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
spgw::run_thread()
|
|
|
|
|
{
|
|
|
|
|
//Mark the thread as running
|
|
|
|
|
m_running=true;
|
|
|
|
|
srslte::byte_buffer_t *msg;
|
|
|
|
|
msg = m_pool->allocate();
|
|
|
|
|
|
|
|
|
|
struct sockaddr src_addr;
|
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
|
|
|
|
|
int sgi = m_sgi_if;
|
|
|
|
|
|
|
|
|
|
fd_set set;
|
|
|
|
|
//struct timeval to;
|
|
|
|
|
int max_fd = std::max(m_s1u,sgi);
|
|
|
|
|
while (m_running)
|
|
|
|
|
{
|
|
|
|
|
msg->reset();
|
|
|
|
|
FD_ZERO(&set);
|
|
|
|
|
FD_SET(m_s1u, &set);
|
|
|
|
|
FD_SET(sgi, &set);
|
|
|
|
|
|
|
|
|
|
m_spgw_log->info("Waiting for S1-U or SGi packets.\n");
|
|
|
|
|
int n = select(max_fd+1, &set, NULL, NULL, NULL);
|
|
|
|
|
if (n == -1)
|
|
|
|
|
{
|
|
|
|
|
m_spgw_log->error("Error from select\n");
|
|
|
|
|
}
|
|
|
|
|
else if (n)
|
|
|
|
|
{
|
|
|
|
|
m_spgw_log->info("Data is available now.\n");
|
|
|
|
|
if (FD_ISSET(m_s1u, &set))
|
|
|
|
|
{
|
|
|
|
|
msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen );
|
|
|
|
|
m_spgw_log->console("Received PDU from S1-U. Bytes %d\n", msg->N_bytes);
|
|
|
|
|
m_spgw_log->debug("Received PDU from S1-U. Bytes %d\n", msg->N_bytes);
|
|
|
|
|
}
|
|
|
|
|
if (FD_ISSET(m_sgi_if, &set))
|
|
|
|
|
{
|
|
|
|
|
m_spgw_log->console("Received PDU from SGi\n");
|
|
|
|
|
msg->N_bytes = read(sgi, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES);
|
|
|
|
|
m_spgw_log->console("Received PDU from SGi. Bytes %d\n", msg->N_bytes);
|
|
|
|
|
m_spgw_log->debug("Received PDU from SGi. Bytes %d\n", msg->N_bytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_spgw_log->debug("No data from select.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_pool->deallocate(msg);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srslte::error_t
|
|
|
|
|
spgw::init_sgi_if(spgw_args_t *args)
|
|
|
|
|
{
|
|
|
|
@ -203,9 +149,9 @@ spgw::init_sgi_if(spgw_args_t *args)
|
|
|
|
|
m_spgw_log->error("Failed to open TUN device: %s\n", strerror(errno));
|
|
|
|
|
return(srslte::ERROR_CANT_START);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
|
|
|
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
|
|
|
|
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
|
|
|
|
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ);
|
|
|
|
|
if(ioctl(m_sgi_if, TUNSETIFF, &ifr) < 0)
|
|
|
|
|
{
|
|
|
|
@ -230,13 +176,13 @@ spgw::init_sgi_if(spgw_args_t *args)
|
|
|
|
|
close(m_sgi_if);
|
|
|
|
|
return(srslte::ERROR_CANT_START);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Set IP of the interface
|
|
|
|
|
struct sockaddr_in *addr = (struct sockaddr_in*)&ifr.ifr_addr;
|
|
|
|
|
addr->sin_family = AF_INET;
|
|
|
|
|
addr->sin_addr.s_addr = inet_addr(args->sgi_if_addr.c_str());
|
|
|
|
|
addr->sin_port = 0;
|
|
|
|
|
|
|
|
|
|
addr->sin_port = 0;
|
|
|
|
|
|
|
|
|
|
if (ioctl(m_sgi_sock, SIOCSIFADDR, &ifr) < 0) {
|
|
|
|
|
m_spgw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_if_addr.c_str(), strerror(errno));
|
|
|
|
|
close(m_sgi_if);
|
|
|
|
@ -252,7 +198,7 @@ spgw::init_sgi_if(spgw_args_t *args)
|
|
|
|
|
close(m_sgi_sock);
|
|
|
|
|
return srslte::ERROR_CANT_START;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_sgi_up = true;
|
|
|
|
|
return(srslte::ERROR_NONE);
|
|
|
|
|
}
|
|
|
|
@ -283,4 +229,97 @@ spgw::init_s1u(spgw_args_t *args)
|
|
|
|
|
return srslte::ERROR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
spgw::run_thread()
|
|
|
|
|
{
|
|
|
|
|
//Mark the thread as running
|
|
|
|
|
m_running=true;
|
|
|
|
|
srslte::byte_buffer_t *msg;
|
|
|
|
|
msg = m_pool->allocate();
|
|
|
|
|
|
|
|
|
|
struct sockaddr src_addr;
|
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
|
|
|
|
|
int sgi = m_sgi_if;
|
|
|
|
|
|
|
|
|
|
fd_set set;
|
|
|
|
|
//struct timeval to;
|
|
|
|
|
int max_fd = std::max(m_s1u,sgi);
|
|
|
|
|
while (m_running)
|
|
|
|
|
{
|
|
|
|
|
msg->reset();
|
|
|
|
|
FD_ZERO(&set);
|
|
|
|
|
FD_SET(m_s1u, &set);
|
|
|
|
|
FD_SET(sgi, &set);
|
|
|
|
|
|
|
|
|
|
m_spgw_log->info("Waiting for S1-U or SGi packets.\n");
|
|
|
|
|
int n = select(max_fd+1, &set, NULL, NULL, NULL);
|
|
|
|
|
if (n == -1)
|
|
|
|
|
{
|
|
|
|
|
m_spgw_log->error("Error from select\n");
|
|
|
|
|
}
|
|
|
|
|
else if (n)
|
|
|
|
|
{
|
|
|
|
|
m_spgw_log->info("Data is available now.\n");
|
|
|
|
|
if (FD_ISSET(m_s1u, &set))
|
|
|
|
|
{
|
|
|
|
|
msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen );
|
|
|
|
|
m_spgw_log->console("Received PDU from S1-U. Bytes %d\n", msg->N_bytes);
|
|
|
|
|
m_spgw_log->debug("Received PDU from S1-U. Bytes %d\n", msg->N_bytes);
|
|
|
|
|
}
|
|
|
|
|
if (FD_ISSET(m_sgi_if, &set))
|
|
|
|
|
{
|
|
|
|
|
m_spgw_log->console("Received PDU from SGi\n");
|
|
|
|
|
msg->N_bytes = read(sgi, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES);
|
|
|
|
|
m_spgw_log->console("Received PDU from SGi. Bytes %d\n", msg->N_bytes);
|
|
|
|
|
m_spgw_log->debug("Received PDU from SGi. Bytes %d\n", msg->N_bytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_spgw_log->debug("No data from select.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_pool->deallocate(msg);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_create_session_response *cs_resp)
|
|
|
|
|
{
|
|
|
|
|
//Setup uplink control TEID
|
|
|
|
|
uint64_t spgw_uplink_ctrl_teid = get_new_ctrl_teid();
|
|
|
|
|
//Setup uplink user TEID
|
|
|
|
|
uint64_t spgw_uplink_user_teid = get_new_user_teid();
|
|
|
|
|
//Allocate UE IP
|
|
|
|
|
in_addr_t ue_ip = get_new_ue_ipv4();
|
|
|
|
|
|
|
|
|
|
//Save the UE context //TODO!!!
|
|
|
|
|
|
|
|
|
|
//Create session response message
|
|
|
|
|
//Initialize to zero\\
|
|
|
|
|
bzero(cs_resp,sizeof(struct srslte::gtpc_create_session_response));
|
|
|
|
|
//Setup Cause\\
|
|
|
|
|
cs_resp->cause = ;
|
|
|
|
|
//Setup sender F-TEID (ctrl)\\
|
|
|
|
|
cs_resp->sender_f_teid.teid_present = true;
|
|
|
|
|
cs_resp->sender_f_teid.teid = spgw_uplink_ctrl_teid;
|
|
|
|
|
cs_resp->sender_f_teid.ipv4 = m_gtpu_bind_addr;//FIXME This is not relevant, as the GTP-C is not transmitted over sockets yet.
|
|
|
|
|
//Bearer context created\\
|
|
|
|
|
cs_resp->eps_bearer_context_created.ebi = 5;
|
|
|
|
|
cs_resp->eps_bearer_context_created.cause = ;
|
|
|
|
|
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present=true;
|
|
|
|
|
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.teid = spgw_uplink_user_teid;
|
|
|
|
|
//Fill in the PDA\\
|
|
|
|
|
cs_resp->pda_present = true;
|
|
|
|
|
cs_resp->pda.pdn_type = srslte::GTPC_IPV4;
|
|
|
|
|
cs_resp->ipv4_present = true;
|
|
|
|
|
cs_resp->ipv4 = ue_ip;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} //namespace srsepc
|
|
|
|
|