Commit 85e85fb9 authored by Cedric Roux's avatar Cedric Roux

- Update S1AP and SCTP layers to use ITTI for eNB: may broke the old version...

- Update S1AP and SCTP layers to use ITTI for eNB: may broke the old version of S1AP/SCTP (compile with USE_MME=R10 and ENABLE_ITTI=1)

pre-ci tests passed

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4342 818b1a75-f10b-46b9-bf7c-635c3b92a50f
parent d0de35dc
S1AP_DIR = $(OPENAIR3_DIR)/OPENAIRMME/S1AP
S1AP_OBJDIR = $(OPENAIR3_DIR)/OPENAIRMME/S1AP/enb_objs
include $(OPENAIR_TARGETS)/SIMU/USER/Makerules
S1AP_OBJDIR = $(S1AP_DIR)/enb_objs
ASN1MESSAGESDIR=$(S1AP_DIR)/MESSAGES
ASN1DIR=$(ASN1MESSAGESDIR)/ASN1
......@@ -26,7 +27,9 @@ libs1ap_OBJECTS = \
$(S1AP_OBJDIR)/s1ap_encoder.o \
$(S1AP_OBJDIR)/s1ap_decoder.o \
$(S1AP_OBJDIR)/s1ap_xer_print.o \
s1ap_eNB_decoder.o s1ap_eNB_encoder.o \
s1ap_eNB_itti_messaging.o \
s1ap_eNB_decoder.o \
s1ap_eNB_encoder.o \
s1ap_eNB_handlers.o \
s1ap_eNB_nnsf.o s1ap_eNB_ue_context.o \
s1ap_eNB_trace.o s1ap_eNB_overload.o \
......@@ -35,42 +38,30 @@ libs1ap_OBJECTS = \
$(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES))
# pull in dependency info for *existing* .o files
-include .*.d
# -include .*.d
-include *.d
CFLAGS = \
CFLAGS = \
-DENB_MODE \
-DENABLE_USE_MME \
-DEMIT_ASN_DEBUG=1 \
-DUSER_MODE \
-I./MESSAGES \
-I$(S1AP_OBJDIR) \
-I../GTPV1-U \
-I../GTPV1-U/nw-gtpv1u/shared \
-I../GTPV1-U/nw-gtpv1u/include \
-I../SCTP \
-I../UDP \
-I../UTILS \
-I../UTILS/HASHTABLE \
-I$(OPENAIR2_DIR)/COMMON \
-I$(S1AP_DIR) \
-I$(OPENAIR2_DIR) \
-I$(OPENAIR2_DIR)/UTIL \
-I../UTILS \
$(ADD_CFLAGS) \
-DENB_MODE \
-DENABLE_USE_MME \
-DEMIT_ASN_DEBUG_EXTERN \
-DUSER_MODE \
-g \
-O2 \
-Wall \
$(S1AP_CFLAGS) \
-Werror=implicit-function-declaration
$(libs1ap_OBJECTS): %.o : %.c
@echo "Compiling $<"
@$(CC) -c $(CFLAGS) -o $@ $<
@$(CC) -MM $(CFLAGS) $*.c > .$(notdir $*).d
@mv -f .$(notdir $*).d .$(notdir $*).d.tmp
@sed -e 's|.*:|$*.o:|' < .$(notdir $*).d.tmp > .$(notdir $*).d
@sed -e 's/.*://' -e 's/\\$$//' < .$(notdir $*).d.tmp | fmt -1 | \
sed -e 's/^ *//' -e 's/$$/:/' >> .$(notdir $*).d
@rm -f .$(notdir $*).tmp
@$(CC) -MM $(CFLAGS) $*.c > $*.d
@mv -f $*.d $*.d.tmp
@sed -e 's|.*:|$*.o:|' < $*.d.tmp > $*.d
@sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \
sed -e 's/^ *//' -e 's/$$/:/' >> $*.d
@rm -f $*.d.tmp
$(S1AP_OBJDIR)/s1ap_ieregen.stamp: $(ASN1DIR)/$(ASN1RELDIR)/S1AP-PDU-Contents.asn $(ASN1DIR)/asn1tostruct.py
mkdir -p $(S1AP_OBJDIR)
......@@ -87,10 +78,19 @@ libs1ap.a: $(S1AP_OBJDIR)/s1ap_ieregen.stamp $(S1AP_OBJDIR)/s1ap_asn1regen.stamp
@$(AR) rcs $@ $(libs1ap_OBJECTS)
clean:
rm -f $(libs1ap_OBJECTS)
rm -f $(libs1ap_OBJECTS:.o=.d)
rm -f libs1ap.a
rm -f $(S1AP_OBJDIR)/s1ap_asn1regen.stamp
rm -f $(S1AP_OBJDIR)/s1ap_ieregen.stamp
rm -f $(S1AP_OBJDIR)/s1ap_decoder.c $(S1AP_OBJDIR)/s1ap_encoder.c
rm -f $(S1AP_OBJDIR)/s1ap_xer_print.c $(S1AP_OBJDIR)/s1ap_ies_defs.h
\ No newline at end of file
@$(RM_F_V) $(libs1ap_OBJECTS)
@$(RM_F_V) .*.d
@$(RM_F_V) $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES))
@$(RM_F_V) $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES:.o=.d))
@$(RM_F_V) libs1ap.a
@$(RM_F_V) $(S1AP_OBJDIR)/s1ap_asn1regen.stamp
@$(RM_F_V) $(S1AP_OBJDIR)/s1ap_ieregen.stamp
@$(RM_F_V) $(S1AP_OBJDIR)/s1ap_decoder.c $(S1AP_OBJDIR)/s1ap_encoder.c
@$(RM_F_V) $(S1AP_OBJDIR)/s1ap_xer_print.c $(S1AP_OBJDIR)/s1ap_ies_defs.h
cleanall: clean
@$(RM_F_V) $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES:.o=.c))
@$(RM_F_V) $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES:.o=.h))
showcflags:
@echo s1ap cflags: $(CFLAGS)
\ No newline at end of file
......@@ -41,8 +41,9 @@
#include "S1AP-PDU.h"
int asn_debug = 0;
int asn1_xer_print = 0;
int asn1_xer_print = 1;
#if defined(EMIT_ASN_DEBUG_EXTERN)
inline void ASN_DEBUG(const char *fmt, ...)
{
if (asn_debug) {
......@@ -56,6 +57,7 @@ inline void ASN_DEBUG(const char *fmt, ...)
va_end(ap);
}
}
#endif
ssize_t s1ap_generate_initiating_message(
uint8_t **buffer,
......
......@@ -44,7 +44,9 @@
// extern int asn_debug_indent;
extern int asn_debug;
#if defined(EMIT_ASN_DEBUG_EXTERN)
inline void ASN_DEBUG(const char *fmt, ...);
#endif
#include "Criticality.h"
#include "Presence.h"
......@@ -400,9 +402,8 @@ extern int asn_debug;
extern int asn1_xer_print;
#if defined(ENB_MODE)
# include "mme_sim.h"
# include "UTIL/LOG/log.h"
# include "eNB_default_values.h"
# include "s1ap_eNB_default_values.h"
# define S1AP_ERROR(x, args...) LOG_E(S1AP, x, ##args)
# define S1AP_WARN(x, args...) LOG_W(S1AP, x, ##args)
# define S1AP_TRAF(x, args...) LOG_T(S1AP, x, ##args)
......@@ -420,19 +421,18 @@ struct s1ap_message_s;
/** \brief Function callback prototype.
**/
#if defined(ENB_MODE)
typedef int (*s1ap_message_decoded_callback)(
eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
struct s1ap_message_s *message_p
);
#else
// typedef int (*s1ap_message_decoded_callback)(
// eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p
// );
typedef int (*s1ap_message_decoded_callback)(
uint32_t assocId,
uint32_t stream,
uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p
);
#endif
/** \brief Encode a successfull outcome message
\param buffer pointer to buffer in which data will be encoded
\param length pointer to the length of buffer
......
......@@ -28,6 +28,7 @@
*******************************************************************************/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
......@@ -35,8 +36,9 @@
#include "tree.h"
#include "queue.h"
#include "mme_sim.h"
#include "eNB_default_values.h"
#include "intertask_interface.h"
#include "s1ap_eNB_default_values.h"
#include "s1ap_common.h"
#include "s1ap_ies_defs.h"
......@@ -50,157 +52,299 @@
#include "s1ap_eNB_nas_procedures.h"
#include "s1ap_eNB_management_procedures.h"
#include "s1ap_eNB_itti_messaging.h"
#include "sctp_primitives_client.h"
#include "assertions.h"
#include "conversions.h"
static int s1ap_eNB_generate_s1_setup_request(eNB_mme_desc_t *eNB_desc_p,
s1ap_eNB_mme_data_t *mme_assoc_p);
s1ap_eNB_internal_data_t s1ap_eNB_internal_data;
static int s1ap_eNB_generate_s1_setup_request(
s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p);
RB_GENERATE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry, s1ap_eNB_compare_assoc_id);
inline int s1ap_eNB_compare_assoc_id(
struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2)
{
if (p1->sctp_data.assoc_id < p2->sctp_data.assoc_id) {
return -1;
}
if (p1->sctp_data.assoc_id > p2->sctp_data.assoc_id) {
return 1;
if (p1->assoc_id == -1) {
if (p1->cnx_id < p2->cnx_id) {
return -1;
}
if (p1->cnx_id > p2->cnx_id) {
return 1;
}
} else {
if (p1->assoc_id < p2->assoc_id) {
return -1;
}
if (p1->assoc_id > p2->assoc_id) {
return 1;
}
}
/* Matching reference */
return 0;
}
inline struct s1ap_eNB_mme_data_s *s1ap_eNB_get_MME(eNB_mme_desc_t *eNB_desc_p,
uint32_t assoc_id)
inline struct s1ap_eNB_mme_data_s *s1ap_eNB_get_MME(
s1ap_eNB_instance_t *instance_p,
int32_t assoc_id, uint16_t cnx_id)
{
struct s1ap_eNB_mme_data_s temp;
struct s1ap_eNB_mme_data_s temp;
struct s1ap_eNB_mme_data_s *found;
memset(&temp, 0, sizeof(struct s1ap_eNB_mme_data_s));
temp.sctp_data.assoc_id = assoc_id;
temp.assoc_id = assoc_id;
temp.cnx_id = cnx_id;
if (instance_p == NULL) {
STAILQ_FOREACH(instance_p, &s1ap_eNB_internal_data.s1ap_eNB_instances_head,
s1ap_eNB_entries)
{
found = RB_FIND(s1ap_mme_map, &instance_p->s1ap_mme_head, &temp);
if (found != NULL) {
return found;
}
}
} else {
return RB_FIND(s1ap_mme_map, &instance_p->s1ap_mme_head, &temp);
}
return RB_FIND(s1ap_mme_map, &eNB_desc_p->s1ap_mme_head, &temp);
return NULL;
}
int s1ap_run(eNB_mme_desc_t *eNB_desc_p)
// int s1ap_run(eNB_mme_desc_t *eNB_desc_p)
// {
// int ret = 0;
// struct s1ap_eNB_mme_data_s *mme_p;
//
// DevAssert(eNB_desc_p != NULL);
//
// RB_FOREACH(mme_p, s1ap_mme_map, &eNB_desc_p->s1ap_mme_head) {
// struct sctp_queue_item_s *item_p;
//
// /* Run the SCTP part for each MME */
// sctp_run(&mme_p->sctp_data);
//
// S1AP_DEBUG("Entering s1ap_run for eNB %d: %d packet(s) to handle\n",
// eNB_desc_p->eNB_id, mme_p->sctp_data.queue_length);
//
// /* Handle every message in the queue */
// TAILQ_FOREACH(item_p, &mme_p->sctp_data.sctp_queue, entry) {
// /* Handle the message in S1AP */
// s1ap_eNB_handle_message(eNB_desc_p, item_p);
// /* Remove the packet from the list and update data */
// TAILQ_REMOVE(&mme_p->sctp_data.sctp_queue, item_p, entry);
// ret += item_p->length;
// mme_p->sctp_data.queue_size -= item_p->length;
// mme_p->sctp_data.queue_length--;
// /* Deallocate memory as the message has been handled */
// free(item_p->buffer);
// free(item_p);
// }
// }
// return ret;
// }
static s1ap_eNB_instance_t *s1ap_eNB_get_instance(uint8_t mod_id)
{
int ret = 0;
struct s1ap_eNB_mme_data_s *mme_p;
DevAssert(eNB_desc_p != NULL);
RB_FOREACH(mme_p, s1ap_mme_map, &eNB_desc_p->s1ap_mme_head) {
struct sctp_queue_item_s *item_p;
/* Run the SCTP part for each MME */
sctp_run(&mme_p->sctp_data);
S1AP_DEBUG("Entering s1ap_run for eNB %d: %d packet(s) to handle\n",
eNB_desc_p->eNB_id, mme_p->sctp_data.queue_length);
/* Handle every message in the queue */
TAILQ_FOREACH(item_p, &mme_p->sctp_data.sctp_queue, entry) {
/* Handle the message in S1AP */
s1ap_eNB_handle_message(eNB_desc_p, item_p);
/* Remove the packet from the list and update data */
TAILQ_REMOVE(&mme_p->sctp_data.sctp_queue, item_p, entry);
ret += item_p->length;
mme_p->sctp_data.queue_size -= item_p->length;
mme_p->sctp_data.queue_length--;
/* Deallocate memory as the message has been handled */
free(item_p->buffer);
free(item_p);
s1ap_eNB_instance_t *temp = NULL;
STAILQ_FOREACH(temp, &s1ap_eNB_internal_data.s1ap_eNB_instances_head,
s1ap_eNB_entries)
{
if (temp->mod_id == mod_id) {
/* Matching occurence */
return temp;
}
}
return ret;
return NULL;
}
int s1ap_eNB_init(eNB_mme_desc_t *eNB_desc_p,
char **local_ip_addr, int nb_local_ip,
char **remote_ip_addr, int nb_remote_ip)
static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
net_ip_address_t *mme_ip_address,
net_ip_address_t *local_ip_addr)
{
int i;
sctp_data_t sctp_data;
char hostname[30];
MessageDef *message_p;
sctp_new_association_req_t *sctp_new_association_req_p;
s1ap_eNB_mme_data_t *s1ap_mme_data_p;
DevAssert(eNB_desc_p != NULL);
DevAssert(instance_p != NULL);
DevAssert(mme_ip_address != NULL);
if (eNB_desc_p->eNB_id >= (1 << 20))
S1AP_WARN("eNB_id exceed limit of 20 bits...\n");
message_p = itti_alloc_new_message(TASK_S1AP, SCTP_NEW_ASSOCIATION_REQ);
if (gethostname(hostname, sizeof(hostname)) == -1) {
hostname[0] = '\0';
}
sctp_new_association_req_p = &message_p->msg.sctp_new_association_req;
/* Set the eNB name */
snprintf(eNB_desc_p->eNB_name, S1AP_ENB_NAME_LENGTH_MAX,
ENB_NAME " %s %u", hostname, eNB_desc_p->eNB_id & 0xFFFFF);
sctp_new_association_req_p->port = S1AP_PORT_NUMBER;
sctp_new_association_req_p->ppid = S1AP_SCTP_PPID;
S1AP_DEBUG("Initializing S1AP layer for eNB %u\n",
eNB_desc_p->eNB_id);
memcpy(&sctp_new_association_req_p->remote_address, mme_ip_address,
sizeof(*mme_ip_address));
/* TODO: RRM configuration... */
eNB_desc_p->tac = ENB_TAC;
eNB_desc_p->mcc = ENB_MCC;
eNB_desc_p->mnc = ENB_MNC;
/* Create new MME descriptor */
s1ap_mme_data_p = calloc(1, sizeof(*s1ap_mme_data_p));
DevAssert(s1ap_mme_data_p != NULL);
RB_INIT(&eNB_desc_p->s1ap_mme_head);
RB_INIT(&eNB_desc_p->s1ap_ue_head);
s1ap_mme_data_p->cnx_id = s1ap_eNB_internal_data.global_cnx_id;
sctp_new_association_req_p->ulp_cnx_id = s1ap_mme_data_p->cnx_id;
s1ap_eNB_internal_data.global_cnx_id++;
memset(&sctp_data, 0, sizeof(sctp_data_t));
s1ap_mme_data_p->assoc_id = -1;
s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
for (i = 0; i < nb_remote_ip; i++)
{
/* Connecting eNB to provided MME IP address and port */
if (sctp_connect_to_remote_host(local_ip_addr, nb_local_ip,
remote_ip_addr[i], S1AP_PORT_NUMBER,
SOCK_STREAM, &sctp_data) <= 0)
{
S1AP_ERROR("Failed to connect to %s:%d\n",
remote_ip_addr[i], S1AP_PORT_NUMBER);
return -1;
} else {
struct s1ap_eNB_mme_data_s *mme_assoc_p;
struct s1ap_eNB_mme_data_s *collision_p;
STAILQ_INIT(&s1ap_mme_data_p->served_gummei);
mme_assoc_p = calloc(1, sizeof(struct s1ap_eNB_mme_data_s));
mme_assoc_p->nextstream = 1;
/* Insert the new descriptor in list of known MME
* but not yet associated.
*/
RB_INSERT(s1ap_mme_map, &instance_p->s1ap_mme_head, s1ap_mme_data_p);
memcpy(&mme_assoc_p->sctp_data, &sctp_data, sizeof(sctp_data_t));
itti_send_msg_to_task(TASK_SCTP, INSTANCE_DEFAULT, message_p);
}
TAILQ_INIT(&mme_assoc_p->sctp_data.sctp_queue);
void s1ap_eNB_handle_register_eNB(s1ap_register_eNB_t *s1ap_register_eNB)
{
s1ap_eNB_instance_t *new_instance;
uint8_t index;
if ((collision_p = RB_INSERT(s1ap_mme_map, &eNB_desc_p->s1ap_mme_head,
mme_assoc_p)) != NULL) {
S1AP_WARN("Failed to add MME to the tree of associated MME\n");
free(mme_assoc_p);
return -1;
}
DevAssert(s1ap_register_eNB != NULL);
S1AP_DEBUG("[%d] Successfully added MME to the list of known host\n",
sctp_data.assoc_id);
S1AP_DEBUG("[%d] Now tries to send S1 setup request\n",
sctp_data.assoc_id);
/* Look if the provided mod id already exists
* If so notify user...
*/
new_instance = s1ap_eNB_get_instance(s1ap_register_eNB->mod_id);
DevAssert(new_instance == NULL);
new_instance = calloc(1, sizeof(s1ap_eNB_instance_t));
DevAssert(new_instance != NULL);
RB_INIT(&new_instance->s1ap_ue_head);
RB_INIT(&new_instance->s1ap_mme_head);
/* Copy usefull parameters */
new_instance->mod_id = s1ap_register_eNB->mod_id;
new_instance->eNB_name = s1ap_register_eNB->eNB_name;
new_instance->eNB_id = s1ap_register_eNB->eNB_id;
new_instance->cell_type = s1ap_register_eNB->cell_type;
new_instance->tac = s1ap_register_eNB->tac;
new_instance->mcc = s1ap_register_eNB->mcc;
new_instance->mnc = s1ap_register_eNB->mnc;
new_instance->default_drx = s1ap_register_eNB->default_drx;
STAILQ_INSERT_TAIL(&s1ap_eNB_internal_data.s1ap_eNB_instances_head,
new_instance, s1ap_eNB_entries);
S1AP_DEBUG("Registered new eNB with mod_id %u and %s eNB id %u\n",
s1ap_register_eNB->mod_id,
s1ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
s1ap_register_eNB->eNB_id);
DevCheck(s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS,
S1AP_MAX_NB_MME_IP_ADDRESS, s1ap_register_eNB->nb_mme, 0);
/* Trying to connect to provided list of MME ip address */
for (index = 0; index < s1ap_register_eNB->nb_mme; index++) {
s1ap_eNB_register_mme(new_instance, &s1ap_register_eNB->mme_ip_address[index],
&s1ap_register_eNB->enb_ip_address);
}
}
STAILQ_INIT(&mme_assoc_p->served_gummei);
if (s1ap_eNB_generate_s1_setup_request(eNB_desc_p, mme_assoc_p) == -1)
{
exit(EXIT_FAILURE);
}
}
void s1ap_eNB_handle_sctp_association_resp(sctp_new_association_resp_t *sctp_new_association_resp)
{
s1ap_eNB_instance_t *instance_p;
s1ap_eNB_mme_data_t *s1ap_mme_data_p;
DevAssert(sctp_new_association_resp != NULL);
instance_p = s1ap_eNB_get_instance(sctp_new_association_resp->mod_id);
DevAssert(instance_p != NULL);
s1ap_mme_data_p = s1ap_eNB_get_MME(instance_p, -1,
sctp_new_association_resp->ulp_cnx_id);
DevAssert(s1ap_mme_data_p != NULL);
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
S1AP_WARN("Received unsuccessful result for SCTP association (%u), mod_id %u, cnx_id %u\n",
sctp_new_association_resp->sctp_state,
sctp_new_association_resp->mod_id,
sctp_new_association_resp->ulp_cnx_id);
}
S1AP_DEBUG("Initializing S1AP layer for eNB %d: DONE\n", eNB_desc_p->eNB_id);
return 0;
/* Update parameters */
s1ap_mme_data_p->assoc_id = sctp_new_association_resp->assoc_id;
s1ap_mme_data_p->in_streams = sctp_new_association_resp->in_streams;
s1ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams;
/* Prepare new S1 Setup Request */
s1ap_eNB_generate_s1_setup_request(instance_p, s1ap_mme_data_p);
}
static
void s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind)
{
DevAssert(sctp_data_ind != NULL);
s1ap_eNB_handle_message(sctp_data_ind->assoc_id, sctp_data_ind->stream,
sctp_data_ind->buffer, sctp_data_ind->buffer_length);
free(sctp_data_ind->buffer);
}
void *s1ap_eNB_task(void *arg)
{
MessageDef *received_msg = NULL;
S1AP_DEBUG("Starting S1AP layer\n");
memset(&s1ap_eNB_internal_data, 0, sizeof(s1ap_eNB_internal_data));
STAILQ_INIT(&s1ap_eNB_internal_data.s1ap_eNB_instances_head);
itti_mark_task_ready(TASK_S1AP);
while (1) {
itti_receive_msg(TASK_S1AP, &received_msg);
switch (received_msg->header.messageId) {
case TERMINATE_MESSAGE:
itti_exit_task();
break;
case S1AP_REGISTER_ENB: {
/* Register a new eNB.
* in Virtual mode eNBs will be distinguished using the mod_id/
* Each eNB has to send an S1AP_REGISTER_ENB message with its
* own parameters.
*/
s1ap_eNB_handle_register_eNB(&received_msg->msg.s1ap_register_eNB);
} break;
case SCTP_NEW_ASSOCIATION_RESP: {
s1ap_eNB_handle_sctp_association_resp(&received_msg->msg.sctp_new_association_resp);
} break;
case SCTP_DATA_IND: {
s1ap_eNB_handle_sctp_data_ind(&received_msg->msg.sctp_data_ind);
} break;
default:
S1AP_ERROR("Received unhandled message with id %d\n",
received_msg->header.messageId);
break;
}
free(received_msg);
received_msg = NULL;
}
return NULL;
}
static int s1ap_eNB_generate_s1_setup_request(
eNB_mme_desc_t *eNB_desc_p,
s1ap_eNB_mme_data_t *mme_assoc_p)
s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p)
{
s1ap_message message;
s1ap_message message;
S1SetupRequestIEs_t *s1SetupRequest_p;
PLMNidentity_t plmnIdentity;
SupportedTAs_Item_t ta;
......@@ -208,39 +352,40 @@ static int s1ap_eNB_generate_s1_setup_request(
uint32_t len;
int ret;
DevAssert(eNB_desc_p != NULL);
DevAssert(mme_assoc_p != NULL);
DevAssert(instance_p != NULL);
DevAssert(s1ap_mme_data_p != NULL);
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_initiatingMessage;
message.direction = S1AP_PDU_PR_initiatingMessage;
message.procedureCode = ProcedureCode_id_S1Setup;
message.criticality = Criticality_reject;
s1SetupRequest_p = &message.msg.s1SetupRequestIEs;
memset((void *)&plmnIdentity, 0, sizeof(PLMNidentity_t));
memset((void *)&ta, 0, sizeof(SupportedTAs_Item_t));
mme_assoc_p->state = S1AP_ENB_STATE_WAITING;
s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
s1SetupRequest_p->global_ENB_ID.eNB_ID.present = ENB_ID_PR_macroENB_ID;
MACRO_ENB_ID_TO_BIT_STRING(eNB_desc_p->eNB_id,
MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id,
&s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID);
MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc,
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc,
&s1SetupRequest_p->global_ENB_ID.pLMNidentity);
INT16_TO_OCTET_STRING(eNB_desc_p->tac, &ta.tAC);
MCC_MNC_TO_TBCD(eNB_desc_p->mcc, eNB_desc_p->mnc, &plmnIdentity);
INT16_TO_OCTET_STRING(instance_p->tac, &ta.tAC);
MCC_MNC_TO_TBCD(instance_p->mcc, instance_p->mnc, &plmnIdentity);
ASN_SEQUENCE_ADD(&ta.broadcastPLMNs.list, &plmnIdentity);
ASN_SEQUENCE_ADD(&s1SetupRequest_p->supportedTAs.list, &ta);
s1SetupRequest_p->defaultPagingDRX = PagingDRX_v64;
s1SetupRequest_p->defaultPagingDRX = instance_p->default_drx;
if (eNB_desc_p->eNB_name != NULL) {
if (instance_p->eNB_name != NULL) {
s1SetupRequest_p->presenceMask |= S1SETUPREQUESTIES_ENBNAME_PRESENT;
OCTET_STRING_fromBuf(&s1SetupRequest_p->eNBname, eNB_desc_p->eNB_name,
strlen(eNB_desc_p->eNB_name));
OCTET_STRING_fromBuf(&s1SetupRequest_p->eNBname, instance_p->eNB_name,
strlen(instance_p->eNB_name));
}
if (s1ap_eNB_encode_pdu(&message, &buffer, &len) < 0) {
......@@ -248,165 +393,128 @@ static int s1ap_eNB_generate_s1_setup_request(
return -1;
}
if ((ret = sctp_send_msg(&mme_assoc_p->sctp_data, S1AP_SCTP_PPID, 0, buffer,
len)) < 0) {
S1AP_ERROR("Failed to send S1 setup request\n");
}
free(buffer);
/* Non UE-Associated signalling -> stream = 0 */
s1ap_eNB_itti_send_sctp_data_req(s1ap_mme_data_p->assoc_id, buffer, len, 0);
return ret;
}
int s1ap_eNB_generate_initial_UE_message(eNB_mme_desc_t *eNB_desc_p,
s1ap_nas_first_req_t nas_req_p)
{
s1ap_message message;
struct s1ap_eNB_mme_data_s *mme_desc_p;
struct s1ap_eNB_ue_context_s *ue_desc_p;
InitialUEMessageIEs_t *initial_ue_message_p;
uint8_t *buffer;
uint32_t length;
DevAssert(eNB_desc_p != NULL);
// int s1ap_eNB_generate_initial_UE_message(eNB_mme_desc_t *eNB_desc_p,
// s1ap_nas_first_req_t nas_req_p)
// {
// s1ap_message message;
// struct s1ap_eNB_mme_data_s *mme_desc_p;
// struct s1ap_eNB_ue_context_s *ue_desc_p;
// InitialUEMessageIEs_t *initial_ue_message_p;
//
// uint8_t *buffer;
// uint32_t length;
//
// DevAssert(eNB_desc_p != NULL);
//
// memset(&message, 0, sizeof(s1ap_message));
//
// message.direction = S1AP_PDU_PR_initiatingMessage;
// message.procedureCode = ProcedureCode_id_initialUEMessage;
//
// initial_ue_message_p = &message.msg.initialUEMessageIEs;
//
// /* Select the MME corresponding to the provided GUMMEI.
// * If no MME corresponds to the GUMMEI, the function selects the MME with the
// * highest capacity.
// * In case eNB has no MME associated, the eNB should inform RRC and discard
// * this request.
// */
// if (nas_req_p.ue_identity.present == GUMMEI_PROVIDED) {
// mme_desc_p = s1ap_eNB_nnsf_select_mme_by_gummei(
// eNB_desc_p,
// nas_req_p.establishment_cause, nas_req_p.ue_identity.identity.gummei);
// } else {
// mme_desc_p = s1ap_eNB_nnsf_select_mme_by_mme_code(
// eNB_desc_p,
// nas_req_p.establishment_cause, nas_req_p.ue_identity.identity.s_tmsi.mme_code);
// }
// if (mme_desc_p == NULL) {
// S1AP_WARN("No MME is associated to the eNB\n");
// // TODO: Inform RRC
// return -1;
// }
//
// /* The eNB should allocate a unique eNB UE S1AP ID for this UE. The value
// * will be used for the duration of the connectivity.
// */
// if ((ue_desc_p = s1ap_eNB_allocate_new_UE_context()) == NULL) {
// return -1;
// }
//
// /* Keep a reference to the selected MME */
// ue_desc_p->mme_ref = mme_desc_p;
// ue_desc_p->rnti = nas_req_p.rnti;
//
// do {
// struct s1ap_eNB_ue_context_s *collision_p;
//
// /* Peek a random value for the eNB_ue_s1ap_id */
// ue_desc_p->eNB_ue_s1ap_id = (random() + random()) & 0x00ffffff;
// if ((collision_p = RB_INSERT(s1ap_ue_map, &eNB_desc_p->s1ap_ue_head, ue_desc_p))
// == NULL) {
// /* Break the loop as the id is not already used by another UE */
// break;
// }
// } while(1);
//
// initial_ue_message_p->eNB_UE_S1AP_ID = ue_desc_p->eNB_ue_s1ap_id;
// /* Prepare the NAS PDU */
// initial_ue_message_p->nas_pdu.buf = nas_req_p.nas_pdu.buffer;
// initial_ue_message_p->nas_pdu.size = nas_req_p.nas_pdu.length;
//
// /* Set the establishment cause according to those provided by RRC */
// DevCheck(nas_req_p.establishment_cause <= RRC_CAUSE_MAX,
// nas_req_p.establishment_cause, 0, 0);
// initial_ue_message_p->rrC_Establishment_Cause = nas_req_p.establishment_cause;
//
// if (nas_req_p.ue_identity.present == S_TMSI_PROVIDED) {
// initial_ue_message_p->presenceMask |= INITIALUEMESSAGEIES_S_TMSI_PRESENT;
//
// MME_CODE_TO_OCTET_STRING(nas_req_p.ue_identity.identity.s_tmsi.mme_code,
// &initial_ue_message_p->s_tmsi.mMEC);
// M_TMSI_TO_OCTET_STRING(nas_req_p.ue_identity.identity.s_tmsi.m_tmsi,
// &initial_ue_message_p->s_tmsi.m_TMSI);
// } else {
// initial_ue_message_p->presenceMask |= INITIALUEMESSAGEIES_GUMMEI_ID_PRESENT;
//
// MCC_MNC_TO_PLMNID(nas_req_p.ue_identity.identity.gummei.mcc,
// nas_req_p.ue_identity.identity.gummei.mnc,
// &initial_ue_message_p->gummei_id.pLMN_Identity);
// MME_GID_TO_OCTET_STRING(nas_req_p.ue_identity.identity.gummei.mme_group_id,
// &initial_ue_message_p->gummei_id.mME_Group_ID);
// MME_CODE_TO_OCTET_STRING(nas_req_p.ue_identity.identity.gummei.mme_code,
// &initial_ue_message_p->gummei_id.mME_Code);
// }
//
// /* Assuming TAI is the TAI from the cell */
// INT16_TO_OCTET_STRING(eNB_desc_p->tac, &initial_ue_message_p->tai.tAC);
// MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc,
// &initial_ue_message_p->tai.pLMNidentity);
//
// /* Set the EUTRAN CGI
// * The cell identity is defined on 28 bits but as we use macro enb id,
// * we have to pad.
// */
// MACRO_ENB_ID_TO_CELL_IDENTITY(eNB_desc_p->eNB_id,
// &initial_ue_message_p->eutran_cgi.cell_ID);
// MCC_MNC_TO_TBCD(eNB_desc_p->mcc, eNB_desc_p->mnc,
// &initial_ue_message_p->eutran_cgi.pLMNidentity);
//
// if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
// /* Failed to encode message */
// return -1;
// }
//
// /* Update the current S1AP UE state */
// ue_desc_p->ue_state = S1AP_UE_WAITING_CSR;
//
// /* Send encoded message over sctp */
// return sctp_send_msg(&mme_desc_p->sctp_data, S1AP_SCTP_PPID, 1, buffer, length);
// }
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_initiatingMessage;
message.procedureCode = ProcedureCode_id_initialUEMessage;
initial_ue_message_p = &message.msg.initialUEMessageIEs;
/* Select the MME corresponding to the provided GUMMEI.
* If no MME corresponds to the GUMMEI, the function selects the MME with the
* highest capacity.
* In case eNB has no MME associated, the eNB should inform RRC and discard
* this request.
*/
if (nas_req_p.ue_identity.present == GUMMEI_PROVIDED) {
mme_desc_p = s1ap_eNB_nnsf_select_mme_by_gummei(
eNB_desc_p,
nas_req_p.establishment_cause, nas_req_p.ue_identity.identity.gummei);
} else {
mme_desc_p = s1ap_eNB_nnsf_select_mme_by_mme_code(
eNB_desc_p,
nas_req_p.establishment_cause, nas_req_p.ue_identity.identity.s_tmsi.mme_code);
}
if (mme_desc_p == NULL) {
S1AP_WARN("No MME is associated to the eNB\n");
// TODO: Inform RRC
return -1;
}
/* The eNB should allocate a unique eNB UE S1AP ID for this UE. The value
* will be used for the duration of the connectivity.
*/
if ((ue_desc_p = s1ap_eNB_allocate_new_UE_context()) == NULL) {
return -1;
}
/* Keep a reference to the selected MME */
ue_desc_p->mme_ref = mme_desc_p;
ue_desc_p->rnti = nas_req_p.rnti;
do {
struct s1ap_eNB_ue_context_s *collision_p;
/* Peek a random value for the eNB_ue_s1ap_id */
ue_desc_p->eNB_ue_s1ap_id = (random() + random()) & 0x00ffffff;
if ((collision_p = RB_INSERT(s1ap_ue_map, &eNB_desc_p->s1ap_ue_head, ue_desc_p))
== NULL) {
/* Break the loop as the id is not already used by another UE */
break;
}
} while(1);
initial_ue_message_p->eNB_UE_S1AP_ID = ue_desc_p->eNB_ue_s1ap_id;
/* Prepare the NAS PDU */
initial_ue_message_p->nas_pdu.buf = nas_req_p.nas_pdu.buffer;
initial_ue_message_p->nas_pdu.size = nas_req_p.nas_pdu.length;
/* Set the establishment cause according to those provided by RRC */
DevCheck(nas_req_p.establishment_cause <= RRC_CAUSE_MAX,
nas_req_p.establishment_cause, 0, 0);
initial_ue_message_p->rrC_Establishment_Cause = nas_req_p.establishment_cause;
if (nas_req_p.ue_identity.present == S_TMSI_PROVIDED) {
initial_ue_message_p->presenceMask |= INITIALUEMESSAGEIES_S_TMSI_PRESENT;
MME_CODE_TO_OCTET_STRING(nas_req_p.ue_identity.identity.s_tmsi.mme_code,
&initial_ue_message_p->s_tmsi.mMEC);
M_TMSI_TO_OCTET_STRING(nas_req_p.ue_identity.identity.s_tmsi.m_tmsi,
&initial_ue_message_p->s_tmsi.m_TMSI);
} else {
initial_ue_message_p->presenceMask |= INITIALUEMESSAGEIES_GUMMEI_ID_PRESENT;
MCC_MNC_TO_PLMNID(nas_req_p.ue_identity.identity.gummei.mcc,
nas_req_p.ue_identity.identity.gummei.mnc,
&initial_ue_message_p->gummei_id.pLMN_Identity);
MME_GID_TO_OCTET_STRING(nas_req_p.ue_identity.identity.gummei.mme_group_id,
&initial_ue_message_p->gummei_id.mME_Group_ID);
MME_CODE_TO_OCTET_STRING(nas_req_p.ue_identity.identity.gummei.mme_code,
&initial_ue_message_p->gummei_id.mME_Code);
}
/* Assuming TAI is the TAI from the cell */
INT16_TO_OCTET_STRING(eNB_desc_p->tac, &initial_ue_message_p->tai.tAC);
MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc,
&initial_ue_message_p->tai.pLMNidentity);
/* Set the EUTRAN CGI
* The cell identity is defined on 28 bits but as we use macro enb id,
* we have to pad.
*/
MACRO_ENB_ID_TO_CELL_IDENTITY(eNB_desc_p->eNB_id,
&initial_ue_message_p->eutran_cgi.cell_ID);
MCC_MNC_TO_TBCD(eNB_desc_p->mcc, eNB_desc_p->mnc,
&initial_ue_message_p->eutran_cgi.pLMNidentity);
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
/* Failed to encode message */
return -1;
}
/* Update the current S1AP UE state */
ue_desc_p->ue_state = S1AP_UE_WAITING_CSR;
/* Send encoded message over sctp */
return sctp_send_msg(&mme_desc_p->sctp_data, S1AP_SCTP_PPID, 1, buffer, length);
}
int s1ap_eNB_handle_api_req(eNB_mme_desc_t *eNB_desc_p,
s1ap_rrc_api_req_t *api_req_p)
{
int ret = -1;
DevAssert(eNB_desc_p != NULL);
DevAssert(api_req_p != NULL);
switch(api_req_p->api_req) {
case S1AP_API_NAS_FIRST_REQ:
return s1ap_eNB_generate_initial_UE_message(eNB_desc_p,
api_req_p->msg.first_nas_req);
case S1AP_API_NAS_UPLINK:
return s1ap_eNB_nas_uplink(eNB_desc_p, &api_req_p->msg.nas_uplink);
case S1AP_API_UE_CAP_INFO_IND:
return s1ap_eNB_ue_capabilities(eNB_desc_p, &api_req_p->msg.ue_cap_info_ind);
case S1AP_API_INITIAL_CONTEXT_SETUP_RESP:
return s1ap_eNB_initial_ctxt_resp(eNB_desc_p, &api_req_p->msg.initial_ctxt_resp);
case S1AP_API_NAS_NON_DELIVERY_IND:
case S1AP_API_PATH_SWITCH_REQ:
case S1AP_API_INITIAL_CONTEXT_SETUP_FAIL:
case S1AP_API_E_RAB_SETUP_RESP:
case S1AP_API_E_RAB_MODIFY_RESP:
case S1AP_API_E_RAB_RELEASE_RESP:
case S1AP_API_RESET:
case S1AP_API_RESET_ACK:
S1AP_ERROR("This API type (%02x) is not implemented yet\n",
api_req_p->api_req);
break;
default:
S1AP_ERROR("Unknown API type %02x\n", api_req_p->api_req);
break;
}
return ret;
}
......@@ -31,101 +31,18 @@
#include <stdio.h>
#include <stdint.h>
#include "tree.h"
#include "queue.h"
#include "mme_sim.h"
#include "s1ap_eNB_defs.h"
/** @defgroup _s1ap_impl_ S1AP Layer Reference Implementation for eNB
* @ingroup _ref_implementation_
* @{
*/
#ifndef S1AP_ENB_H_
#define S1AP_ENB_H_
/* Served PLMN identity element */
struct plmn_identity_s {
uint16_t mcc;
uint16_t mnc;
STAILQ_ENTRY(plmn_identity_s) next;
};
/* Served group id element */
struct served_group_id_s {
uint16_t mme_group_id;
STAILQ_ENTRY(served_group_id_s) next;
};
/* Served mme code for a particular MME */
struct mme_code_s {
uint8_t mme_code;
STAILQ_ENTRY(mme_code_s) next;
};
/* Served gummei element */
struct served_gummei_s {
/* Number of MME served PLMNs */
uint8_t nb_served_plmns;
/* List of served PLMNs by MME */
STAILQ_HEAD(served_plmns_s, plmn_identity_s) served_plmns;
/* Number of group id in list */
uint8_t nb_group_id;
/* Served group id list */
STAILQ_HEAD(served_group_ids_s, served_group_id_s) served_group_ids;
/* Number of MME code */
uint8_t nb_mme_code;
/* MME Code to uniquely identify an MME within an MME pool area */
STAILQ_HEAD(mme_codes_s, mme_code_s) mme_codes;
/* Next GUMMEI element */
STAILQ_ENTRY(served_gummei_s) next;
};
/* This structure describes association of a eNB to a MME */
typedef struct s1ap_eNB_mme_data_s {
/* This is the optional name provided by the MME */
char *mme_name;
/* Remote MME IP addr */
char *ip_addr;
/* List of served GUMMEI per MME. There is one GUMMEI per RAT with a max
* number of 8 RATs but in our case only one is used. The LTE related pool
* configuration is included on the first place in the list.
*/
STAILQ_HEAD(served_gummeis_s, served_gummei_s) served_gummei;
/* Relative processing capacity of an MME with respect to the other MMEs
* in the pool in order to load-balance MMEs within a pool as defined
* in TS 23.401.
*/
uint8_t relative_mme_capacity;
/* Current MME overload information (if any). */
s1ap_overload_state_t overload_state;
/* Current eNB->MME S1AP association state */
s1ap_eNB_state_t state;
/* SCTP related data for this MME */
sctp_data_t sctp_data;
/* Next usable stream for UE signalling */
int32_t nextstream;
/* MME descriptors tree, ordered by sctp assoc id */
RB_ENTRY(s1ap_eNB_mme_data_s) entry;
} s1ap_eNB_mme_data_t;
inline int s1ap_eNB_compare_assoc_id(
struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2);
/* Generate the tree management functions */
RB_PROTOTYPE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry,
s1ap_eNB_compare_assoc_id);
struct s1ap_eNB_mme_data_s *s1ap_eNB_get_MME(eNB_mme_desc_t *eNB_desc_p,
uint32_t assocId);
int s1ap_eNB_init(eNB_mme_desc_t *eNB_desc_p,
char *local_ip_addr[], int nb_local_ip,
char *remote_ip_addr[], int nb_remote_ip);
void *s1ap_eNB_task(void *arg);
#endif /* S1AP_ENB_H_ */
/**
* @}
*/
......@@ -106,7 +106,8 @@ static int s1ap_eNB_decode_unsuccessful_outcome(s1ap_message *message,
return -1;
}
int s1ap_eNB_decode_pdu(s1ap_message *message, uint8_t *buffer, uint32_t length)
int s1ap_eNB_decode_pdu(s1ap_message *message, const uint8_t * const buffer,
const uint32_t length)
{
S1AP_PDU_t pdu;
S1AP_PDU_t *pdu_p = &pdu;
......
......@@ -34,7 +34,7 @@
#ifndef S1AP_ENB_DECODER_H_
#define S1AP_ENB_DECODER_H_
int s1ap_eNB_decode_pdu(s1ap_message *message, uint8_t *buffer, uint32_t length)
__attribute__ ((warn_unused_result));
int s1ap_eNB_decode_pdu(s1ap_message *message, const uint8_t * const buffer,
const uint32_t length) __attribute__ ((warn_unused_result));
#endif /* S1AP_ENB_DECODER_H_ */
#ifndef S1AP_ENB_DEFAULT_VALUES_H_
#define S1AP_ENB_DEFAULT_VALUES_H_
#define ENB_TAC (0)
#define ENB_MCC (208)
#define ENB_MNC (34)
#define ENB_NAME "Eurecom ENB"
#define ENB_NAME_FORMAT (ENB_NAME" %u")
#define S1AP_PORT_NUMBER (36412)
#define S1AP_SCTP_PPID (18)
#define X2AP_PORT_NUMBER (36422)
#define X2AP_SCTP_PPID (27)
#define SCTP_OUT_STREAMS (64)
#define SCTP_IN_STREAMS (64)
#define SCTP_MAX_ATTEMPTS (5)
#define SCTP_RECV_BUFFER_SIZE (1024)
#endif /* S1AP_ENB_DEFAULT_VALUES_H_ */
......@@ -82,12 +82,12 @@ typedef enum {
S1AP_OVERLOAD_MAX,
} s1ap_overload_state_t;
typedef enum {
PAGING_DRX_32 = 0x0,
PAGING_DRX_64 = 0x1,
PAGING_DRX_128 = 0x2,
PAGING_DRX_256 = 0x3,
} paging_drx_t;
// typedef enum {
// PAGING_DRX_32 = 0x0,
// PAGING_DRX_64 = 0x1,
// PAGING_DRX_128 = 0x2,
// PAGING_DRX_256 = 0x3,
// } paging_drx_t;
typedef struct {
/* Octet string data */
......@@ -176,161 +176,156 @@ typedef struct {
} identity;
} ue_identity_t;
typedef struct {
/* The NAS First Req is the first message exchanged between RRC and S1AP
* for an UE.
* The rnti uniquely identifies an UE within a cell. Later the enb_ue_s1ap_id
* will be the unique identifier used between RRC and S1AP.
/* Served PLMN identity element */
struct plmn_identity_s {
uint16_t mcc;
uint16_t mnc;
STAILQ_ENTRY(plmn_identity_s) next;
};
/* Served group id element */
struct served_group_id_s {
uint16_t mme_group_id;
STAILQ_ENTRY(served_group_id_s) next;
};
/* Served mme code for a particular MME */
struct mme_code_s {
uint8_t mme_code;
STAILQ_ENTRY(mme_code_s) next;
};
/* Served gummei element */
struct served_gummei_s {
/* Number of MME served PLMNs */
uint8_t nb_served_plmns;
/* List of served PLMNs by MME */
STAILQ_HEAD(served_plmns_s, plmn_identity_s) served_plmns;
/* Number of group id in list */
uint8_t nb_group_id;
/* Served group id list */
STAILQ_HEAD(served_group_ids_s, served_group_id_s) served_group_ids;
/* Number of MME code */
uint8_t nb_mme_code;
/* MME Code to uniquely identify an MME within an MME pool area */
STAILQ_HEAD(mme_codes_s, mme_code_s) mme_codes;
/* Next GUMMEI element */
STAILQ_ENTRY(served_gummei_s) next;
};
struct s1ap_eNB_instance_s;
/* This structure describes association of a eNB to a MME */
typedef struct s1ap_eNB_mme_data_s {
/* MME descriptors tree, ordered by sctp assoc id */
RB_ENTRY(s1ap_eNB_mme_data_s) entry;
/* This is the optional name provided by the MME */
char *mme_name;
/* List of served GUMMEI per MME. There is one GUMMEI per RAT with a max
* number of 8 RATs but in our case only one is used. The LTE related pool
* configuration is included on the first place in the list.
*/
uint16_t rnti;
STAILQ_HEAD(served_gummeis_s, served_gummei_s) served_gummei;
rrc_establishment_cause_t establishment_cause;
nas_pdu_t nas_pdu;
/* If this flag is set S1AP layer is expecting the GUMMEI. If = 0,
* the temporary s-tmsi is used.
/* Relative processing capacity of an MME with respect to the other MMEs
* in the pool in order to load-balance MMEs within a pool as defined
* in TS 23.401.
*/
ue_identity_t ue_identity;
} s1ap_nas_first_req_t;
uint8_t relative_mme_capacity;
typedef struct {
unsigned eNB_ue_s1ap_id:24;
nas_pdu_t nas_pdu;
} s1ap_nas_uplink_t;
/* Current MME overload information (if any). */
s1ap_overload_state_t overload_state;
/* Current eNB->MME S1AP association state */
s1ap_eNB_state_t state;
typedef struct {
nas_pdu_t nas_pdu;
// cause_t cause;
} s1ap_nas_non_delivery_t;
/* Next usable stream for UE signalling */
int32_t nextstream;
typedef struct {
uint16_t rnti;
unsigned eNB_ue_s1ap_id:24;
/* Number of input/ouput streams */
uint16_t in_streams;
uint16_t out_streams;
/* Number of e_rab to be setup in the list */
uint8_t nb_of_e_rabs;
/* list of e_rab to be setup by RRC layers */
e_rab_t **e_rab_param;
} s1ap_e_rab_setup_req_t,
s1ap_initial_ctxt_setup_req_t;
/* Connexion id used when SCTP association is not established yet */
uint16_t cnx_id;
typedef struct {
unsigned eNB_ue_s1ap_id:24;
ue_radio_cap_t ue_radio_cap;
} s1ap_ue_cap_info_ind_t;
/* SCTP association id */
int32_t assoc_id;
typedef struct {
unsigned eNB_ue_s1ap_id:24;
/* Number of e_rab setup-ed in the list */
uint8_t nb_of_e_rabs;
/* list of e_rab setup-ed by RRC layers */
e_rab_setup_t *e_rabs;
/* Number of e_rab failed to be setup in list */
uint8_t nb_of_e_rabs_failed;
/* list of e_rabs that failed to be setup */
e_rab_failed_t *e_rabs_failed;
} s1ap_initial_ctxt_setup_resp_t;
/* Only meaningfull in virtual mode */
struct s1ap_eNB_instance_s *s1ap_eNB_instance;
} s1ap_eNB_mme_data_t;
typedef enum {
/** RRC -> S1AP API **/
#define S1AP_API_REQ_IS_INPUT(x) (x & 0x10)
/* RRC should use this api request for the first NAS message */
S1AP_API_NAS_FIRST_REQ = 0x10,
/* NAS messages with no context activation */
S1AP_API_NAS_UPLINK = 0x11,
/* When the eNB decides to not start the delivery of a NAS message that has
* been received over a UE-associated logical S1-connection or the eNB is
* unable to ensure that the message has been received by the UE, it shall
* report the non-delivery of this NAS message.
*/
S1AP_API_NAS_NON_DELIVERY_IND = 0x12,
/* This message is sent by the eNB to request the MME to switch DL GTP
* tunnel termination point(s) from one end-point to another.
*/
S1AP_API_PATH_SWITCH_REQ = 0x13,
/* This message is used to report the outcome of the request from the
* S1AP_API_NAS_INITIAL_CONTEXT_SETUP_REQ API request.
*/
S1AP_API_INITIAL_CONTEXT_SETUP_RESP = 0x14,
/* This message is used to report the unsuccessfull outcome of the request
* from the S1AP_API_NAS_INITIAL_CONTEXT_SETUP_REQ API request.
*/
S1AP_API_INITIAL_CONTEXT_SETUP_FAIL = 0x15,
/* This message is used to report the outcome of the request from the
* S1AP_API_INITIAL_CONTEXT_SETUP_REQ API request.
*/
S1AP_API_E_RAB_SETUP_RESP = 0x16,
/* This message is used to report the outcome of the request from the
* S1AP_API_E_RAB_SETUP_REQ API request.
*/
S1AP_API_E_RAB_MODIFY_RESP = 0x17,
/* This message is used to report the outcome of the request from the
* S1AP_API_E_RAB_MODIFY_REQ API request.
*/
S1AP_API_E_RAB_RELEASE_RESP = 0x18,
/* The purpose of the UE Capability Info Indication procedure is to enable
* the eNB to provide to the MME UE capability-related information.
*/
S1AP_API_UE_CAP_INFO_IND = 0x19,
/** S1AP -> RRC API **/
#define S1AP_API_REQ_IS_OUTPUT(x) (x & 0x20)
/* S1AP layer received a valid downlink info transfer message */
S1AP_API_NAS_DOWNLINK = 0x20,
/* The purpose of the Initial Context Setup procedure is to establish the
* necessary overall initial UE Context including ERAB context, the Security
* Key, Handover Restriction List, UE Radio capability and UE Security
* Capabilities etc.
typedef struct s1ap_eNB_instance_s {
/* Next s1ap eNB association.
* Only used for virtual mode.
*/
S1AP_API_NAS_INITIAL_CONTEXT_SETUP_REQ = 0x21,
/* The purpose of the E-RAB Setup procedure is to assign resources on Uu and
* S1 for one or several E-RABs and to setup corresponding Data Radio
* Bearers for a given UE.
*/
S1AP_API_E_RAB_SETUP_REQ = 0x22,
/* This message is sent by the MME and is used to request the eNB to modify
* the Data Radio Bearers and the allocated resources on Uu and S1 for one
* or several E-RABs.
*/
S1AP_API_E_RAB_MODIFY_REQ = 0x23,
/* This message is sent by the MME and is used to request the eNB to release
* allocated resources on Uu and S1 for one or several E-RABs.
STAILQ_ENTRY(s1ap_eNB_instance_s) s1ap_eNB_entries;
/* Tree of S1AP MME associations ordered by association ID */
RB_HEAD(s1ap_mme_map, s1ap_eNB_mme_data_s) s1ap_mme_head;
/* TODO: add a map ordered by relative MME capacity */
/* Tree of UE ordered by eNB_ue_s1ap_id's */
RB_HEAD(s1ap_ue_map, s1ap_eNB_ue_context_s) s1ap_ue_head;
/* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */
uint8_t mod_id;
/* Displayable name of eNB */
char *eNB_name;
/* Unique eNB_id to identify the eNB within EPC.
* In our case the eNB is a macro eNB so the id will be 20 bits long.
* For Home eNB id, this field should be 28 bits long.
*/
S1AP_API_E_RAB_RELEASE_REQ = 0x24,
/** S1AP <-> RRC API **/
/** Messages below are bi-directionnal and can be triggered by both RRC and
* S1AP.
**/
#define S1AP_API_REQ_IS_BIDIR(x) (x & 0x40)
/* At reception of RESET message, the eNB (or MME) shall release all
* allocated resources on S1 and Uu related to the UE association(s)
* indicated explicitly or implicitly in the RESET message and remove the
* indicated UE contexts including S1AP ID.
uint32_t eNB_id;
/* The type of the cell */
enum cell_type_e cell_type;
/* Tracking area code */
uint16_t tac;
/* Mobile Country Code
* Mobile Network Code
*/
S1AP_API_RESET = 0x40,
S1AP_API_RESET_ACK = 0x41,
} s1ap_rrc_api_req_type_t;
uint16_t mcc;
uint16_t mnc;
/* Default Paging DRX of the eNB as defined in TS 36.304 */
paging_drx_t default_drx;
} s1ap_eNB_instance_t;
typedef struct {
/* The API request type */
s1ap_rrc_api_req_type_t api_req;
union {
/** RRC -> S1AP requests **/
s1ap_nas_first_req_t first_nas_req;
s1ap_nas_uplink_t nas_uplink;
s1ap_initial_ctxt_setup_resp_t initial_ctxt_resp;
s1ap_nas_non_delivery_t nas_non_delivery;
s1ap_ue_cap_info_ind_t ue_cap_info_ind;
/** S1AP -> RRC requests **/
s1ap_e_rab_setup_req_t e_rab_setup_req;
s1ap_initial_ctxt_setup_req_t initial_ctxt_setup_req;
} msg;
} s1ap_rrc_api_req_t;
/* Callback notifier.
* Called when a new event has to be notified between S1AP -> RRC
*/
typedef int (*rrc_event_notify_t)(s1ap_rrc_api_req_t *api_req);
/* List of served eNBs
* Only used for virtual mode
*/
STAILQ_HEAD(s1ap_eNB_instances_head_s, s1ap_eNB_instance_s) s1ap_eNB_instances_head;
/* Nb of registered eNBs */
uint8_t nb_registered_eNBs;
/* Generate a unique connexion id used between S1AP and SCTP */
uint16_t global_cnx_id;
} s1ap_eNB_internal_data_t;
inline int s1ap_eNB_compare_assoc_id(
struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2);
/* Generate the tree management functions */
RB_PROTOTYPE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry,
s1ap_eNB_compare_assoc_id);
inline struct s1ap_eNB_mme_data_s *s1ap_eNB_get_MME(
s1ap_eNB_instance_t *instance_p,
int32_t assoc_id, uint16_t cnx_id);
int s1ap_eNB_init(s1ap_eNB_instance_t *eNB_desc_p,
char *local_ip_addr[], int nb_local_ip,
char *remote_ip_addr[], int nb_remote_ip);
#endif /* S1AP_ENB_DEFS_H_ */
......@@ -37,9 +37,12 @@
#include <stdint.h>
#include "intertask_interface.h"
#include "s1ap_common.h"
#include "s1ap_ies_defs.h"
#include "s1ap_eNB.h"
// #include "s1ap_eNB.h"
#include "s1ap_eNB_defs.h"
#include "s1ap_eNB_handlers.h"
#include "s1ap_eNB_decoder.h"
......@@ -47,12 +50,22 @@
#include "s1ap_eNB_trace.h"
#include "s1ap_eNB_nas_procedures.h"
#include "eNB_default_values.h"
#include "s1ap_eNB_default_values.h"
#include "conversions.h"
//Forward declaration
struct s1ap_message_s;
static
int s1ap_eNB_handle_s1_setup_response(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p);
int s1ap_eNB_handle_s1_setup_failure(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p);
static
int s1ap_eNB_handle_initial_context_request(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p);
/* Handlers matrix. Only eNB related procedure present here */
s1ap_message_decoded_callback messages_callback[][3] = {
......@@ -73,7 +86,7 @@ s1ap_message_decoded_callback messages_callback[][3] = {
{ 0, 0, 0 }, /* Reset */
{ 0, 0, 0 }, /* ErrorIndication */
{ 0, 0, 0 }, /* NASNonDeliveryIndication */
{ 0, s1ap_eNB_handle_s1_setup_response, 0 }, /* S1Setup */
{ 0, s1ap_eNB_handle_s1_setup_response, s1ap_eNB_handle_s1_setup_failure }, /* S1Setup */
{ 0, 0, 0 }, /* UEContextReleaseRequest */
{ 0, 0, 0 }, /* DownlinkS1cdma2000tunneling */
{ 0, 0, 0 }, /* UplinkS1cdma2000tunneling */
......@@ -115,23 +128,16 @@ static const char *direction2String[] = {
"UnSuccessfull outcome", /* successfull outcome */
};
int s1ap_eNB_handle_message(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p)
int s1ap_eNB_handle_message(uint32_t assoc_id, int32_t stream,
const uint8_t * const data, const uint32_t data_length)
{
struct s1ap_message_s message;
DevAssert(eNB_desc_p != NULL);
DevAssert(packet_p != NULL);
if (packet_p->ppid != S1AP_SCTP_PPID) {
S1AP_ERROR("Received data on unexpected PPID %d, expecting %d\n",
packet_p->ppid, S1AP_SCTP_PPID);
return -1;
}
DevAssert(data != NULL);
memset(&message, 0, sizeof(struct s1ap_message_s));
if (s1ap_eNB_decode_pdu(&message, packet_p->buffer, packet_p->length) < 0) {
if (s1ap_eNB_decode_pdu(&message, data, data_length) < 0) {
S1AP_ERROR("Failed to decode PDU\n");
return -1;
}
......@@ -140,7 +146,7 @@ int s1ap_eNB_handle_message(eNB_mme_desc_t *eNB_desc_p,
s1ap_message_decoded_callback))
|| (message.direction > S1AP_PDU_PR_unsuccessfulOutcome)) {
S1AP_ERROR("[SCTP %d] Either procedureCode %d or direction %d exceed expected\n",
packet_p->assoc_id, message.procedureCode, message.direction);
assoc_id, message.procedureCode, message.direction);
return -1;
}
/* No handler present.
......@@ -148,40 +154,56 @@ int s1ap_eNB_handle_message(eNB_mme_desc_t *eNB_desc_p,
*/
if (messages_callback[message.procedureCode][message.direction-1] == NULL) {
S1AP_ERROR("[SCTP %d] No handler for procedureCode %d in %s\n",
packet_p->assoc_id, message.procedureCode,
assoc_id, message.procedureCode,
direction2String[message.direction]);
return -1;
}
/* Calling the right handler */
return (*messages_callback[message.procedureCode][message.direction-1])(
eNB_desc_p, packet_p, &message);
return (*messages_callback[message.procedureCode][message.direction-1])
(assoc_id, stream, &message);
}
int s1ap_eNB_handle_s1_setup_response(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
int s1ap_eNB_handle_s1_setup_failure(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p)
{
/* S1 Setup Failure == Non UE-related procedure -> stream 0 */
if (stream != 0) {
S1AP_WARN("[SCTP %d] Received s1 setup failure on stream != 0 (%d)\n",
assoc_id, stream);
}
S1AP_DEBUG("Received s1 setup failure for MME... please check your parameters\n");
return 0;
}
// int s1ap_eNB_handle_s1_setup_response(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p)
static
int s1ap_eNB_handle_s1_setup_response(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p)
{
S1SetupResponseIEs_t *s1SetupResponse_p;
s1ap_eNB_mme_data_t *mme_desc_p;
int i;
DevAssert(eNB_desc_p != NULL);
DevAssert(packet_p != NULL);
DevAssert(message_p != NULL);
s1SetupResponse_p = &message_p->msg.s1SetupResponseIEs;
/* S1 Setup Response == Non UE-related procedure -> stream 0 */
if (packet_p->local_stream != 0) {
if (stream != 0) {
S1AP_ERROR("[SCTP %d] Received s1 setup response on stream != 0 (%d)\n",
packet_p->assoc_id, packet_p->local_stream);
assoc_id, stream);
return -1;
}
if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) {
if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
S1AP_ERROR("[SCTP %d] Received S1 setup response for non existing "
"MME context\n", packet_p->assoc_id);
"MME context\n", assoc_id);
return -1;
}
......@@ -255,128 +277,136 @@ int s1ap_eNB_handle_s1_setup_response(eNB_mme_desc_t *eNB_desc_p,
*/
mme_desc_p->state = S1AP_ENB_STATE_CONNECTED;
/* We call back our self
* -> generate a dummy initial UE message
*/
{
extern int s1ap_eNB_handle_api_req(eNB_mme_desc_t *eNB_desc_p,
s1ap_rrc_api_req_t *api_req_p);
s1ap_rrc_api_req_t api_req;
s1ap_nas_first_req_t *nas_req_p;
memset(&api_req, 0, sizeof(s1ap_rrc_api_req_t));
nas_req_p = &api_req.msg.first_nas_req;
api_req.api_req = S1AP_API_NAS_FIRST_REQ;
nas_req_p->rnti = 0xC03A;
nas_req_p->establishment_cause = RRC_CAUSE_MO_DATA;
nas_req_p->ue_identity.present = GUMMEI_PROVIDED;
nas_req_p->ue_identity.identity.gummei.mcc = 208;
nas_req_p->ue_identity.identity.gummei.mnc = 34;
nas_req_p->ue_identity.identity.gummei.mme_code = 0;
nas_req_p->ue_identity.identity.gummei.mme_group_id = 0;
/* NAS Attach request with IMSI */
uint8_t nas_attach_req_imsi[] =
{
0x07, 0x41,
/* EPS Mobile identity = IMSI */
0x71, 0x08, 0x29, 0x80, 0x43, 0x21, 0x43, 0x65, 0x87,
0xF9,
/* End of EPS Mobile Identity */
0x02, 0xE0, 0xE0, 0x00, 0x20, 0x02, 0x03,
0xD0, 0x11, 0x27, 0x1A, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00,
0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x52, 0x12, 0xF2,
0x01, 0x27, 0x11,
};
/* NAS Attach request with GUTI */
uint8_t nas_attach_req_guti[] =
{
0x07, 0x41,
/* EPS Mobile identity = IMSI */
0x71, 0x0B, 0xF6, 0x12, 0xF2, 0x01, 0x80, 0x00, 0x01, 0xE0, 0x00,
0xDA, 0x1F,
/* End of EPS Mobile Identity */
0x02, 0xE0, 0xE0, 0x00, 0x20, 0x02, 0x03,
0xD0, 0x11, 0x27, 0x1A, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00,
0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x52, 0x12, 0xF2,
0x01, 0x27, 0x11,
};
nas_req_p->nas_pdu.buffer = nas_attach_req_guti;
nas_req_p->nas_pdu.length = sizeof(nas_attach_req_guti);
s1ap_eNB_handle_api_req(eNB_desc_p, &api_req);
}
// /* We call back our self
// * -> generate a dummy initial UE message
// */
// {
// extern int s1ap_eNB_handle_api_req(eNB_mme_desc_t *eNB_desc_p,
// s1ap_rrc_api_req_t *api_req_p);
// s1ap_rrc_api_req_t api_req;
// s1ap_nas_first_req_t *nas_req_p;
//
// memset(&api_req, 0, sizeof(s1ap_rrc_api_req_t));
//
// nas_req_p = &api_req.msg.first_nas_req;
// api_req.api_req = S1AP_API_NAS_FIRST_REQ;
//
// nas_req_p->rnti = 0xC03A;
// nas_req_p->establishment_cause = RRC_CAUSE_MO_DATA;
// nas_req_p->ue_identity.present = GUMMEI_PROVIDED;
//
// nas_req_p->ue_identity.identity.gummei.mcc = 208;
// nas_req_p->ue_identity.identity.gummei.mnc = 34;
// nas_req_p->ue_identity.identity.gummei.mme_code = 0;
// nas_req_p->ue_identity.identity.gummei.mme_group_id = 0;
//
// /* NAS Attach request with IMSI */
// uint8_t nas_attach_req_imsi[] =
// {
// 0x07, 0x41,
// /* EPS Mobile identity = IMSI */
// 0x71, 0x08, 0x29, 0x80, 0x43, 0x21, 0x43, 0x65, 0x87,
// 0xF9,
// /* End of EPS Mobile Identity */
// 0x02, 0xE0, 0xE0, 0x00, 0x20, 0x02, 0x03,
// 0xD0, 0x11, 0x27, 0x1A, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00,
// 0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x52, 0x12, 0xF2,
// 0x01, 0x27, 0x11,
// };
//
// /* NAS Attach request with GUTI */
// uint8_t nas_attach_req_guti[] =
// {
// 0x07, 0x41,
// /* EPS Mobile identity = IMSI */
// 0x71, 0x0B, 0xF6, 0x12, 0xF2, 0x01, 0x80, 0x00, 0x01, 0xE0, 0x00,
// 0xDA, 0x1F,
// /* End of EPS Mobile Identity */
// 0x02, 0xE0, 0xE0, 0x00, 0x20, 0x02, 0x03,
// 0xD0, 0x11, 0x27, 0x1A, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00,
// 0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x52, 0x12, 0xF2,
// 0x01, 0x27, 0x11,
// };
//
// nas_req_p->nas_pdu.buffer = nas_attach_req_guti;
// nas_req_p->nas_pdu.length = sizeof(nas_attach_req_guti);
//
// s1ap_eNB_handle_api_req(eNB_desc_p, &api_req);
// }
return 0;
}
int s1ap_eNB_handle_initial_context_request(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
struct s1ap_message_s *message_p)
// int s1ap_eNB_handle_initial_context_request(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p)
static
int s1ap_eNB_handle_initial_context_request(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p)
{
s1ap_eNB_mme_data_t *mme_desc_p;
s1ap_eNB_ue_context_t *ue_desc_p;
InitialContextSetupRequestIEs_t *initialContextSetupRequest_p;
DevAssert(eNB_desc_p != NULL);
DevAssert(packet_p != NULL);
// DevAssert(eNB_desc_p != NULL);
DevAssert(message_p != NULL);
initialContextSetupRequest_p = &message_p->msg.initialContextSetupRequestIEs;
DevAssert(packet_p->local_stream > 0);
if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) {
S1AP_ERROR("[SCTP %d] Received initial context setup request for non "
"existing MME context\n", packet_p->assoc_id);
return -1;
}
if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p,
initialContextSetupRequest_p->eNB_UE_S1AP_ID)) == NULL) {
S1AP_ERROR("[SCTP %d] Received initial context setup request for non "
"existing UE context\n", packet_p->assoc_id);
/* Initial context request = UE-related procedure -> stream != 0 */
if (stream == 0) {
S1AP_ERROR("[SCTP %d] Received UE-related procedure on stream = 0 (%d)\n",
assoc_id, stream);
return -1;
}
ue_desc_p->mme_ue_s1ap_id = initialContextSetupRequest_p->mme_ue_s1ap_id;
{
int i;
extern int s1ap_eNB_handle_api_req(eNB_mme_desc_t *eNB_desc_p,
s1ap_rrc_api_req_t *api_req_p);
s1ap_rrc_api_req_t api_req;
s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p;
// if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, assoc_id)) == NULL) {
// S1AP_ERROR("[SCTP %d] Received initial context setup request for non "
// "existing MME context\n", packet_p->assoc_id);
// return -1;
// }
// if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p,
// initialContextSetupRequest_p->eNB_UE_S1AP_ID)) == NULL) {
// S1AP_ERROR("[SCTP %d] Received initial context setup request for non "
// "existing UE context\n", packet_p->assoc_id);
// return -1;
// }
memset(&api_req, 0, sizeof(s1ap_rrc_api_req_t));
initial_ctxt_resp_p = &api_req.msg.initial_ctxt_resp;
api_req.api_req = S1AP_API_INITIAL_CONTEXT_SETUP_RESP;
initial_ctxt_resp_p->eNB_ue_s1ap_id = ue_desc_p->eNB_ue_s1ap_id;
initial_ctxt_resp_p->e_rabs_failed = 0;
initial_ctxt_resp_p->nb_of_e_rabs
= initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.count;
for (i = 0; i < initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.count; i++)
{
struct E_RABToBeSetupItemCtxtSUReq_s *item;
item = (struct E_RABToBeSetupItemCtxtSUReq_s *)initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.array[i];
initial_ctxt_resp_p->e_rabs = realloc(initial_ctxt_resp_p->e_rabs, i * sizeof(e_rab_setup_t));
initial_ctxt_resp_p->e_rabs[i].e_rab_id = 5;
}
ue_desc_p->mme_ue_s1ap_id = initialContextSetupRequest_p->mme_ue_s1ap_id;
s1ap_eNB_handle_api_req(eNB_desc_p, &api_req);
}
// {
// int i;
//
// extern int s1ap_eNB_handle_api_req(eNB_mme_desc_t *eNB_desc_p,
// s1ap_rrc_api_req_t *api_req_p);
//
// s1ap_rrc_api_req_t api_req;
// s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p;
//
// memset(&api_req, 0, sizeof(s1ap_rrc_api_req_t));
//
// initial_ctxt_resp_p = &api_req.msg.initial_ctxt_resp;
// api_req.api_req = S1AP_API_INITIAL_CONTEXT_SETUP_RESP;
//
// initial_ctxt_resp_p->eNB_ue_s1ap_id = ue_desc_p->eNB_ue_s1ap_id;
// initial_ctxt_resp_p->e_rabs_failed = 0;
// initial_ctxt_resp_p->nb_of_e_rabs
// = initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.count;
// for (i = 0; i < initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.count; i++)
// {
// struct E_RABToBeSetupItemCtxtSUReq_s *item;
// item = (struct E_RABToBeSetupItemCtxtSUReq_s *)initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.array[i];
// initial_ctxt_resp_p->e_rabs = realloc(initial_ctxt_resp_p->e_rabs, i * sizeof(e_rab_setup_t));
// initial_ctxt_resp_p->e_rabs[i].e_rab_id = 5;
//
// }
//
// s1ap_eNB_handle_api_req(eNB_desc_p, &api_req);
// }
return 0;
}
......@@ -31,19 +31,7 @@
#ifndef S1AP_ENB_HANDLERS_H_
#define S1AP_ENB_HANDLERS_H_
int s1ap_eNB_handle_message(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p);
int s1ap_eNB_handle_s1_setup_response(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
struct s1ap_message_s *message);
int s1ap_eNB_handle_s1_setup_failure(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
struct s1ap_message_s *message);
int s1ap_eNB_handle_initial_context_request(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
struct s1ap_message_s *message_p);
int s1ap_eNB_handle_message(uint32_t assoc_id, int32_t stream,
const uint8_t * const data, const uint32_t data_length);
#endif /* S1AP_ENB_HANDLERS_H_ */
#include "intertask_interface.h"
#include "s1ap_eNB_itti_messaging.h"
void s1ap_eNB_itti_send_sctp_data_req(int32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream)
{
MessageDef *message_p;
sctp_data_req_t *sctp_data_req;
message_p = itti_alloc_new_message(TASK_S1AP, SCTP_DATA_REQ);
sctp_data_req = &message_p->msg.sctp_data_req;
sctp_data_req->assoc_id = assoc_id;
sctp_data_req->buffer = buffer;
sctp_data_req->buffer_length = buffer_length;
sctp_data_req->stream = stream;
itti_send_msg_to_task(TASK_SCTP, INSTANCE_DEFAULT, message_p);
}
#ifndef S1AP_ENB_ITTI_MESSAGING_H_
#define S1AP_ENB_ITTI_MESSAGING_H_
void s1ap_eNB_itti_send_sctp_data_req(int32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream);
#endif /* S1AP_ENB_ITTI_MESSAGING_H_ */
......@@ -32,7 +32,10 @@
#include <stdlib.h>
#include <stdint.h>
#include "mme_sim.h"
#include "intertask_interface.h"
#include "assertions.h"
// #include "conversions.h"
#include "s1ap_common.h"
#include "s1ap_ies_defs.h"
......@@ -44,72 +47,69 @@
#include "sctp_primitives_client.h"
#include "assertions.h"
#include "conversions.h"
int s1ap_eNB_ue_capabilities(eNB_mme_desc_t *eNB_desc_p,
s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p)
{
struct s1ap_eNB_ue_context_s *ue_context_p;
UECapabilityInfoIndicationIEs_t *ue_cap_info_ind_ies_p;
s1ap_message message;
uint8_t *buffer;
uint32_t length;
int ret = -1;
DevAssert(ue_cap_info_ind_p != NULL);
DevAssert(eNB_desc_p != NULL);
if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p, ue_cap_info_ind_p->eNB_ue_s1ap_id)) == NULL)
{
/* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
ue_cap_info_ind_p->eNB_ue_s1ap_id);
return -1;
}
/* UE capabilities message can occur either during an s1ap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
ue_context_p->ue_state == S1AP_UE_WAITING_CSR))
{
S1AP_WARN("You are attempting to send NAS data over non-connected "
"eNB ue s1ap id: %u, current state: %d\n",
ue_cap_info_ind_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the S1AP message to encode */
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_initiatingMessage;
message.procedureCode = ProcedureCode_id_UECapabilityInfoIndication;
ue_cap_info_ind_ies_p = &message.msg.ueCapabilityInfoIndicationIEs;
ue_cap_info_ind_ies_p->ueRadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer;
ue_cap_info_ind_ies_p->ueRadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length;
ue_cap_info_ind_ies_p->eNB_UE_S1AP_ID = ue_cap_info_ind_p->eNB_ue_s1ap_id;
ue_cap_info_ind_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
/* Encode procedure has failed... */
S1AP_ERROR("Failed to encode UE capabilities indication\n");
return -1;
}
/* UE associated signalling -> use the allocated stream */
if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID,
ue_context_p->stream, buffer, length)) < 0)
{
S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n",
ue_context_p->mme_ref->sctp_data.assoc_id, ret);
}
free(buffer);
return ret;
}
// int s1ap_eNB_ue_capabilities(eNB_mme_desc_t *eNB_desc_p,
// s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p)
// {
// struct s1ap_eNB_ue_context_s *ue_context_p;
// UECapabilityInfoIndicationIEs_t *ue_cap_info_ind_ies_p;
//
// s1ap_message message;
//
// uint8_t *buffer;
// uint32_t length;
// int ret = -1;
//
// DevAssert(ue_cap_info_ind_p != NULL);
// DevAssert(eNB_desc_p != NULL);
//
// if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p, ue_cap_info_ind_p->eNB_ue_s1ap_id)) == NULL)
// {
// /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
// S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
// ue_cap_info_ind_p->eNB_ue_s1ap_id);
// return -1;
// }
//
// /* UE capabilities message can occur either during an s1ap connected state
// * or during initial attach (for example: NAS authentication).
// */
// if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
// ue_context_p->ue_state == S1AP_UE_WAITING_CSR))
// {
// S1AP_WARN("You are attempting to send NAS data over non-connected "
// "eNB ue s1ap id: %u, current state: %d\n",
// ue_cap_info_ind_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
// return -1;
// }
//
// /* Prepare the S1AP message to encode */
// memset(&message, 0, sizeof(s1ap_message));
//
// message.direction = S1AP_PDU_PR_initiatingMessage;
// message.procedureCode = ProcedureCode_id_UECapabilityInfoIndication;
//
// ue_cap_info_ind_ies_p = &message.msg.ueCapabilityInfoIndicationIEs;
//
// ue_cap_info_ind_ies_p->ueRadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer;
// ue_cap_info_ind_ies_p->ueRadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length;
//
// ue_cap_info_ind_ies_p->eNB_UE_S1AP_ID = ue_cap_info_ind_p->eNB_ue_s1ap_id;
// ue_cap_info_ind_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
//
// if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
// /* Encode procedure has failed... */
// S1AP_ERROR("Failed to encode UE capabilities indication\n");
// return -1;
// }
//
// /* UE associated signalling -> use the allocated stream */
// if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID,
// ue_context_p->stream, buffer, length)) < 0)
// {
// S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n",
// ue_context_p->mme_ref->sctp_data.assoc_id, ret);
// }
//
// free(buffer);
// return ret;
// }
......@@ -31,7 +31,7 @@
#ifndef S1AP_ENB_MANAGEMENT_PROCEDURES_H_
#define S1AP_ENB_MANAGEMENT_PROCEDURES_H_
int s1ap_eNB_ue_capabilities(eNB_mme_desc_t *eNB_desc_p,
s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p);
// int s1ap_eNB_ue_capabilities(eNB_mme_desc_t *eNB_desc_p,
// s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p);
#endif /* S1AP_ENB_MANAGEMENT_PROCEDURES_H_ */
......@@ -32,229 +32,230 @@
#include <stdlib.h>
#include <stdint.h>
#include "mme_sim.h"
#include "assertions.h"
#include "conversions.h"
#include "intertask_interface.h"
#include "s1ap_common.h"
#include "s1ap_ies_defs.h"
#include "s1ap_eNB_defs.h"
#include "s1ap_eNB.h"
#include "s1ap_ies_defs.h"
#include "s1ap_eNB_encoder.h"
#include "s1ap_eNB_ue_context.h"
#include "s1ap_eNB_nas_procedures.h"
#include "sctp_primitives_client.h"
#include "assertions.h"
#include "conversions.h"
int s1ap_eNB_handle_nas_downlink(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
// int s1ap_eNB_handle_nas_downlink(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p)
int s1ap_eNB_handle_nas_downlink(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p)
{
DownlinkNASTransportIEs_t *downlink_NAS_transport_p;
s1ap_eNB_mme_data_t *mme_desc_p;
s1ap_eNB_ue_context_t *ue_desc_p;
DevAssert(eNB_desc_p != NULL);
DevAssert(packet_p != NULL);
DevAssert(message_p != NULL);
downlink_NAS_transport_p = &message_p->msg.downlinkNASTransportIEs;
/* UE-related procedure -> stream != 0 */
if (packet_p->local_stream == 0) {
S1AP_ERROR("[SCTP %d] Received s1 setup response on stream == 0\n",
packet_p->assoc_id);
if (stream == 0) {
S1AP_ERROR("[SCTP %d] Received UE-related procedure on stream == 0\n",
assoc_id);
return -1;
}
if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) {
S1AP_ERROR("[SCTP %d] Received initial context setup request for non "
"existing MME context\n", packet_p->assoc_id);
return -1;
}
if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p,
downlink_NAS_transport_p->eNB_UE_S1AP_ID)) == NULL)
{
S1AP_ERROR("[SCTP %d] Received initial context setup request for non "
"existing UE context\n", packet_p->assoc_id);
return -1;
}
// if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, assoc_id)) == NULL) {
// S1AP_ERROR("[SCTP %d] Received initial context setup request for non "
// "existing MME context\n", assoc_id);
// return -1;
// }
// if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p,
// downlink_NAS_transport_p->eNB_UE_S1AP_ID)) == NULL)
// {
// S1AP_ERROR("[SCTP %d] Received initial context setup request for non "
// "existing UE context\n", assoc_id);
// return -1;
// }
/* Is it the first outcome of the MME for this UE ? If so store the mme
* UE s1ap id.
*/
if (ue_desc_p->mme_ue_s1ap_id == 0) {
ue_desc_p->mme_ue_s1ap_id = downlink_NAS_transport_p->mme_ue_s1ap_id;
} else {
/* We already have a mme ue s1ap id check the received is the same */
if (ue_desc_p->mme_ue_s1ap_id != downlink_NAS_transport_p->mme_ue_s1ap_id) {
S1AP_ERROR("[SCTP %d] Mismatch is MME UE S1AP ID (0x%08x != 0x%08x)\n",
downlink_NAS_transport_p->mme_ue_s1ap_id,
ue_desc_p->mme_ue_s1ap_id,
packet_p->assoc_id);
}
}
// if (ue_desc_p->mme_ue_s1ap_id == 0) {
// ue_desc_p->mme_ue_s1ap_id = downlink_NAS_transport_p->mme_ue_s1ap_id;
// } else {
// /* We already have a mme ue s1ap id check the received is the same */
// if (ue_desc_p->mme_ue_s1ap_id != downlink_NAS_transport_p->mme_ue_s1ap_id) {
// S1AP_ERROR("[SCTP %d] Mismatch is MME UE S1AP ID (0x%08x != 0x%08x)\n",
// downlink_NAS_transport_p->mme_ue_s1ap_id,
// ue_desc_p->mme_ue_s1ap_id,
// packet_p->assoc_id);
// }
// }
/* TODO: forward NAS pdu to RRC for transmission */
return 0;
}
int s1ap_eNB_nas_uplink(eNB_mme_desc_t *eNB_desc_p,
s1ap_nas_uplink_t *nas_uplink_p)
{
struct s1ap_eNB_ue_context_s *ue_context_p;
UplinkNASTransportIEs_t *uplink_NAS_transport_p;
s1ap_message message;
uint8_t *buffer;
uint32_t length;
int ret = -1;
DevAssert(nas_uplink_p != NULL);
DevAssert(eNB_desc_p != NULL);
if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p, nas_uplink_p->eNB_ue_s1ap_id)) == NULL)
{
/* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
nas_uplink_p->eNB_ue_s1ap_id);
return -1;
}
/* Uplink NAS transport can occur either during an s1ap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
ue_context_p->ue_state == S1AP_UE_WAITING_CSR))
{
S1AP_WARN("You are attempting to send NAS data over non-connected "
"eNB ue s1ap id: %u, current state: %d\n",
nas_uplink_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the S1AP message to encode */
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_initiatingMessage;
message.procedureCode = ProcedureCode_id_uplinkNASTransport;
uplink_NAS_transport_p = &message.msg.uplinkNASTransportIEs;
uplink_NAS_transport_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
uplink_NAS_transport_p->eNB_UE_S1AP_ID = ue_context_p->eNB_ue_s1ap_id;
uplink_NAS_transport_p->nas_pdu.buf = nas_uplink_p->nas_pdu.buffer;
uplink_NAS_transport_p->nas_pdu.size = nas_uplink_p->nas_pdu.length;
MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc,
&uplink_NAS_transport_p->eutran_cgi.pLMNidentity);
MACRO_ENB_ID_TO_CELL_IDENTITY(eNB_desc_p->eNB_id,
&uplink_NAS_transport_p->eutran_cgi.cell_ID);
/* MCC/MNC should be repeated in TAI and EUTRAN CGI */
MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc,
&uplink_NAS_transport_p->tai.pLMNidentity);
TAC_TO_ASN1(eNB_desc_p->tac, &uplink_NAS_transport_p->tai.tAC);
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
S1AP_ERROR("Failed to encode uplink NAS transport\n");
/* Encode procedure has failed... */
return -1;
}
/* UE associated signalling -> use the allocated stream */
if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID,
ue_context_p->stream, buffer, length)) < 0)
{
S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n",
ue_context_p->mme_ref->sctp_data.assoc_id, ret);
}
free(buffer);
return ret;
}
int s1ap_eNB_initial_ctxt_resp(eNB_mme_desc_t *eNB_desc_p,
s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p)
{
struct s1ap_eNB_ue_context_s *ue_context_p;
InitialContextSetupResponseIEs_t *initial_ies_p;
s1ap_message message;
uint8_t *buffer;
uint32_t length;
int ret = -1;
int i;
DevAssert(initial_ctxt_resp_p != NULL);
DevAssert(eNB_desc_p != NULL);
if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p,
initial_ctxt_resp_p->eNB_ue_s1ap_id)) == NULL)
{
/* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
initial_ctxt_resp_p->eNB_ue_s1ap_id);
return -1;
}
/* Uplink NAS transport can occur either during an s1ap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
ue_context_p->ue_state == S1AP_UE_WAITING_CSR))
{
S1AP_WARN("You are attempting to send NAS data over non-connected "
"eNB ue s1ap id: %u, current state: %d\n",
initial_ctxt_resp_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the S1AP message to encode */
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_successfulOutcome;
message.procedureCode = ProcedureCode_id_InitialContextSetup;
initial_ies_p = &message.msg.initialContextSetupResponseIEs;
initial_ies_p->eNB_UE_S1AP_ID = initial_ctxt_resp_p->eNB_ue_s1ap_id;
initial_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
for (i = 0; i < initial_ctxt_resp_p->nb_of_e_rabs; i++)
{
E_RABSetupItemCtxtSURes_t *new_item;
new_item = calloc(1, sizeof(E_RABSetupItemCtxtSURes_t));
new_item->e_RAB_ID = initial_ctxt_resp_p->e_rabs[i].e_rab_id;
GTP_TEID_TO_ASN1(initial_ctxt_resp_p->e_rabs[i].gtp_teid, &new_item->gTP_TEID);
new_item->transportLayerAddress.buf = initial_ctxt_resp_p->e_rabs[i].eNB_addr.buffer;
new_item->transportLayerAddress.size = initial_ctxt_resp_p->e_rabs[i].eNB_addr.length;
new_item->transportLayerAddress.bits_unused = 0;
ASN_SEQUENCE_ADD(&initial_ies_p->e_RABSetupListCtxtSURes.e_RABSetupItemCtxtSURes, new_item);
}
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
S1AP_ERROR("Failed to encode uplink NAS transport\n");
/* Encode procedure has failed... */
return -1;
}
/* UE associated signalling -> use the allocated stream */
if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID,
ue_context_p->stream, buffer, length)) < 0)
{
S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n",
ue_context_p->mme_ref->sctp_data.assoc_id, ret);
}
free(buffer);
return ret;
}
// int s1ap_eNB_nas_uplink(eNB_mme_desc_t *eNB_desc_p,
// s1ap_nas_uplink_t *nas_uplink_p)
// {
// struct s1ap_eNB_ue_context_s *ue_context_p;
// UplinkNASTransportIEs_t *uplink_NAS_transport_p;
//
// s1ap_message message;
//
// uint8_t *buffer;
// uint32_t length;
// int ret = -1;
//
// DevAssert(nas_uplink_p != NULL);
// DevAssert(eNB_desc_p != NULL);
//
// if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p, nas_uplink_p->eNB_ue_s1ap_id)) == NULL)
// {
// /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
// S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
// nas_uplink_p->eNB_ue_s1ap_id);
// return -1;
// }
//
// /* Uplink NAS transport can occur either during an s1ap connected state
// * or during initial attach (for example: NAS authentication).
// */
// if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
// ue_context_p->ue_state == S1AP_UE_WAITING_CSR))
// {
// S1AP_WARN("You are attempting to send NAS data over non-connected "
// "eNB ue s1ap id: %u, current state: %d\n",
// nas_uplink_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
// return -1;
// }
//
// /* Prepare the S1AP message to encode */
// memset(&message, 0, sizeof(s1ap_message));
//
// message.direction = S1AP_PDU_PR_initiatingMessage;
// message.procedureCode = ProcedureCode_id_uplinkNASTransport;
//
// uplink_NAS_transport_p = &message.msg.uplinkNASTransportIEs;
//
// uplink_NAS_transport_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
// uplink_NAS_transport_p->eNB_UE_S1AP_ID = ue_context_p->eNB_ue_s1ap_id;
//
// uplink_NAS_transport_p->nas_pdu.buf = nas_uplink_p->nas_pdu.buffer;
// uplink_NAS_transport_p->nas_pdu.size = nas_uplink_p->nas_pdu.length;
//
// MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc,
// &uplink_NAS_transport_p->eutran_cgi.pLMNidentity);
// MACRO_ENB_ID_TO_CELL_IDENTITY(eNB_desc_p->eNB_id,
// &uplink_NAS_transport_p->eutran_cgi.cell_ID);
//
// /* MCC/MNC should be repeated in TAI and EUTRAN CGI */
// MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc,
// &uplink_NAS_transport_p->tai.pLMNidentity);
// TAC_TO_ASN1(eNB_desc_p->tac, &uplink_NAS_transport_p->tai.tAC);
//
// if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
// S1AP_ERROR("Failed to encode uplink NAS transport\n");
// /* Encode procedure has failed... */
// return -1;
// }
//
// /* UE associated signalling -> use the allocated stream */
// if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID,
// ue_context_p->stream, buffer, length)) < 0)
// {
// S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n",
// ue_context_p->mme_ref->sctp_data.assoc_id, ret);
// }
//
// free(buffer);
// return ret;
// }
// int s1ap_eNB_initial_ctxt_resp(eNB_mme_desc_t *eNB_desc_p,
// s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p)
// {
// struct s1ap_eNB_ue_context_s *ue_context_p;
// InitialContextSetupResponseIEs_t *initial_ies_p;
//
// s1ap_message message;
//
// uint8_t *buffer;
// uint32_t length;
// int ret = -1;
// int i;
//
// DevAssert(initial_ctxt_resp_p != NULL);
// DevAssert(eNB_desc_p != NULL);
//
// if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p,
// initial_ctxt_resp_p->eNB_ue_s1ap_id)) == NULL)
// {
// /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
// S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
// initial_ctxt_resp_p->eNB_ue_s1ap_id);
// return -1;
// }
//
// /* Uplink NAS transport can occur either during an s1ap connected state
// * or during initial attach (for example: NAS authentication).
// */
// if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
// ue_context_p->ue_state == S1AP_UE_WAITING_CSR))
// {
// S1AP_WARN("You are attempting to send NAS data over non-connected "
// "eNB ue s1ap id: %u, current state: %d\n",
// initial_ctxt_resp_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
// return -1;
// }
//
// /* Prepare the S1AP message to encode */
// memset(&message, 0, sizeof(s1ap_message));
//
// message.direction = S1AP_PDU_PR_successfulOutcome;
// message.procedureCode = ProcedureCode_id_InitialContextSetup;
//
// initial_ies_p = &message.msg.initialContextSetupResponseIEs;
//
// initial_ies_p->eNB_UE_S1AP_ID = initial_ctxt_resp_p->eNB_ue_s1ap_id;
// initial_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
//
// for (i = 0; i < initial_ctxt_resp_p->nb_of_e_rabs; i++)
// {
// E_RABSetupItemCtxtSURes_t *new_item;
//
// new_item = calloc(1, sizeof(E_RABSetupItemCtxtSURes_t));
//
// new_item->e_RAB_ID = initial_ctxt_resp_p->e_rabs[i].e_rab_id;
// GTP_TEID_TO_ASN1(initial_ctxt_resp_p->e_rabs[i].gtp_teid, &new_item->gTP_TEID);
// new_item->transportLayerAddress.buf = initial_ctxt_resp_p->e_rabs[i].eNB_addr.buffer;
// new_item->transportLayerAddress.size = initial_ctxt_resp_p->e_rabs[i].eNB_addr.length;
// new_item->transportLayerAddress.bits_unused = 0;
//
// ASN_SEQUENCE_ADD(&initial_ies_p->e_RABSetupListCtxtSURes.e_RABSetupItemCtxtSURes, new_item);
// }
//
// if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
// S1AP_ERROR("Failed to encode uplink NAS transport\n");
// /* Encode procedure has failed... */
// return -1;
// }
//
// /* UE associated signalling -> use the allocated stream */
// if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID,
// ue_context_p->stream, buffer, length)) < 0)
// {
// S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n",
// ue_context_p->mme_ref->sctp_data.assoc_id, ret);
// }
//
// free(buffer);
// return ret;
// }
......@@ -31,14 +31,11 @@
#ifndef S1AP_ENB_NAS_PROCEDURES_H_
#define S1AP_ENB_NAS_PROCEDURES_H_
int s1ap_eNB_nas_uplink(eNB_mme_desc_t *eNB_desc_p,
s1ap_nas_uplink_t *nas_uplink_p);
int s1ap_eNB_handle_nas_downlink(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
int s1ap_eNB_handle_nas_downlink(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p);
int s1ap_eNB_initial_ctxt_resp(eNB_mme_desc_t *eNB_desc_p,
s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p);
// int s1ap_eNB_initial_ctxt_resp(eNB_mme_desc_t *eNB_desc_p,
// s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p);
#endif /* S1AP_ENB_NAS_PROCEDURES_H_ */
......@@ -38,13 +38,15 @@
#include <stdio.h>
#include <stdlib.h>
#include "mme_sim.h"
#include "intertask_interface.h"
#include "s1ap_eNB.h"
#include "s1ap_common.h"
#include "s1ap_eNB_defs.h"
#include "s1ap_eNB_nnsf.h"
struct s1ap_eNB_mme_data_s *
s1ap_eNB_nnsf_select_mme_by_mme_code(eNB_mme_desc_t *eNB_desc_p,
s1ap_eNB_nnsf_select_mme_by_mme_code(s1ap_eNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
uint8_t mme_code)
{
......@@ -52,7 +54,7 @@ s1ap_eNB_nnsf_select_mme_by_mme_code(eNB_mme_desc_t *eNB_desc_p,
struct s1ap_eNB_mme_data_s *mme_highest_capacity_p = NULL;
uint8_t current_capacity = 0;
RB_FOREACH(mme_data_p, s1ap_mme_map, &eNB_desc_p->s1ap_mme_head) {
RB_FOREACH(mme_data_p, s1ap_mme_map, &instance_p->s1ap_mme_head) {
struct served_gummei_s *gummei_p = NULL;
if (mme_data_p->state != S1AP_ENB_STATE_CONNECTED) {
......@@ -112,7 +114,7 @@ s1ap_eNB_nnsf_select_mme_by_mme_code(eNB_mme_desc_t *eNB_desc_p,
}
struct s1ap_eNB_mme_data_s *
s1ap_eNB_nnsf_select_mme_by_gummei(eNB_mme_desc_t *eNB_desc_p,
s1ap_eNB_nnsf_select_mme_by_gummei(s1ap_eNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
gummei_t gummei)
{
......@@ -120,7 +122,7 @@ s1ap_eNB_nnsf_select_mme_by_gummei(eNB_mme_desc_t *eNB_desc_p,
struct s1ap_eNB_mme_data_s *mme_highest_capacity_p = NULL;
uint8_t current_capacity = 0;
RB_FOREACH(mme_data_p, s1ap_mme_map, &eNB_desc_p->s1ap_mme_head) {
RB_FOREACH(mme_data_p, s1ap_mme_map, &instance_p->s1ap_mme_head) {
struct served_gummei_s *gummei_p = NULL;
if (mme_data_p->state != S1AP_ENB_STATE_CONNECTED) {
......
......@@ -37,12 +37,12 @@
#define S1AP_ENB_NNSF_H_
struct s1ap_eNB_mme_data_s*
s1ap_eNB_nnsf_select_mme_by_mme_code(eNB_mme_desc_t *eNB_desc_p,
s1ap_eNB_nnsf_select_mme_by_mme_code(s1ap_eNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
uint8_t mme_code);
struct s1ap_eNB_mme_data_s*
s1ap_eNB_nnsf_select_mme_by_gummei(eNB_mme_desc_t *eNB_desc_p,
s1ap_eNB_nnsf_select_mme_by_gummei(s1ap_eNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
gummei_t gummei);
......
......@@ -39,6 +39,8 @@
#include <stdlib.h>
#include <stdint.h>
#include "intertask_interface.h"
#include "s1ap_common.h"
#include "s1ap_ies_defs.h"
#include "s1ap_eNB_defs.h"
......@@ -52,58 +54,69 @@
#include "assertions.h"
int s1ap_eNB_handle_overload_start(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
// int s1ap_eNB_handle_overload_start(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p)
int s1ap_eNB_handle_overload_start(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p)
{
OverloadStartIEs_t *overload_start_p;
s1ap_eNB_mme_data_t *mme_desc_p;
overload_start_p = &message_p->msg.overloadStartIEs;
DevCheck(overload_start_p->overloadResponse.present ==
OverloadResponse_PR_overloadAction,
OverloadResponse_PR_overloadAction, 0, 0);
DevAssert(message_p != NULL);
/* Non UE-associated signalling -> stream 0 */
DevCheck(packet_p->local_stream == 0, packet_p->local_stream,
packet_p->remote_port, packet_p->assoc_id);
overload_start_p = &message_p->msg.overloadStartIEs;
if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) {
/* No MME context associated */
return -1;
}
/* Mark the MME as overloaded and set the overload state according to
* the value received.
*/
mme_desc_p->state = S1AP_ENB_OVERLOAD;
mme_desc_p->overload_state =
overload_start_p->overloadResponse.choice.overloadAction;
// DevCheck(overload_start_p->overloadResponse.present ==
// OverloadResponse_PR_overloadAction,
// OverloadResponse_PR_overloadAction, 0, 0);
//
// /* Non UE-associated signalling -> stream 0 */
// DevCheck(packet_p->local_stream == 0, packet_p->local_stream,
// packet_p->remote_port, packet_p->assoc_id);
//
// if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) {
// /* No MME context associated */
// return -1;
// }
//
// /* Mark the MME as overloaded and set the overload state according to
// * the value received.
// */
// mme_desc_p->state = S1AP_ENB_OVERLOAD;
// mme_desc_p->overload_state =
// overload_start_p->overloadResponse.choice.overloadAction;
return 0;
}
int s1ap_eNB_handle_overload_stop(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
int s1ap_eNB_handle_overload_stop(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p)
// int s1ap_eNB_handle_overload_stop(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p)
{
/* We received Overload stop message, meaning that the MME is no more
* overloaded. This is an empty message, with only message header and no
* Information Element.
*/
s1ap_eNB_mme_data_t *mme_desc_p;
/* Non UE-associated signalling -> stream 0 */
DevCheck(packet_p->local_stream == 0, packet_p->local_stream,
packet_p->remote_port, packet_p->assoc_id);
if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) {
/* No MME context associated */
return -1;
}
mme_desc_p->state = S1AP_ENB_STATE_CONNECTED;
mme_desc_p->overload_state = S1AP_NO_OVERLOAD;
DevAssert(message_p != NULL);
// s1ap_eNB_mme_data_t *mme_desc_p;
//
// /* Non UE-associated signalling -> stream 0 */
// DevCheck(packet_p->local_stream == 0, packet_p->local_stream,
// packet_p->remote_port, packet_p->assoc_id);
//
// if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) {
// /* No MME context associated */
// return -1;
// }
//
// mme_desc_p->state = S1AP_ENB_STATE_CONNECTED;
// mme_desc_p->overload_state = S1AP_NO_OVERLOAD;
return 0;
}
......@@ -34,15 +34,21 @@
/**
* \brief Handle an overload start message
**/
int s1ap_eNB_handle_overload_start(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
// int s1ap_eNB_handle_overload_start(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p);
int s1ap_eNB_handle_overload_start(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p);
/**
* \brief Handle an overload stop message
**/
int s1ap_eNB_handle_overload_stop(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
// int s1ap_eNB_handle_overload_stop(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p);
int s1ap_eNB_handle_overload_stop(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p);
#endif /* S1AP_ENB_OVERLOAD_H_ */
......@@ -28,6 +28,12 @@
*******************************************************************************/
#include <stdint.h>
#include "intertask_interface.h"
#include "s1ap_eNB_default_values.h"
#include "s1ap_common.h"
#include "s1ap_ies_defs.h"
#include "s1ap_eNB_defs.h"
......@@ -37,84 +43,90 @@
#include "s1ap_eNB_encoder.h"
#include "s1ap_eNB_trace.h"
#include "eNB_default_values.h"
#include "sctp_primitives_client.h"
#include "assertions.h"
int s1ap_eNB_generate_trace_failure(sctp_data_t *sctp_data_p,
int32_t stream,
uint32_t eNB_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
E_UTRAN_Trace_ID_t *trace_id,
Cause_t *cause_p)
{
s1ap_message message;
TraceFailureIndicationIEs_t *trace_failure_p;
uint8_t *buffer;
uint32_t length;
int ret;
DevAssert(sctp_data_p != NULL);
memset(&message, 0, sizeof(s1ap_message));
trace_failure_p = &message.msg.traceFailureIndicationIEs;
trace_failure_p->mme_ue_s1ap_id = mme_ue_s1ap_id;
trace_failure_p->eNB_UE_S1AP_ID = eNB_ue_s1ap_id;
memcpy(&trace_failure_p->e_UTRAN_Trace_ID, trace_id, sizeof(E_UTRAN_Trace_ID_t));
memcpy(&trace_failure_p->cause, cause_p, sizeof(Cause_t));
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
return -1;
}
if ((ret = sctp_send_msg(sctp_data_p, S1AP_SCTP_PPID,
stream, buffer, length)) < 0) {
S1AP_ERROR("Failed to send Trace failure\n");
}
free(buffer);
return ret;
}
int s1ap_eNB_handle_trace_start(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
// int s1ap_eNB_generate_trace_failure(sctp_data_t *sctp_data_p,
// int32_t stream,
// uint32_t eNB_ue_s1ap_id,
// uint32_t mme_ue_s1ap_id,
// E_UTRAN_Trace_ID_t *trace_id,
// Cause_t *cause_p)
// {
// s1ap_message message;
// TraceFailureIndicationIEs_t *trace_failure_p;
// uint8_t *buffer;
// uint32_t length;
// int ret;
//
// DevAssert(sctp_data_p != NULL);
//
// memset(&message, 0, sizeof(s1ap_message));
//
// trace_failure_p = &message.msg.traceFailureIndicationIEs;
//
// trace_failure_p->mme_ue_s1ap_id = mme_ue_s1ap_id;
// trace_failure_p->eNB_UE_S1AP_ID = eNB_ue_s1ap_id;
//
// memcpy(&trace_failure_p->e_UTRAN_Trace_ID, trace_id, sizeof(E_UTRAN_Trace_ID_t));
// memcpy(&trace_failure_p->cause, cause_p, sizeof(Cause_t));
//
// if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
// return -1;
// }
// if ((ret = sctp_send_msg(sctp_data_p, S1AP_SCTP_PPID,
// stream, buffer, length)) < 0) {
// S1AP_ERROR("Failed to send Trace failure\n");
// }
// free(buffer);
// return ret;
// }
int s1ap_eNB_handle_trace_start(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p)
// int s1ap_eNB_handle_trace_start(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p)
{
TraceStartIEs_t *trace_start_p;
struct s1ap_eNB_ue_context_s *ue_desc_p;
DevAssert(message_p != NULL);
trace_start_p = &message_p->msg.traceStartIEs;
if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p,
trace_start_p->eNB_UE_S1AP_ID)) == NULL) {
/* Could not find context associated with this eNB_ue_s1ap_id -> generate
* trace failure indication.
*/
struct s1ap_eNB_mme_data_s *mme_ref_p;
E_UTRAN_Trace_ID_t trace_id;
Cause_t cause;
memset(&trace_id, 0, sizeof(E_UTRAN_Trace_ID_t));
memset(&cause, 0, sizeof(Cause_t));
mme_ref_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id);
cause.present = Cause_PR_radioNetwork;
cause.choice.radioNetwork = CauseRadioNetwork_unknown_pair_ue_s1ap_id;
return s1ap_eNB_generate_trace_failure(&mme_ref_p->sctp_data,
packet_p->local_stream,
trace_start_p->eNB_UE_S1AP_ID,
trace_start_p->mme_ue_s1ap_id, &trace_id, &cause);
}
// if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p,
// trace_start_p->eNB_UE_S1AP_ID)) == NULL) {
// /* Could not find context associated with this eNB_ue_s1ap_id -> generate
// * trace failure indication.
// */
// struct s1ap_eNB_mme_data_s *mme_ref_p;
// E_UTRAN_Trace_ID_t trace_id;
// Cause_t cause;
//
// memset(&trace_id, 0, sizeof(E_UTRAN_Trace_ID_t));
// memset(&cause, 0, sizeof(Cause_t));
// mme_ref_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id);
//
// cause.present = Cause_PR_radioNetwork;
// cause.choice.radioNetwork = CauseRadioNetwork_unknown_pair_ue_s1ap_id;
//
// return s1ap_eNB_generate_trace_failure(&mme_ref_p->sctp_data,
// packet_p->local_stream,
// trace_start_p->eNB_UE_S1AP_ID,
// trace_start_p->mme_ue_s1ap_id, &trace_id, &cause);
// }
return 0;
}
int s1ap_eNB_handle_deactivate_trace(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
int s1ap_eNB_handle_deactivate_trace(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p)
// int s1ap_eNB_handle_deactivate_trace(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p)
{
DeactivateTraceIEs_t *deactivate_trace_p;
......
......@@ -31,19 +31,25 @@
#ifndef S1AP_ENB_TRACE_H_
#define S1AP_ENB_TRACE_H_
int s1ap_eNB_generate_trace_failure(sctp_data_t *sctp_data_p,
int32_t stream,
uint32_t eNB_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
E_UTRAN_Trace_ID_t *trace_id,
Cause_t *cause_p);
int s1ap_eNB_handle_trace_start(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
// int s1ap_eNB_generate_trace_failure(sctp_data_t *sctp_data_p,
// int32_t stream,
// uint32_t eNB_ue_s1ap_id,
// uint32_t mme_ue_s1ap_id,
// E_UTRAN_Trace_ID_t *trace_id,
// Cause_t *cause_p);
// int s1ap_eNB_handle_trace_start(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p);
int s1ap_eNB_handle_trace_start(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p);
int s1ap_eNB_handle_deactivate_trace(eNB_mme_desc_t *eNB_desc_p,
sctp_queue_item_t *packet_p,
// int s1ap_eNB_handle_deactivate_trace(eNB_mme_desc_t *eNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct s1ap_message_s *message_p);
int s1ap_eNB_handle_deactivate_trace(uint32_t assoc_id,
uint32_t stream,
struct s1ap_message_s *message_p);
#endif /* S1AP_ENB_TRACE_H_ */
......@@ -42,8 +42,10 @@
#include "tree.h"
#include "intertask_interface.h"
#include "s1ap_common.h"
#include "s1ap_eNB.h"
#include "s1ap_eNB_defs.h"
#include "s1ap_eNB_ue_context.h"
inline int s1ap_eNB_compare_eNB_ue_s1ap_id(
......@@ -79,7 +81,7 @@ struct s1ap_eNB_ue_context_s *s1ap_eNB_allocate_new_UE_context(void)
}
struct s1ap_eNB_ue_context_s *s1ap_eNB_get_ue_context(
struct eNB_mme_desc_s *eNB_desc_p,
s1ap_eNB_instance_t *instance_p,
uint32_t eNB_ue_s1ap_id)
{
s1ap_eNB_ue_context_t temp;
......@@ -89,7 +91,7 @@ struct s1ap_eNB_ue_context_s *s1ap_eNB_get_ue_context(
/* eNB ue s1ap id = 24 bits wide */
temp.eNB_ue_s1ap_id = eNB_ue_s1ap_id & 0x00FFFFFF;
return RB_FIND(s1ap_ue_map, &eNB_desc_p->s1ap_ue_head, &temp);
return RB_FIND(s1ap_ue_map, &instance_p->s1ap_ue_head, &temp);
}
void s1ap_eNB_free_ue_context(struct s1ap_eNB_ue_context_s *ue_context_p)
......
......@@ -50,6 +50,9 @@ typedef enum {
} s1ap_ue_state;
typedef struct s1ap_eNB_ue_context_s {
/* Tree related data */
RB_ENTRY(s1ap_eNB_ue_context_s) entries;
/* Uniquely identifies the UE between MME and eNB within the eNB.
* This id is encoded on 24bits.
*/
......@@ -69,9 +72,6 @@ typedef struct s1ap_eNB_ue_context_s {
/* Reference to MME data this UE is attached to */
struct s1ap_eNB_mme_data_s *mme_ref;
/* Tree related data */
RB_ENTRY(s1ap_eNB_ue_context_s) entries;
} s1ap_eNB_ue_context_t;
inline int s1ap_eNB_compare_eNB_ue_s1ap_id(
......@@ -83,8 +83,8 @@ RB_PROTOTYPE(s1ap_ue_map, s1ap_eNB_ue_context_s, entries,
struct s1ap_eNB_ue_context_s *s1ap_eNB_allocate_new_UE_context(void);
struct s1ap_eNB_ue_context_s *s1ap_eNB_get_ue_context(struct eNB_mme_desc_s
*eNB_desc_p,
uint32_t eNB_ue_s1ap_id);
struct s1ap_eNB_ue_context_s *s1ap_eNB_get_ue_context(
s1ap_eNB_instance_t *instance_p,
uint32_t eNB_ue_s1ap_id);
#endif /* S1AP_ENB_UE_CONTEXT_H_ */
libsctp_OBJECTS = \
sctp_primitives_client.o \
sctp_common.o
include $(OPENAIR_TARGETS)/SIMU/USER/Makerules
-include .deps/*.d
libsctp_OBJECTS = \
sctp_common.o \
sctp_eNB_task.o \
sctp_eNB_itti_messaging.o
.PHONY = depdir
# pull in dependency info for *existing* .o files
-include .*.d
CFLAGS = \
$(S1AP_CFLAGS) \
-I../SCTP \
-I../UTILS \
-I$(OPENAIR2_DIR) \
-I$(OPENAIR2_DIR)/COMMON \
-I$(OPENAIR2_DIR)/S1AP \
-I$(OPENAIR2_DIR)/GTPV1U \
-I$(OPENAIR2_DIR)/GTPV1U/nw-gtpv1u/include \
-I$(OPENAIR2_DIR)/GTPV1U/nw-gtpv1u/shared \
-I$(OPENAIR2_DIR)/UTIL \
-I$(OPENAIR2_DIR)/UTIL/UDP \
-DUPDATE_RELEASE_9 \
-DENB_MODE \
-DENABLE_USE_MME \
-DUSER_MODE \
-O2 \
-g \
-Wall \
-Werror=implicit-function-declaration
$(libsctp_OBJECTS): %.o : %.c
@echo "Compiling $<"
@$(CC) -c $(CFLAGS) -o $@ $<
@if ! test -d ".deps/" ; then mkdir -p .deps; fi
@$(CC) -MM $(CFLAGS) $*.c > .deps/$*.d
@mv -f .deps/$*.d .deps/$*.d.tmp
@sed -e 's|.*:|$*.o:|' < .deps/$*.d.tmp > .deps/$*.d
@sed -e 's/.*://' -e 's/\\$$//' < .deps/$*.d.tmp | fmt -1 | \
sed -e 's/^ *//' -e 's/$$/:/' >> .deps/$*.d
@rm -f .deps/$*.d.tmp
@$(CC) -MM $(CFLAGS) $*.c > $*.d
@mv -f $*.d $*.d.tmp
@sed -e 's|.*:|$*.o:|' < $*.d.tmp > $*.d
@sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \
sed -e 's/^ *//' -e 's/$$/:/' >> $*.d
@rm -f $*.d.tmp
libsctp.a: $(libsctp_OBJECTS)
@echo Creating SCTP archive
@$(AR) rcvs $@ $(libsctp_OBJECTS)
@$(AR) rcs $@ $(libsctp_OBJECTS)
clean:
rm -f $(libsctp_OBJECTS)
rm -rf .deps/
rm -f libsctp.a
\ No newline at end of file
@$(RM_F_V) $(libsctp_OBJECTS)
@$(RM_F_V) *.d
@$(RM_F_V) libsctp.a
\ No newline at end of file
......@@ -83,7 +83,7 @@ int sctp_set_init_opt(int sd, uint16_t instreams, uint16_t outstreams,
}
int sctp_get_sockinfo(int sock, uint16_t *instream, uint16_t *outstream,
uint32_t *assoc_id)
int32_t *assoc_id)
{
socklen_t i;
struct sctp_status status;
......@@ -95,7 +95,7 @@ int sctp_get_sockinfo(int sock, uint16_t *instream, uint16_t *outstream,
memset(&status, 0, sizeof(struct sctp_status));
i = sizeof(struct sctp_status);
if(getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &i) < 0) {
if (getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &i) < 0) {
SCTP_ERROR("Getsockopt SCTP_STATUS failed: %s\n", strerror(errno));
return -1;
}
......
......@@ -47,6 +47,11 @@
# define SCTP_ERROR(x, args...) LOG_E(SCTP, x, ##args)
# define SCTP_WARN(x, args...) LOG_W(SCTP, x, ##args)
# define SCTP_DEBUG(x, args...) LOG_D(SCTP, x, ##args)
# define SCTP_OUT_STREAMS (64)
# define SCTP_IN_STREAMS (64)
# define SCTP_MAX_ATTEMPTS (5)
# define SCTP_RECV_BUFFER_SIZE (1024)
#else
# define SCTP_ERROR(x, args...) do { fprintf(stderr, "[SCTP][E]"x, ##args); } while(0)
# define SCTP_DEBUG(x, args...) do { fprintf(stdout, "[SCTP][D]"x, ##args); } while(0)
......@@ -57,7 +62,7 @@ int sctp_set_init_opt(int sd, uint16_t instreams, uint16_t outstreams,
uint16_t max_attempts, uint16_t init_timeout);
int sctp_get_sockinfo(int sock, uint16_t *instream, uint16_t *outstream,
uint32_t *assoc_id);
int32_t *assoc_id);
int sctp_get_peeraddresses(int sock, struct sockaddr **remote_addr,
int *nb_remote_addresses);
......
#include "intertask_interface.h"
#include "sctp_common.h"
#include "sctp_eNB_itti_messaging.h"
int sctp_itti_send_new_message_ind(task_id_t task_id, uint32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream)
{
MessageDef *message_p;
sctp_data_ind_t *sctp_data_ind_p;
message_p = itti_alloc_new_message(TASK_SCTP, SCTP_DATA_IND);
sctp_data_ind_p = &message_p->msg.sctp_data_ind;
sctp_data_ind_p->buffer = malloc(sizeof(uint8_t) * buffer_length);
/* Copy the buffer */
memcpy((void *)sctp_data_ind_p->buffer, (void *)buffer, buffer_length);
sctp_data_ind_p->stream = stream;
sctp_data_ind_p->buffer_length = buffer_length;
sctp_data_ind_p->assoc_id = assoc_id;
return itti_send_msg_to_task(task_id, INSTANCE_DEFAULT, message_p);
}
#ifndef SCTP_ITTI_MESSAGING_H_
#define SCTP_ITTI_MESSAGING_H_
int sctp_itti_send_new_message_ind(task_id_t task_id, uint32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream);
#endif /* SCTP_ITTI_MESSAGING_H_ */
/*******************************************************************************
Eurecom OpenAirInterface
Copyright(c) 1999 - 2013 Eurecom
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information
Openair Admin: openair_admin@eurecom.fr
Openair Tech : openair_tech@eurecom.fr
Forums : http://forums.eurecom.fr/openairinterface
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
06410 Biot FRANCE
*******************************************************************************/
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include "assertions.h"
#include "queue.h"
#include "intertask_interface.h"
#include "sctp_common.h"
#include "sctp_eNB_itti_messaging.h"
struct sctp_cnx_list_elm_s {
STAILQ_ENTRY(sctp_cnx_list_elm_s) entries;
/* Socket descriptor of connection */
int sd;
/* IN/OUT streams */
uint16_t in_streams;
uint16_t out_streams;
/* Configured PPID */
uint16_t ppid;
/* Association id */
int32_t assoc_id;
/* Nb of messages received on interface */
uint32_t nb_messages;
/* Task id of the task who asked for this connection */
task_id_t task_id;
/* Upper layer identifier */
uint16_t cnx_id;
};
static STAILQ_HEAD(sctp_cnx_list_head, sctp_cnx_list_elm_s) sctp_cnx_list;
static uint16_t sctp_nb_cnx = 0;
struct sctp_cnx_list_elm_s *sctp_get_cnx(int32_t assoc_id, int sd)
{
struct sctp_cnx_list_elm_s *elm;
STAILQ_FOREACH(elm, &sctp_cnx_list, entries)
{
if (assoc_id != -1) {
if (elm->assoc_id == assoc_id) {
return elm;
}
} else {
if (elm->sd == sd) {
return elm;
}
}
}
return NULL;
}
void sctp_handle_new_association_req(
const task_id_t requestor,
const sctp_new_association_req_t * const sctp_new_association_req_p)
{
int sd;
int32_t assoc_id;
struct sctp_initmsg init;
struct sctp_event_subscribe events;
/* Prepare a new SCTP association as requested by upper layer and try to connect
* to remote host.
*/
DevAssert(sctp_new_association_req_p != NULL);
/* Create new socket with IPv6 affinity */
if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
SCTP_ERROR("Socket creation failed: %s\n", strerror(errno));
return;
}
/* Add the socket to list of fd monitored by ITTI */
itti_subscribe_event_fd(TASK_SCTP, sd);
/* Request a number of in/out streams */
init.sinit_num_ostreams = SCTP_OUT_STREAMS;
init.sinit_max_instreams = SCTP_IN_STREAMS;
init.sinit_max_attempts = SCTP_MAX_ATTEMPTS;
SCTP_DEBUG("Requesting (%d %d) (in out) streams\n", init.sinit_num_ostreams,
init.sinit_max_instreams);
if (setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG,
&init, (socklen_t)sizeof(struct sctp_initmsg)) < 0) {
SCTP_ERROR("Setsockopt IPPROTO_SCTP_INITMSG failed: %s\n",
strerror(errno));
return;
}
/* Subscribe to all events */
memset((void *)&events, 1, sizeof(struct sctp_event_subscribe));
if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &events,
sizeof(struct sctp_event_subscribe)) < 0) {
SCTP_ERROR("Setsockopt IPPROTO_SCTP_EVENTS failed: %s\n",
strerror(errno));
return;
}
/* SOCK_STREAM socket type requires an explicit connect to the remote host
* address and port.
* Only use IPv4 for the first connection attempt
*/
{
uint8_t address_index = 0;
uint8_t used_address = sctp_new_association_req_p->remote_address.ipv6 +
sctp_new_association_req_p->remote_address.ipv4;
struct sockaddr_in addr[used_address];
memset(addr, 0, used_address * sizeof(struct sockaddr_in));
if (sctp_new_association_req_p->remote_address.ipv6 == 1) {
if (inet_pton(AF_INET6, sctp_new_association_req_p->remote_address.ipv6_address,
&addr[address_index].sin_addr.s_addr) != 1)
{
SCTP_ERROR("Failed to convert ipv6 address %*s to network type\n",
strlen(sctp_new_association_req_p->remote_address.ipv6_address),
sctp_new_association_req_p->remote_address.ipv6_address);
return;
}
SCTP_DEBUG("Converted ipv6 address %*s to network type\n",
strlen(sctp_new_association_req_p->remote_address.ipv6_address),
sctp_new_association_req_p->remote_address.ipv6_address);
addr[address_index].sin_family = AF_INET6;
addr[address_index].sin_port = htons(sctp_new_association_req_p->port);
address_index++;
}
if (sctp_new_association_req_p->remote_address.ipv4 == 1) {
if (inet_pton(AF_INET, sctp_new_association_req_p->remote_address.ipv4_address,
&addr[address_index].sin_addr.s_addr) != 1)
{
SCTP_ERROR("Failed to convert ipv4 address %*s to network type\n",
strlen(sctp_new_association_req_p->remote_address.ipv4_address),
sctp_new_association_req_p->remote_address.ipv4_address);
return;
}
SCTP_DEBUG("Converted ipv4 address %*s to network type\n",
strlen(sctp_new_association_req_p->remote_address.ipv4_address),
sctp_new_association_req_p->remote_address.ipv4_address);
addr[address_index].sin_family = AF_INET;
addr[address_index].sin_port = htons(sctp_new_association_req_p->port);
address_index++;
}
SCTP_DEBUG("Connecting...\n");
/* Connect to remote host and port */
if (sctp_connectx(sd, (struct sockaddr *)addr, used_address, &assoc_id) < 0) {
SCTP_ERROR("Connect failed: %s\n", strerror(errno));
return;
}
SCTP_DEBUG("Connected... assoc_id %u\n", assoc_id);
}
if (sctp_get_peeraddresses(sd, NULL, NULL) != 0) {
/* TODO Failure -> notify upper layer */
} else {
MessageDef *new_message_p;
sctp_new_association_resp_t *sctp_new_association_resp;
struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
sctp_cnx = calloc(1, sizeof(*sctp_cnx));
sctp_cnx->sd = sd;
sctp_cnx->task_id = requestor;
sctp_cnx->cnx_id = sctp_new_association_req_p->ulp_cnx_id;
sctp_cnx->ppid = sctp_new_association_req_p->ppid;
/* Get socket info */
sctp_get_sockinfo(sd,
&sctp_cnx->in_streams,
&sctp_cnx->out_streams,
&sctp_cnx->assoc_id);
/* Insert new element at end of list */
STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
sctp_nb_cnx++;
SCTP_DEBUG("Inserted new descriptor for sd %d in list, nb elements %u, assoc_id %d\n",
sd, sctp_nb_cnx, assoc_id);
new_message_p = itti_alloc_new_message(TASK_SCTP, SCTP_NEW_ASSOCIATION_RESP);
sctp_new_association_resp = &new_message_p->msg.sctp_new_association_resp;
sctp_new_association_resp->in_streams = sctp_cnx->in_streams;
sctp_new_association_resp->out_streams = sctp_cnx->out_streams;
sctp_new_association_resp->sctp_state = SCTP_STATE_ESTABLISHED;
sctp_new_association_resp->ulp_cnx_id = sctp_new_association_req_p->ulp_cnx_id;
sctp_new_association_resp->assoc_id = sctp_cnx->assoc_id;
SCTP_DEBUG("Sending SCTP new association resp message to %s\n",
itti_get_task_name(requestor));
itti_send_msg_to_task(requestor, INSTANCE_DEFAULT, new_message_p);
}
}
void sctp_send_data(task_id_t task_id, sctp_data_req_t *sctp_data_req_p)
{
struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
DevAssert(sctp_data_req_p != NULL);
sctp_cnx = sctp_get_cnx(sctp_data_req_p->assoc_id, 0);
if (sctp_cnx == NULL) {
SCTP_ERROR("Failed to find SCTP description for assoc_id %d\n",
sctp_data_req_p->assoc_id);
/* TODO: notify upper layer */
return;
}
if (sctp_data_req_p->stream >= sctp_cnx->out_streams) {
SCTP_ERROR("Requested stream (%u) >= nb out streams\n",
sctp_data_req_p->stream, sctp_cnx->out_streams);
return;
}
/* Send message on specified stream of the sd association
* NOTE: PPID should be defined in network order
*/
if (sctp_sendmsg(sctp_cnx->sd, sctp_data_req_p->buffer,
sctp_data_req_p->buffer_length, NULL, 0,
htonl(sctp_cnx->ppid), 0, sctp_data_req_p->stream, 0, 0) < 0) {
SCTP_ERROR("Sctp_sendmsg failed: %s\n", strerror(errno));
/* TODO: notify upper lkayer */
return;
}
SCTP_DEBUG("Successfully sent %u bytes on stream %d for assoc_id %u\n",
sctp_data_req_p->buffer_length, sctp_data_req_p->stream,
sctp_cnx->assoc_id);
}
static
inline void sctp_eNB_read_from_socket(struct sctp_cnx_list_elm_s *sctp_cnx)
{
int flags = 0, n;
socklen_t from_len;
struct sctp_sndrcvinfo sinfo;
struct sockaddr_in addr;
uint8_t buffer[SCTP_RECV_BUFFER_SIZE];
DevAssert(sctp_cnx != NULL);
memset((void *)&addr, 0, sizeof(struct sockaddr_in));
from_len = (socklen_t)sizeof(struct sockaddr_in);
memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
n = sctp_recvmsg(sctp_cnx->sd, (void *)buffer, SCTP_RECV_BUFFER_SIZE,
(struct sockaddr *)&addr, &from_len,
&sinfo, &flags);
if (n < 0) {
SCTP_DEBUG("An error occured during read\n");
SCTP_ERROR("sctp_recvmsg: %s:%d\n", strerror(errno), errno);
return;
}
if (flags & MSG_NOTIFICATION) {
union sctp_notification *snp;
snp = (union sctp_notification *)buffer;
/* Client deconnection */
if (SCTP_SHUTDOWN_EVENT == snp->sn_header.sn_type) {
DevMessage("Other peer has requested a com down -> not handled\n");
// return sctp_handle_com_down(snp->sn_shutdown_event.sse_assoc_id);
itti_unsubscribe_event_fd(TASK_SCTP, sctp_cnx->sd);
}
/* Association has changed. */
else if (SCTP_ASSOC_CHANGE == snp->sn_header.sn_type) {
struct sctp_assoc_change *sctp_assoc_changed;
sctp_assoc_changed = &snp->sn_assoc_change;
SCTP_DEBUG("Client association changed: %d\n", sctp_assoc_changed->sac_state);
/* New physical association requested by a peer */
switch (sctp_assoc_changed->sac_state) {
case SCTP_COMM_UP: {
// struct sctp_association_s *new_association;
//
// sctp_get_sockinfo(sd, NULL, NULL, NULL);
//
// SCTP_DEBUG("New connection\n");
// if ((new_association = sctp_add_new_peer()) == NULL) {
// // TODO: handle this case
// DevMessage("Unexpected error...\n");
// return SCTP_RC_ERROR;
// } else {
// new_association->sd = sd;
// new_association->ppid = ppid;
// new_association->instreams = sctp_assoc_changed->sac_inbound_streams;
// new_association->outstreams = sctp_assoc_changed->sac_outbound_streams;
// new_association->assoc_id = sctp_assoc_changed->sac_assoc_id;
//
// sctp_get_localaddresses(sd, NULL, NULL);
// sctp_get_peeraddresses(sd, &new_association->peer_addresses,
// &new_association->nb_peer_addresses);
//
// if (sctp_itti_send_new_association(
// new_association->assoc_id, new_association->instreams,
// new_association->outstreams) < 0)
// {
// SCTP_ERROR("Failed to send message to S1AP\n");
// return SCTP_RC_ERROR;
// }
// }
} break;
default:
break;
}
}
} else {
sctp_cnx->nb_messages++;
if (sinfo.sinfo_ppid != sctp_cnx->ppid) {
/* Mismatch in Payload Protocol Identifier,
* may be we received unsollicited traffic from stack other than S1AP.
*/
SCTP_ERROR("Received data from peer with unsollicited PPID %d, expecting %d\n",
sinfo.sinfo_ppid, sctp_cnx->ppid);
}
SCTP_DEBUG("[%d][%d] Msg of length %d received from port %u, on stream %d, PPID %d\n",
sinfo.sinfo_assoc_id, sctp_cnx->sd, n, ntohs(addr.sin_port),
sinfo.sinfo_stream, sinfo.sinfo_ppid);
sctp_itti_send_new_message_ind(sctp_cnx->task_id,
sinfo.sinfo_assoc_id,
buffer, n, sinfo.sinfo_stream);
}
}
void sctp_eNB_flush_sockets(struct epoll_event *events, int nb_events)
{
int i;
struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
if (events == NULL) {
return;
}
for (i = 0; i < nb_events; i++) {
sctp_cnx = sctp_get_cnx(-1, events[i].data.fd);
if (sctp_cnx == NULL) {
continue;
}
SCTP_DEBUG("Found data for descriptor %d\n", events[i].data.fd);
sctp_eNB_read_from_socket(sctp_cnx);
}
}
void *sctp_eNB_task(void *arg)
{
int nb_events;
struct epoll_event *events;
MessageDef *received_msg = NULL;
SCTP_DEBUG("Starting SCTP layer\n");
STAILQ_INIT(&sctp_cnx_list);
itti_mark_task_ready(TASK_SCTP);
while (1) {
itti_receive_msg(TASK_SCTP, &received_msg);
/* Check if there is a packet to handle */
if (received_msg != NULL) {
switch (received_msg->header.messageId) {
case TERMINATE_MESSAGE:
itti_exit_task();
break;
case SCTP_NEW_ASSOCIATION_REQ: {
sctp_handle_new_association_req(received_msg->header.originTaskId,
&received_msg->msg.sctp_new_association_req);
} break;
case SCTP_DATA_REQ: {
sctp_send_data(received_msg->header.originTaskId,
&received_msg->msg.sctp_data_req);
} break;
default:
SCTP_ERROR("Received unhandled message with id %d\n",
received_msg->header.messageId);
break;
}
}
free(received_msg);
received_msg = NULL;
nb_events = itti_get_events(TASK_SCTP, &events);
/* Now handle notifications for other sockets */
sctp_eNB_flush_sockets(events, nb_events);
}
return NULL;
}
/*******************************************************************************
Eurecom OpenAirInterface
Copyright(c) 1999 - 2013 Eurecom
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information
Openair Admin: openair_admin@eurecom.fr
Openair Tech : openair_tech@eurecom.fr
Forums : http://forums.eurecom.fr/openairinterface
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
06410 Biot FRANCE
*******************************************************************************/
#ifndef SCTP_ENB_TASK_H_
#define SCTP_ENB_TASK_H_
void *sctp_eNB_task(void *arg);
#endif /* SCTP_ENB_TASK_H_ */
......@@ -4,3 +4,5 @@
// Messages files used between tasks
#include "rrc_messages_def.h"
#include "s1ap_messages_def.h"
#include "sctp_messages_def.h"
\ No newline at end of file
......@@ -11,5 +11,7 @@
#include "timer_messages_types.h"
#include "rrc_messages_types.h"
#include "s1ap_messages_types.h"
#include "sctp_messages_types.h"
#endif /* MESSAGES_TYPES_H_ */
MESSAGE_DEF(S1AP_REGISTER_ENB, MESSAGE_PRIORITY_MED, s1ap_register_eNB_t, s1ap_register_eNB)
#ifndef S1AP_MESSAGES_TYPES_H_
#define S1AP_MESSAGES_TYPES_H_
enum cell_type_e {
CELL_MACRO_ENB,
CELL_HOME_ENB
};
typedef enum {
PAGING_DRX_32 = 0x0,
PAGING_DRX_64 = 0x1,
PAGING_DRX_128 = 0x2,
PAGING_DRX_256 = 0x3,
} paging_drx_t;
typedef struct {
unsigned ipv4:1;
unsigned ipv6:1;
char ipv4_address[16];
char ipv6_address[40];
} net_ip_address_t;
#define S1AP_MAX_NB_MME_IP_ADDRESS 10
typedef struct {
/* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */
uint8_t mod_id;
/* Unique eNB_id to identify the eNB within EPC.
* For macro eNB ids this field should be 20 bits long.
* For home eNB ids this field should be 28 bits long.
*/
uint32_t eNB_id;
/* The type of the cell */
enum cell_type_e cell_type;
/* Optional name for the cell
* NOTE: the name can be NULL (i.e no name) and will be cropped to 150
* characters.
*/
char *eNB_name;
/* Tracking area code */
uint16_t tac;
/* Mobile Country Code
* Mobile Network Code
*/
uint16_t mcc;
uint16_t mnc;
/* Default Paging DRX of the eNB as defined in TS 36.304 */
paging_drx_t default_drx;
/* The eNB IP address to bind */
net_ip_address_t enb_ip_address;
/* Nb of MME to connect to */
uint8_t nb_mme;
/* List of MME to connect to */
net_ip_address_t mme_ip_address[S1AP_MAX_NB_MME_IP_ADDRESS];
} s1ap_register_eNB_t;
#endif /* S1AP_MESSAGES_TYPES_H_ */
MESSAGE_DEF(SCTP_NEW_ASSOCIATION_REQ , MESSAGE_PRIORITY_MED, sctp_new_association_req_t , sctp_new_association_req)
MESSAGE_DEF(SCTP_NEW_ASSOCIATION_RESP, MESSAGE_PRIORITY_MED, sctp_new_association_resp_t , sctp_new_association_resp)
MESSAGE_DEF(SCTP_REGISTER_UPPER_LAYER, MESSAGE_PRIORITY_MED, sctp_listener_register_upper_layer_t, sctp_listener_register_upper_layer)
MESSAGE_DEF(SCTP_DATA_REQ, MESSAGE_PRIORITY_MED, sctp_data_req_t , sctp_data_req)
MESSAGE_DEF(SCTP_DATA_IND, MESSAGE_PRIORITY_MED, sctp_data_ind_t , sctp_data_ind)
\ No newline at end of file
#ifndef SCTP_MESSAGES_TYPES_H_
#define SCTP_MESSAGES_TYPES_H_
enum sctp_state_e {
SCTP_STATE_CLOSED,
SCTP_STATE_SHUTDOWN_PENDING,
SCTP_STATE_ESTABLISHED
};
typedef struct {
/* Module id: used in virtual mode */
uint8_t mod_id;
/* Upper layer connexion identifier */
uint16_t ulp_cnx_id;
/* The port to connect to */
uint16_t port;
/* Payload Protocol Identifier to use */
uint32_t ppid;
/* Local address to bind to */
net_ip_address_t local_address;
/* Remote address to connect to */
net_ip_address_t remote_address;
} sctp_new_association_req_t;
typedef struct {
/* Module id: used in virtual mode */
uint8_t mod_id;
/* Upper layer connexion identifier */
uint16_t ulp_cnx_id;
/* SCTP Association ID */
int32_t assoc_id;
/* Input/output streams */
uint16_t out_streams;
uint16_t in_streams;
/* State of the association at SCTP level */
enum sctp_state_e sctp_state;
} sctp_new_association_resp_t;
typedef struct {
int32_t assoc_id;
uint32_t buffer_length;
uint8_t *buffer;
/* Streams on which data will be sent/received */
uint16_t stream;
} sctp_data_ind_t;
typedef sctp_data_ind_t sctp_data_req_t;
typedef struct {
/* Port to listen to */
uint16_t port;
/* Payload protocol identifier
* Any data receveid on PPID != will be discarded
*/
uint32_t ppid;
} sctp_listener_register_upper_layer_t;
#endif /* SCTP_MESSAGES_TYPES_H_ */
......@@ -31,3 +31,6 @@ TASK_DEF(TASK_NAS_UE, TASK_PRIORITY_MED)
/// S1ap task for eNodeB
TASK_DEF(TASK_S1AP, TASK_PRIORITY_MED)
/// Sctp task for eNodeB (Used by both S1AP and X2AP)
TASK_DEF(TASK_SCTP, TASK_PRIORITY_MED)
......@@ -476,11 +476,13 @@ openair_rrc_lite_eNB_init (u8 Mod_id)
/* Connect eNB to MME */
if (oai_emulation.info.mme_enabled > 0)
{
# if !defined(ENABLE_ITTI)
if (s1ap_eNB_init (oai_emulation.info.mme_ip_address, Mod_id) < 0)
{
mac_xface->macphy_exit ("");
return -1;
}
# endif
}
#endif
......@@ -796,7 +798,7 @@ rrc_eNB_decode_dcch (u8 Mod_id, u32 frame, u8 Srb_id, u8 UE_index,
case UL_DCCH_MessageType__c1_PR_ulHandoverPreparationTransfer:
break;
case UL_DCCH_MessageType__c1_PR_ulInformationTransfer:
#if defined(ENABLE_USE_MME)
#if defined(ENABLE_USE_MME) && !defined(ENABLE_ITTI)
{
if (oai_emulation.info.mme_enabled == 1)
{
......@@ -1053,7 +1055,7 @@ rrc_eNB_process_RRCConnectionSetupComplete (u8 Mod_id,
Mod_id, frame, UE_index);
// Forward message to S1AP layer
#if defined(ENABLE_USE_MME)
#if defined(ENABLE_USE_MME) && !defined(ENABLE_ITTI)
if (oai_emulation.info.mme_enabled == 1)
s1ap_eNB_new_data_request (Mod_id, UE_index,
rrcConnectionSetupComplete->dedicatedInfoNAS.
......
......@@ -10,7 +10,6 @@ OMG_DIR=$(OPENAIR2_TOP)/UTIL/OMG
OTG_DIR=$(OPENAIR2_TOP)/UTIL/OTG
CLI_DIR=$(OPENAIR2_TOP)/UTIL/CLI
OMV_DIR=$(OPENAIR2_TOP)/UTIL/OMV
SCTP_DIR=$(OPENAIR2_TOP)/UTIL/SCTP
LFDS_DIR=$(OPENAIR2_TOP)/UTIL/LFDS/liblfds6.1.1/liblfds611
OSA_DIR=$(OPENAIR2_TOP)/UTIL/OSA
......@@ -71,12 +70,19 @@ CLI_OBJ = $(CLI_DIR)/cli_server.o
CLI_OBJ += $(CLI_DIR)/cli.o
CLI_OBJ += $(CLI_DIR)/cli_cmd.o
ifdef $(USE_MME)
SCTP_OBJS = $(SCTP_DIR)/sctp_primitives_client.o
else
SCTP_OBJS =
endif
UTIL_OBJ = $(OSA_OBJS) $(FIFO_OBJ) $(LIST_OBJ) $(TIMER_OBJ) $(MEM_OBJ) $(LOG_OBJS) $(OCG_OBJS) $(MATH_OBJS) $(OTG_OBJS) $(CLI_OBJ) $(OMG_OBJS) $(OPT_OBJS) $(SCTP_OBJS)
UTIL_OBJ = \
$(OSA_OBJS) \
$(FIFO_OBJ) \
$(LIST_OBJ) \
$(TIMER_OBJ) \
$(MEM_OBJ) \
$(LOG_OBJS) \
$(OCG_OBJS) \
$(MATH_OBJS) \
$(OTG_OBJS) \
$(CLI_OBJ) \
$(OMG_OBJS) \
$(OPT_OBJS)
UTIL_incl = \
-I$(OPENAIR2_TOP)/UTIL \
......@@ -93,5 +99,4 @@ UTIL_incl = \
-I$(OTG_DIR) \
-I$(CLI_DIR) \
-I$(OPT_DIR) \
-I$(OMV_DIR) \
-I$(SCTP_DIR)
-I$(OMV_DIR)
CC = gcc
MPICC = gcc #mpicc
RM_F_V = rm -f -v
# Include some standard directives
include Makerules
CPUFLAGS = -mmmx -msse -msse2 -msse4.1 -march=native
# FORCE ssse3 for compilation of openair on User Mode Linux
......@@ -8,8 +7,6 @@ CPUFLAGS += $(shell if grep --silent ssse3 /proc/cpuinfo ; then echo "-mssse3" ;
CPUFLAGS += $(shell if grep --silent sse4 /proc/cpuinfo ; then echo "-msse4" ; else echo ""; fi)
linux = $(shell if [ `uname` = "Linux" ] ; then echo "1" ; else echo "0" ; fi)
NUM_CORES=$(shell cat /proc/cpuinfo | grep processor | wc -l)
COMMON_UTILS_DIR = $(OPENAIR_HOME)/common/utils
TOP_DIR = $(OPENAIR1_DIR)
OPENAIR1_TOP = $(OPENAIR1_DIR)
......@@ -17,6 +14,12 @@ OPENAIR2_TOP = $(OPENAIR2_DIR)
OPENAIR3_TOP = $(OPENAIR3_DIR)
OPENAIR3 = $(OPENAIR3_DIR)
S1AP_DIR = $(OPENAIR_HOME)/openair-cn/S1AP
SCTP_DIR = $(OPENAIR_HOME)/openair-cn/SCTP
export S1AP_DIR
export COMMON_UTILS_DIR
CFLAGS = -Wall -fno-strict-aliasing -DUSER_MODE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -g -ggdb $(CPUFLAGS) -I/usr/include/X11 #-Wno-packed-bitfield-compat
ifdef ENABLE_ITTI
......@@ -172,9 +175,6 @@ UPDATE_RELEASE_9=1
endif
ifdef SECU
NETTLE_FOUND = $(shell if pkg-config --exists nettle; then echo "1" ; else echo "0"; fi)
OPENSSL_FOUND = $(shell if pkg-config --exists openssl; then echo "1" ; else echo "0"; fi)
ifeq ($(NETTLE_FOUND), 0)
@echo "Nettle library >= 2.5 is not installed on your system, continuing with security disabled"
SECU=0
......@@ -204,15 +204,6 @@ include $(OPENAIR2_DIR)/S1AP/MESSAGES/Makefile.inc
#LOG_OBJS += $(LOG_DIR)/vcd_signal_dumper.o
#LOG_OBJS += $(LOG_DIR)/log.o
CFLAGS += -DENB_MODE
S1AP_BUILT_OBJS=
ifdef USE_MME
CFLAGS += -DENABLE_USE_MME
CFLAGS_S1AP += -DENB_MODE -DENABLE_USE_MME -DEMIT_ASN_DEBUG=1 -DUSER_MODE
S1AP_BUILT_OBJS += $(S1AP_OBJS) $(addprefix $(OPENAIR2_DIR)/S1AP/MESSAGES/, $(S1AP_ASN_MODULE_SOURCES))
endif
ITTI_MESSAGES_H = messages_xml.h
ITTI_MESSAGES_XML = messages.xml
......@@ -274,8 +265,7 @@ endif
# Check if libpgm is installed and use it if found instead of the unreliable
# multicast
ENABLE_PGM = $(shell if pkg-config --exists openpgm-5.1; then echo "1" ; else echo "0"; fi)
ifeq ($(ENABLE_PGM), 1)
ifeq ($(PGM_FOUND), 1)
CFLAGS += `pkg-config --cflags openpgm-5.1` -DENABLE_PGM_TRANSPORT
PGM_LDFLAGS = `pkg-config --libs openpgm-5.1`
endif
......@@ -285,9 +275,19 @@ ifeq ($(OPENAIR2),1)
OBJ += $(L2_OBJS)
endif
LIB = $(LFDS_DIR)/bin/liblfds611.a
LIBS = $(LFDS_DIR)/bin/liblfds611.a
ifdef USE_MME
LIB += $(S1AP_DIR)/libs1ap.a
CFLAGS += -DENB_MODE -DENABLE_USE_MME -DENABLE_EVENT_FD -I$(S1AP_DIR) -I$(SCTP_DIR)
S1AP_CFLAGS = $(CFLAGS) -I$(TOP_DIR) $(L2_incl) $(UTIL_incl) $(UTILS_incl)
LIBS += $(S1AP_DIR)/libs1ap.a $(SCTP_DIR)/libsctp.a -lsctp
export S1AP_CFLAGS
$(S1AP_DIR)/libs1ap.a: force_look
$(MAKE) -C $(S1AP_DIR) -f Makefile.eNB libs1ap.a
$(SCTP_DIR)/libsctp.a: force_look
$(MAKE) -C $(SCTP_DIR) -f Makefile.eNB libsctp.a
endif
default: oaisim
......@@ -313,16 +313,6 @@ printvars:
@echo CFLAGS: $(CFLAGS)
@echo Enable PGM: $(ENABLE_PGM)
ASN1RELDIR=R9.8
ifeq ($(USE_MME), R8)
ASN1RELDIR=R8.10
else
CFLAGS_S1AP += -DUPDATE_RELEASE_9
endif
S1AP_DIR=$(OPENAIR2_DIR)/S1AP
ASN1MESSAGESDIR=$(S1AP_DIR)/MESSAGES
ASN1DIR=$(ASN1MESSAGESDIR)/ASN1
-include $(ITTI_MESSAGES_XML:.xml=.d)
-include $(OBJ:.o=.d)
-include $(OAISIM_OBJS:.o=.d)
......@@ -333,7 +323,7 @@ ifdef ENABLE_ITTI
gccxml_available = $(shell if [ `gccxml --version | grep GCC-XML -c` = "0" ]; then echo "0" ; else echo "1" ; fi )
ifeq ($(gccxml_available), 0)
$(error gccxml is missing, please install)
endif
endif
endif
$(ITTI_MESSAGES_XML): $(ITTI_MESSAGES_FILE)
......@@ -366,22 +356,6 @@ $(OBJ) $(OAISIM_OBJS) $(OAISIM_PAD_OBJS) $(ASN1_MSG_OBJS1): %.o : %.c
sed -e 's/^ *//' -e 's/$$/:/' >> $*.d
@rm -f $*.d.tmp
$(S1AP_BUILT_OBJS): %.o : %.c
@echo Compiling $<
@$(CC) -Wall -c $(CFLAGS_S1AP) $(S1AP_Incl) $(UTIL_incl) $(UTILS_incl) -o $@ $<
$(ASN1MESSAGESDIR)/s1ap_ieregen.stamp: $(ASN1DIR)/$(ASN1RELDIR)/S1AP-PDU-Contents.asn $(ASN1DIR)/asn1tostruct.py
echo Timestamp > $@
(cd $(ASN1DIR) && python $(ASN1DIR)/asn1tostruct.py -f$<)
$(ASN1MESSAGESDIR)/s1ap_asn1regen.stamp: $(ASN1DIR)/$(ASN1RELDIR)/S1AP-CommonDataTypes.asn $(ASN1DIR)/$(ASN1RELDIR)/S1AP-Constants.asn $(ASN1DIR)/$(ASN1RELDIR)/S1AP-IEs.asn $(ASN1DIR)/$(ASN1RELDIR)/S1AP-PDU.asn
echo Timestamp > $@
(cd $(ASN1MESSAGESDIR) && asn1c -gen-PER -fnative-types -fskeletons-copy $^)
$(S1AP_DIR)/libs1ap.a: $(ASN1MESSAGESDIR)/s1ap_ieregen.stamp $(ASN1MESSAGESDIR)/s1ap_asn1regen.stamp $(S1AP_BUILT_OBJS)
@echo Creating $@
$(AR) rcs $@ $^
$(LFDS_DIR)/bin/liblfds611.a:
$(MAKE) -C $(LFDS_DIR) -f makefile.linux
......@@ -390,11 +364,11 @@ oaisim_pad: $(OBJ) $(OAISIM_PAD_OBJS) $(ASN1_MSG_OBJS1)
@$(MPICC) -I$(TOP_DIR) $(L2_incl) $(UTIL_incl) $(UTILS_incl) -I$(ASN1_MSG_INC) $(S1AP_Incl) -o oaisim_pad $(CFLAGS) $(EXTRA_CFLAGS) $(OBJ) $(OAISIM_PAD_OBJS) $(ASN1_MSG_OBJS1) \
-lm -lblas -lpthread -llapack_atlas -lforms -lxml2 -lX11 -lXpm -lrt
oaisim: $(OBJ) $(OAISIM_OBJS) $(ASN1_MSG_OBJS1) $(LIB)
oaisim: $(OBJ) $(OAISIM_OBJS) $(ASN1_MSG_OBJS1) $(LIBS)
@echo "Linking oaisim ..."
@$(CC) -I$(TOP_DIR) $(L2_incl) $(UTIL_incl) $(UTILS_incl) -I$(ASN1_MSG_INC) $(S1AP_Incl) -o oaisim $(CFLAGS) $(EXTRA_CFLAGS) $(OBJ) $(OAISIM_OBJS) $(ASN1_MSG_OBJS1) \
-lm -lblas -lpthread -llapack_atlas -lforms -lxml2 -lX11 -lXpm -lrt \
$(LIB) $(PGM_LDFLAGS) $(DB_LDFLAGS) $(OSA_LDFLAGS)
$(LIBS) $(PGM_LDFLAGS) $(DB_LDFLAGS) $(OSA_LDFLAGS)
ifeq ($(rrc_cellular_eNB),1)
mv oaisim oaisim_eNB
......@@ -438,7 +412,7 @@ rrm_std_cellular:
( cd $(OPENAIR2_DIR)/NAS/SIMU_CELLULAR && make cell_rrm CELL_RRM=1 CELLULAR=1 NO_RRM=1)
cleanall: clean cleanasn1 cleanmmeasn1
cleanall: clean cleanasn1
clean:
@$(MAKE) -C $(LFDS_DIR) -f makefile.linux clean
......@@ -449,10 +423,10 @@ clean:
@$(RM_F_V) $(OAISIM_OBJS) $(OAISIM_OBJS:.o=.d)
@$(RM_F_V) $(OAISIM_PAD_OBJS) $(OAISIM_PAD_OBJS:.o=.d)
@$(RM_F_V) $(ASN1_MSG_OBJS1) $(ASN1_MSG_OBJS1:.o=.d)
@$(RM_F_V) $(S1AP_BUILT_OBJS)
@$(RM_F_V) $(ASN1MESSAGESDIR)/libs1ap.a
@$(RM_F_V) *.exe*
@$(RM_F_V) $(ASN1_MSG_INC)/asn1_msg.o
@$(MAKE) -C $(S1AP_DIR) -f Makefile.eNB clean
@$(MAKE) -C $(SCTP_DIR) -f Makefile.eNB clean
cleanl1:
@$(RM_F_V) LOG_THREAD oaisim
......@@ -471,13 +445,7 @@ cleanasn1:
@$(RM_F_V) $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc.generated
@$(RM_F_V) $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1c/ASN1_files/.lock-rel10
@$(RM_F_V) $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1c/ASN1_files/.lock-rel8
cleanmmeasn1:
@$(RM_F_V) $(S1AP_BUILT_OBJS)
@$(RM_F_V) $(S1AP_BUILT_OBJS:.o:.c)
@$(RM_F_V) $(ASN1MESSAGESDIR)/libs1ap.a
@$(RM_F_V) $(ASN1MESSAGESDIR)/s1ap_asn1regen.stamp
@$(RM_F_V) $(ASN1MESSAGESDIR)/s1ap_ieregen.stamp
@$(MAKE) -C $(S1AP_DIR) -f Makefile.eNB cleanall
cleancell:
@$(RM_F_V) $(OPENAIR2_DIR)/RRC/CELLULAR/*.o
......@@ -489,15 +457,15 @@ cleancell:
print:
# @echo $(cygwin)
@echo "OBJ " $(OBJ)
@echo "OBJ " $(OBJ)
@echo "OAISIM_OBJS " $(OAISIM_OBJS)
@echo "OAISIM_PAD_OBJS " $(OAISIM_PAD_OBJS)
@echo "OCG_FLAG are " $(OCG_FLAG)
@echo "CFLAGS are " $(CFLAGS)
@echo "EXTRA_CFLAGS are" $(EXTRA_CFLAGS)
@echo "L2 includes are" $(L2_incl)
@echo "S1AP Includes are" $(S1AP_Incl)
@echo "TOP_DIR Include is" I$(TOP_DIR)
@echo "L2 includes are" $(L2_incl)
@echo "S1AP Includes are" $(S1AP_Incl)
@echo "TOP_DIR Include is" I$(TOP_DIR)
@echo "UTIL includes are" $(UTIL_incl)
@echo "UTILS includes are" $(UTILS_incl)
@echo "IS_REL8 is " $(IS_REL8)
......@@ -505,7 +473,11 @@ print:
@echo "ENABLE_DB is " $(ENABLE_DB)
showcflags:
@echo $(CFLAGS)
@echo oaisim cflags: $(CFLAGS)
@$(MAKE) -C $(S1AP_DIR) -f Makefile.eNB showcflags
force_look:
true
otg_all: otg_latency otg_gp
......@@ -537,10 +509,10 @@ ifeq ($(pexpect), 1)
ifndef PW
@echo "Usage: make pre-ci PW=mypassword"
@echo "Password is used to access the local host through ssh."
python $(OPENAIR_TARGETS)/TEST/OAI/test01.py
python $(OPENAIR_TARGETS)/TEST/OAI/test01.py
else
python $(OPENAIR_TARGETS)/TEST/OAI/test01.py -w $(PW)
endif
else
@echo "Python pexpect package is missing, please install"
endif
endif
CC = gcc
MPICC = gcc #mpicc
RM_F_V = rm -f -v
NUM_CORES=$(shell cat /proc/cpuinfo | grep processor | wc -l)
NETTLE_FOUND = $(shell if pkg-config --exists nettle; then echo "1" ; else echo "0"; fi)
OPENSSL_FOUND = $(shell if pkg-config --exists openssl; then echo "1" ; else echo "0"; fi)
PGM_FOUND = $(shell if pkg-config --exists openpgm-5.1; then echo "1" ; else echo "0"; fi)
......@@ -73,6 +73,10 @@ char smbv_ip[16];
#if defined(ENABLE_ITTI)
# include "intertask_interface_init.h"
# include "timer.h"
# if defined(ENABLE_USE_MME)
# include "s1ap_eNB.h"
# include "sctp_eNB_task.h"
# endif
#endif
#define RF
......@@ -381,6 +385,40 @@ void *l2l1_task(void *args_p) {
MessageDef *message_p;
itti_mark_task_ready (TASK_L2L1);
# if defined(ENABLE_USE_MME)
/* Trying to register each eNB */
for (eNB_id = oai_emulation.info.first_enb_local;
(eNB_id < (oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local)) && (oai_emulation.info.cli_start_enb[eNB_id] == 1);
eNB_id++)
{
/* FIXME: acquire MMEs IP address by XML file or command line */
char *mme_address_v4 = "192.168.12.87";
char *mme_address_v6 = "2001:660:5502:12:30da:829a:2343:b6cf";
s1ap_register_eNB_t *s1ap_register_eNB;
message_p = itti_alloc_new_message(TASK_L2L1, S1AP_REGISTER_ENB);
s1ap_register_eNB = &message_p->msg.s1ap_register_eNB;
/* Some default/random parameters */
s1ap_register_eNB->mod_id = eNB_id;
/* FIXME: generate unique eNB id */
s1ap_register_eNB->eNB_id = 1 + eNB_id;
s1ap_register_eNB->cell_type = CELL_MACRO_ENB;
s1ap_register_eNB->tac = 8;
s1ap_register_eNB->mcc = 208;
s1ap_register_eNB->mnc = 35;
s1ap_register_eNB->default_drx = PAGING_DRX_256;
s1ap_register_eNB->nb_mme = 1;
s1ap_register_eNB->mme_ip_address[0].ipv4 = 1;
s1ap_register_eNB->mme_ip_address[0].ipv6 = 0;
memcpy(s1ap_register_eNB->mme_ip_address[0].ipv4_address, mme_address_v4,
strlen(mme_address_v4));
memcpy(s1ap_register_eNB->mme_ip_address[0].ipv6_address, mme_address_v6,
strlen(mme_address_v6));
itti_send_msg_to_task(TASK_S1AP, INSTANCE_DEFAULT, message_p);
}
# endif
#endif
for (frame = 0; frame < oai_emulation.info.n_frames; frame++) {
......@@ -987,6 +1025,19 @@ int main(int argc, char **argv) {
LOG_N(EMU, "\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>> OAIEMU initialization done <<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
#if defined(ENABLE_ITTI)
# if defined(ENABLE_USE_MME)
if (itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0) {
LOG_E(EMU, "Create task failed");
LOG_D(EMU, "Initializing SCTP task interface: FAILED\n");
return -1;
}
if (itti_create_task(TASK_S1AP, s1ap_eNB_task, NULL) < 0) {
LOG_E(EMU, "Create task failed");
LOG_D(EMU, "Initializing S1AP task interface: FAILED\n");
return -1;
}
# endif
if (itti_create_task(TASK_L2L1, l2l1_task, NULL) < 0) {
LOG_E(EMU, "Create task failed");
LOG_D(EMU, "Initializing L2L1 task interface: FAILED\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment