intermediate

This commit is contained in:
Sukchan Lee 2017-02-13 13:19:53 +09:00
parent 03f50ca6a0
commit 02452852be
10 changed files with 550 additions and 99 deletions

12
main.c
View File

@ -189,6 +189,17 @@ int main(int argc, char *argv[])
/* Parent */
}
/* FIXME: Pass built symbol table to HypcerCell module. */
{
extern int _mme_sm;
extern int _ctx;
extern int _s1_path;
d_trace_level(&_mme_sm, 100);
d_trace_level(&_ctx, 100);
d_trace_level(&_s1_path, 100);
}
signal_init();
if (cellwire_initialize(config_path) != CORE_OK)
@ -196,7 +207,6 @@ int main(int argc, char *argv[])
d_fatal("CellWire initialization failed. Aborted");
return EXIT_FAILURE;
}
show_version();
d_info("CellWire daemon start");

View File

@ -3,14 +3,12 @@
noinst_LTLIBRARIES = libcellwire.la
libcellwire_la_SOURCES = \
cellwire.h event.h context.h \
s1ap_message.h s1ap_conv.h \
sm.h
cellwire.h event.h context.h s1ap_message.h s1ap_conv.h s1_path.h \
sm.h
nodist_libcellwire_la_SOURCES = \
init.c mme_main.c event.c context.c \
s1ap_message.c s1ap_conv.c \
init.c event.c context.c s1ap_message.c s1ap_conv.c s1_path.c \
mme_sm.c
AM_CPPFLAGS = \

View File

@ -9,8 +9,14 @@
static mme_ctx_t self;
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 g_mme_ctx_initialized = 0;
static list_t g_enb_list;
static rwlock_id g_rwlock;
static int g_cpath_post_q;
@ -19,12 +25,21 @@ status_t context_init()
d_assert(g_mme_ctx_initialized == 0, return CORE_ERROR,
"MME context already has been initialized");
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(&g_enb_list);
rwlock_create(&g_rwlock);
d_assert(g_rwlock, return CORE_ERROR, "RW-lock creation failed");
/* Initialize MME context */
memset(&self, 0, sizeof(mme_ctx_t));
self.enb_local_addr = inet_addr("127.0.0.1");
self.enb_s1_port = S1_SCTP_PORT;
self.plmn_id.mnc_len = 2;
self.plmn_id.mcc = 1; /* 001 */
self.plmn_id.mnc = 1; /* 01 */
@ -50,6 +65,12 @@ status_t context_final()
d_assert(g_mme_ctx_initialized == 1, return CORE_ERROR,
"HyperCell context already has been finalized");
enb_ctx_remove_all();
pool_final(&enb_pool);
pool_final(&ue_pool);
pool_final(&rab_pool);
g_mme_ctx_initialized = 0;
return CORE_OK;
@ -90,3 +111,90 @@ mme_ctx_t* mme_self()
{
return &self;
}
enb_ctx_t* enb_ctx_add()
{
enb_ctx_t *enb = NULL;
/* Allocate new eNB context */
pool_alloc_node(&enb_pool, &enb);
d_assert(enb, return NULL, "eNB context allocation failed");
/* Initialize eNB context */
memset(enb, 0, sizeof(enb_ctx_t));
/* Add new eNB context to list */
list_append(&g_enb_list, enb);
return enb;
}
status_t enb_ctx_remove(enb_ctx_t *enb)
{
d_assert(enb, return CORE_ERROR, "Null param");
list_remove(&g_enb_list, enb);
pool_free_node(&enb_pool, enb);
return CORE_OK;
}
status_t enb_ctx_remove_all()
{
enb_ctx_t *enb = NULL, *next_enb = NULL;
enb = list_first(&g_enb_list);
while (enb)
{
next_enb = list_next(enb);
enb_ctx_remove(enb);
enb = next_enb;
}
return CORE_OK;
}
enb_ctx_t* enb_ctx_find_by_ip(c_uint32_t ip)
{
enb_ctx_t *enb = NULL;
enb = list_first(&g_enb_list);
while (enb)
{
if (ip == enb->ip)
break;
enb = list_next(enb);
}
return enb;
}
enb_ctx_t* enb_ctx_find_by_id(c_uint32_t id)
{
enb_ctx_t *enb = NULL;
enb = list_first(&g_enb_list);
while (enb)
{
if (id == enb->id)
break;
enb = list_next(enb);
}
return enb;
}
enb_ctx_t* enb_ctx_first()
{
return list_first(&g_enb_list);
}
enb_ctx_t* enb_ctx_next(enb_ctx_t *enb)
{
return list_next(enb);
}

