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-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-04-06 08:20:17 +00:00
|
|
|
#define GTP_XACT_LOCAL_DURATION 3000 /* 3 seconds */
|
|
|
|
#define GTP_XACT_LOCAL_RETRY_COUNT 3
|
2017-04-01 14:28:22 +00:00
|
|
|
#define GTP_XACT_REMOTE_DURATION \
|
|
|
|
(GTP_XACT_LOCAL_DURATION * GTP_XACT_LOCAL_RETRY_COUNT) /* 9 seconds */
|
|
|
|
#define GTP_XACT_REMOTE_RETRY_COUNT 1
|
|
|
|
|
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-04-10 13:48:07 +00:00
|
|
|
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-04-01 14:28:22 +00:00
|
|
|
status_t gtp_xact_init(gtp_xact_ctx_t *context,
|
|
|
|
tm_service_t *tm_service, c_uintptr_t event)
|
2017-03-26 15:48:33 +00:00
|
|
|
{
|
2017-08-04 09:02:19 +00:00
|
|
|
index_init(>p_xact_pool, SIZE_OF_GTP_XACT_POOL);
|
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-04-01 14:13:15 +00:00
|
|
|
context->g_xact_id = 0;
|
2017-03-28 07:35:57 +00:00
|
|
|
|
|
|
|
context->tm_service = tm_service;
|
|
|
|
context->event = event;;
|
2017-03-26 15:48:33 +00:00
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t gtp_xact_final(void)
|
|
|
|
{
|
2017-08-04 09:02:19 +00:00
|
|
|
if (pool_size(>p_xact_pool) != pool_avail(>p_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(>p_xact_pool) - pool_avail(>p_xact_pool),
|
|
|
|
pool_size(>p_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(>p_xact_pool) - pool_avail(>p_xact_pool),
|
|
|
|
pool_size(>p_xact_pool));
|
|
|
|
index_final(>p_xact_pool);
|
2017-03-26 15:48:33 +00:00
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-04-03 13:46:19 +00:00
|
|
|
static 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,
|
2017-04-02 11:53:59 +00:00
|
|
|
c_uint32_t duration, c_uint8_t retry_count)
|
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(context, return NULL, "Null param");
|
|
|
|
d_assert(sock, return NULL, "Null param");
|
|
|
|
d_assert(gnode, return NULL, "Null param");
|
2017-03-27 10:12:45 +00:00
|
|
|
|
2017-04-10 13:48:07 +00:00
|
|
|
index_alloc(>p_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-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-27 10:12:45 +00:00
|
|
|
|
2017-03-28 07:35:57 +00:00
|
|
|
xact->tm_wait = event_timer(context->tm_service, context->event,
|
2017-04-10 13:48:07 +00:00
|
|
|
duration, xact->index);
|
2017-04-01 14:13:15 +00:00
|
|
|
d_assert(xact->tm_wait,
|
2017-04-10 13:48:07 +00:00
|
|
|
index_free(>p_xact_pool, xact); return NULL,
|
2017-04-01 14:13:15 +00:00
|
|
|
"Timer allocation failed");
|
2017-03-30 13:23:47 +00:00
|
|
|
xact->retry_count = retry_count;
|
2017-04-01 14:13:15 +00:00
|
|
|
tm_start(xact->tm_wait);
|
2017-03-27 10:12:45 +00:00
|
|
|
|
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-04-03 13:46:19 +00:00
|
|
|
static status_t gtp_xact_delete(gtp_xact_t *xact)
|
2017-03-26 15:48:33 +00:00
|
|
|
{
|
2017-07-31 13:35:25 +00:00
|
|
|
char buf[INET_ADDRSTRLEN];
|
|
|
|
|
2017-03-30 00:06:56 +00:00
|
|
|
d_assert(xact, , "Null param");
|
2017-03-30 15:15:13 +00:00
|
|
|
d_assert(xact->gnode, , "Null param");
|
2017-04-01 14:13:15 +00:00
|
|
|
d_assert(xact->tm_wait, , "Null param");
|
2017-03-30 15:15:13 +00:00
|
|
|
|
2017-08-01 01:16:06 +00:00
|
|
|
d_trace(3, "[%d] %s Delete 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(&xact->gnode->addr, buf), xact->gnode->port);
|
2017-03-30 14:27:26 +00:00
|
|
|
|
2017-04-01 14:13:15 +00:00
|
|
|
if (xact->pkbuf)
|
|
|
|
pkbuf_free(xact->pkbuf);
|
2017-03-29 14:23:21 +00:00
|
|
|
|
2017-03-27 10:12:45 +00:00
|
|
|
tm_delete(xact->tm_wait);
|
|
|
|
|
2017-04-03 06:31:57 +00:00
|
|
|
list_remove(xact->org == GTP_LOCAL_ORIGINATOR ? &xact->gnode->local_list :
|
|
|
|
&xact->gnode->remote_list, xact);
|
2017-04-10 13:48:07 +00:00
|
|
|
index_free(>p_xact_pool, xact);
|
2017-03-27 10:12:45 +00:00
|
|
|
|
2017-03-26 15:48:33 +00:00
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-04-03 14:40:22 +00:00
|
|
|
static 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static 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-04-03 13:46:19 +00:00
|
|
|
|
|
|
|
gtp_xact_t *gtp_xact_local_create(
|
|
|
|
gtp_xact_ctx_t *context, net_sock_t *sock, gtp_node_t *gnode)
|
|
|
|
{
|
|
|
|
return gtp_xact_create(context, sock, gnode, GTP_LOCAL_ORIGINATOR,
|
2017-04-11 14:55:21 +00:00
|
|
|
NEXT_ID(context->g_xact_id, GTP_MIN_XACT_ID, GTP_MAX_XACT_ID),
|
2017-04-03 13:46:19 +00:00
|
|
|
GTP_XACT_LOCAL_DURATION, GTP_XACT_LOCAL_RETRY_COUNT);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtp_xact_t *gtp_xact_remote_create(gtp_xact_ctx_t *context,
|
|
|
|
net_sock_t *sock, gtp_node_t *gnode, c_uint32_t sqn)
|
|
|
|
{
|
|
|
|
return gtp_xact_create(context, sock, gnode,
|
|
|
|
GTP_REMOTE_ORIGINATOR, GTP_SQN_TO_XID(sqn),
|
|
|
|
GTP_XACT_REMOTE_DURATION, GTP_XACT_REMOTE_RETRY_COUNT);
|
|
|
|
}
|
|
|
|
|
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-04-06 03:23:07 +00:00
|
|
|
status_t gtp_xact_commit(gtp_xact_t *xact,
|
|
|
|
c_uint8_t type, c_uint32_t teid, pkbuf_t *pkbuf)
|
2017-04-03 14:12:59 +00:00
|
|
|
{
|
2017-04-06 03:23:07 +00:00
|
|
|
return gtp_xact_associated_commit(xact, NULL, type, teid, pkbuf);
|
2017-04-03 14:12:59 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 00:57:56 +00:00
|
|
|
status_t gtp_xact_associated_commit(gtp_xact_t *xact,
|
2017-04-06 03:23:07 +00:00
|
|
|
gtp_xact_t *assoc_xact, 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 01:48:14 +00:00
|
|
|
gtp_header_t *h = NULL;
|
2017-04-03 05:18:25 +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-04-06 00:57:56 +00:00
|
|
|
d_assert(pkbuf, goto out, "Null param");
|
2017-03-29 14:19:31 +00:00
|
|
|
|
2017-08-01 01:16:06 +00:00
|
|
|
d_trace(3, "[%d] %s Commit peer %s:%d\n",
|
|
|
|
xact->xid,
|
2017-04-01 14:13:15 +00:00
|
|
|
xact->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
|
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-04-03 12:13:52 +00:00
|
|
|
xact->pkbuf = pkbuf;
|
2017-04-03 05:18:25 +00:00
|
|
|
|
|
|
|
pkbuf_header(pkbuf, GTPV2C_HEADER_LEN);
|
|
|
|
h = pkbuf->payload;
|
|
|
|
d_assert(h, goto out, "Null param");
|
|
|
|
|
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-04-01 14:13:15 +00:00
|
|
|
d_assert(gtp_send(xact->sock, xact->gnode, xact->pkbuf) == CORE_OK,
|
2017-04-03 05:18:25 +00:00
|
|
|
goto out, "gtp_send error");
|
2017-04-01 14:13:15 +00:00
|
|
|
|
2017-04-03 14:12:59 +00:00
|
|
|
if (assoc_xact)
|
2017-04-03 14:40:22 +00:00
|
|
|
gtp_xact_associate(xact, assoc_xact);
|
2017-04-03 14:12:59 +00:00
|
|
|
|
2017-04-01 14:13:15 +00:00
|
|
|
return CORE_OK;
|
2017-04-03 05:18:25 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
gtp_xact_delete(xact);
|
|
|
|
return CORE_ERROR;
|
2017-04-01 14:13:15 +00:00
|
|
|
}
|
2017-03-30 15:15:13 +00:00
|
|
|
|
2017-04-10 13:48:07 +00:00
|
|
|
status_t gtp_xact_timeout(index_t index)
|
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(>p_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-01 01:16:06 +00:00
|
|
|
d_trace(3, "[%d] %s Timeout 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(&xact->gnode->addr, buf), xact->gnode->port);
|
2017-03-30 14:27:26 +00:00
|
|
|
|
2017-04-03 04:06:56 +00:00
|
|
|
if (xact->org == GTP_LOCAL_ORIGINATOR)
|
2017-03-29 12:09:29 +00:00
|
|
|
{
|
2017-04-01 14:28:22 +00:00
|
|
|
if (--xact->retry_count > 0)
|
|
|
|
{
|
|
|
|
tm_start(xact->tm_wait);
|
|
|
|
|
|
|
|
d_assert(xact->pkbuf, goto out, "Null param");
|
|
|
|
d_assert(gtp_send(xact->sock, xact->gnode, xact->pkbuf) == CORE_OK,
|
|
|
|
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-04-03 04:06:56 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
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:
|
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-19 04:29:09 +00:00
|
|
|
static gtp_xact_t *gtp_xact_find_by_sqn(
|
2017-04-03 13:46:19 +00:00
|
|
|
gtp_node_t *gnode, c_uint8_t type, 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-03-27 10:12:45 +00:00
|
|
|
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");
|
2017-08-31 01:48:14 +00:00
|
|
|
|
|
|
|
switch(gtp_xact_get_stage(type, sqn))
|
2017-03-27 10:12:45 +00:00
|
|
|
{
|
2017-08-31 01:48:14 +00:00
|
|
|
case GTP_XACT_INITIAL_STAGE:
|
2017-04-03 06:31:57 +00:00
|
|
|
xact = list_first(&gnode->remote_list);
|
2017-03-27 10:12:45 +00:00
|
|
|
break;
|
2017-08-31 01:48:14 +00:00
|
|
|
case GTP_XACT_INTERMEDIATE_STAGE:
|
2017-04-03 06:31:57 +00:00
|
|
|
xact = list_first(&gnode->local_list);
|
2017-03-27 10:12:45 +00:00
|
|
|
break;
|
2017-08-31 01:48:14 +00:00
|
|
|
case GTP_XACT_FINAL_STAGE:
|
|
|
|
if (sqn & GTP_MAX_XACT_ID)
|
|
|
|
xact = list_first(&gnode->remote_list);
|
|
|
|
else
|
|
|
|
xact = list_first(&gnode->local_list);
|
|
|
|
break;
|
2017-03-27 10:12:45 +00:00
|
|
|
|
|
|
|
default:
|
2017-08-31 01:48:14 +00:00
|
|
|
d_assert(0, return NULL, "Unknown stage");
|
2017-03-27 10:12:45 +00:00
|
|
|
}
|
|
|
|
|
2017-04-03 12:17:08 +00:00
|
|
|
xid = GTP_SQN_TO_XID(sqn);
|
2017-03-27 10:12:45 +00:00
|
|
|
while(xact)
|
|
|
|
{
|
|
|
|
if (xact->xid == xid)
|
|
|
|
break;
|
|
|
|
xact = list_next(xact);
|
|
|
|
}
|
|
|
|
|
2017-03-30 14:27:26 +00:00
|
|
|
if (xact)
|
|
|
|
{
|
2017-08-01 01:16:06 +00:00
|
|
|
d_trace(3, "[%d] %s Find 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-27 10:12:45 +00:00
|
|
|
return xact;
|
2017-03-26 15:48:33 +00:00
|
|
|
}
|
2017-03-29 14:19:31 +00:00
|
|
|
|
2017-04-06 03:13:38 +00:00
|
|
|
status_t gtp_xact_receive(
|
|
|
|
gtp_xact_ctx_t *context, net_sock_t *sock, gtp_node_t *gnode,
|
|
|
|
gtp_xact_t **xact,
|
|
|
|
c_uint8_t *type, c_uint32_t *teid, gtp_message_t *gtp_message,
|
|
|
|
pkbuf_t *pkbuf)
|
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-08-31 01:48:14 +00:00
|
|
|
gtp_header_t *h = NULL;
|
2017-04-06 03:13:38 +00:00
|
|
|
gtp_xact_t *new = NULL;
|
2017-03-29 14:19:31 +00:00
|
|
|
|
2017-04-06 03:13:38 +00:00
|
|
|
d_assert(pkbuf, return CORE_ERROR, "Null param");
|
|
|
|
|
|
|
|
d_assert(context, goto out1, "Null param");
|
|
|
|
d_assert(sock, goto out1, "Null param");
|
|
|
|
d_assert(gnode, goto out1, "Null param");
|
|
|
|
d_assert(type, goto out1, "Null param");
|
2017-03-29 14:19:31 +00:00
|
|
|
|
|
|
|
h = pkbuf->payload;
|
2017-04-06 03:13:38 +00:00
|
|
|
d_assert(h, goto out1, "Null param");
|
2017-03-30 14:27:26 +00:00
|
|
|
|
2017-08-19 04:29:09 +00:00
|
|
|
new = gtp_xact_find_by_sqn(gnode, h->type, h->sqn);
|
2017-04-06 03:13:38 +00:00
|
|
|
if (!new)
|
2017-03-29 14:19:31 +00:00
|
|
|
{
|
2017-04-06 03:13:38 +00:00
|
|
|
new = gtp_xact_remote_create(context, sock, gnode, h->sqn);
|
2017-03-29 14:19:31 +00:00
|
|
|
}
|
2017-04-06 03:13:38 +00:00
|
|
|
d_assert(new, goto out1, "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-04-06 03:13:38 +00:00
|
|
|
if (new->org == GTP_LOCAL_ORIGINATOR)
|
2017-04-03 06:48:43 +00:00
|
|
|
{
|
2017-04-06 03:13:38 +00:00
|
|
|
gtp_xact_t *assoc_xact = new->assoc_xact;
|
2017-04-03 12:37:20 +00:00
|
|
|
|
2017-04-03 14:40:22 +00:00
|
|
|
if (assoc_xact)
|
2017-04-06 03:13:38 +00:00
|
|
|
gtp_xact_deassociate(new, assoc_xact);
|
2017-04-03 14:40:22 +00:00
|
|
|
|
2017-04-06 03:13:38 +00:00
|
|
|
gtp_xact_delete(new);
|
|
|
|
new = assoc_xact;
|
2017-04-03 06:48:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-04-06 03:13:38 +00:00
|
|
|
if (new->pkbuf)
|
2017-04-03 06:48:43 +00:00
|
|
|
{
|
|
|
|
d_warn("[%d]%s Request Duplicated. Retransmit!",
|
2017-04-06 03:13:38 +00:00
|
|
|
new->gnode->port,
|
|
|
|
new->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE");
|
|
|
|
rv = gtp_send(new->sock, new->gnode, new->pkbuf);
|
|
|
|
d_assert(rv == CORE_OK, goto out2, "gtp_send error");
|
|
|
|
|
|
|
|
pkbuf_free(pkbuf);
|
|
|
|
return CORE_EAGAIN;
|
2017-04-03 06:48:43 +00:00
|
|
|
}
|
2017-04-06 03:13:38 +00:00
|
|
|
else if (new->assoc_xact)
|
2017-04-03 14:43:54 +00:00
|
|
|
{
|
|
|
|
d_warn("[%d]%s Request Duplicated. Discard Associated transaction!",
|
2017-04-06 03:13:38 +00:00
|
|
|
new->gnode->port,
|
|
|
|
new->org == GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE");
|
|
|
|
|
|
|
|
pkbuf_free(pkbuf);
|
|
|
|
return CORE_EAGAIN;
|
2017-04-03 14:43:54 +00:00
|
|
|
}
|
2017-04-03 06:48:43 +00:00
|
|
|
}
|
2017-03-29 14:19:31 +00:00
|
|
|
|
|
|
|
if (h->teid_presence)
|
2017-04-06 03:13:38 +00:00
|
|
|
{
|
2017-03-29 14:19:31 +00:00
|
|
|
pkbuf_header(pkbuf, -GTPV2C_HEADER_LEN);
|
2017-04-06 14:29:20 +00:00
|
|
|
*teid = ntohl(h->teid);
|
2017-04-06 03:13:38 +00:00
|
|
|
}
|
2017-03-29 14:19:31 +00:00
|
|
|
else
|
2017-04-03 13:46:19 +00:00
|
|
|
{
|
2017-04-06 03:13:38 +00:00
|
|
|
pkbuf_header(pkbuf, -(GTPV2C_HEADER_LEN-GTPV2C_TEID_LEN));
|
2017-04-06 14:29:20 +00:00
|
|
|
*teid = 0;
|
2017-04-03 13:46:19 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 03:13:38 +00:00
|
|
|
*type = h->type;
|
|
|
|
|
|
|
|
rv = gtp_parse_msg(gtp_message, *type, 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;
|
|
|
|
|
|
|
|
out2:
|
|
|
|
gtp_xact_delete(new);
|
|
|
|
|
|
|
|
out1:
|
|
|
|
pkbuf_free(pkbuf);
|
|
|
|
return CORE_ERROR;
|
2017-04-03 13:46:19 +00:00
|
|
|
}
|
2017-08-19 04:29:09 +00:00
|
|
|
|
|
|
|
gtp_xact_t *gtp_xact_find(index_t index)
|
|
|
|
{
|
|
|
|
d_assert(index, return NULL, "Invalid Index");
|
|
|
|
return index_find(>p_xact_pool, index);
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
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:
|
|
|
|
if (sqn & GTP_MAX_XACT_ID)
|
|
|
|
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;
|
|
|
|
}
|