diff --git a/openair-cn/S1AP/Makefile.eNB b/openair-cn/S1AP/Makefile.eNB index c9faf35cb8..e3b8daffab 100644 --- a/openair-cn/S1AP/Makefile.eNB +++ b/openair-cn/S1AP/Makefile.eNB @@ -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 \ No newline at end of file + @$(RM_F_V) $(libs1ap_OBJECTS) + @$(RM_F_V) .*.d + @$(RM_F_V) $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES)) + @$(RM_F_V) $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES:.o=.d)) + @$(RM_F_V) libs1ap.a + @$(RM_F_V) $(S1AP_OBJDIR)/s1ap_asn1regen.stamp + @$(RM_F_V) $(S1AP_OBJDIR)/s1ap_ieregen.stamp + @$(RM_F_V) $(S1AP_OBJDIR)/s1ap_decoder.c $(S1AP_OBJDIR)/s1ap_encoder.c + @$(RM_F_V) $(S1AP_OBJDIR)/s1ap_xer_print.c $(S1AP_OBJDIR)/s1ap_ies_defs.h + +cleanall: clean + @$(RM_F_V) $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES:.o=.c)) + @$(RM_F_V) $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES:.o=.h)) + +showcflags: + @echo s1ap cflags: $(CFLAGS) \ No newline at end of file diff --git a/openair-cn/S1AP/s1ap_common.c b/openair-cn/S1AP/s1ap_common.c index 655b4c9d71..4364ef1b9f 100644 --- a/openair-cn/S1AP/s1ap_common.c +++ b/openair-cn/S1AP/s1ap_common.c @@ -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, diff --git a/openair-cn/S1AP/s1ap_common.h b/openair-cn/S1AP/s1ap_common.h index bd0d9e5c81..685455d4a9 100644 --- a/openair-cn/S1AP/s1ap_common.h +++ b/openair-cn/S1AP/s1ap_common.h @@ -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 diff --git a/openair-cn/S1AP/s1ap_eNB.c b/openair-cn/S1AP/s1ap_eNB.c index 68598cf3e0..51d9b95cb7 100644 --- a/openair-cn/S1AP/s1ap_eNB.c +++ b/openair-cn/S1AP/s1ap_eNB.c @@ -28,6 +28,7 @@ *******************************************************************************/ +#include #include #include #include @@ -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; -} diff --git a/openair-cn/S1AP/s1ap_eNB.h b/openair-cn/S1AP/s1ap_eNB.h index b46b2bf22b..5d57251885 100644 --- a/openair-cn/S1AP/s1ap_eNB.h +++ b/openair-cn/S1AP/s1ap_eNB.h @@ -31,101 +31,18 @@ #include #include -#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_ */ + +/** + * @} + */ diff --git a/openair-cn/S1AP/s1ap_eNB_decoder.c b/openair-cn/S1AP/s1ap_eNB_decoder.c index 072a98febf..4509839d6a 100644 --- a/openair-cn/S1AP/s1ap_eNB_decoder.c +++ b/openair-cn/S1AP/s1ap_eNB_decoder.c @@ -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; diff --git a/openair-cn/S1AP/s1ap_eNB_decoder.h b/openair-cn/S1AP/s1ap_eNB_decoder.h index 37745f79ab..8ccdef46f5 100644 --- a/openair-cn/S1AP/s1ap_eNB_decoder.h +++ b/openair-cn/S1AP/s1ap_eNB_decoder.h @@ -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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_default_values.h b/openair-cn/S1AP/s1ap_eNB_default_values.h new file mode 100644 index 0000000000..f1b38a73c8 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_default_values.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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_defs.h b/openair-cn/S1AP/s1ap_eNB_defs.h index 1e6c38155b..67c75b641a 100644 --- a/openair-cn/S1AP/s1ap_eNB_defs.h +++ b/openair-cn/S1AP/s1ap_eNB_defs.h @@ -82,12 +82,12 @@ typedef enum { S1AP_OVERLOAD_MAX, } s1ap_overload_state_t; -typedef enum { - PAGING_DRX_32 = 0x0, - PAGING_DRX_64 = 0x1, - PAGING_DRX_128 = 0x2, - PAGING_DRX_256 = 0x3, -} paging_drx_t; +// typedef enum { +// PAGING_DRX_32 = 0x0, +// PAGING_DRX_64 = 0x1, +// PAGING_DRX_128 = 0x2, +// PAGING_DRX_256 = 0x3, +// } paging_drx_t; typedef struct { /* Octet string data */ @@ -176,161 +176,156 @@ typedef struct { } identity; } ue_identity_t; -typedef struct { - /* The NAS First Req is the first message exchanged between RRC and S1AP - * for an UE. - * The rnti uniquely identifies an UE within a cell. Later the enb_ue_s1ap_id - * will be the unique identifier used between RRC and S1AP. - */ - 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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_handlers.c b/openair-cn/S1AP/s1ap_eNB_handlers.c index fe3891f2bd..8cbe2fa386 100644 --- a/openair-cn/S1AP/s1ap_eNB_handlers.c +++ b/openair-cn/S1AP/s1ap_eNB_handlers.c @@ -37,9 +37,12 @@ #include +#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; } diff --git a/openair-cn/S1AP/s1ap_eNB_handlers.h b/openair-cn/S1AP/s1ap_eNB_handlers.h index cc95cb7536..0ae1cb2fcb 100644 --- a/openair-cn/S1AP/s1ap_eNB_handlers.h +++ b/openair-cn/S1AP/s1ap_eNB_handlers.h @@ -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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_itti_messaging.c b/openair-cn/S1AP/s1ap_eNB_itti_messaging.c new file mode 100644 index 0000000000..b9be86165e --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_itti_messaging.c @@ -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); +} diff --git a/openair-cn/S1AP/s1ap_eNB_itti_messaging.h b/openair-cn/S1AP/s1ap_eNB_itti_messaging.h new file mode 100644 index 0000000000..c111eb5076 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_itti_messaging.h @@ -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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_management_procedures.c b/openair-cn/S1AP/s1ap_eNB_management_procedures.c index c4e637f6f3..44e23eed13 100644 --- a/openair-cn/S1AP/s1ap_eNB_management_procedures.c +++ b/openair-cn/S1AP/s1ap_eNB_management_procedures.c @@ -32,7 +32,10 @@ #include #include -#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; +// } diff --git a/openair-cn/S1AP/s1ap_eNB_management_procedures.h b/openair-cn/S1AP/s1ap_eNB_management_procedures.h index 3c550312ba..93c19257e2 100644 --- a/openair-cn/S1AP/s1ap_eNB_management_procedures.h +++ b/openair-cn/S1AP/s1ap_eNB_management_procedures.h @@ -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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_nas_procedures.c b/openair-cn/S1AP/s1ap_eNB_nas_procedures.c index 6ea899e391..6c5322ef6f 100644 --- a/openair-cn/S1AP/s1ap_eNB_nas_procedures.c +++ b/openair-cn/S1AP/s1ap_eNB_nas_procedures.c @@ -32,229 +32,230 @@ #include #include -#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; +// } diff --git a/openair-cn/S1AP/s1ap_eNB_nas_procedures.h b/openair-cn/S1AP/s1ap_eNB_nas_procedures.h index 4e0eb0001c..50828b8aed 100644 --- a/openair-cn/S1AP/s1ap_eNB_nas_procedures.h +++ b/openair-cn/S1AP/s1ap_eNB_nas_procedures.h @@ -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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_nnsf.c b/openair-cn/S1AP/s1ap_eNB_nnsf.c index 0dd02092fc..f9a0cffa99 100644 --- a/openair-cn/S1AP/s1ap_eNB_nnsf.c +++ b/openair-cn/S1AP/s1ap_eNB_nnsf.c @@ -38,13 +38,15 @@ #include #include -#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) { diff --git a/openair-cn/S1AP/s1ap_eNB_nnsf.h b/openair-cn/S1AP/s1ap_eNB_nnsf.h index 30169f8b61..f24e7be7c4 100644 --- a/openair-cn/S1AP/s1ap_eNB_nnsf.h +++ b/openair-cn/S1AP/s1ap_eNB_nnsf.h @@ -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); diff --git a/openair-cn/S1AP/s1ap_eNB_overload.c b/openair-cn/S1AP/s1ap_eNB_overload.c index ccca7c920e..1e85763ab0 100644 --- a/openair-cn/S1AP/s1ap_eNB_overload.c +++ b/openair-cn/S1AP/s1ap_eNB_overload.c @@ -39,6 +39,8 @@ #include #include +#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; } diff --git a/openair-cn/S1AP/s1ap_eNB_overload.h b/openair-cn/S1AP/s1ap_eNB_overload.h index 5e836879dc..af766d51b8 100644 --- a/openair-cn/S1AP/s1ap_eNB_overload.h +++ b/openair-cn/S1AP/s1ap_eNB_overload.h @@ -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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_trace.c b/openair-cn/S1AP/s1ap_eNB_trace.c index b99cc257fa..90ff42a294 100644 --- a/openair-cn/S1AP/s1ap_eNB_trace.c +++ b/openair-cn/S1AP/s1ap_eNB_trace.c @@ -28,6 +28,12 @@ *******************************************************************************/ +#include + +#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; diff --git a/openair-cn/S1AP/s1ap_eNB_trace.h b/openair-cn/S1AP/s1ap_eNB_trace.h index 6b1f4ed105..7d7d49781b 100644 --- a/openair-cn/S1AP/s1ap_eNB_trace.h +++ b/openair-cn/S1AP/s1ap_eNB_trace.h @@ -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_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_ue_context.c b/openair-cn/S1AP/s1ap_eNB_ue_context.c index 3c1c45891e..1b2d3d9aee 100644 --- a/openair-cn/S1AP/s1ap_eNB_ue_context.c +++ b/openair-cn/S1AP/s1ap_eNB_ue_context.c @@ -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) diff --git a/openair-cn/S1AP/s1ap_eNB_ue_context.h b/openair-cn/S1AP/s1ap_eNB_ue_context.h index 621f1fc991..26ceff968b 100644 --- a/openair-cn/S1AP/s1ap_eNB_ue_context.h +++ b/openair-cn/S1AP/s1ap_eNB_ue_context.h @@ -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_ */ diff --git a/openair-cn/SCTP/Makefile.eNB b/openair-cn/SCTP/Makefile.eNB index 0f40c2b8bb..dd665ddf5b 100644 --- a/openair-cn/SCTP/Makefile.eNB +++ b/openair-cn/SCTP/Makefile.eNB @@ -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 \ No newline at end of file + @$(RM_F_V) $(libsctp_OBJECTS) + @$(RM_F_V) *.d + @$(RM_F_V) libsctp.a \ No newline at end of file diff --git a/openair-cn/SCTP/sctp_common.c b/openair-cn/SCTP/sctp_common.c index c2d8656884..26b2dd281e 100644 --- a/openair-cn/SCTP/sctp_common.c +++ b/openair-cn/SCTP/sctp_common.c @@ -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; } diff --git a/openair-cn/SCTP/sctp_common.h b/openair-cn/SCTP/sctp_common.h index af861d4c90..a9e2494a21 100644 --- a/openair-cn/SCTP/sctp_common.h +++ b/openair-cn/SCTP/sctp_common.h @@ -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); diff --git a/openair-cn/SCTP/sctp_eNB_itti_messaging.c b/openair-cn/SCTP/sctp_eNB_itti_messaging.c new file mode 100644 index 0000000000..e8371987c2 --- /dev/null +++ b/openair-cn/SCTP/sctp_eNB_itti_messaging.c @@ -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); +} diff --git a/openair-cn/SCTP/sctp_eNB_itti_messaging.h b/openair-cn/SCTP/sctp_eNB_itti_messaging.h new file mode 100644 index 0000000000..b077d8ac8f --- /dev/null +++ b/openair-cn/SCTP/sctp_eNB_itti_messaging.h @@ -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_ */ diff --git a/openair-cn/SCTP/sctp_eNB_task.c b/openair-cn/SCTP/sctp_eNB_task.c new file mode 100644 index 0000000000..00792d3d3a --- /dev/null +++ b/openair-cn/SCTP/sctp_eNB_task.c @@ -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 +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#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; +} diff --git a/openair-cn/SCTP/sctp_eNB_task.h b/openair-cn/SCTP/sctp_eNB_task.h new file mode 100644 index 0000000000..6b03a3773b --- /dev/null +++ b/openair-cn/SCTP/sctp_eNB_task.h @@ -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_ */ diff --git a/openair2/COMMON/messages_def.h b/openair2/COMMON/messages_def.h index a3871916fc..7df0cdfc10 100644 --- a/openair2/COMMON/messages_def.h +++ b/openair2/COMMON/messages_def.h @@ -4,3 +4,5 @@ // Messages files used between tasks #include "rrc_messages_def.h" +#include "s1ap_messages_def.h" +#include "sctp_messages_def.h" \ No newline at end of file diff --git a/openair2/COMMON/messages_types.h b/openair2/COMMON/messages_types.h index 102915f253..0b1f67bb8e 100644 --- a/openair2/COMMON/messages_types.h +++ b/openair2/COMMON/messages_types.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_ */ diff --git a/openair2/COMMON/s1ap_messages_def.h b/openair2/COMMON/s1ap_messages_def.h new file mode 100644 index 0000000000..3a0cde80a9 --- /dev/null +++ b/openair2/COMMON/s1ap_messages_def.h @@ -0,0 +1 @@ +MESSAGE_DEF(S1AP_REGISTER_ENB, MESSAGE_PRIORITY_MED, s1ap_register_eNB_t, s1ap_register_eNB) diff --git a/openair2/COMMON/s1ap_messages_types.h b/openair2/COMMON/s1ap_messages_types.h new file mode 100644 index 0000000000..55c7b26c87 --- /dev/null +++ b/openair2/COMMON/s1ap_messages_types.h @@ -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_ */ diff --git a/openair2/COMMON/sctp_messages_def.h b/openair2/COMMON/sctp_messages_def.h new file mode 100644 index 0000000000..c009e39638 --- /dev/null +++ b/openair2/COMMON/sctp_messages_def.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) \ No newline at end of file diff --git a/openair2/COMMON/sctp_messages_types.h b/openair2/COMMON/sctp_messages_types.h new file mode 100644 index 0000000000..e07f530164 --- /dev/null +++ b/openair2/COMMON/sctp_messages_types.h @@ -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_ */ diff --git a/openair2/COMMON/tasks_def.h b/openair2/COMMON/tasks_def.h index dd05551958..8d96472653 100644 --- a/openair2/COMMON/tasks_def.h +++ b/openair2/COMMON/tasks_def.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) diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 7c198e77c3..d3d84efe69 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -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. diff --git a/openair2/UTIL/Makefile.inc b/openair2/UTIL/Makefile.inc index 75ec78cf43..1f8274f5d6 100644 --- a/openair2/UTIL/Makefile.inc +++ b/openair2/UTIL/Makefile.inc @@ -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) diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index 2607b8c1d2..f985c4bfa1 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -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 diff --git a/targets/SIMU/USER/Makerules b/targets/SIMU/USER/Makerules new file mode 100644 index 0000000000..59644a637e --- /dev/null +++ b/targets/SIMU/USER/Makerules @@ -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) diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 391517e060..004f9e98d1 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -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");