View File

@ -3,6 +3,9 @@
#include "core_list.h"
#include "core_errno.h"
#include "core_net.h"
#include "sm.h"
#ifdef __cplusplus
extern "C" {
@ -12,6 +15,16 @@ extern "C" {
#define GRP_PER_MME 256 /* According to spec it is 65535 */
#define CODE_PER_MME 256 /* According to spec it is 256*/
#define CELL_PER_ENB 8
#define UE_PER_ENB 128
#define RAB_PER_UE 16
#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)
typedef list_t rab_list_t;
typedef struct _plmn_id_t {
c_uint16_t mcc;
c_uint16_t mnc;
@ -31,12 +44,54 @@ typedef struct _served_gummei {
/**
* This structure represents HypcerCell */
typedef struct _mme_ctx_t {
net_sock_t *enb_s1_sock;
c_uint16_t enb_s1_port;
c_uint32_t enb_local_addr; /** Network byte order */
plmn_id_t plmn_id;
c_uint8_t relative_capacity;
srvd_gummei_t srvd_gummei;
c_uint8_t relative_capacity;
c_uint16_t tac;
} mme_ctx_t;
/**
* This structure represents eNB */
typedef struct _enb_ctx_t {
lnode_t node; /**< A node of list_t */
enb_s1_sm_t s1_sm; /**< eNB S1 state machine */
net_sock_t *s1_sock;
c_uint32_t ip; /** Network byte order */
c_uint32_t id;
} enb_ctx_t;
/**
* This structure represents UE-S1 */
typedef struct _ue_ctx_t {
lnode_t node; /**< A node of list_t */
c_uint32_t enb_id; /** eNB-UE-S1AP-ID received from eNB */
c_uint32_t mme_id; /** MME-UE-S1AP-ID received from MME */
rab_list_t rab_list;
enb_ctx_t *enb;
mme_ctx_t *mme;
} ue_ctx_t;
/**
* This structure represents RAB */
typedef struct _rab_ctx_t {
lnode_t node; /**< A node of list_t */
c_uint32_t id;
ue_ctx_t *ue;
} rab_ctx_t;
CORE_DECLARE(status_t) context_init(void);
CORE_DECLARE(status_t) context_final(void);
@ -48,6 +103,14 @@ CORE_DECLARE(void) context_post_cpath(void);
CORE_DECLARE(int) context_fetch_cpath(void);
CORE_DECLARE(mme_ctx_t*) mme_self(void);
CORE_DECLARE(enb_ctx_t*) enb_ctx_add(void);
CORE_DECLARE(status_t) enb_ctx_remove(enb_ctx_t *enb);
CORE_DECLARE(status_t) enb_ctx_remove_all(void);
CORE_DECLARE(enb_ctx_t*) enb_ctx_find_by_ip(c_uint32_t ip);
CORE_DECLARE(enb_ctx_t*) enb_ctx_find_by_id(c_uint32_t id);
CORE_DECLARE(enb_ctx_t*) enb_ctx_first(void);
CORE_DECLARE(enb_ctx_t*) enb_ctx_next(enb_ctx_t *enb);
#define self() mme_self()
#ifdef __cplusplus

View File

@ -20,7 +20,7 @@ msgq_id event_create(void)
queue_id = msgq_create(EVT_Q_DEPTH, EVENT_SIZE, MSGQ_O_BLOCK);
d_assert(queue_id != 0, return CORE_ERROR, "Message queue creation failed");
return CORE_OK;
return queue_id;
}
status_t event_delete(msgq_id queue_id)

View File

@ -10,22 +10,10 @@
#include "context.h"
#include "event.h"
#define EVENT_WAIT_TIMEOUT 10000 /* 10 msec */
static thread_id mme_thread;
extern void *THREAD_FUNC mme_main(void *data);
void threads_start()
{
status_t rv;
rv = thread_create(&mme_thread, NULL, mme_main, NULL);
d_assert(rv == CORE_OK, return,
"MME State machine thread creation failed");
}
void threads_stop()
{
thread_delete(mme_thread);
}
static thread_id path_thread;
status_t cellwire_initialize(char *config_path)
{
@ -44,3 +32,86 @@ void cellwire_terminate(void)
{
context_final();
}
void *THREAD_FUNC mme_main(void *data)
{
event_t event;
msgq_id queue_id;
mme_sm_t mme_sm;
c_time_t prev_tm, now_tm;
int r;
memset(&event, 0, sizeof(event_t));
queue_id = event_create();
d_assert(queue_id, return NULL, "MME event queue creation failed");
fsm_create(&mme_sm.fsm, mme_state_initial, mme_state_final);
d_assert(&mme_sm.fsm, return NULL, "MME state machine creation failed");
mme_sm.queue_id = queue_id;
tm_service_init(&mme_sm.tm_service);
fsm_init((fsm_t*)&mme_sm, 0);
prev_tm = time_now();
while (!thread_should_stop())
{
r = event_timedrecv(queue_id, &event, EVENT_WAIT_TIMEOUT);
d_assert(r != CORE_ERROR, continue,
"While receiving a event message, error occurs");
now_tm = time_now();
/* if the gap is over 10 ms, execute preriodic jobs */
if (now_tm - prev_tm > EVENT_WAIT_TIMEOUT)
{
event_timer_execute(&mme_sm.tm_service);
prev_tm = now_tm;
}
if (r == CORE_TIMEUP)
{
continue;
}
fsm_dispatch((fsm_t*)&mme_sm, (fsm_event_t*)&event);
}
fsm_final((fsm_t*)&mme_sm, 0);
fsm_clear((fsm_t*)&mme_sm);
event_delete(queue_id);
return NULL;
}
void *THREAD_FUNC path_main(void *data)
{
while (!thread_should_stop())
{
net_fds_read_run(50);
}
return NULL;
}
void threads_start()
{
status_t rv;
rv = thread_create(&mme_thread, NULL, mme_main, NULL);
d_assert(rv == CORE_OK, return,
"MME State machine thread creation failed");
rv = thread_create(&path_thread, NULL, path_main, NULL);
d_assert(rv == CORE_OK, return,
"Network PATH thread creation failed");
}
void threads_stop()
{
thread_delete(mme_thread);
thread_delete(path_thread);
}

View File

@ -1,73 +0,0 @@
/**
* @file cp_main.c
*/
/* Server */
#include "event.h"
#include "sm.h"
/* Core library */
#include "core.h"
#define TRACE_MODULE _smmain
#include "core_debug.h"
#include "core_thread.h"
#include "core_msgq.h"
#include "context.h"
#define EVENT_WAIT_TIMEOUT 10000 /* 10 msec */
void *THREAD_FUNC mme_main(void *data)
{
event_t event;
msgq_id queue_id;
mme_sm_t mme_sm;
c_time_t prev_tm, now_tm;
int r;
memset(&event, 0, sizeof(event_t));
queue_id = event_create();
d_assert(queue_id, return NULL, "MME event queue creation failed");
fsm_create(&mme_sm.fsm, mme_state_initial, mme_state_final);
d_assert(&mme_sm.fsm, return NULL, "MME state machine creation failed");
mme_sm.queue_id = queue_id;
tm_service_init(&mme_sm.tm_service);
fsm_init((fsm_t*)&mme_sm, 0);
prev_tm = time_now();
while (!thread_should_stop())
{
r = event_timedrecv(queue_id, &event, EVENT_WAIT_TIMEOUT);
d_assert(r != CORE_ERROR, continue,
"While receiving a event message, error occurs");
now_tm = time_now();
/* if the gap is over 10 ms, execute preriodic jobs */
if (now_tm - prev_tm > EVENT_WAIT_TIMEOUT)
{
event_timer_execute(&mme_sm.tm_service);
prev_tm = now_tm;
}
if (r == CORE_TIMEUP)
{
continue;
}
fsm_dispatch((fsm_t*)&mme_sm, (fsm_event_t*)&event);
}
fsm_final((fsm_t*)&mme_sm, 0);
fsm_clear((fsm_t*)&mme_sm);
event_delete(queue_id);
return NULL;
}

View File

@ -1,9 +1,10 @@
#define TRACE_MODULE _master_sm
#define TRACE_MODULE _mme_sm
#include "core_debug.h"
#include "sm.h"
#include "context.h"
#include "event.h"
#include "s1_path.h"
void mme_state_initial(mme_sm_t *s, event_t *e)
{
@ -23,22 +24,65 @@ void mme_state_final(mme_sm_t *s, event_t *e)
void mme_state_operational(mme_sm_t *s, event_t *e)
{
#if 0
status_t rv;
char buf[INET_ADDRSTRLEN];
#endif
sm_trace(1, e);
d_assert(s, return, "Null param");
d_assert(s->queue_id, return, "Null param");
switch (event_get(e))
{
case FSM_ENTRY_SIG:
{
rv = s1_open(s->queue_id);
if (rv != CORE_OK)
{
d_error("Can't establish S1 path");
break;
}
break;
}
case FSM_EXIT_SIG:
{
rv = s1_close();
if (rv != CORE_OK)
{
d_error("Can't close S1 path");
break;
}
break;
}
case EVT_LO_ENB_S1_CONNREFUSED:
{
net_sock_t *sock = (net_sock_t *)event_get_param1(e);
d_assert(sock, break, "Null param");
c_uint32_t ip_addr = (c_uint32_t)event_get_param2(e);
d_info("Socket[%s] connection refused", INET_NTOP(&ip_addr, buf));
net_unregister_sock(sock);
net_close(sock);
enb_ctx_t *enb = enb_ctx_find_by_ip(ip_addr);
if (enb)
{
/* Remove eNB S1 state machine if exist */
if (FSM_STATE(&enb->s1_sm))
{
fsm_final((fsm_t*)&enb->s1_sm, 0);
fsm_clear((fsm_t*)&enb->s1_sm);
}
enb_ctx_remove(enb);
d_info("eNB-S1[%x] connection refused!!!", enb->id);
}
else
{
d_error("Can't find eNB-S1 for [%s]!!!",
INET_NTOP(&ip_addr, buf));
}
break;
}
default:

204
src/s1_path.c Normal file
View File

@ -0,0 +1,204 @@
#define TRACE_MODULE _s1_path
#include "core.h"
#include "core_debug.h"
#include "core_net.h"
#include "event.h"
#include "s1_path.h"
#define MAX_S1_PKBUF_SIZE 8192
static int _s1_accept_cb(net_sock_t *net_sock, void *data);
status_t s1_open(msgq_id queue_id)
{
char buf[INET_ADDRSTRLEN];
int rc;
rc = net_listen_with_addr(&mme_self()->enb_s1_sock,
SOCK_STREAM, IPPROTO_SCTP, mme_self()->enb_s1_port,
mme_self()->enb_local_addr);
if (rc != 0)
{
d_error("Can't establish S1-ENB(port:%d) path(%d:%s)",
mme_self()->enb_s1_port, errno, strerror(errno));
mme_self()->enb_s1_sock = NULL;
return CORE_ERROR;
}
rc = net_register_sock(
mme_self()->enb_s1_sock, _s1_accept_cb, (void *)queue_id);
if (rc != 0)
{
d_error("Can't establish S1-ENB path(%d:%s)",
errno, strerror(errno));
net_close(mme_self()->enb_s1_sock);
mme_self()->enb_s1_sock = NULL;
return CORE_ERROR;
}
d_trace(1, "s1_enb_listen() %s:%d\n",
INET_NTOP(&mme_self()->enb_local_addr, buf), mme_self()->enb_s1_port);
return CORE_OK;
}
status_t s1_close()
{
d_assert(mme_self(), return CORE_ERROR, "Null param");
d_assert(mme_self()->enb_s1_sock != NULL, return CORE_ERROR,
"S1-ENB path already opened");
net_unregister_sock(mme_self()->enb_s1_sock);
net_close(mme_self()->enb_s1_sock);
mme_self()->enb_s1_sock = NULL;
return CORE_OK;
}
static int _s1_accept_cb(net_sock_t *net_sock, void *data)
{
char buf[INET_ADDRSTRLEN];
ssize_t r;
net_sock_t *remote_sock;
msgq_id queue_id = (msgq_id)data;
d_assert(net_sock, return -1, "Null param");
d_assert(queue_id, return -1, "Null param");
r = net_accept(&remote_sock, net_sock, 0);
if (r > 0)
{
d_trace(1, "eNB-S1 accepted[%s] in s1_path module\n",
INET_NTOP(&remote_sock->remote.sin_addr.s_addr, buf));
event_t e;
event_set(&e, EVT_LO_ENB_S1_ACCEPT, (c_uintptr_t)remote_sock);
event_send(queue_id, &e);
}
else
{
d_error("net_accept failed(r = %d, errno = %d)", r, errno);
}
return r;
}
static status_t s1_recv(net_sock_t *net_sock, pkbuf_t *pkb,
msgq_id queue_id, event_e event)
{
event_t e;
d_assert(net_sock, return CORE_ERROR, "Null param");
d_assert(pkb, return CORE_ERROR, "Null param");
d_assert(event == EVT_S1_ENB_INF,
return CORE_ERROR, "Invalid event = %d", event);
d_assert(queue_id, return -1, "Null param");
d_trace(1, "S1AP_PDU is received from eNB-Inf\n");
d_trace_hex(1, pkb->payload, pkb->len);
event_set(&e, event, 0);
event_set_msg(&e, pkb, net_sock->remote.sin_addr.s_addr);
return event_send(queue_id, &e);
}
int _s1_recv_cb(net_sock_t *net_sock, msgq_id queue_id, event_e event)
{
status_t rv;
pkbuf_t *pkb;
ssize_t r;
c_uint32_t ip_addr = net_sock->remote.sin_addr.s_addr;
d_assert(net_sock, return -1, "Null param");
d_assert(event, return -1, "Null param");
d_assert(queue_id, return -1, "Null param");
pkb = pkbuf_alloc(0, MAX_S1_PKBUF_SIZE);
d_assert(pkb, return -1, "Can't allocate pkbuf");
r = net_read(net_sock, pkb->payload, pkb->len, 0);
if (r == -2)
{
pkbuf_free(pkb);
}
else if (r <= 0)
{
pkbuf_free(pkb);
if (net_sock->sndrcv_errno == EAGAIN)
{
d_warn("net_read(event:%d) failed(%d:%s)", event,
net_sock->sndrcv_errno, strerror(net_sock->sndrcv_errno));
return 0;
}
else if (net_sock->sndrcv_errno == ECONNREFUSED)
{
d_warn("net_read(event:%d) failed(%d:%s)", event,
net_sock->sndrcv_errno, strerror(net_sock->sndrcv_errno));
}
else
{
d_error("net_read(event:%d) failed(%d:%s)", event,
net_sock->sndrcv_errno, strerror(net_sock->sndrcv_errno));
}
event_t e;
d_assert(event == EVT_S1_ENB_INF, return -1,
"Invalid event = %d", event);
event_set(&e, EVT_LO_ENB_S1_CONNREFUSED, (c_uintptr_t)net_sock);
event_set_param2(&e, (c_uintptr_t)ip_addr);
event_send(queue_id, &e);
return -1;
}
else
{
pkb->len = r;
rv = s1_recv(net_sock, pkb, queue_id, event);
if (rv == CORE_ERROR)
{
pkbuf_free(pkb);
d_error("s1_recv() failed");
return -1;
}
}
return 0;
}
status_t s1_send(net_sock_t *s, pkbuf_t *pkb)
{
char buf[INET_ADDRSTRLEN];
ssize_t sent;
d_assert(s, return CORE_ERROR, "Null param");
d_assert(pkb, return CORE_ERROR, "Null param");
sent = net_send(s, pkb->payload, pkb->len);
d_trace(1,"Sent %d->%d bytes to [%s:%d]\n",
pkb->len, sent, INET_NTOP(&s->remote.sin_addr.s_addr, buf),
ntohs(s->remote.sin_port));
d_trace_hex(1, pkb->payload, pkb->len);
if (sent < 0 || sent != pkb->len)
{
d_error("net_send error (%d:%s)",
s->sndrcv_errno, strerror(s->sndrcv_errno));
return CORE_ERROR;
}
return CORE_OK;
}
status_t s1_send_to_enb(enb_ctx_t *enb, pkbuf_t *pkb)
{
d_assert(enb, return CORE_ERROR, "Null param");
d_assert(pkb, return CORE_ERROR, "Null param");
d_assert(enb->s1_sock, return CORE_ERROR, "No S1 path with ENB");
return s1_send(enb->s1_sock, pkb);
}

26
src/s1_path.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __S1_PATH_H__
#define __S1_PATH_H__
#include "core.h"
#include "core_pkbuf.h"
#include "core_msgq.h"
#include "context.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
CORE_DECLARE(status_t) s1_open(msgq_id queue_id);
CORE_DECLARE(status_t) s1_close();
CORE_DECLARE(status_t) s1_send(net_sock_t *s, pkbuf_t *pkb);
CORE_DECLARE(status_t) s1_send_to_enb(enb_ctx_t *enb, pkbuf_t *pkb);
int _s1_recv_cb(net_sock_t *net_sock, msgq_id queue_id, event_e event);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* !__S1_PATH_H__ */