open5gs/src/sgw/sgw_gtp_path.c

411 lines
11 KiB
C

#define TRACE_MODULE _sgw_path
#include "core_debug.h"
#include "core_pkbuf.h"
#include "core_net.h"
#include "types.h"
#include "gtp_types.h"
#include "gtp_path.h"
#include "sgw_context.h"
#include "sgw_event.h"
#include "sgw_gtp_path.h"
static int _gtpv2_c_recv_cb(net_sock_t *sock, void *data)
{
event_t e;
status_t rv;
pkbuf_t *pkbuf = NULL;
c_uint32_t addr;
c_uint16_t port;
event_e event = (event_e)data;
d_assert(sock, return -1, "Null param");
d_assert(data, return -1, "Null param");
pkbuf = gtp_read(sock);
if (pkbuf == NULL)
{
if (sock->sndrcv_errno == EAGAIN)
return 0;
return -1;
}
addr = sock->remote.sin_addr.s_addr;
port = ntohs(sock->remote.sin_port);
event_set(&e, event);
event_set_param2(&e, (c_uintptr_t)pkbuf);
if (event == SGW_EVT_S11_MESSAGE)
{
sgw_mme_t *mme = sgw_mme_find(addr, port);
if (!mme)
{
mme = sgw_mme_add();
d_assert(mme, return -1, "Can't add MME-GTP node");
mme->addr = addr;
mme->port = port;
mme->sock = sock;
}
d_trace(10, "S11 PDU received from MME\n");
event_set_param1(&e, (c_uintptr_t)mme);
}
else if (event == SGW_EVT_S5C_MESSAGE)
{
sgw_pgw_t *pgw = sgw_pgw_find(addr, port);
d_assert(pgw, return -1, "Can't add PGW-GTP node");
d_trace(10, "S5-C PDU received from PGW\n");
event_set_param1(&e, (c_uintptr_t)pgw);
}
else
d_assert(0, pkbuf_free(pkbuf); return -1, "Unknown GTP-Node");
d_trace_hex(10, pkbuf->payload, pkbuf->len);
rv = sgw_event_send(&e);
if (rv != CORE_OK)
{
d_error("sgw_event_send error");
pkbuf_free(pkbuf);
return -1;
}
return 0;
}
static int _gtpv1_s5u_recv_cb(net_sock_t *sock, void *data)
{
pkbuf_t *pkbuf = NULL;
gtp_node_t gnode;
gtp_header_t *gtp_h = NULL;
sgw_bearer_t *bearer = NULL;
c_uint32_t teid;
d_assert(sock, return -1, "Null param");
pkbuf = gtp_read(sock);
if (pkbuf == NULL)
{
if (sock->sndrcv_errno == EAGAIN)
return 0;
return -1;
}
d_trace(50, "S5-U PDU received from PGW\n");
d_trace_hex(50, pkbuf->payload, pkbuf->len);
gtp_h = (gtp_header_t *)pkbuf->payload;
if (gtp_h->type == GTPU_MSGTYPE_ECHO_REQ)
{
pkbuf_t *echo_rsp;
d_trace(3, "Received echo-req");
echo_rsp = gtp_handle_echo_req(pkbuf);
if (echo_rsp)
{
/* Echo reply */
d_trace(3, "Send echo-rsp to peer(PGW) ");
gnode.addr = sock->remote.sin_addr.s_addr;
gnode.port = GTPV1_U_UDP_PORT;
gnode.sock = sgw_self()->s5u_sock;
gtp_send(&gnode, echo_rsp);
pkbuf_free(echo_rsp);
}
}
else if (gtp_h->type == GTPU_MSGTYPE_GPDU)
{
teid = ntohl(gtp_h->teid);
d_trace(50, "Recv GPDU (teid = 0x%x)",teid);
bearer = sgw_bearer_find_by_sgw_s5u_teid(teid);
if (bearer)
{
if (bearer->enb_s1u_teid)
{
/* Convert Teid and send to enodeB via s1u */
gtp_h->teid = htonl(bearer->enb_s1u_teid);
gnode.addr = bearer->enb_s1u_addr;
gnode.port = GTPV1_U_UDP_PORT;
gnode.sock = sgw_self()->s1u_sock;
/* If there is buffered packet, send it first */
if (bearer->num_buffered_pkt)
{
int i;
for (i = 0; i < bearer->num_buffered_pkt; i++)
{
gtp_h =
(gtp_header_t *)bearer->buffered_pkts[i]->payload;
gtp_h->teid = htonl(bearer->enb_s1u_teid);
gtp_send(&gnode, bearer->buffered_pkts[i]);
pkbuf_free(bearer->buffered_pkts[i]);
}
bearer->num_buffered_pkt = 0;
}
gtp_send(&gnode, pkbuf);
}
else
{
/* S1U path is deactivated.
* Send downlink_data_notification to MME.
*
*/
sgw_ue_t *sgw_ue = NULL;
d_assert(bearer->sess, pkbuf_free(pkbuf); return 0,
"Session is NULL");
d_assert(bearer->sess->sgw_ue, pkbuf_free(pkbuf); return 0,
"SGW_UE is NULL");
sgw_ue = bearer->sess->sgw_ue;
if ((SGW_GET_UE_STATE(sgw_ue) & SGW_S1U_INACTIVE))
{
if ( !(SGW_GET_UE_STATE(sgw_ue) & SGW_DL_NOTI_SENT))
{
event_t e;
status_t rv;
event_set(&e, SGW_EVT_LO_DLDATA_NOTI);
event_set_param1(&e, (c_uintptr_t)bearer->index);
rv = sgw_event_send(&e);
if (rv != CORE_OK)
{
d_error("sgw_event_send error");
pkbuf_free(pkbuf);
return -1;
}
SGW_SET_UE_STATE(sgw_ue, SGW_DL_NOTI_SENT);
}
/* Buffer the packet */
if (bearer->num_buffered_pkt < MAX_NUM_BUFFER_PKT)
{
bearer->buffered_pkts[bearer->num_buffered_pkt++] =
pkbuf;
return 0;
}
}
else
{
/* UE is S1U_ACTIVE state but there is no s1u teid */
d_warn("UE is ACITVE but there is no matched "
"s1u_teid(tedid = 0x%x)",teid);
/* Just drop it */
}
}
}
}
pkbuf_free(pkbuf);
return 0;
}
static int _gtpv1_s1u_recv_cb(net_sock_t *sock, void *data)
{
pkbuf_t *pkbuf = NULL;
gtp_node_t gnode;
gtp_header_t *gtp_h = NULL;
sgw_tunnel_t *tunnel = NULL;
c_uint32_t teid;
d_assert(sock, return -1, "Null param");
pkbuf = gtp_read(sock);
if (pkbuf == NULL)
{
if (sock->sndrcv_errno == EAGAIN)
return 0;
return -1;
}
d_trace(50, "S1-U PDU received from ENB\n");
d_trace_hex(50, pkbuf->payload, pkbuf->len);
gtp_h = (gtp_header_t *)pkbuf->payload;
if (gtp_h->type == GTPU_MSGTYPE_ECHO_REQ)
{
pkbuf_t *echo_rsp;
d_trace(3, "Received echo-req\n");
echo_rsp = gtp_handle_echo_req(pkbuf);
if (echo_rsp)
{
/* Echo reply */
d_trace(3, "Send echo-rsp to peer(ENB)\n");
gnode.addr = sock->remote.sin_addr.s_addr;
gnode.port = GTPV1_U_UDP_PORT;
gnode.sock = sgw_self()->s1u_sock;
gtp_send(&gnode, echo_rsp);
pkbuf_free(echo_rsp);
}
}
else if (gtp_h->type == GTPU_MSGTYPE_GPDU)
{
teid = ntohl(gtp_h->teid);
d_trace(50, "Recv GPDU (teid = 0x%x) from ENB\n",teid);
tunnel = sgw_tunnel_find_by_teid(teid);
if (tunnel)
{
gtp_h->teid = htonl(tunnel->remote_teid);
gnode.addr = tunnel->remote_addr;
gnode.port = GTPV1_U_UDP_PORT;
if (tunnel->interface_type == GTP_F_TEID_S1_U_SGW_GTP_U)
gnode.sock = sgw_self()->s5u_sock;
else if (tunnel->interface_type ==
GTP_F_TEID_SGW_GTP_U_FOR_DL_DATA_FORWARDING)
gnode.sock = sgw_self()->s1u_sock;
else if (tunnel->interface_type ==
GTP_F_TEID_SGW_GTP_U_FOR_UL_DATA_FORWARDING)
gnode.sock = sgw_self()->s1u_sock;
else
d_assert(0, return -1, "Invalid type(%d)",
tunnel->interface_type);
gtp_send(&gnode, pkbuf);
}
#if 0
bearer = sgw_bearer_find_by_sgw_s1u_teid(teid);
if (bearer)
{
/* Convert Teid and send to PGW via s5u */
gtp_h->teid = htonl(bearer->pgw_s5u_teid);
gnode.addr = bearer->pgw_s5u_addr;
gnode.port = GTPV1_U_UDP_PORT;
gnode.sock = sgw_self()->s5u_sock;
gtp_send(&gnode, pkbuf);
}
#endif
}
pkbuf_free(pkbuf);
return 0;
}
status_t sgw_gtp_open()
{
status_t rv;
rv = gtp_listen(&sgw_self()->s11_sock, _gtpv2_c_recv_cb,
sgw_self()->s11_addr, sgw_self()->s11_port,
(void*)SGW_EVT_S11_MESSAGE);
if (rv != CORE_OK)
{
d_error("Can't establish S11 Path for SGW");
return rv;
}
rv = gtp_listen(&sgw_self()->s5c_sock, _gtpv2_c_recv_cb,
sgw_self()->s5c_addr, sgw_self()->s5c_port,
(void*)SGW_EVT_S5C_MESSAGE);
if (rv != CORE_OK)
{
d_error("Can't establish S5-C Path for SGW");
return rv;
}
rv = gtp_listen(&sgw_self()->s5u_sock, _gtpv1_s5u_recv_cb,
sgw_self()->s5u_addr, sgw_self()->s5u_port, NULL);
if (rv != CORE_OK)
{
d_error("Can't establish S5-U Path for SGW");
return rv;
}
rv = gtp_listen(&sgw_self()->s1u_sock, _gtpv1_s1u_recv_cb,
sgw_self()->s1u_addr, sgw_self()->s1u_port, NULL);
if (rv != CORE_OK)
{
d_error("Can't establish S1-U Path for SGW");
return rv;
}
return CORE_OK;
}
status_t sgw_gtp_close()
{
status_t rv;
rv = gtp_close(sgw_self()->s11_sock);
if (rv != CORE_OK)
{
d_error("Can't close S11 Path for MME");
return rv;
}
rv = gtp_close(sgw_self()->s5c_sock);
if (rv != CORE_OK)
{
d_error("Can't close S5-C Path for MME");
return rv;
}
rv = gtp_close(sgw_self()->s5u_sock);
if (rv != CORE_OK)
{
d_error("Can't close S5-U Path for MME");
return rv;
}
return CORE_OK;
}
status_t sgw_gtp_send_end_marker(sgw_bearer_t *bearer)
{
status_t rv;
pkbuf_t *pkbuf = NULL;
gtp_header_t *h = NULL;
gtp_node_t gnode;
d_assert(bearer, return CORE_ERROR,);
pkbuf = pkbuf_alloc(0, 100 /* enough for END_MARKER; use smaller buffer */);
d_assert(pkbuf, return CORE_ERROR,);
h = (gtp_header_t *)pkbuf->payload;
memset(h, 0, GTPV1U_HEADER_LEN);
/*
* Flags
* 0x20 - Version : GTP release 99 version (1)
* 0x10 - Protocol Type : GTP (1)
*/
h->flags = 0x30;
h->type = GTPU_MSGTYPE_END_MARKER;
h->teid = htonl(bearer->enb_s1u_teid);
gnode.addr = bearer->enb_s1u_addr;
gnode.port = GTPV1_U_UDP_PORT;
gnode.sock = sgw_self()->s1u_sock;
rv = gtp_send(&gnode, pkbuf);
d_assert(rv == CORE_OK, , "gtp send failed");
pkbuf_free(pkbuf);
return rv;
}