open5gs/lib/gtp/gtp_xact.c

828 lines
26 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
2017-07-13 01:31:07 +00:00
#include "types.h"
2017-03-26 15:48:33 +00:00
#include "gtp_xact.h"
2017-08-31 05:03:00 +00:00
#include "gtp_message.h"
2017-03-26 15:48:33 +00:00
2017-04-06 08:20:17 +00:00
#define SIZE_OF_GTP_XACT_POOL 32
2017-04-11 14:55:21 +00:00
#define GTP_MIN_XACT_ID 1
2017-04-06 08:20:17 +00:00
#define GTP_MAX_XACT_ID 0x800000
2017-03-26 15:48:33 +00:00
2017-08-31 11:48:15 +00:00
#define GTP_T3_RESPONSE_DURATION 3000 /* 3 seconds */
#define GTP_T3_RESPONSE_RETRY_COUNT 3
#define GTP_T3_DUPLICATED_DURATION \
(GTP_T3_RESPONSE_DURATION * GTP_T3_RESPONSE_RETRY_COUNT) /* 9 seconds */
#define GTP_T3_DUPLICATED_RETRY_COUNT 1
2017-04-01 14:28:22 +00:00
2017-08-31 01:48:14 +00:00
typedef enum {
GTP_XACT_UNKNOWN_STAGE,
GTP_XACT_INITIAL_STAGE,
GTP_XACT_INTERMEDIATE_STAGE,
GTP_XACT_FINAL_STAGE,
} gtp_xact_stage_t;
2017-04-03 11:50:20 +00:00
2017-08-31 05:03:00 +00:00
static int gtp_xact_initialized = 0;
static tm_service_t *g_tm_service = NULL;
2017-08-31 11:48:15 +00:00
static c_uintptr_t g_response_event = 0;
static c_uintptr_t g_duplicated_event = 0;
2017-08-31 05:03:00 +00:00
static c_uint32_t g_xact_id = 0;
index_declare(gtp_xact_pool, gtp_xact_t, SIZE_OF_GTP_XACT_POOL);
2017-03-26 15:48:33 +00:00
2017-08-31 01:48:14 +00:00
static gtp_xact_stage_t gtp_xact_get_stage(c_uint8_t type, c_uint32_t sqn);
2017-08-31 05:03:00 +00:00
static status_t gtp_xact_delete(gtp_xact_t *xact);
2017-08-31 01:48:14 +00:00
2017-08-31 11:48:15 +00:00
status_t gtp_xact_init(tm_service_t *tm_service,
c_uintptr_t response_event, c_uintptr_t duplicated_event)
2017-03-26 15:48:33 +00:00
{
2017-08-31 05:03:00 +00:00
d_assert(gtp_xact_initialized == 0, return CORE_ERROR,
"GTP Transaction already has been initialized");
2017-08-04 09:02:19 +00:00
index_init(&gtp_xact_pool, SIZE_OF_GTP_XACT_POOL);
2017-03-26 15:48:33 +00:00
2017-08-31 05:03:00 +00:00
g_xact_id = 0;
g_tm_service = tm_service;
2017-08-31 11:48:15 +00:00
g_response_event = response_event;
g_duplicated_event = duplicated_event;
2017-03-26 15:48:33 +00:00
2017-08-31 05:03:00 +00:00
gtp_xact_initialized = 1;
2017-03-26 15:48:33 +00:00
return CORE_OK;
}
status_t gtp_xact_final(void)
{
2017-08-31 05:03:00 +00:00
d_assert(gtp_xact_initialized == 1, return CORE_ERROR,
"GTP Transaction context already has been finalized");
2017-08-04 09:02:19 +00:00
if (pool_size(&gtp_xact_pool) != pool_avail(&gtp_xact_pool))
2017-08-11 04:11:13 +00:00
d_error("%d not freed in gtp_xact_pool[%d] of GTP Transaction",
2017-03-30 13:23:47 +00:00
pool_size(&gtp_xact_pool) - pool_avail(&gtp_xact_pool),
pool_size(&gtp_xact_pool));
2017-04-11 13:44:57 +00:00
2017-08-04 09:02:19 +00:00
d_trace(3, "%d not freed in gtp_xact_pool[%d] of GTP Transaction\n",
pool_size(&gtp_xact_pool) - pool_avail(&gtp_xact_pool),
pool_size(&gtp_xact_pool));
index_final(&gtp_xact_pool);
2017-03-26 15:48:33 +00:00
2017-08-31 05:03:00 +00:00
gtp_xact_initialized = 0;
2017-08-31 03:06:11 +00:00
return CORE_OK;
}
2017-08-31 05:03:00 +00:00
gtp_xact_t *gtp_xact_local_create(net_sock_t *sock, gtp_node_t *gnode)
2017-03-26 15:48:33 +00:00
{
2017-07-31 13:35:25 +00:00
char buf[INET_ADDRSTRLEN];
2017-03-29 02:54:18 +00:00
gtp_xact_t *xact = NULL;
2017-03-27 10:12:45 +00:00
2017-04-01 14:13:15 +00:00
d_assert(sock, return NULL, "Null param");
d_assert(gnode, return NULL, "Null param");
2017-03-27 10:12:45 +00:00
index_alloc(&gtp_xact_pool, &xact);
2017-04-01 14:13:15 +00:00
d_assert(xact, return NULL, "Transaction allocation failed");
2017-03-30 00:06:56 +00:00
2017-08-31 03:06:11 +00:00
xact->org = GTP_LOCAL_ORIGINATOR;
2017-08-31 05:03:00 +00:00
xact->xid = NEXT_ID(g_xact_id, GTP_MIN_XACT_ID, GTP_MAX_XACT_ID);
2017-03-28 07:35:57 +00:00
xact->sock = sock;
xact->gnode = gnode;
2017-03-27 10:12:45 +00:00
2017-08-31 11:48:15 +00:00
if (g_response_event)
{
xact->tm_response = event_timer(g_tm_service,
g_response_event, GTP_T3_RESPONSE_DURATION, xact->index);
d_assert(xact->tm_response, return NULL, "Timer allocation failed");
xact->response_rcount = GTP_T3_RESPONSE_RETRY_COUNT;
}
if (g_duplicated_event)
{
xact->tm_duplicated = event_timer(g_tm_service,
g_duplicated_event, GTP_T3_DUPLICATED_DURATION, xact->index);
d_assert(xact->tm_duplicated, return NULL, "Timer allocation failed");
xact->duplicated_rcount = GTP_T3_DUPLICATED_RETRY_COUNT;
}
2017-03-30 00:20:40 +00:00
list_append(xact->org == GTP_LOCAL_ORIGINATOR ?
2017-04-03 06:31:57 +00:00
&xact->gnode->local_list : &xact->gnode->remote_list, xact);
2017-03-27 10:12:45 +00:00
2017-08-01 01:16:06 +00:00
d_trace(3, "[%d] %s Create peer %s:%d\n",
xact->xid,
2017-03-30 14:27:26 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-01 01:16:06 +00:00
INET_NTOP(&gnode->addr, buf), gnode->port);
2017-03-30 14:27:26 +00:00
2017-03-28 07:35:57 +00:00
return xact;
2017-03-26 15:48:33 +00:00
}
2017-08-31 05:03:00 +00:00
gtp_xact_t *gtp_xact_remote_create(
2017-08-31 11:48:15 +00:00
net_sock_t *sock, gtp_node_t *gnode, c_uint32_t sqn)
2017-03-26 15:48:33 +00:00
{
2017-07-31 13:35:25 +00:00
char buf[INET_ADDRSTRLEN];
2017-08-31 03:06:11 +00:00
gtp_xact_t *xact = NULL;
2017-07-31 13:35:25 +00:00
2017-08-31 03:06:11 +00:00
d_assert(sock, return NULL, "Null param");
d_assert(gnode, return NULL, "Null param");
2017-04-03 14:40:22 +00:00
2017-08-31 03:06:11 +00:00
index_alloc(&gtp_xact_pool, &xact);
d_assert(xact, return NULL, "Transaction allocation failed");
2017-04-03 14:40:22 +00:00
2017-08-31 03:06:11 +00:00
xact->org = GTP_REMOTE_ORIGINATOR;
xact->xid = GTP_SQN_TO_XID(sqn);
xact->sock = sock;
xact->gnode = gnode;
2017-04-03 14:40:22 +00:00
2017-08-31 11:48:15 +00:00
if (g_response_event)
2017-08-31 05:03:00 +00:00
{
2017-08-31 11:48:15 +00:00
xact->tm_response = event_timer(g_tm_service,
g_response_event, GTP_T3_RESPONSE_DURATION, xact->index);
d_assert(xact->tm_response, return NULL, "Timer allocation failed");
xact->response_rcount = GTP_T3_RESPONSE_RETRY_COUNT;
}
if (g_duplicated_event)
{
xact->tm_duplicated = event_timer(g_tm_service,
g_duplicated_event, GTP_T3_DUPLICATED_DURATION, xact->index);
d_assert(xact->tm_duplicated, return NULL, "Timer allocation failed");
xact->duplicated_rcount = GTP_T3_DUPLICATED_RETRY_COUNT;
2017-08-31 05:03:00 +00:00
}
2017-04-03 14:40:22 +00:00
2017-08-31 03:06:11 +00:00
list_append(xact->org == GTP_LOCAL_ORIGINATOR ?
&xact->gnode->local_list : &xact->gnode->remote_list, xact);
2017-04-03 13:46:19 +00:00
2017-08-31 03:06:11 +00:00
d_trace(3, "[%d] %s Create peer %s:%d\n",
xact->xid,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
INET_NTOP(&gnode->addr, buf), gnode->port);
2017-04-03 13:46:19 +00:00
2017-08-31 03:06:11 +00:00
return xact;
2017-04-03 13:46:19 +00:00
}
2017-04-11 13:44:57 +00:00
void gtp_xact_delete_all(gtp_node_t *gnode)
{
gtp_xact_t *xact = NULL;
xact = list_first(&gnode->local_list);
while(xact)
{
gtp_xact_delete(xact);
xact = list_next(xact);
}
xact = list_first(&gnode->remote_list);
while(xact)
{
gtp_xact_delete(xact);
xact = list_next(xact);
}
}
2017-08-31 05:03:00 +00:00
status_t gtp_xact_update_tx(gtp_xact_t *xact,
2017-08-31 11:48:15 +00:00
c_uint8_t type, c_uint32_t teid, pkbuf_t *pkbuf)
2017-03-26 15:48:33 +00:00
{
2017-07-31 13:35:25 +00:00
char buf[INET_ADDRSTRLEN];
2017-08-31 11:48:15 +00:00
gtp_xact_stage_t stage;
2017-08-31 01:48:14 +00:00
gtp_header_t *h = NULL;
2017-04-03 05:18:25 +00:00
2017-08-31 05:03:00 +00:00
d_assert(xact, return CORE_ERROR, "Null param");
d_assert(xact->sock, return CORE_ERROR, "Null param");
d_assert(xact->gnode, return CORE_ERROR, "Null param");
d_assert(pkbuf, return CORE_ERROR, "Null param");
2017-03-29 14:19:31 +00:00
2017-08-31 15:29:56 +00:00
d_trace(3, "[%d] %s UPD TX-%d peer %s:%d\n",
2017-08-01 01:16:06 +00:00
xact->xid,
2017-04-01 14:13:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:29:56 +00:00
type,
2017-08-01 01:16:06 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
2017-04-01 14:13:15 +00:00
2017-08-31 11:48:15 +00:00
stage = gtp_xact_get_stage(type, xact->xid);
if (xact->org == GTP_LOCAL_ORIGINATOR)
{
switch(stage)
{
case GTP_XACT_INITIAL_STAGE:
d_assert(xact->step == 0, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 11:48:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
break;
2017-08-31 15:29:56 +00:00
2017-08-31 11:48:15 +00:00
case GTP_XACT_INTERMEDIATE_STAGE:
2017-08-31 15:29:56 +00:00
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 11:48:15 +00:00
case GTP_XACT_FINAL_STAGE:
d_assert(xact->step == 2, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 11:48:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
break;
2017-08-31 15:29:56 +00:00
2017-08-31 11:48:15 +00:00
default:
2017-08-31 15:29:56 +00:00
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 11:48:15 +00:00
}
}
else if (xact->org == GTP_REMOTE_ORIGINATOR)
{
switch(stage)
{
case GTP_XACT_INITIAL_STAGE:
2017-08-31 15:29:56 +00:00
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 11:48:15 +00:00
case GTP_XACT_INTERMEDIATE_STAGE:
case GTP_XACT_FINAL_STAGE:
d_assert(xact->step == 1, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 11:48:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
break;
2017-08-31 15:29:56 +00:00
2017-08-31 11:48:15 +00:00
default:
2017-08-31 15:29:56 +00:00
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 11:48:15 +00:00
}
}
else
d_assert(0, return CORE_ERROR, "invalid orginator(%d)", xact->org);
2017-04-03 05:18:25 +00:00
pkbuf_header(pkbuf, GTPV2C_HEADER_LEN);
h = pkbuf->payload;
2017-08-31 05:03:00 +00:00
d_assert(h, return CORE_ERROR, "Null param");
2017-04-03 05:18:25 +00:00
2017-08-31 01:48:14 +00:00
memset(h, 0, sizeof(gtp_header_t));
2017-04-03 05:18:25 +00:00
h->version = 2;
h->teid_presence = 1;
2017-04-03 13:09:48 +00:00
h->type = type;
2017-04-03 05:18:25 +00:00
h->length = htons(pkbuf->len - 4);
2017-04-06 03:23:07 +00:00
h->teid = htonl(teid);
2017-04-03 05:18:25 +00:00
h->sqn = GTP_XID_TO_SQN(xact->xid);
2017-08-31 11:48:15 +00:00
/* Save Message type and packet of this step */
xact->seq[xact->step].type = h->type;
xact->seq[xact->step].pkbuf = pkbuf;
2017-04-01 14:13:15 +00:00
2017-08-31 11:48:15 +00:00
/* Step */
xact->step++;
2017-04-03 14:12:59 +00:00
2017-04-01 14:13:15 +00:00
return CORE_OK;
2017-08-31 05:03:00 +00:00
}
2017-04-03 05:18:25 +00:00
2017-08-31 11:48:15 +00:00
status_t gtp_xact_update_rx(gtp_xact_t *xact, c_uint8_t type)
2017-08-31 05:03:00 +00:00
{
2017-08-31 11:48:15 +00:00
status_t rv = CORE_OK;
2017-08-31 05:03:00 +00:00
char buf[INET_ADDRSTRLEN];
2017-08-31 11:48:15 +00:00
gtp_xact_stage_t stage;
2017-08-31 05:03:00 +00:00
2017-08-31 15:29:56 +00:00
d_trace(3, "[%d] %s UPD RX-%d peer %s:%d\n",
2017-08-31 05:03:00 +00:00
xact->xid,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:29:56 +00:00
type,
2017-08-31 05:03:00 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
2017-08-31 11:48:15 +00:00
stage = gtp_xact_get_stage(type, xact->xid);
if (xact->org == GTP_LOCAL_ORIGINATOR)
2017-08-31 05:03:00 +00:00
{
2017-08-31 11:48:15 +00:00
switch(stage)
2017-08-31 05:03:00 +00:00
{
2017-08-31 11:48:15 +00:00
case GTP_XACT_INITIAL_STAGE:
2017-08-31 15:29:56 +00:00
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 11:48:15 +00:00
case GTP_XACT_INTERMEDIATE_STAGE:
if (xact->seq[1].type == type)
{
pkbuf_t *pkbuf = NULL;
d_assert(xact->step == 3, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 11:48:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
pkbuf = xact->seq[2].pkbuf;
if (pkbuf)
{
if (xact->tm_duplicated)
tm_start(xact->tm_duplicated);
d_warn("[%d]%s Request Duplicated. Retransmit!",
xact->gnode->port,
xact->org == GTP_LOCAL_ORIGINATOR ?
"LOCAL " : "REMOTE");
rv = gtp_send(xact->sock, xact->gnode, pkbuf);
d_assert(rv == CORE_OK, return CORE_ERROR,
"gtp_send error");
}
else
{
d_warn("[%d]%s Request Duplicated. Discard!",
xact->gnode->port,
xact->org == GTP_LOCAL_ORIGINATOR ?
"LOCAL " : "REMOTE");
}
return CORE_EAGAIN;
}
d_assert(xact->step == 1, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 11:48:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
if (xact->tm_duplicated)
tm_start(xact->tm_duplicated);
break;
case GTP_XACT_FINAL_STAGE:
d_assert(xact->step == 1, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
2017-08-31 11:48:15 +00:00
xact->xid,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
break;
default:
2017-08-31 15:29:56 +00:00
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 05:03:00 +00:00
}
2017-08-31 11:48:15 +00:00
}
else if (xact->org == GTP_REMOTE_ORIGINATOR)
{
switch(stage)
2017-08-31 05:03:00 +00:00
{
2017-08-31 11:48:15 +00:00
case GTP_XACT_INITIAL_STAGE:
if (xact->seq[0].type == type)
{
pkbuf_t *pkbuf = NULL;
d_assert(xact->step == 2, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 11:48:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
pkbuf = xact->seq[1].pkbuf;
if (pkbuf)
{
if (xact->tm_duplicated)
tm_start(xact->tm_duplicated);
d_warn("[%d]%s Request Duplicated. Retransmit!",
xact->gnode->port,
xact->org == GTP_LOCAL_ORIGINATOR ?
"LOCAL " : "REMOTE");
rv = gtp_send(xact->sock, xact->gnode, pkbuf);
d_assert(rv == CORE_OK, return CORE_ERROR,
"gtp_send error");
}
else
{
d_warn("[%d]%s Request Duplicated. Discard!",
xact->gnode->port,
xact->org == GTP_LOCAL_ORIGINATOR ?
"LOCAL " : "REMOTE");
}
return CORE_EAGAIN;
}
d_assert(xact->step == 0, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 11:48:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
if (xact->tm_duplicated)
tm_start(xact->tm_duplicated);
break;
case GTP_XACT_INTERMEDIATE_STAGE:
2017-08-31 15:29:56 +00:00
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 11:48:15 +00:00
case GTP_XACT_FINAL_STAGE:
d_assert(xact->step == 2, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 11:48:15 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 11:48:15 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
/* continue */
break;
default:
2017-08-31 15:29:56 +00:00
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 05:03:00 +00:00
}
}
2017-08-31 11:48:15 +00:00
else
d_assert(0, return CORE_ERROR, "invalid orginator(%d)", xact->org);
2017-08-31 05:03:00 +00:00
2017-08-31 15:29:56 +00:00
if (xact->tm_response)
tm_stop(xact->tm_response);
2017-08-31 11:48:15 +00:00
/* Save Message type of this step */
xact->seq[xact->step].type = type;
/* Step */
xact->step++;
2017-08-31 05:03:00 +00:00
return CORE_OK;
}
status_t gtp_xact_commit(gtp_xact_t *xact)
{
2017-08-31 15:29:56 +00:00
status_t rv;
2017-08-31 05:03:00 +00:00
char buf[INET_ADDRSTRLEN];
2017-08-31 15:29:56 +00:00
2017-08-31 11:48:15 +00:00
c_uint8_t type;
2017-08-31 15:29:56 +00:00
pkbuf_t *pkbuf = NULL;
gtp_xact_stage_t stage;
2017-08-31 05:03:00 +00:00
d_assert(xact, return CORE_ERROR, "Null param");
d_assert(xact->sock, return CORE_ERROR, "Null param");
d_assert(xact->gnode, return CORE_ERROR, "Null param");
d_trace(3, "[%d] %s Commit peer %s:%d\n",
xact->xid,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
2017-08-31 15:29:56 +00:00
type = xact->seq[xact->step-1].type;
stage = gtp_xact_get_stage(type, xact->xid);
2017-08-31 05:03:00 +00:00
if (xact->org == GTP_LOCAL_ORIGINATOR)
{
2017-08-31 15:29:56 +00:00
switch(stage)
2017-08-31 05:03:00 +00:00
{
2017-08-31 15:29:56 +00:00
case GTP_XACT_INITIAL_STAGE:
{
d_assert(xact->step == 1, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 15:29:56 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 15:29:56 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
if (xact->tm_response)
tm_start(xact->tm_response);
break;
}
case GTP_XACT_INTERMEDIATE_STAGE:
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
case GTP_XACT_FINAL_STAGE:
2017-08-31 15:46:07 +00:00
d_assert(xact->step == 2 || xact->step == 3, return CORE_ERROR,
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 15:29:56 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 15:29:56 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
if (xact->step == 2)
{
gtp_xact_delete(xact);
return CORE_OK;
}
break;
default:
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
2017-08-31 05:03:00 +00:00
}
}
2017-08-31 15:29:56 +00:00
else if (xact->org == GTP_REMOTE_ORIGINATOR)
{
switch(stage)
{
case GTP_XACT_INITIAL_STAGE:
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
case GTP_XACT_INTERMEDIATE_STAGE:
d_assert(xact->step == 2, return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 15:29:56 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 15:29:56 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
if (xact->tm_response)
tm_start(xact->tm_response);
break;
case GTP_XACT_FINAL_STAGE:
d_assert(xact->step == 2 || xact->step == 3,
return CORE_ERROR,
2017-08-31 15:46:07 +00:00
"[%d] %s invalid step %d for type %d peer %s:%d\n",
xact->xid,
2017-08-31 15:29:56 +00:00
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-31 15:46:07 +00:00
xact->step, type,
2017-08-31 15:29:56 +00:00
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
if (xact->step == 3)
{
gtp_xact_delete(xact);
return CORE_OK;
}
break;
default:
d_assert(0, return CORE_ERROR, "invalid step(%d)", xact->step);
}
}
else
d_assert(0, return CORE_ERROR, "invalid orginator(%d)", xact->org);
2017-08-31 05:03:00 +00:00
2017-08-31 11:48:15 +00:00
pkbuf = xact->seq[xact->step-1].pkbuf;
d_assert(pkbuf, return CORE_ERROR, "Null param");
2017-08-31 15:29:56 +00:00
rv = gtp_send(xact->sock, xact->gnode, pkbuf);
d_assert(rv == CORE_OK, return CORE_ERROR, "gtp_send error");
2017-08-31 05:03:00 +00:00
return CORE_OK;
2017-04-01 14:13:15 +00:00
}
2017-03-30 15:15:13 +00:00
2017-08-31 11:48:15 +00:00
status_t gtp_xact_timeout(index_t index, c_uintptr_t event)
2017-04-01 14:13:15 +00:00
{
2017-07-31 13:35:25 +00:00
char buf[INET_ADDRSTRLEN];
2017-04-10 14:59:59 +00:00
gtp_xact_t *xact = NULL;
d_assert(index, goto out, "Invalid Index");
xact = index_find(&gtp_xact_pool, index);
2017-04-01 14:13:15 +00:00
d_assert(xact, goto out, "Null param");
d_assert(xact->sock, goto out, "Null param");
d_assert(xact->gnode, goto out, "Null param");
2017-08-31 11:48:15 +00:00
if (event == g_response_event)
2017-03-29 12:09:29 +00:00
{
2017-08-31 15:29:56 +00:00
d_trace(3, "[%d] %s Response Timeout peer %s:%d\n",
xact->xid,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
2017-08-31 11:48:15 +00:00
if (--xact->response_rcount > 0)
2017-04-01 14:28:22 +00:00
{
2017-08-31 11:48:15 +00:00
pkbuf_t *pkbuf = NULL;
if (xact->tm_response)
tm_start(xact->tm_response);
pkbuf = xact->seq[xact->step-1].pkbuf;
d_assert(pkbuf, return CORE_ERROR, "Null param");
2017-04-01 14:28:22 +00:00
2017-08-31 11:48:15 +00:00
d_assert(gtp_send(xact->sock, xact->gnode, pkbuf) == CORE_OK,
2017-04-01 14:28:22 +00:00
goto out, "gtp_send error");
}
else
{
d_warn("[%d]%s No Reponse. Give up",
xact->gnode->port,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE");
gtp_xact_delete(xact);
}
2017-03-29 12:09:29 +00:00
}
2017-08-31 11:48:15 +00:00
else if (event == g_duplicated_event)
2017-04-03 04:06:56 +00:00
{
2017-08-31 15:29:56 +00:00
d_trace(3, "[%d] %s Duplicated Timeout peer %s:%d\n",
xact->xid,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
2017-08-31 11:48:15 +00:00
if (--xact->duplicated_rcount > 0)
{
if (xact->tm_duplicated)
tm_start(xact->tm_duplicated);
}
else
{
gtp_xact_delete(xact);
}
2017-04-03 04:06:56 +00:00
}
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:
2017-04-01 14:13:15 +00:00
gtp_xact_delete(xact);
2017-03-30 00:06:56 +00:00
return CORE_ERROR;
2017-03-26 15:48:33 +00:00
}
2017-08-31 05:03:00 +00:00
status_t gtp_xact_receive(
2017-08-31 03:06:11 +00:00
net_sock_t *sock, gtp_node_t *gnode, pkbuf_t *pkbuf,
gtp_xact_t **xact, gtp_message_t *message)
2017-03-29 14:19:31 +00:00
{
2017-07-31 13:35:25 +00:00
char buf[INET_ADDRSTRLEN];
2017-04-03 13:46:19 +00:00
status_t rv;
2017-04-06 03:13:38 +00:00
gtp_xact_t *new = NULL;
2017-08-31 03:06:11 +00:00
gtp_header_t *h = NULL;
2017-03-29 14:19:31 +00:00
2017-08-31 03:06:11 +00:00
d_assert(sock, return CORE_ERROR, "Null param");
d_assert(gnode, return CORE_ERROR, "Null param");
2017-04-06 03:13:38 +00:00
d_assert(pkbuf, return CORE_ERROR, "Null param");
2017-08-31 03:06:11 +00:00
d_assert(pkbuf->payload, return CORE_ERROR, "Null param");
2017-03-29 14:19:31 +00:00
h = pkbuf->payload;
2017-08-31 03:06:11 +00:00
d_assert(h, return CORE_ERROR, "Null param");
2017-03-30 14:27:26 +00:00
2017-08-31 05:03:00 +00:00
new = gtp_xact_find_by_xid(gnode, h->type, GTP_SQN_TO_XID(h->sqn));
2017-04-06 03:13:38 +00:00
if (!new)
2017-03-29 14:19:31 +00:00
{
2017-08-31 05:03:00 +00:00
new = gtp_xact_remote_create(sock, gnode, h->sqn);
2017-03-29 14:19:31 +00:00
}
2017-08-31 03:06:11 +00:00
d_assert(new, return CORE_ERROR, "Null param");
2017-04-03 06:48:43 +00:00
2017-08-01 01:16:06 +00:00
d_trace(3, "[%d] %s Receive peer %s:%d\n",
new->xid,
2017-04-06 03:13:38 +00:00
new->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
2017-08-01 01:16:06 +00:00
INET_NTOP(&gnode->addr, buf), gnode->port);
2017-04-03 13:46:19 +00:00
2017-08-31 11:48:15 +00:00
rv = gtp_xact_update_rx(new, h->type);
2017-08-31 05:03:00 +00:00
if (rv != CORE_OK)
2017-04-03 06:48:43 +00:00
{
2017-08-31 05:03:00 +00:00
pkbuf_free(pkbuf);
return rv;
2017-04-03 06:48:43 +00:00
}
2017-03-29 14:19:31 +00:00
2017-08-31 03:06:11 +00:00
rv = gtp_parse_msg(message, pkbuf);
2017-04-03 13:48:37 +00:00
d_assert(rv == CORE_OK,
pkbuf_free(pkbuf); return CORE_ERROR, "parse error");
2017-04-03 13:46:19 +00:00
2017-04-06 03:13:38 +00:00
*xact = new;
return CORE_OK;
2017-04-03 13:46:19 +00:00
}
gtp_xact_t *gtp_xact_find(index_t index)
{
d_assert(index, return NULL, "Invalid Index");
return index_find(&gtp_xact_pool, index);
}
2017-08-31 05:03:00 +00:00
static gtp_xact_stage_t gtp_xact_get_stage(c_uint8_t type, c_uint32_t xid)
2017-08-31 01:48:14 +00:00
{
gtp_xact_stage_t stage = GTP_XACT_UNKNOWN_STAGE;
switch(type)
{
case GTP_CREATE_SESSION_REQUEST_TYPE:
case GTP_MODIFY_BEARER_REQUEST_TYPE:
case GTP_DELETE_SESSION_REQUEST_TYPE:
case GTP_MODIFY_BEARER_COMMAND_TYPE:
case GTP_DELETE_BEARER_COMMAND_TYPE:
case GTP_BEARER_RESOURCE_COMMAND_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:
case GTP_DOWNLINK_DATA_NOTIFICATION_TYPE:
stage = GTP_XACT_INITIAL_STAGE;
break;
case GTP_CREATE_BEARER_REQUEST_TYPE:
case GTP_UPDATE_BEARER_REQUEST_TYPE:
case GTP_DELETE_BEARER_REQUEST_TYPE:
2017-08-31 05:03:00 +00:00
if (xid & GTP_MAX_XACT_ID)
2017-08-31 01:48:14 +00:00
stage = GTP_XACT_INTERMEDIATE_STAGE;
else
stage = GTP_XACT_INITIAL_STAGE;
break;
case GTP_CREATE_SESSION_RESPONSE_TYPE:
case GTP_MODIFY_BEARER_RESPONSE_TYPE:
case GTP_DELETE_SESSION_RESPONSE_TYPE:
case GTP_MODIFY_BEARER_FAILURE_INDICATION_TYPE:
case GTP_DELETE_BEARER_FAILURE_INDICATION_TYPE:
case GTP_BEARER_RESOURCE_FAILURE_INDICATION_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:
case GTP_DOWNLINK_DATA_NOTIFICATION_ACKNOWLEDGE_TYPE:
stage = GTP_XACT_FINAL_STAGE;
break;
default:
d_error("Not implemented GTPv2 Message Type(%d)", type);
break;
}
return stage;
}
2017-08-31 03:06:11 +00:00
2017-08-31 05:03:00 +00:00
gtp_xact_t *gtp_xact_find_by_xid(
gtp_node_t *gnode, c_uint8_t type, c_uint32_t xid)
{
char buf[INET_ADDRSTRLEN];
gtp_xact_t *xact = NULL;
d_assert(gnode, return NULL, "Null param");
switch(gtp_xact_get_stage(type, xid))
{
case GTP_XACT_INITIAL_STAGE:
xact = list_first(&gnode->remote_list);
break;
case GTP_XACT_INTERMEDIATE_STAGE:
xact = list_first(&gnode->local_list);
break;
case GTP_XACT_FINAL_STAGE:
if (xid & GTP_MAX_XACT_ID)
xact = list_first(&gnode->remote_list);
else
xact = list_first(&gnode->local_list);
break;
default:
d_assert(0, return NULL, "Unknown stage");
}
while(xact)
{
if (xact->xid == xid)
break;
xact = list_next(xact);
}
if (xact)
{
d_trace(3, "[%d] %s Find peer %s:%d\n",
xact->xid,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
INET_NTOP(&gnode->addr, buf), gnode->port);
}
return xact;
}
2017-08-31 03:06:11 +00:00
void gtp_xact_associate(gtp_xact_t *xact1, gtp_xact_t *xact2)
{
d_assert(xact1, return, "Null param");
d_assert(xact2, return, "Null param");
d_assert(xact1->assoc_xact == NULL, return, "Already assocaited");
d_assert(xact2->assoc_xact == NULL, return, "Already assocaited");
xact1->assoc_xact = xact2;
xact2->assoc_xact = xact1;
}
void gtp_xact_deassociate(gtp_xact_t *xact1, gtp_xact_t *xact2)
{
d_assert(xact1, return, "Null param");
d_assert(xact2, return, "Null param");
d_assert(xact1->assoc_xact != NULL, return, "Already deassocaited");
d_assert(xact2->assoc_xact != NULL, return, "Already deassocaited");
xact1->assoc_xact = NULL;
xact2->assoc_xact = NULL;
}
2017-08-31 05:03:00 +00:00
static status_t gtp_xact_delete(gtp_xact_t *xact)
{
char buf[INET_ADDRSTRLEN];
d_assert(xact, , "Null param");
d_assert(xact->gnode, , "Null param");
d_trace(3, "[%d] %s Delete peer %s:%d\n",
xact->xid,
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
INET_NTOP(&xact->gnode->addr, buf), xact->gnode->port);
2017-08-31 11:48:15 +00:00
if (xact->seq[0].pkbuf)
pkbuf_free(xact->seq[0].pkbuf);
if (xact->seq[1].pkbuf)
pkbuf_free(xact->seq[1].pkbuf);
if (xact->seq[2].pkbuf)
pkbuf_free(xact->seq[2].pkbuf);
if (xact->tm_response)
tm_delete(xact->tm_response);
if (xact->tm_duplicated)
tm_delete(xact->tm_duplicated);
2017-08-31 05:03:00 +00:00
if (xact->assoc_xact)
gtp_xact_deassociate(xact, xact->assoc_xact);
list_remove(xact->org == GTP_LOCAL_ORIGINATOR ? &xact->gnode->local_list :
&xact->gnode->remote_list, xact);
index_free(&gtp_xact_pool, xact);
return CORE_OK;
}