forked from acouzens/open5gs
update it
This commit is contained in:
parent
4cdefe152d
commit
814e3f7e94
|
@ -3,10 +3,10 @@
|
|||
noinst_LTLIBRARIES = libgtp.la
|
||||
|
||||
libgtp_la_SOURCES = \
|
||||
gtp_tlv.h gtp_types.h gtp_path.h
|
||||
gtp_tlv.h gtp_types.h gtp_path.h gtp_xact.h
|
||||
|
||||
nodist_libgtp_la_SOURCES = \
|
||||
gtp_tlv.c gtp_types.c gtp_path.c
|
||||
gtp_tlv.c gtp_types.c gtp_path.c gtp_xact.c
|
||||
|
||||
libgtp_la_DEPENDENCIES = \
|
||||
$(top_srcdir)/lib/3gpp/lib3gpp.la
|
||||
|
|
|
@ -6,63 +6,69 @@
|
|||
#include "3gpp_defs.h"
|
||||
#include "gtp_path.h"
|
||||
|
||||
status_t gtp_open(net_sock_t **sock, net_sock_handler handler, void *data,
|
||||
const c_uint32_t addr, const c_uint16_t port)
|
||||
status_t gtp_open(gtp_node_t *gnode, net_sock_handler handler)
|
||||
{
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
int rc;
|
||||
|
||||
rc = net_listen_with_addr(sock, SOCK_DGRAM, IPPROTO_UDP, port, addr);
|
||||
d_assert(gnode, return CORE_ERROR, "Null param");
|
||||
|
||||
rc = net_listen_with_addr(&gnode->s, SOCK_DGRAM, IPPROTO_UDP,
|
||||
gnode->local_port, gnode->local_addr);
|
||||
if (rc != 0)
|
||||
{
|
||||
d_error("Can't establish GTP[%s:%d] path(%d:%s)",
|
||||
INET_NTOP(&addr, buf), port, errno, strerror(errno));
|
||||
INET_NTOP(&gnode->local_addr, buf), gnode->local_port,
|
||||
errno, strerror(errno));
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
rc = net_register_sock(*sock, handler, data);
|
||||
rc = net_register_sock(gnode->s, handler, gnode);
|
||||
if (rc != 0)
|
||||
{
|
||||
d_error("Can't establish GTP path(%d:%s)",
|
||||
errno, strerror(errno));
|
||||
net_close(*sock);
|
||||
net_close(gnode->s);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
d_trace(1, "gtp_listen() %s:%d\n", INET_NTOP(&addr, buf), port);
|
||||
d_trace(1, "gtp_listen() %s:%d\n",
|
||||
INET_NTOP(&gnode->local_addr, buf), gnode->local_port);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t gtp_close(net_sock_t *sock)
|
||||
status_t gtp_close(gtp_node_t *gnode)
|
||||
{
|
||||
d_assert(sock, return CORE_ERROR, "Null param");
|
||||
d_assert(gnode, return CORE_ERROR, "Null param");
|
||||
d_assert(gnode->s, return CORE_ERROR, "Null param");
|
||||
|
||||
net_unregister_sock(sock);
|
||||
net_close(sock);
|
||||
net_unregister_sock(gnode->s);
|
||||
net_close(gnode->s);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
pkbuf_t *gtp_read(net_sock_t *net_sock)
|
||||
pkbuf_t *gtp_read(gtp_node_t *gnode)
|
||||
{
|
||||
pkbuf_t *pkb;
|
||||
int r;
|
||||
|
||||
d_assert(net_sock, return NULL, "Null param");
|
||||
d_assert(gnode, return NULL, "Null param");
|
||||
d_assert(gnode->s, return NULL, "Null param");
|
||||
|
||||
pkb = pkbuf_alloc(0, MAX_SDU_LEN);
|
||||
d_assert(pkb, return NULL, "Can't allocate pkbuf");
|
||||
|
||||
r = net_read(net_sock, pkb->payload, pkb->len, 0);
|
||||
r = net_read(gnode->s, pkb->payload, pkb->len, 0);
|
||||
if (r <= 0)
|
||||
{
|
||||
pkbuf_free(pkb);
|
||||
|
||||
if (net_sock->sndrcv_errno != EAGAIN)
|
||||
if (gnode->s->sndrcv_errno != EAGAIN)
|
||||
{
|
||||
d_warn("net_read failed(%d:%s)",
|
||||
net_sock->sndrcv_errno, strerror(net_sock->sndrcv_errno));
|
||||
gnode->s->sndrcv_errno, strerror(gnode->s->sndrcv_errno));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -75,23 +81,24 @@ pkbuf_t *gtp_read(net_sock_t *net_sock)
|
|||
}
|
||||
}
|
||||
|
||||
status_t gtp_send(net_sock_t *s,
|
||||
pkbuf_t *pkbuf, c_uint32_t ip_addr, c_uint16_t port)
|
||||
status_t gtp_send(gtp_node_t *gnode, pkbuf_t *pkbuf)
|
||||
{
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
ssize_t sent;
|
||||
|
||||
d_assert(s, return CORE_ERROR, "Null param");
|
||||
d_assert(gnode, return CORE_ERROR, "Null param");
|
||||
d_assert(gnode->s, return CORE_ERROR, "Null param");
|
||||
d_assert(pkbuf, return CORE_ERROR, "Null param");
|
||||
|
||||
sent = net_sendto(s, pkbuf->payload, pkbuf->len, ip_addr, port);
|
||||
d_trace(1,"Sent %d->%d bytes to [%s:%d]\n",
|
||||
pkbuf->len, sent, INET_NTOP(&ip_addr, buf), port);
|
||||
sent = net_sendto(gnode->s, pkbuf->payload, pkbuf->len,
|
||||
gnode->remote_addr, gnode->remote_port);
|
||||
d_trace(1,"Sent %d->%d bytes to [%s:%d]\n", pkbuf->len, sent,
|
||||
INET_NTOP(&gnode->remote_addr, buf), gnode->remote_port);
|
||||
d_trace_hex(1, pkbuf->payload, pkbuf->len);
|
||||
if (sent < 0 || sent != pkbuf->len)
|
||||
{
|
||||
d_error("net_send error (%d:%s)",
|
||||
s->sndrcv_errno, strerror(s->sndrcv_errno));
|
||||
gnode->s->sndrcv_errno, strerror(gnode->s->sndrcv_errno));
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,22 +3,49 @@
|
|||
|
||||
#include "core_pkbuf.h"
|
||||
#include "core_net.h"
|
||||
#include "core_list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define S11_UDP_PORT 2123
|
||||
#define S5_UDP_PORT 2152
|
||||
#define GTPV2_C_UDP_PORT 2123
|
||||
#define GTPV1_U_UDP_PORT 2152
|
||||
|
||||
CORE_DECLARE(status_t) gtp_open(net_sock_t **sock, net_sock_handler handler,
|
||||
void *data, const c_uint32_t addr, const c_uint16_t port);
|
||||
CORE_DECLARE(status_t) gtp_close(net_sock_t *sock);
|
||||
#define GTP_COMPARE_REMOTE_NODE(__id1, __id2) \
|
||||
(((__id1)->remote_addr) == ((__id2)->remote_addr) && \
|
||||
((__id1)->remote_port) == ((__id2)->remote_port))
|
||||
|
||||
CORE_DECLARE(pkbuf_t *) gtp_read(net_sock_t *net_sock);
|
||||
/**
|
||||
* This structure keeps active transactions and their histrory */
|
||||
typedef struct _gtp_xact_info_t {
|
||||
list_t local_xlist; /**< List of local initiated transactions */
|
||||
list_t remote_xlist; /**< List of Remote initiated transactions */
|
||||
} gtp_xact_info_t;
|
||||
|
||||
CORE_DECLARE(status_t) gtp_send(net_sock_t *s,
|
||||
pkbuf_t *pkb, c_uint32_t ip_addr, c_uint16_t port);
|
||||
/**
|
||||
* This structure represents the commonalities of GTP node such as MME, SGW,
|
||||
* PGW gateway. Some of members may not be used by the specific type of node */
|
||||
typedef struct _gtp_node_t {
|
||||
lnode_t node; /**< A node of list_t */
|
||||
|
||||
c_uint32_t local_addr; /**< Network byte order IP Address */
|
||||
c_uint16_t local_port; /**< Host byte order Port number */
|
||||
c_uint32_t remote_addr; /**< Network byte order IP Address */
|
||||
c_uint16_t remote_port; /**< Host byte order Port number */
|
||||
|
||||
gtp_xact_info_t xi; /**< Transaction information */
|
||||
|
||||
net_sock_t *s; /**< Network socket */
|
||||
} gtp_node_t;
|
||||
|
||||
CORE_DECLARE(status_t) gtp_open(
|
||||
gtp_node_t *gnode, net_sock_handler handler);
|
||||
CORE_DECLARE(status_t) gtp_close(gtp_node_t *gnode);
|
||||
|
||||
CORE_DECLARE(pkbuf_t *) gtp_read(gtp_node_t *gnode);
|
||||
|
||||
CORE_DECLARE(status_t) gtp_send(gtp_node_t *gnode, pkbuf_t *pkbuf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -9,6 +9,27 @@
|
|||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* 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 */
|
||||
c_uint32_t sqn;
|
||||
};
|
||||
/* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */
|
||||
c_uint32_t spare2;
|
||||
};
|
||||
} __attribute__ ((packed)) gtpv2c_header_t;
|
||||
|
||||
/* 8.7 Aggregate Maximum Bit Rate (AMBR) */
|
||||
typedef struct _gtp_ambr_t {
|
||||
c_uint32_t uplink;
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
#define TRACE_MODULE _gtp_xact
|
||||
#include "core_debug.h"
|
||||
#include "core_pool.h"
|
||||
|
||||
#include "gtp_xact.h"
|
||||
|
||||
#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)
|
||||
|
||||
static int g_gtp_xact_initialized = 0;
|
||||
|
||||
pool_declare(gtp_xact_pool, gtp_xact_ctx_t, SIZE_OF_GTP_XACT_POOL);
|
||||
|
||||
/**
|
||||
* Initialize the transaction framework
|
||||
*/
|
||||
status_t gtp_xact_init(void)
|
||||
{
|
||||
d_assert(g_gtp_xact_initialized == 0, return CORE_ERROR,
|
||||
"XACTION already has been initialized");
|
||||
|
||||
pool_init(>p_xact_pool, SIZE_OF_GTP_XACT_POOL);
|
||||
|
||||
g_gtp_xact_initialized = 1;
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the transaction framework
|
||||
*/
|
||||
status_t gtp_xact_final(void)
|
||||
{
|
||||
d_assert(g_gtp_xact_initialized == 1, return CORE_ERROR,
|
||||
"XACTION ASNGW context already has been finalized");
|
||||
|
||||
pool_final(>p_xact_pool);
|
||||
|
||||
g_gtp_xact_initialized = 0;
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new transaction which was initiated by local ASN node.
|
||||
*/
|
||||
status_t gtp_xact_new_local(gtp_xact_ctx_t **xact, c_uint8_t type,
|
||||
pkbuf_t *pkb, gtp_node_t *gnode)
|
||||
{
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new transaction which was initiated by remote node
|
||||
*/
|
||||
status_t gtp_xact_new_remote(gtp_xact_ctx_t **xact)
|
||||
{
|
||||
return CORE_OK;
|
||||
}
|
||||
/**
|
||||
* Delete a transaction
|
||||
*/
|
||||
status_t gtp_xact_delete(gtp_xact_ctx_t *xact)
|
||||
{
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the transaction with the new packet to be sent for the next step
|
||||
*/
|
||||
status_t gtp_xact_update_tx(gtp_xact_ctx_t *xact, pkbuf_t *pkb)
|
||||
{
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the transaction with the new received packet for the next step
|
||||
*/
|
||||
status_t gtp_xact_update_rx(gtp_xact_ctx_t *xact)
|
||||
{
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply and commit the updated of the transcation
|
||||
*/
|
||||
status_t gtp_xact_commit(gtp_xact_ctx_t *xact)
|
||||
{
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the transaction with the given ASN header
|
||||
*/
|
||||
gtp_xact_ctx_t * gtp_xact_find()
|
||||
{
|
||||
return CORE_OK;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
#ifndef __GTP_XACT_H__
|
||||
#define __GTP_XACT_H__
|
||||
|
||||
#include "core_pkbuf.h"
|
||||
#include "core_list.h"
|
||||
#include "core_net.h"
|
||||
#include "core_timer.h"
|
||||
|
||||
#include "gtp_path.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define GTP_MAX_MESSAGE_TYPE 256
|
||||
|
||||
/**
|
||||
* Transaction context
|
||||
*/
|
||||
typedef struct _gtp_xact_ctx_t {
|
||||
lnode_t node; /**< A node of list */
|
||||
|
||||
c_uint32_t xid; /**< Transaction ID */
|
||||
|
||||
#define GTP_LOCAL_ORIGINATOR 0
|
||||
#define GTP_REMOTE_ORIGINATOR 1
|
||||
c_uint8_t org; /**< Transaction' originator.
|
||||
local or remote */
|
||||
gtp_node_t *gnode; /**< RElevant GTP node context */
|
||||
void *xctx; /**< Relevant context */
|
||||
tm_block_id tm_wait; /**< Timer waiting for next message */
|
||||
int retry_count; /**< Retry count waiting for next message */
|
||||
|
||||
} gtp_xact_ctx_t;
|
||||
|
||||
/**
|
||||
* Initialize the transaction framework
|
||||
*/
|
||||
CORE_DECLARE(status_t) gtp_xact_init(void);
|
||||
|
||||
/**
|
||||
* Finalize the transaction framework
|
||||
*/
|
||||
CORE_DECLARE(status_t) gtp_xact_final(void);
|
||||
|
||||
/**
|
||||
* Create a new transaction which was initiated by local ASN node.
|
||||
*/
|
||||
CORE_DECLARE(status_t) gtp_xact_new_local(gtp_xact_ctx_t **xact, c_uint8_t type,
|
||||
pkbuf_t *pkb, gtp_node_t *gnode);
|
||||
|
||||
/**
|
||||
* Create a new transaction which was initiated by remote node
|
||||
*/
|
||||
CORE_DECLARE(status_t) gtp_xact_new_remote(gtp_xact_ctx_t **xact);
|
||||
|
||||
/**
|
||||
* Delete a transaction
|
||||
*/
|
||||
CORE_DECLARE(status_t) gtp_xact_delete(gtp_xact_ctx_t *xact);
|
||||
|
||||
/**
|
||||
* Update the transaction with the new packet to be sent for the next step
|
||||
*/
|
||||
CORE_DECLARE(status_t) gtp_xact_update_tx(gtp_xact_ctx_t *xact, pkbuf_t *pkb);
|
||||
|
||||
/**
|
||||
* Update the transaction with the new received packet for the next step
|
||||
*/
|
||||
CORE_DECLARE(status_t) gtp_xact_update_rx(gtp_xact_ctx_t *xact);
|
||||
|
||||
/**
|
||||
* Apply and commit the updated of the transcation
|
||||
*/
|
||||
CORE_DECLARE(status_t) gtp_xact_commit(gtp_xact_ctx_t *xact);
|
||||
|
||||
/**
|
||||
* Find the transaction with the given ASN header
|
||||
*/
|
||||
CORE_DECLARE(gtp_xact_ctx_t *) gtp_xact_find();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __GTP_XACT_H__ */
|
5
main.c
5
main.c
|
@ -53,11 +53,12 @@ static int check_signal(int signum)
|
|||
{
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
CORE_DECLARE(status_t) s11_build_create_session_req(pkbuf_t **pkbuf, void *ue);
|
||||
CORE_DECLARE(status_t) mme_s11_send_to_sgw(pkbuf_t *pkbuf);
|
||||
CORE_DECLARE(status_t) mme_s11_send_to_sgw(void *sgw, pkbuf_t *pkbuf);
|
||||
CORE_DECLARE(void*) mme_ctx_sgw_first(void);
|
||||
|
||||
s11_build_create_session_req(&pkbuf, NULL);
|
||||
d_print_hex(pkbuf->payload, pkbuf->len);
|
||||
mme_s11_send_to_sgw(pkbuf);
|
||||
mme_s11_send_to_sgw(mme_ctx_sgw_first(), pkbuf);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define UE_PER_ENB 128
|
||||
#define RAB_PER_UE 16
|
||||
|
||||
#define SIZE_OF_SGW_POOL 8
|
||||
#define SIZE_OF_ENB_POOL 128
|
||||
#define SIZE_OF_UE_POOL (SIZE_OF_ENB_POOL * UE_PER_ENB)
|
||||
#define SIZE_OF_RAB_POOL (SIZE_OF_UE_POOL * RAB_PER_UE)
|
||||
|
@ -21,12 +22,14 @@
|
|||
|
||||
static mme_ctx_t self;
|
||||
|
||||
pool_declare(sgw_pool, sgw_ctx_t, SIZE_OF_SGW_POOL);
|
||||
pool_declare(enb_pool, enb_ctx_t, SIZE_OF_ENB_POOL);
|
||||
pool_declare(ue_pool, ue_ctx_t, SIZE_OF_UE_POOL);
|
||||
pool_declare(rab_pool, rab_ctx_t, SIZE_OF_RAB_POOL);
|
||||
|
||||
static int ctx_initialized = 0;
|
||||
|
||||
static list_t sgw_list;
|
||||
static list_t enb_list;
|
||||
|
||||
status_t mme_ctx_init()
|
||||
|
@ -34,21 +37,19 @@ status_t mme_ctx_init()
|
|||
d_assert(ctx_initialized == 0, return CORE_ERROR,
|
||||
"MME context already has been ctx_initialized");
|
||||
|
||||
pool_init(&sgw_pool, SIZE_OF_SGW_POOL);
|
||||
pool_init(&enb_pool, SIZE_OF_ENB_POOL);
|
||||
pool_init(&ue_pool, SIZE_OF_UE_POOL);
|
||||
pool_init(&rab_pool, SIZE_OF_RAB_POOL);
|
||||
|
||||
list_init(&sgw_list);
|
||||
list_init(&enb_list);
|
||||
|
||||
/* Initialize MME context */
|
||||
memset(&self, 0, sizeof(mme_ctx_t));
|
||||
|
||||
self.mme_local_addr = inet_addr("127.0.0.1");
|
||||
self.sgw_remote_addr = inet_addr("127.0.0.1");
|
||||
|
||||
self.s1ap_addr = inet_addr("127.0.0.1");
|
||||
self.s1ap_port = S1AP_SCTP_PORT;
|
||||
self.s11_local_port = S11_UDP_PORT;
|
||||
self.s11_remote_port = S11_UDP_PORT + 1;
|
||||
|
||||
/* MCC : 001, MNC : 01 */
|
||||
plmn_id_build(&self.plmn_id, 1, 1, 2);
|
||||
|
@ -80,6 +81,7 @@ status_t mme_ctx_final()
|
|||
|
||||
mme_ctx_enb_remove_all();
|
||||
|
||||
pool_final(&sgw_pool);
|
||||
pool_final(&enb_pool);
|
||||
pool_final(&ue_pool);
|
||||
pool_final(&rab_pool);
|
||||
|
@ -94,6 +96,73 @@ mme_ctx_t* mme_self()
|
|||
return &self;
|
||||
}
|
||||
|
||||
sgw_ctx_t* mme_ctx_sgw_add()
|
||||
{
|
||||
sgw_ctx_t *sgw = NULL;
|
||||
|
||||
pool_alloc_node(&sgw_pool, &sgw);
|
||||
d_assert(sgw, return NULL, "Null param");
|
||||
|
||||
memset(sgw, 0, sizeof(sgw_ctx_t));
|
||||
|
||||
list_append(&sgw_list, sgw);
|
||||
|
||||
return sgw;
|
||||
}
|
||||
|
||||
status_t mme_ctx_sgw_remove(sgw_ctx_t *sgw)
|
||||
{
|
||||
d_assert(sgw, return CORE_ERROR, "Null param");
|
||||
|
||||
list_remove(&sgw_list, sgw);
|
||||
pool_free_node(&sgw_pool, sgw);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t mme_ctx_sgw_remove_all()
|
||||
{
|
||||
sgw_ctx_t *sgw = NULL, *next_sgw = NULL;
|
||||
|
||||
sgw = mme_ctx_sgw_first();
|
||||
while (sgw)
|
||||
{
|
||||
next_sgw = mme_ctx_sgw_next(sgw);
|
||||
|
||||
mme_ctx_sgw_remove(sgw);
|
||||
|
||||
sgw = next_sgw;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
sgw_ctx_t* mme_ctx_sgw_find_by_node(gtp_node_t *gnode)
|
||||
{
|
||||
sgw_ctx_t *sgw = NULL;
|
||||
|
||||
sgw = mme_ctx_sgw_first();
|
||||
while (sgw)
|
||||
{
|
||||
if (GTP_COMPARE_REMOTE_NODE(&sgw->gnode, gnode))
|
||||
break;
|
||||
|
||||
sgw = mme_ctx_sgw_next(sgw);
|
||||
}
|
||||
|
||||
return sgw;
|
||||
}
|
||||
|
||||
sgw_ctx_t* mme_ctx_sgw_first()
|
||||
{
|
||||
return list_first(&sgw_list);
|
||||
}
|
||||
|
||||
sgw_ctx_t* mme_ctx_sgw_next(sgw_ctx_t *sgw)
|
||||
{
|
||||
return list_next(sgw);
|
||||
}
|
||||
|
||||
enb_ctx_t* mme_ctx_enb_add()
|
||||
{
|
||||
enb_ctx_t *enb = NULL;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "3gpp_defs.h"
|
||||
#include "3gpp_types.h"
|
||||
#include "nas_types.h"
|
||||
#include "gtp_path.h"
|
||||
|
||||
#include "sm.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -33,15 +35,9 @@ typedef struct _served_gummei {
|
|||
} srvd_gummei_t;
|
||||
|
||||
typedef struct _mme_ctx_t {
|
||||
c_uint32_t mme_local_addr;
|
||||
c_uint32_t sgw_remote_addr;
|
||||
|
||||
net_sock_t *s1ap_sock;
|
||||
c_uint32_t s1ap_addr;
|
||||
c_uint16_t s1ap_port;
|
||||
|
||||
net_sock_t *s11_sock;
|
||||
c_uint16_t s11_local_port;
|
||||
c_uint16_t s11_remote_port;
|
||||
net_sock_t *s1ap_sock;
|
||||
|
||||
msgq_id queue_id;
|
||||
tm_service_t tm_service;
|
||||
|
@ -71,6 +67,11 @@ typedef struct _mme_ctx_t {
|
|||
c_uint8_t relative_capacity;
|
||||
} mme_ctx_t;
|
||||
|
||||
typedef struct _sgw_ctx_t {
|
||||
gtp_node_t gnode;
|
||||
|
||||
} sgw_ctx_t;
|
||||
|
||||
typedef struct _enb_ctx_t {
|
||||
lnode_t node; /**< A node of list_t */
|
||||
|
||||
|
@ -134,6 +135,13 @@ CORE_DECLARE(status_t) mme_ctx_final(void);
|
|||
|
||||
CORE_DECLARE(mme_ctx_t*) mme_self(void);
|
||||
|
||||
CORE_DECLARE(sgw_ctx_t*) mme_ctx_sgw_add(void);
|
||||
CORE_DECLARE(status_t) mme_ctx_sgw_remove(sgw_ctx_t *sgw);
|
||||
CORE_DECLARE(status_t) mme_ctx_sgw_remove_all(void);
|
||||
CORE_DECLARE(sgw_ctx_t*) mme_ctx_sgw_find_by_node(gtp_node_t *gnode);
|
||||
CORE_DECLARE(sgw_ctx_t*) mme_ctx_sgw_first(void);
|
||||
CORE_DECLARE(sgw_ctx_t*) mme_ctx_sgw_next(sgw_ctx_t *sgw);
|
||||
|
||||
CORE_DECLARE(enb_ctx_t*) mme_ctx_enb_add(void);
|
||||
CORE_DECLARE(status_t) mme_ctx_enb_remove(enb_ctx_t *enb);
|
||||
CORE_DECLARE(status_t) mme_ctx_enb_remove_all(void);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "s1ap_path.h"
|
||||
#include "nas_message.h"
|
||||
|
||||
static char EVT_NAME_LO_MME_ENGAGE_SGW[] = "LO_MME_ENGAGE_SGW";
|
||||
|
||||
static char EVT_NAME_LO_ENB_S1AP_ACCEPT[] = "LO_ENB_S1AP_ACCEPT";
|
||||
static char EVT_NAME_LO_ENB_S1AP_CONNREFUSED[] = "LO_ENB_S1AP_CONNREFUSED";
|
||||
|
||||
|
@ -25,17 +27,20 @@ char* mme_event_get_name(event_t *e)
|
|||
case FSM_EXIT_SIG:
|
||||
return FSM_NAME_EXIT_SIG;
|
||||
|
||||
case EVT_LO_MME_ENGAGE_SGW:
|
||||
return EVT_NAME_LO_MME_ENGAGE_SGW;
|
||||
|
||||
case EVT_LO_ENB_S1AP_ACCEPT:
|
||||
return EVT_NAME_LO_ENB_S1AP_ACCEPT;
|
||||
return EVT_NAME_LO_ENB_S1AP_ACCEPT;
|
||||
case EVT_LO_ENB_S1AP_CONNREFUSED:
|
||||
return EVT_NAME_LO_ENB_S1AP_CONNREFUSED;
|
||||
return EVT_NAME_LO_ENB_S1AP_CONNREFUSED;
|
||||
|
||||
case EVT_MSG_ENB_S1AP:
|
||||
return EVT_NAME_MSG_ENB_S1AP;
|
||||
return EVT_NAME_MSG_ENB_S1AP;
|
||||
case EVT_MSG_UE_EMM:
|
||||
return EVT_NAME_MSG_UE_EMM;
|
||||
return EVT_NAME_MSG_UE_EMM;
|
||||
case EVT_MSG_MME_S11:
|
||||
return EVT_NAME_MSG_MME_S11;
|
||||
return EVT_NAME_MSG_MME_S11;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -15,6 +15,8 @@ extern "C" {
|
|||
typedef enum {
|
||||
MME_EVT_BASE = FSM_USER_SIG,
|
||||
|
||||
EVT_LO_MME_ENGAGE_SGW,
|
||||
|
||||
EVT_LO_ENB_S1AP_ACCEPT,
|
||||
EVT_LO_ENB_S1AP_CONNREFUSED,
|
||||
|
||||
|
|
|
@ -35,34 +35,55 @@ void mme_state_operational(mme_sm_t *s, event_t *e)
|
|||
{
|
||||
case FSM_ENTRY_SIG:
|
||||
{
|
||||
/* FIXME: for test */
|
||||
{
|
||||
event_t e;
|
||||
sgw_ctx_t *sgw = mme_ctx_sgw_add();
|
||||
|
||||
d_assert(sgw, break, "Can't add SGW context");
|
||||
|
||||
sgw->gnode.local_addr = inet_addr("127.0.0.1");
|
||||
sgw->gnode.local_port = GTPV2_C_UDP_PORT;
|
||||
sgw->gnode.remote_addr = inet_addr("127.0.0.1");
|
||||
sgw->gnode.remote_port = GTPV2_C_UDP_PORT+1;
|
||||
|
||||
event_set(&e, EVT_LO_MME_ENGAGE_SGW);
|
||||
event_set_param1(&e, sgw);
|
||||
event_send(mme_self()->queue_id, &e);
|
||||
}
|
||||
|
||||
rv = s1ap_open();
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't establish S1AP path");
|
||||
break;
|
||||
}
|
||||
rv = mme_s11_open();
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't establish S11 path");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FSM_EXIT_SIG:
|
||||
{
|
||||
sgw_ctx_t *sgw = mme_ctx_sgw_first();
|
||||
while(sgw)
|
||||
{
|
||||
mme_s11_close(sgw);
|
||||
sgw = mme_ctx_sgw_next(sgw);
|
||||
}
|
||||
|
||||
rv = s1ap_close();
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't close S1AP path");
|
||||
break;
|
||||
}
|
||||
rv = mme_s11_close();
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't close S11 path");
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EVT_LO_MME_ENGAGE_SGW:
|
||||
{
|
||||
sgw_ctx_t *sgw = (sgw_ctx_t *)event_get_param1(e);
|
||||
d_assert(sgw, break, "LO_MME_ENGAGE_SGW has no BS context");
|
||||
|
||||
mme_s11_open(sgw);
|
||||
break;
|
||||
}
|
||||
case EVT_LO_ENB_S1AP_ACCEPT:
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
#define TRACE_MODULE _s11_build
|
||||
|
||||
#include "core_debug.h"
|
||||
|
||||
#include "context.h"
|
||||
|
||||
#include "3gpp_conv.h"
|
||||
#include "gtp_types.h"
|
||||
#include "gtp_tlv.h"
|
||||
|
||||
status_t s11_build_create_session_req(pkbuf_t **pkbuf, ue_ctx_t *ue)
|
||||
{
|
||||
gtp_create_session_request_t req;
|
||||
gtp_uli_t uli;
|
||||
char uli_buf[GTP_MAX_ULI_LEN];
|
||||
plmn_id_t serving_network;
|
||||
gtp_f_teid_t s11, s5;
|
||||
gtp_paa_t paa;
|
||||
gtp_ambr_t ambr;
|
||||
gtp_pco_t pco;
|
||||
char pcobuf[GTP_MAX_PCO_LEN];
|
||||
gtp_bearer_qos_t bearer_qos;
|
||||
char bearer_qos_buf[GTP_BEARER_QOS_LEN];
|
||||
gtp_ue_timezone_t ue_timezone;
|
||||
|
||||
memset(&req, 0, sizeof(gtp_create_session_request_t));
|
||||
|
||||
req.imsi.presence = 1;
|
||||
req.imsi.data = (c_uint8_t *)"\x55\x15\x30\x11\x34\x00\x10\xf4";
|
||||
req.imsi.len = 8;
|
||||
|
||||
req.msisdn.presence = 1;
|
||||
req.msisdn.data = (c_uint8_t *)"\x94\x71\x52\x76\x00\x41";
|
||||
req.msisdn.len = 6;
|
||||
|
||||
req.me_identity.presence = 1;
|
||||
req.me_identity.data = (c_uint8_t *)"\x53\x61\x20\x00\x91\x78\x84\x00";
|
||||
req.me_identity.len = 8;
|
||||
|
||||
memset(&uli, 0, sizeof(gtp_uli_t));
|
||||
uli.flags.ecgi = 1;
|
||||
uli.flags.tai = 1;
|
||||
plmn_id_build(&uli.tai.plmn_id, 555, 10, 2);
|
||||
uli.tai.tac = 4130;
|
||||
plmn_id_build(&uli.ecgi.plmn_id, 555, 10, 2);
|
||||
uli.ecgi.eci = 105729;
|
||||
req.user_location_information.presence = 1;
|
||||
gtp_build_uli(&req.user_location_information, &uli,
|
||||
uli_buf, GTP_MAX_ULI_LEN);
|
||||
|
||||
req.serving_network.presence = 1;
|
||||
req.serving_network.data = plmn_id_build(&serving_network, 555, 10, 2);
|
||||
req.serving_network.len = sizeof(serving_network);
|
||||
|
||||
req.rat_type.presence = 1;
|
||||
req.rat_type.u8 = GTP_RAT_TYPE_EUTRAN;
|
||||
|
||||
memset(&s11, 0, sizeof(gtp_f_teid_t));
|
||||
s11.ipv4 = 1;
|
||||
s11.interface_type = GTP_F_TEID_S11_MME_GTP_C;
|
||||
s11.teid = htonl(0x80000084);
|
||||
s11.ipv4_addr = inet_addr("10.50.54.10");
|
||||
req.sender_f_teid_for_control_plane.presence = 1;
|
||||
req.sender_f_teid_for_control_plane.data = &s11;
|
||||
req.sender_f_teid_for_control_plane.len = GTP_F_TEID_IPV4_LEN;
|
||||
|
||||
memset(&s5, 0, sizeof(gtp_f_teid_t));
|
||||
s5.ipv4 = 1;
|
||||
s5.interface_type = GTP_F_TEID_S5_S8_PGW_GTP_C;
|
||||
s5.ipv4_addr = inet_addr("10.50.54.37");
|
||||
req.pgw_s5_s8_address_for_control_plane_or_pmip.presence = 1;
|
||||
req.pgw_s5_s8_address_for_control_plane_or_pmip.data = &s5;
|
||||
req.pgw_s5_s8_address_for_control_plane_or_pmip.len = GTP_F_TEID_IPV4_LEN;
|
||||
|
||||
req.access_point_name.presence = 1;
|
||||
req.access_point_name.data = "cellwire.com";
|
||||
req.access_point_name.len = strlen(req.access_point_name.data);
|
||||
|
||||
req.selection_mode.presence = 1;
|
||||
req.selection_mode.u8 = GTP_SELECTION_MODE_MS_OR_NETWORK_PROVIDED_APN | 0xfc;
|
||||
|
||||
req.pdn_type.presence = 1;
|
||||
req.pdn_type.u8 = GTP_PDN_TYPE_IPV4;
|
||||
|
||||
memset(&paa, 0, sizeof(gtp_paa_t));
|
||||
paa.pdn_type = GTP_PDN_TYPE_IPV4;
|
||||
req.pdn_address_allocation.presence = 1;
|
||||
req.pdn_address_allocation.data = &paa;
|
||||
req.pdn_address_allocation.len = GTP_PAA_IPV4_LEN;
|
||||
|
||||
req.maximum_apn_restriction.presence = 1;
|
||||
req.maximum_apn_restriction.u8 = GTP_APN_NO_RESTRICTION;
|
||||
|
||||
memset(&ambr, 0, sizeof(gtp_ambr_t));
|
||||
ambr.uplink = htonl(1000);
|
||||
ambr.downlink = htonl(2000);
|
||||
req.aggregate_maximum_bit_rate.presence = 1;
|
||||
req.aggregate_maximum_bit_rate.data = &ambr;
|
||||
req.aggregate_maximum_bit_rate.len = sizeof(ambr);
|
||||
|
||||
memset(&pco, 0, sizeof(gtp_pco_t));
|
||||
pco.ext = 1;
|
||||
pco.configuration_protocol =
|
||||
GTP_PCO_PPP_FOR_USE_WITH_IP_PDP_TYPE_OR_IP_PDN_TYPE;
|
||||
pco.num_of_id = 3;
|
||||
pco.ids[0].id = GTP_PROTOCOL_OR_CONTAINER_ID_INTERNET_PROTOCOL_CONTROL_PROTOCOL;
|
||||
pco.ids[0].contents = (c_uint8_t *)"\x01\x00\x00\x10\x81\x06\x00\x00\x00\x00\x83\x06\x00\x00\x00\x00";
|
||||
pco.ids[0].length = 16;
|
||||
pco.ids[1].id = GTP_PROTOCOL_OR_CONTAINER_ID_DNS_SERVER_IPV4_ADDRESS_REQUEST;
|
||||
pco.ids[1].length = 0;
|
||||
pco.ids[2].id = GTP_PROTOCOL_OR_CONTAINER_ID_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING;
|
||||
pco.ids[2].length = 0;
|
||||
req.protocol_configuration_options.presence = 1;
|
||||
gtp_build_pco(&req.protocol_configuration_options, &pco,
|
||||
pcobuf, GTP_MAX_PCO_LEN);
|
||||
|
||||
req.bearer_contexts_to_be_created.presence = 1;
|
||||
req.bearer_contexts_to_be_created.eps_bearer_id.presence = 1;
|
||||
req.bearer_contexts_to_be_created.eps_bearer_id.u8 = 5;
|
||||
|
||||
memset(&bearer_qos, 0, sizeof(bearer_qos));
|
||||
bearer_qos.pvi = 1;
|
||||
bearer_qos.pl = 1;
|
||||
bearer_qos.pci = 1;
|
||||
bearer_qos.qci = 5;
|
||||
req.bearer_contexts_to_be_created.bearer_level_qos.presence = 1;
|
||||
gtp_build_bearer_qos(&req.bearer_contexts_to_be_created.bearer_level_qos,
|
||||
&bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN);
|
||||
|
||||
memset(&ue_timezone, 0, sizeof(ue_timezone));
|
||||
ue_timezone.timezone = 0x40;
|
||||
ue_timezone.daylight_saving_time =
|
||||
GTP_UE_TIME_ZONE_NO_ADJUSTMENT_FOR_DAYLIGHT_SAVING_TIME;
|
||||
req.ue_time_zone.presence = 1;
|
||||
req.ue_time_zone.data = &ue_timezone;
|
||||
req.ue_time_zone.len = sizeof(ue_timezone);
|
||||
|
||||
req.charging_characteristics.presence = 1;
|
||||
req.charging_characteristics.data = (c_uint8_t *)"\x54\x00";
|
||||
req.charging_characteristics.len = 2;
|
||||
|
||||
return tlv_build_msg(pkbuf, &tlv_desc_create_session_request, &req,
|
||||
TLV_MODE_T1_L2_I1);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef __S11_BUILD_H__
|
||||
#define __S11_BUILD_H__
|
||||
|
||||
#include "s1ap_message.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
CORE_DECLARE(status_t) s11_build_create_session_req(
|
||||
pkbuf_t **pkbuf, ue_ctx_t *ue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __S11_BUILD_H__ */
|
|
@ -8,12 +8,16 @@
|
|||
|
||||
static int _mme_s11_recv_cb(net_sock_t *net_sock, void *data)
|
||||
{
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
event_t e;
|
||||
int rc;
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
d_assert(net_sock, return -1, "Null param");
|
||||
gtp_node_t *gnode = data;
|
||||
|
||||
pkbuf = gtp_read(net_sock);
|
||||
d_assert(net_sock, return -1, "Null param");
|
||||
d_assert(gnode, return -1, "Null param");
|
||||
|
||||
pkbuf = gtp_read(gnode);
|
||||
if (pkbuf == NULL)
|
||||
{
|
||||
if (net_sock->sndrcv_errno == EAGAIN)
|
||||
|
@ -22,33 +26,59 @@ static int _mme_s11_recv_cb(net_sock_t *net_sock, void *data)
|
|||
return -1;
|
||||
}
|
||||
|
||||
d_trace(1, "S11_PDU is received from SGW\n");
|
||||
d_trace(1, "S11_PDU is received from SGW[%s:%d]\n",
|
||||
INET_NTOP(&gnode->remote_addr, buf), gnode->remote_port);
|
||||
d_trace_hex(1, pkbuf->payload, pkbuf->len);
|
||||
|
||||
event_set(&e, EVT_MSG_MME_S11);
|
||||
event_set_param1(&e, (c_uintptr_t)net_sock);
|
||||
event_set_param1(&e, (c_uintptr_t)gnode);
|
||||
event_set_param2(&e, (c_uintptr_t)pkbuf);
|
||||
|
||||
rc = event_send(mme_self()->queue_id, &e);
|
||||
if (rc <= 0)
|
||||
{
|
||||
pkbuf_free(pkbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t mme_s11_open()
|
||||
status_t mme_s11_open(void *sgw)
|
||||
{
|
||||
return gtp_open(&mme_self()->s11_sock, _mme_s11_recv_cb, NULL,
|
||||
mme_self()->sgw_remote_addr, mme_self()->s11_local_port);
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
status_t rv;
|
||||
gtp_node_t *gnode = sgw;
|
||||
|
||||
rv = gtp_open(gnode, _mme_s11_recv_cb);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't establish S11 Path with SGW[%s:%d]",
|
||||
INET_NTOP(&gnode->remote_addr, buf), gnode->remote_port);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t mme_s11_close()
|
||||
status_t mme_s11_close(void *sgw)
|
||||
{
|
||||
return gtp_close(mme_self()->s11_sock);
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
status_t rv;
|
||||
gtp_node_t *gnode = sgw;
|
||||
|
||||
rv = gtp_close(gnode);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't close S11 Path with SGW[%s:%d]",
|
||||
INET_NTOP(&gnode->remote_addr, buf), gnode->remote_port);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t mme_s11_send_to_sgw(pkbuf_t *pkbuf)
|
||||
status_t mme_s11_send_to_sgw(void *sgw, pkbuf_t *pkbuf)
|
||||
{
|
||||
return gtp_send(mme_self()->s11_sock, pkbuf,
|
||||
mme_self()->sgw_remote_addr, mme_self()->s11_remote_port);
|
||||
return gtp_send(sgw, pkbuf);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
CORE_DECLARE(status_t) mme_s11_open();
|
||||
CORE_DECLARE(status_t) mme_s11_close();
|
||||
CORE_DECLARE(status_t) mme_s11_open(void *sgw);
|
||||
CORE_DECLARE(status_t) mme_s11_close(void *sgw);
|
||||
|
||||
CORE_DECLARE(status_t) mme_s11_send_to_sgw(pkbuf_t *pkbuf);
|
||||
CORE_DECLARE(status_t) mme_s11_send_to_sgw(void *sgw, pkbuf_t *pkbuf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ status_t s1ap_open(void)
|
|||
|
||||
rc = net_listen_with_addr(&mme_self()->s1ap_sock,
|
||||
SOCK_STREAM, IPPROTO_SCTP, mme_self()->s1ap_port,
|
||||
mme_self()->mme_local_addr);
|
||||
mme_self()->s1ap_addr);
|
||||
if (rc != 0)
|
||||
{
|
||||
d_error("Can't establish S1-ENB(port:%d) path(%d:%s)",
|
||||
|
@ -36,7 +36,7 @@ status_t s1ap_open(void)
|
|||
}
|
||||
|
||||
d_trace(1, "s1_enb_listen() %s:%d\n",
|
||||
INET_NTOP(&mme_self()->mme_local_addr, buf), mme_self()->s1ap_port);
|
||||
INET_NTOP(&mme_self()->s1ap_addr, buf), mme_self()->s1ap_port);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ noinst_LTLIBRARIES = libsgw.la
|
|||
|
||||
libsgw_la_SOURCES = \
|
||||
event.h context.h \
|
||||
s11_path.h \
|
||||
sgw_path.h \
|
||||
sm.h
|
||||
|
||||
nodist_libsgw_la_SOURCES = \
|
||||
init.c event.c context.c \
|
||||
s11_path.c \
|
||||
sgw_path.c \
|
||||
sgw_sm.c
|
||||
|
||||
libsgw_la_DEPENDENCIES = \
|
||||
|
|
|
@ -19,12 +19,20 @@ status_t sgw_ctx_init()
|
|||
/* Initialize MME context */
|
||||
memset(&self, 0, sizeof(sgw_ctx_t));
|
||||
|
||||
self.sgw_local_addr = inet_addr("127.0.0.1");
|
||||
self.mme_remote_addr = inet_addr("127.0.0.1");
|
||||
self.pgw_remote_addr = inet_addr("127.0.0.1");
|
||||
self.s11_node.local_addr = inet_addr("127.0.0.1");
|
||||
self.s11_node.local_port = GTPV2_C_UDP_PORT + 1;
|
||||
self.s11_node.remote_addr = inet_addr("127.0.0.1");
|
||||
self.s11_node.remote_port = GTPV2_C_UDP_PORT;
|
||||
|
||||
self.s11_local_port = S11_UDP_PORT + 1;
|
||||
self.s11_remote_port = S11_UDP_PORT;
|
||||
self.s5c_node.local_addr = inet_addr("127.0.0.1");
|
||||
self.s5c_node.local_port = GTPV2_C_UDP_PORT + 2;
|
||||
self.s5c_node.remote_addr = inet_addr("127.0.0.1");
|
||||
self.s5c_node.remote_port = GTPV2_C_UDP_PORT + 3;
|
||||
|
||||
self.s5u_node.local_addr = inet_addr("127.0.0.1");
|
||||
self.s5u_node.local_port = GTPV1_U_UDP_PORT;
|
||||
self.s5u_node.remote_addr = inet_addr("127.0.0.1");
|
||||
self.s5u_node.remote_port = GTPV1_U_UDP_PORT + 1;
|
||||
|
||||
ctx_initialized = 1;
|
||||
|
||||
|
|
|
@ -7,18 +7,16 @@
|
|||
|
||||
#include "sm.h"
|
||||
|
||||
#include "gtp_path.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct _sgw_ctx_t {
|
||||
c_uint32_t sgw_local_addr;
|
||||
c_uint32_t mme_remote_addr;
|
||||
c_uint32_t pgw_remote_addr;
|
||||
|
||||
net_sock_t *s11_sock;
|
||||
c_uint16_t s11_local_port;
|
||||
c_uint16_t s11_remote_port;
|
||||
gtp_node_t s11_node;
|
||||
gtp_node_t s5c_node;
|
||||
gtp_node_t s5u_node;
|
||||
|
||||
msgq_id queue_id;
|
||||
tm_service_t tm_service;
|
||||
|
|
|
@ -11,6 +11,7 @@ typedef enum {
|
|||
SGW_EVT_BASE = FSM_USER_SIG,
|
||||
|
||||
EVT_MSG_SGW_S11,
|
||||
EVT_MSG_SGW_S5C,
|
||||
|
||||
SGW_EVT_TOP,
|
||||
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
#define TRACE_MODULE _sgw_s11_path
|
||||
#include "core_debug.h"
|
||||
#include "core_pkbuf.h"
|
||||
#include "core_net.h"
|
||||
|
||||
#include "3gpp_defs.h"
|
||||
#include "gtp_path.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "s11_path.h"
|
||||
|
||||
static int _sgw_s11_recv_cb(net_sock_t *net_sock, void *data)
|
||||
{
|
||||
event_t e;
|
||||
int rc;
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
d_assert(net_sock, return -1, "Null param");
|
||||
|
||||
pkbuf = gtp_read(net_sock);
|
||||
if (pkbuf == NULL)
|
||||
{
|
||||
if (net_sock->sndrcv_errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
d_trace(1, "S11_PDU is received from SGW\n");
|
||||
d_trace_hex(1, pkbuf->payload, pkbuf->len);
|
||||
|
||||
event_set(&e, EVT_MSG_SGW_S11);
|
||||
event_set_param1(&e, (c_uintptr_t)net_sock);
|
||||
event_set_param2(&e, (c_uintptr_t)pkbuf);
|
||||
|
||||
rc = event_send(sgw_self()->queue_id, &e);
|
||||
if (rc <= 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t sgw_s11_open()
|
||||
{
|
||||
return gtp_open(&sgw_self()->s11_sock, _sgw_s11_recv_cb, NULL,
|
||||
sgw_self()->sgw_local_addr, sgw_self()->s11_local_port);
|
||||
}
|
||||
|
||||
status_t sgw_s11_close()
|
||||
{
|
||||
return gtp_close(sgw_self()->s11_sock);
|
||||
}
|
||||
|
||||
status_t sgw_s11_send_to_mme(pkbuf_t *pkbuf)
|
||||
{
|
||||
return gtp_send(sgw_self()->s11_sock, pkbuf,
|
||||
sgw_self()->mme_remote_addr, sgw_self()->s11_remote_port);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef __SGW_S11_PATH_H__
|
||||
#define __SGW_S11_PATH_H__
|
||||
|
||||
#include "gtp_path.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
CORE_DECLARE(status_t) sgw_s11_open();
|
||||
CORE_DECLARE(status_t) sgw_s11_close();
|
||||
|
||||
CORE_DECLARE(status_t) sgw_s11_send_to_mme(pkbuf_t *pkbuf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __SGW_S11_PATH_H__ */
|
|
@ -0,0 +1,155 @@
|
|||
#define TRACE_MODULE _sgw_path
|
||||
#include "core_debug.h"
|
||||
#include "core_pkbuf.h"
|
||||
#include "core_net.h"
|
||||
|
||||
#include "3gpp_defs.h"
|
||||
#include "gtp_path.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "sgw_path.h"
|
||||
|
||||
static int _gtpv2_c_recv_cb(net_sock_t *net_sock, void *data)
|
||||
{
|
||||
event_t e;
|
||||
int rc;
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
gtp_node_t *gnode = data;
|
||||
|
||||
d_assert(net_sock, return -1, "Null param");
|
||||
d_assert(gnode, return -1, "Null param");
|
||||
|
||||
pkbuf = gtp_read(gnode);
|
||||
if (pkbuf == NULL)
|
||||
{
|
||||
if (net_sock->sndrcv_errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (GTP_COMPARE_REMOTE_NODE(gnode, &sgw_self()->s11_node))
|
||||
{
|
||||
d_trace(1, "S11 PDU received from MME\n");
|
||||
event_set(&e, EVT_MSG_SGW_S11);
|
||||
}
|
||||
else if (GTP_COMPARE_REMOTE_NODE(gnode, &sgw_self()->s5c_node))
|
||||
{
|
||||
d_trace(1, "S5-C PDU received from PGW\n");
|
||||
event_set(&e, EVT_MSG_SGW_S5C);
|
||||
}
|
||||
else
|
||||
d_assert(0, pkbuf_free(pkbuf); return -1, "Unknown GTP-Node");
|
||||
|
||||
d_trace_hex(1, pkbuf->payload, pkbuf->len);
|
||||
|
||||
event_set_param1(&e, (c_uintptr_t)gnode);
|
||||
event_set_param2(&e, (c_uintptr_t)pkbuf);
|
||||
|
||||
rc = event_send(sgw_self()->queue_id, &e);
|
||||
if (rc <= 0)
|
||||
{
|
||||
pkbuf_free(pkbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _gtpv1_u_recv_cb(net_sock_t *net_sock, void *data)
|
||||
{
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
gtp_node_t *gnode = data;
|
||||
|
||||
d_assert(net_sock, return -1, "Null param");
|
||||
d_assert(gnode, return -1, "Null param");
|
||||
|
||||
pkbuf = gtp_read(gnode);
|
||||
if (pkbuf == NULL)
|
||||
{
|
||||
if (net_sock->sndrcv_errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
d_trace(1, "S5U PDU received from GTP\n");
|
||||
d_trace_hex(1, pkbuf->payload, pkbuf->len);
|
||||
|
||||
/* TODO */
|
||||
|
||||
pkbuf_free(pkbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t sgw_path_open()
|
||||
{
|
||||
status_t rv;
|
||||
|
||||
rv = gtp_open(&sgw_self()->s11_node, _gtpv2_c_recv_cb);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't establish S11 Path with MME");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = gtp_open(&sgw_self()->s5c_node, _gtpv2_c_recv_cb);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't establish S5-C Path with PGW");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = gtp_open(&sgw_self()->s5u_node, _gtpv1_u_recv_cb);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't establish S5-U Path with PGW");
|
||||
return rv;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t sgw_path_close()
|
||||
{
|
||||
status_t rv;
|
||||
|
||||
rv = gtp_close(&sgw_self()->s11_node);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't close S11 Path with MME");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = gtp_close(&sgw_self()->s5c_node);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't close S5-C Path with MME");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = gtp_close(&sgw_self()->s5u_node);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't close S5-U Path with MME");
|
||||
return rv;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t sgw_path_send_to_s11(pkbuf_t *pkbuf)
|
||||
{
|
||||
return gtp_send(&sgw_self()->s11_node, pkbuf);
|
||||
}
|
||||
|
||||
status_t sgw_path_send_to_s5c(pkbuf_t *pkbuf)
|
||||
{
|
||||
return gtp_send(&sgw_self()->s5c_node, pkbuf);
|
||||
}
|
||||
|
||||
status_t sgw_path_send_to_s5u(pkbuf_t *pkbuf)
|
||||
{
|
||||
return gtp_send(&sgw_self()->s5u_node, pkbuf);
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef __SGW_PATH_H__
|
||||
#define __SGW_PATH_H__
|
||||
|
||||
#include "gtp_path.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
CORE_DECLARE(status_t) sgw_path_open();
|
||||
CORE_DECLARE(status_t) sgw_path_close();
|
||||
|
||||
CORE_DECLARE(status_t) sgw_path_send_to_s11(pkbuf_t *pkbuf);
|
||||
CORE_DECLARE(status_t) sgw_path_send_to_s5c(pkbuf_t *pkbuf);
|
||||
CORE_DECLARE(status_t) sgw_path_send_to_s5u(pkbuf_t *pkbuf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __SGW_PATH_H__ */
|
|
@ -4,7 +4,7 @@
|
|||
#include "sm.h"
|
||||
#include "context.h"
|
||||
#include "event.h"
|
||||
#include "s11_path.h"
|
||||
#include "sgw_path.h"
|
||||
|
||||
void sgw_state_initial(sgw_sm_t *s, event_t *e)
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ void sgw_state_operational(sgw_sm_t *s, event_t *e)
|
|||
{
|
||||
case FSM_ENTRY_SIG:
|
||||
{
|
||||
rv = sgw_s11_open();
|
||||
rv = sgw_path_open();
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't establish S11 path");
|
||||
|
@ -44,7 +44,7 @@ void sgw_state_operational(sgw_sm_t *s, event_t *e)
|
|||
}
|
||||
case FSM_EXIT_SIG:
|
||||
{
|
||||
rv = sgw_s11_close();
|
||||
rv = sgw_path_close();
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Can't close S11 path");
|
||||
|
@ -54,12 +54,20 @@ void sgw_state_operational(sgw_sm_t *s, event_t *e)
|
|||
}
|
||||
case EVT_MSG_SGW_S11:
|
||||
{
|
||||
net_sock_t *sock = (net_sock_t *)event_get_param1(e);
|
||||
d_assert(sock, break, "Null param");
|
||||
gtp_node_t *gnode = (gtp_node_t *)event_get_param1(e);
|
||||
d_assert(gnode, break, "Null param");
|
||||
|
||||
d_info("EVT_MSG_MME_S11 received");
|
||||
break;
|
||||
}
|
||||
case EVT_MSG_SGW_S5C:
|
||||
{
|
||||
gtp_node_t *gnode = (gtp_node_t *)event_get_param1(e);
|
||||
d_assert(gnode, break, "Null param");
|
||||
|
||||
d_info("EVT_MSG_MME_S5C received");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
d_error("No handler for event %s", sgw_event_get_name(e));
|
||||
|
|
|
@ -17,7 +17,7 @@ net_sock_t *tests1ap_enb_connect(void)
|
|||
|
||||
if (!mme) return NULL;
|
||||
|
||||
rv = net_open_with_addr(&sock, mme->mme_local_addr, "127.0.0.1", 0,
|
||||
rv = net_open_with_addr(&sock, mme->s1ap_addr, "127.0.0.1", 0,
|
||||
mme->s1ap_port, SOCK_SEQPACKET, IPPROTO_SCTP, 0);
|
||||
if (rv != CORE_OK) return NULL;
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ void test_initialize(void)
|
|||
{
|
||||
cellwire_initialize(NULL, NULL);
|
||||
|
||||
inet_pton(AF_INET, "127.0.0.1", &mme_self()->mme_local_addr);
|
||||
inet_pton(AF_INET, "127.0.0.1", &mme_self()->s1ap_addr);
|
||||
|
||||
atexit(test_terminate);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue