- 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
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
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 = \
|
||||
-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 \
|
||||
$(ADD_CFLAGS) \
|
||||
CFLAGS = \
|
||||
-DENB_MODE \
|
||||
-DENABLE_USE_MME \
|
||||
-DEMIT_ASN_DEBUG_EXTERN \
|
||||
-DEMIT_ASN_DEBUG=1 \
|
||||
-DUSER_MODE \
|
||||
-g \
|
||||
-O2 \
|
||||
-Wall \
|
||||
-I./MESSAGES \
|
||||
-I$(S1AP_OBJDIR) \
|
||||
-I../UTILS \
|
||||
$(ADD_CFLAGS) \
|
||||
-DENB_MODE \
|
||||
$(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
|
||||
@$(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)
|
||||
@@ -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
|
||||
// );
|
||||
|
||||
typedef int (*s1ap_message_decoded_callback)(
|
||||
eNB_mme_desc_t *eNB_desc_p,
|
||||
sctp_queue_item_t *packet_p,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct s1ap_message_s *message_p
|
||||
);
|
||||
#else
|
||||
typedef int (*s1ap_message_decoded_callback)(
|
||||
uint32_t assocId,
|
||||
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
|
||||
|
||||
+400
-292
@@ -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;
|
||||
|
||||
return RB_FIND(s1ap_mme_map, &eNB_desc_p->s1ap_mme_head, &temp);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
sctp_data_t sctp_data;
|
||||
char hostname[30];
|
||||
|
||||
DevAssert(eNB_desc_p != NULL);
|
||||
|
||||
if (eNB_desc_p->eNB_id >= (1 << 20))
|
||||
S1AP_WARN("eNB_id exceed limit of 20 bits...\n");
|
||||
|
||||
if (gethostname(hostname, sizeof(hostname)) == -1) {
|
||||
hostname[0] = '\0';
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
S1AP_DEBUG("Initializing S1AP layer for eNB %u\n",
|
||||
eNB_desc_p->eNB_id);
|
||||
|
||||
/* TODO: RRM configuration... */
|
||||
eNB_desc_p->tac = ENB_TAC;
|
||||
eNB_desc_p->mcc = ENB_MCC;
|
||||
eNB_desc_p->mnc = ENB_MNC;
|
||||
|
||||
RB_INIT(&eNB_desc_p->s1ap_mme_head);
|
||||
RB_INIT(&eNB_desc_p->s1ap_ue_head);
|
||||
|
||||
memset(&sctp_data, 0, sizeof(sctp_data_t));
|
||||
|
||||
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)
|
||||
if (instance_p == NULL) {
|
||||
STAILQ_FOREACH(instance_p, &s1ap_eNB_internal_data.s1ap_eNB_instances_head,
|
||||
s1ap_eNB_entries)
|
||||
{
|
||||
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;
|
||||
|
||||
mme_assoc_p = calloc(1, sizeof(struct s1ap_eNB_mme_data_s));
|
||||
mme_assoc_p->nextstream = 1;
|
||||
|
||||
memcpy(&mme_assoc_p->sctp_data, &sctp_data, sizeof(sctp_data_t));
|
||||
|
||||
TAILQ_INIT(&mme_assoc_p->sctp_data.sctp_queue);
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STAILQ_INIT(&mme_assoc_p->served_gummei);
|
||||
if (s1ap_eNB_generate_s1_setup_request(eNB_desc_p, mme_assoc_p) == -1)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
S1AP_DEBUG("Initializing S1AP layer for eNB %d: DONE\n", eNB_desc_p->eNB_id);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MessageDef *message_p;
|
||||
sctp_new_association_req_t *sctp_new_association_req_p;
|
||||
s1ap_eNB_mme_data_t *s1ap_mme_data_p;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(mme_ip_address != NULL);
|
||||
|
||||
message_p = itti_alloc_new_message(TASK_S1AP, SCTP_NEW_ASSOCIATION_REQ);
|
||||
|
||||
sctp_new_association_req_p = &message_p->msg.sctp_new_association_req;
|
||||
|
||||
sctp_new_association_req_p->port = S1AP_PORT_NUMBER;
|
||||
sctp_new_association_req_p->ppid = S1AP_SCTP_PPID;
|
||||
|
||||
memcpy(&sctp_new_association_req_p->remote_address, mme_ip_address,
|
||||
sizeof(*mme_ip_address));
|
||||
|
||||
/* Create new MME descriptor */
|
||||
s1ap_mme_data_p = calloc(1, sizeof(*s1ap_mme_data_p));
|
||||
DevAssert(s1ap_mme_data_p != NULL);
|
||||
|
||||
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++;
|
||||
|
||||
s1ap_mme_data_p->assoc_id = -1;
|
||||
s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
|
||||
|
||||
STAILQ_INIT(&s1ap_mme_data_p->served_gummei);
|
||||
|
||||
/* 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);
|
||||
|
||||
itti_send_msg_to_task(TASK_SCTP, INSTANCE_DEFAULT, message_p);
|
||||
}
|
||||
|
||||
void s1ap_eNB_handle_register_eNB(s1ap_register_eNB_t *s1ap_register_eNB)
|
||||
{
|
||||
s1ap_eNB_instance_t *new_instance;
|
||||
uint8_t index;
|
||||
|
||||
DevAssert(s1ap_register_eNB != NULL);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
// 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);
|
||||
// }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_ */
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#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_ */
|
||||
+148
-153
@@ -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.
|
||||
*/
|
||||
uint16_t rnti;
|
||||
/* Served PLMN identity element */
|
||||
struct plmn_identity_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
STAILQ_ENTRY(plmn_identity_s) next;
|
||||
};
|
||||
|
||||
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.
|
||||
/* 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.
|
||||
*/
|
||||
ue_identity_t ue_identity;
|
||||
} s1ap_nas_first_req_t;
|
||||
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;
|
||||
|
||||
/* Next usable stream for UE signalling */
|
||||
int32_t nextstream;
|
||||
|
||||
/* Number of input/ouput streams */
|
||||
uint16_t in_streams;
|
||||
uint16_t out_streams;
|
||||
|
||||
/* Connexion id used when SCTP association is not established yet */
|
||||
uint16_t cnx_id;
|
||||
|
||||
/* SCTP association id */
|
||||
int32_t assoc_id;
|
||||
|
||||
/* Only meaningfull in virtual mode */
|
||||
struct s1ap_eNB_instance_s *s1ap_eNB_instance;
|
||||
} s1ap_eNB_mme_data_t;
|
||||
|
||||
typedef struct s1ap_eNB_instance_s {
|
||||
/* Next s1ap eNB association.
|
||||
* Only used for virtual mode.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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 {
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
nas_pdu_t nas_pdu;
|
||||
} s1ap_nas_uplink_t;
|
||||
/* 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;
|
||||
|
||||
typedef struct {
|
||||
nas_pdu_t nas_pdu;
|
||||
// cause_t cause;
|
||||
} s1ap_nas_non_delivery_t;
|
||||
/* Generate a unique connexion id used between S1AP and SCTP */
|
||||
uint16_t global_cnx_id;
|
||||
} s1ap_eNB_internal_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t rnti;
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
inline int s1ap_eNB_compare_assoc_id(
|
||||
struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2);
|
||||
|
||||
/* 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;
|
||||
/* Generate the tree management functions */
|
||||
RB_PROTOTYPE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry,
|
||||
s1ap_eNB_compare_assoc_id);
|
||||
|
||||
typedef struct {
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
ue_radio_cap_t ue_radio_cap;
|
||||
} s1ap_ue_cap_info_ind_t;
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
S1AP_API_RESET = 0x40,
|
||||
S1AP_API_RESET_ACK = 0x41,
|
||||
} s1ap_rrc_api_req_type_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);
|
||||
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_ */
|
||||
|
||||
+162
-132
@@ -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);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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);
|
||||
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", 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;
|
||||
// }
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
// {
|
||||
// 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_ */
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#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);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#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;
|
||||
// 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;
|
||||
// }
|
||||
|
||||
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_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;
|
||||
|
||||
DevAssert(message_p != NULL);
|
||||
|
||||
overload_start_p = &message_p->msg.overloadStartIEs;
|
||||
|
||||
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;
|
||||
// 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);
|
||||
DevAssert(message_p != NULL);
|
||||
|
||||
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;
|
||||
// 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;
|
||||
// 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;
|
||||
// }
|
||||
|
||||
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_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_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_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_ */
|
||||
|
||||
@@ -1,47 +1,34 @@
|
||||
include $(OPENAIR_TARGETS)/SIMU/USER/Makerules
|
||||
|
||||
libsctp_OBJECTS = \
|
||||
sctp_primitives_client.o \
|
||||
sctp_common.o
|
||||
sctp_common.o \
|
||||
sctp_eNB_task.o \
|
||||
sctp_eNB_itti_messaging.o
|
||||
|
||||
-include .deps/*.d
|
||||
|
||||
.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
|
||||
@$(RM_F_V) $(libsctp_OBJECTS)
|
||||
@$(RM_F_V) *.d
|
||||
@$(RM_F_V) libsctp.a
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#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);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#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_ */
|
||||
@@ -0,0 +1,451 @@
|
||||
/*******************************************************************************
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*******************************************************************************
|
||||
|
||||
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"
|
||||
@@ -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_ */
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
MESSAGE_DEF(S1AP_REGISTER_ENB, MESSAGE_PRIORITY_MED, s1ap_register_eNB_t, s1ap_register_eNB)
|
||||
@@ -0,0 +1,64 @@
|
||||
#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_ */
|
||||
@@ -0,0 +1,5 @@
|
||||
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)
|
||||
@@ -0,0 +1,64 @@
|
||||
#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)
|
||||
|
||||
+39
-67
@@ -1,6 +1,5 @@
|
||||
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
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
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");
|
||||
|
||||
Reference in New Issue
Block a user