update it

This commit is contained in:
Sukchan Lee 2017-03-27 00:48:33 +09:00
parent 4cdefe152d
commit 814e3f7e94
28 changed files with 836 additions and 179 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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
}

View File

@ -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;

103
lib/gtp/gtp_xact.c Normal file
View File

@ -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(&gtp_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(&gtp_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;
}

86
lib/gtp/gtp_xact.h Normal file
View File

@ -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
View File

@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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:

145
src/mme/s11_build.c Normal file
View File

@ -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);
}

17
src/mme/s11_build.h Normal file
View File

@ -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__ */

View File

@ -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);
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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 = \

View File

@ -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;

View File

@ -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;

View File

@ -11,6 +11,7 @@ typedef enum {
SGW_EVT_BASE = FSM_USER_SIG,
EVT_MSG_SGW_S11,
EVT_MSG_SGW_S5C,
SGW_EVT_TOP,

View File

@ -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);
}

View File

@ -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__ */

155
src/sgw/sgw_path.c Normal file
View File

@ -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);
}

21
src/sgw/sgw_path.h Normal file
View File

@ -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__ */

View File

@ -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));

View File

@ -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;

View File

@ -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);
}