open5gs/lib/gtp/gtp_xact.c

398 lines
11 KiB
C
Raw Normal View History

2017-03-26 15:48:33 +00:00
#define TRACE_MODULE _gtp_xact
#include "core_debug.h"
#include "core_pool.h"
2017-03-27 10:12:45 +00:00
#include "core_event.h"
2017-03-26 15:48:33 +00:00
#include "gtp_xact.h"
2017-03-27 10:12:45 +00:00
#include "gtp_tlv.h"
2017-03-26 15:48:33 +00:00
#define SIZE_OF_GTP_XACT_POOL 32
#define GTP_XACT_NEXT_ID(__id) \
((__id) == 0x800000 ? 1 : ((__id) + 1))
#define GTP_XACT_COMPARE_ID(__id1, __id2) \
((__id2) > (__id1) ? ((__id2) - (__id1) < 0x7fffff ? -1 : 1) : \
(__id1) > (__id2) ? ((__id1) - (__id2) < 0x7fffff ? 1 : -1) : 0)
2017-03-29 14:19:31 +00:00
/* 5.1 General format */
#define GTPV2C_HEADER_LEN 12
#define GTPV2C_TEID_LEN 4
typedef struct _gtpv2c_header_t {
ED4(c_uint8_t version:3;,
c_uint8_t piggybacked:1;,
c_uint8_t teid_presence:1;,
c_uint8_t spare1:3;)
c_uint8_t type;
c_uint16_t length;
union {
struct {
c_uint32_t teid;
/* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */
2017-03-27 10:12:45 +00:00
#define GTP_XID_TO_SQN(__xid) ((__xid) << 8)
#define GTP_SQN_TO_XID(__sqn) ((__sqn) >> 8)
2017-03-29 14:19:31 +00:00
c_uint32_t sqn;
};
/* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */
c_uint32_t spare2;
};
} __attribute__ ((packed)) gtpv2c_header_t;
2017-03-26 15:48:33 +00:00
2017-03-28 07:35:57 +00:00
static int gtp_xact_pool_initialized = 0;
2017-03-29 02:54:18 +00:00
pool_declare(gtp_xact_pool, gtp_xact_t, SIZE_OF_GTP_XACT_POOL);
2017-03-26 15:48:33 +00:00
2017-03-28 07:35:57 +00:00
status_t gtp_xact_init(gtp_xact_ctx_t *context, tm_service_t *tm_service,
c_uintptr_t event, c_uint32_t duration, int retry_count)
2017-03-26 15:48:33 +00:00
{
2017-03-28 07:35:57 +00:00
if (gtp_xact_pool_initialized == 0)
{
pool_init(&gtp_xact_pool, SIZE_OF_GTP_XACT_POOL);
}
gtp_xact_pool_initialized = 1;
2017-03-26 15:48:33 +00:00
2017-03-28 07:35:57 +00:00
memset(context, 0, sizeof(gtp_xact_ctx_t));
2017-03-26 15:48:33 +00:00
2017-03-28 07:35:57 +00:00
context->g_xact_id = 1;
context->tm_service = tm_service;
context->event = event;;
context->duration = duration;;
context->retry_count = retry_count;;
2017-03-26 15:48:33 +00:00
return CORE_OK;
}
status_t gtp_xact_final(void)
{
2017-03-28 07:35:57 +00:00
if (gtp_xact_pool_initialized == 1)
{
2017-03-30 13:23:47 +00:00
d_print("%d not freed in gtp_xact_pool[%d] of S11/S5-SM\n",
pool_size(&gtp_xact_pool) - pool_avail(&gtp_xact_pool),
pool_size(&gtp_xact_pool));
2017-03-28 07:35:57 +00:00
pool_final(&gtp_xact_pool);
}
gtp_xact_pool_initialized = 0;
2017-03-26 15:48:33 +00:00
return CORE_OK;
}
2017-03-30 12:26:42 +00:00
gtp_xact_t *gtp_xact_create(gtp_xact_ctx_t *context,
2017-03-30 00:20:40 +00:00
net_sock_t *sock, gtp_node_t *gnode, c_uint8_t org, c_uint32_t xid,
c_uint8_t type, pkbuf_t *pkbuf)
2017-03-26 15:48:33 +00:00
{
2017-03-29 02:54:18 +00:00
gtp_xact_t *xact = NULL;
2017-03-30 13:23:47 +00:00
c_uint32_t duration = context->duration;
int retry_count = context->retry_count;
2017-03-27 10:12:45 +00:00
2017-03-30 00:06:56 +00:00
d_assert(context, goto out1, "Null param");
d_assert(sock, goto out1, "Null param");
d_assert(gnode, goto out1, "Null param");
d_assert(pkbuf, goto out1, "Null param");
2017-03-27 10:12:45 +00:00
2017-03-28 07:35:57 +00:00
pool_alloc_node(&gtp_xact_pool, &xact);
2017-03-30 00:06:56 +00:00
d_assert(xact, goto out1, "Transaction allocation failed");
2017-03-29 02:54:18 +00:00
memset(xact, 0, sizeof(gtp_xact_t));
2017-03-27 10:12:45 +00:00
2017-03-30 00:20:40 +00:00
xact->org = org;
xact->xid = xid;
2017-03-28 07:35:57 +00:00
xact->sock = sock;
xact->gnode = gnode;
2017-03-30 00:06:56 +00:00
xact->type = type;
2017-03-28 07:35:57 +00:00
xact->pkbuf = pkbuf;
2017-03-27 10:12:45 +00:00
2017-03-30 13:23:47 +00:00
if (xact->org == GTP_REMOTE_ORIGINATOR)
{
duration = context->duration * context->retry_count;
retry_count = 1;
}
2017-03-28 07:35:57 +00:00
xact->tm_wait = event_timer(context->tm_service, context->event,
2017-03-30 13:23:47 +00:00
duration, (c_uintptr_t)xact);
2017-03-30 00:06:56 +00:00
d_assert(xact->tm_wait, goto out2, "Timer allocation failed");
2017-03-30 13:23:47 +00:00
xact->retry_count = retry_count;
2017-03-27 10:12:45 +00:00
2017-03-30 00:20:40 +00:00
list_append(xact->org == GTP_LOCAL_ORIGINATOR ?
2017-03-30 12:17:05 +00:00
xact->gnode->local_list : xact->gnode->remote_list, xact);
2017-03-27 10:12:45 +00:00
2017-03-30 15:15:13 +00:00
d_trace(1, "[%d]%s Create : xid = 0x%x, type = %d\n",
gnode->port,
2017-03-30 14:27:26 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->xid, xact->type);
2017-03-28 07:35:57 +00:00
return xact;
2017-03-30 00:06:56 +00:00
out2:
pool_free_node(&gtp_xact_pool, xact);
out1:
pkbuf_free(pkbuf);
return NULL;
2017-03-26 15:48:33 +00:00
}
2017-03-29 02:54:18 +00:00
status_t gtp_xact_delete(gtp_xact_t *xact)
2017-03-26 15:48:33 +00:00
{
2017-03-30 00:06:56 +00:00
d_assert(xact, , "Null param");
2017-03-30 14:27:26 +00:00
2017-03-30 15:15:13 +00:00
d_assert(xact->gnode, , "Null param");
d_trace(1, "[%d]%s Delete : xid = 0x%x, type = %d\n",
xact->gnode->port,
2017-03-30 14:27:26 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->xid, xact->type);
2017-03-30 00:06:56 +00:00
d_assert(xact->pkbuf, , "Null param");
2017-03-29 14:23:21 +00:00
pkbuf_free(xact->pkbuf);
2017-03-30 00:06:56 +00:00
d_assert(xact->tm_wait, , "Null param");
2017-03-27 10:12:45 +00:00
tm_delete(xact->tm_wait);
2017-03-30 12:17:05 +00:00
list_remove(xact->org == GTP_LOCAL_ORIGINATOR ? xact->gnode->local_list :
xact->gnode->remote_list, xact);
2017-03-27 10:12:45 +00:00
pool_free_node(&gtp_xact_pool, xact);
2017-03-26 15:48:33 +00:00
return CORE_OK;
}
2017-03-30 00:20:40 +00:00
status_t gtp_xact_associate(gtp_xact_t *xact1, gtp_xact_t *xact2)
{
d_assert(xact1, return CORE_ERROR, "Null param");
d_assert(xact2, return CORE_ERROR, "Null param");
d_assert(xact1->assoc_xact == NULL,
return CORE_ERROR, "Already assocaited");
d_assert(xact2->assoc_xact == NULL,
return CORE_ERROR, "Already assocaited");
xact1->assoc_xact = xact2;
xact2->assoc_xact = xact1;
return CORE_OK;
}
status_t gtp_xact_deassociate(gtp_xact_t *xact1, gtp_xact_t *xact2)
{
d_assert(xact1, return CORE_ERROR, "Null param");
d_assert(xact2, return CORE_ERROR, "Null param");
d_assert(xact1->assoc_xact != NULL,
return CORE_ERROR, "Already deassocaited");
d_assert(xact2->assoc_xact != NULL,
return CORE_ERROR, "Already deassocaited");
xact1->assoc_xact = NULL;
xact2->assoc_xact = NULL;
return CORE_OK;
}
2017-03-29 02:54:18 +00:00
status_t gtp_xact_commit(gtp_xact_t *xact)
2017-03-26 15:48:33 +00:00
{
2017-03-29 12:09:29 +00:00
status_t rv;
net_sock_t *sock = NULL;
gtp_node_t *gnode = NULL;
pkbuf_t *pkbuf = NULL;
2017-03-30 00:06:56 +00:00
d_assert(xact, goto out, "Null param");
2017-03-29 14:19:31 +00:00
2017-03-30 15:15:13 +00:00
sock = xact->sock;
d_assert(sock, goto out, "Null param");
gnode = xact->gnode;
d_assert(gnode, goto out, "Null param");
pkbuf = xact->pkbuf;
d_assert(pkbuf, goto out, "Null param");
d_trace(1, "[%d]%s Commit : xid = 0x%x, type = %d, "
2017-03-30 14:27:26 +00:00
"retry_count = %d\n",
2017-03-30 15:15:13 +00:00
xact->gnode->port,
2017-03-30 14:27:26 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->xid, xact->type, xact->retry_count);
2017-03-30 00:06:56 +00:00
if (xact->retry_count > 0)
2017-03-29 14:19:31 +00:00
{
2017-03-30 13:23:47 +00:00
if (xact->org == GTP_LOCAL_ORIGINATOR)
2017-03-30 00:06:56 +00:00
{
2017-03-30 13:23:47 +00:00
rv = gtp_send(sock, gnode, pkbuf);
if (rv != CORE_OK)
{
d_error("failed to send GTP message");
goto out;
}
2017-03-30 00:06:56 +00:00
}
xact->retry_count--;
d_assert(xact->tm_wait, goto out, "Null param");
tm_start(xact->tm_wait);
2017-03-29 14:19:31 +00:00
}
2017-03-30 00:06:56 +00:00
else
2017-03-29 12:09:29 +00:00
{
2017-03-30 13:23:47 +00:00
if (xact->org == GTP_LOCAL_ORIGINATOR)
{
d_warn("No Response. Give up");
}
2017-03-30 00:06:56 +00:00
gtp_xact_delete(xact);
2017-03-29 12:09:29 +00:00
}
2017-03-26 15:48:33 +00:00
return CORE_OK;
2017-03-30 00:06:56 +00:00
out:
pkbuf_free(pkbuf);
return CORE_ERROR;
2017-03-26 15:48:33 +00:00
}
2017-03-29 02:54:18 +00:00
gtp_xact_t *gtp_xact_find(gtp_node_t *gnode, pkbuf_t *pkbuf)
2017-03-26 15:48:33 +00:00
{
2017-03-27 10:12:45 +00:00
gtpv2c_header_t *h = NULL;
c_uint32_t xid;
2017-03-29 02:54:18 +00:00
gtp_xact_t *xact = NULL;
2017-03-27 10:12:45 +00:00
d_assert(gnode, return NULL, "Null param");
d_assert(pkbuf, return NULL, "Null param");
d_assert(pkbuf->payload, return NULL, "Null param");
h = pkbuf->payload;
switch(h->type)
{
case GTP_CREATE_SESSION_REQUEST_TYPE:
case GTP_MODIFY_BEARER_REQUEST_TYPE:
case GTP_DELETE_SESSION_REQUEST_TYPE:
case GTP_CREATE_BEARER_REQUEST_TYPE:
case GTP_UPDATE_BEARER_REQUEST_TYPE:
case GTP_DELETE_BEARER_REQUEST_TYPE:
case GTP_RELEASE_ACCESS_BEARERS_REQUEST_TYPE:
case GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST_TYPE:
case GTP_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST_TYPE:
2017-03-30 12:17:05 +00:00
xact = list_first(&gnode->initial_list);
2017-03-27 10:12:45 +00:00
break;
case GTP_CREATE_SESSION_RESPONSE_TYPE:
case GTP_MODIFY_BEARER_RESPONSE_TYPE:
case GTP_DELETE_SESSION_RESPONSE_TYPE:
case GTP_CREATE_BEARER_RESPONSE_TYPE:
case GTP_UPDATE_BEARER_RESPONSE_TYPE:
case GTP_DELETE_BEARER_RESPONSE_TYPE:
case GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE:
case GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE_TYPE:
case GTP_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE_TYPE:
2017-03-30 12:17:05 +00:00
xact = list_first(&gnode->triggered_list);
2017-03-27 10:12:45 +00:00
break;
default:
d_error("Not implemented GTPv2 Message Type(%d)", h->type);
return NULL;
}
xid = GTP_SQN_TO_XID(h->sqn);
while(xact)
{
if (xact->xid == xid)
break;
xact = list_next(xact);
}
2017-03-30 14:27:26 +00:00
if (xact)
{
2017-03-30 15:15:13 +00:00
d_trace(1, "[%d]%s Find : xid = 0x%x, type = %d\n",
gnode->port,
2017-03-30 14:27:26 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->xid, xact->type);
}
2017-03-27 10:12:45 +00:00
return xact;
2017-03-26 15:48:33 +00:00
}
2017-03-29 14:19:31 +00:00
gtp_xact_t *gtp_xact_recv(gtp_xact_ctx_t *context,
net_sock_t *sock, gtp_node_t *gnode, pkbuf_t *pkbuf)
{
2017-03-30 13:23:47 +00:00
status_t rv;
2017-03-29 14:19:31 +00:00
gtp_xact_t *xact = NULL;
gtpv2c_header_t *h = NULL;
2017-03-30 00:06:56 +00:00
d_assert(context, goto out, "Null param");
d_assert(sock, goto out, "Null param");
d_assert(gnode, goto out, "Null param");
d_assert(pkbuf, goto out, "Null param");
2017-03-29 14:19:31 +00:00
h = pkbuf->payload;
2017-03-30 00:06:56 +00:00
d_assert(h, goto out, "Null param");
2017-03-30 14:27:26 +00:00
2017-03-29 14:19:31 +00:00
xact = gtp_xact_find(gnode, pkbuf);
if (!xact)
{
2017-03-30 12:26:42 +00:00
xact = gtp_xact_create(context, sock, gnode, GTP_REMOTE_ORIGINATOR,
GTP_SQN_TO_XID(h->sqn), h->type, pkbuf);
2017-03-29 14:19:31 +00:00
}
2017-03-30 15:15:13 +00:00
d_trace(1, "[%d]%s Receive : xid = 0x%x, type = %d\n",
gnode->port,
2017-03-30 14:27:26 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->xid, xact->type);
2017-03-29 14:19:31 +00:00
if (h->teid_presence)
pkbuf_header(pkbuf, -GTPV2C_HEADER_LEN);
else
pkbuf_header(pkbuf, -(GTPV2C_HEADER_LEN-GTPV2C_TEID_LEN));
2017-03-30 13:23:47 +00:00
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return NULL, "Null param");
2017-03-29 14:19:31 +00:00
return xact;
2017-03-30 00:06:56 +00:00
out:
pkbuf_free(pkbuf);
return NULL;
2017-03-29 14:19:31 +00:00
}
2017-03-30 14:27:26 +00:00
gtp_xact_t *gtp_xact_associated_send(gtp_xact_ctx_t *context,
2017-03-30 13:23:47 +00:00
net_sock_t *sock, gtp_node_t *gnode, c_uint8_t type, pkbuf_t *pkbuf,
gtp_xact_t *associated_xact)
2017-03-29 14:19:31 +00:00
{
2017-03-30 00:06:56 +00:00
status_t rv;
2017-03-29 14:19:31 +00:00
gtp_xact_t *xact = NULL;
2017-03-30 13:23:47 +00:00
gtpv2c_header_t *h = NULL;
2017-03-29 14:19:31 +00:00
2017-03-30 00:06:56 +00:00
d_assert(context, goto out, "Null param");
d_assert(sock, goto out, "Null param");
d_assert(gnode, goto out, "Null param");
d_assert(pkbuf, goto out, "Null param");
2017-03-29 14:19:31 +00:00
2017-03-30 12:26:42 +00:00
xact = gtp_xact_create(context, sock, gnode, GTP_LOCAL_ORIGINATOR,
GTP_XACT_NEXT_ID(context->g_xact_id), type, pkbuf);
2017-03-30 00:06:56 +00:00
d_assert(xact, return NULL, "Null param");
2017-03-30 13:23:47 +00:00
pkbuf_header(pkbuf, GTPV2C_HEADER_LEN);
h = pkbuf->payload;
d_assert(h, goto out, "Null param");
h->version = 2;
h->teid_presence = 1;
h->type = xact->type;
h->length = htons(pkbuf->len - 4);
h->sqn = GTP_XID_TO_SQN(xact->xid);
if (associated_xact)
gtp_xact_associate(xact, associated_xact);
2017-03-30 00:06:56 +00:00
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return NULL, "Null param");
2017-03-30 15:15:13 +00:00
d_trace(1, "[%d]%s Send : xid = 0x%x, type = %d\n",
gnode->port,
2017-03-30 14:27:26 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->xid, xact->type);
2017-03-30 00:06:56 +00:00
return xact;
2017-03-29 14:19:31 +00:00
2017-03-30 00:06:56 +00:00
out:
pkbuf_free(pkbuf);
return NULL;
2017-03-29 14:19:31 +00:00
}
2017-03-30 13:23:47 +00:00
gtp_xact_t *gtp_xact_send(gtp_xact_ctx_t *context,
net_sock_t *sock, gtp_node_t *gnode, c_uint8_t type, pkbuf_t *pkbuf)
{
2017-03-30 14:27:26 +00:00
return gtp_xact_associated_send(context, sock, gnode, type, pkbuf, NULL);
2017-03-30 13:23:47 +00:00
}