From 0ef04198b5ba02ced02ec9fe48d04b97e7e101a0 Mon Sep 17 00:00:00 2001 From: winckel <winckel@eurecom.fr> Date: Wed, 4 Dec 2013 08:32:21 +0000 Subject: [PATCH] Added a mechanism to wait for eNB MME link to be establish for all eNB before starting L2L1 task. git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4577 818b1a75-f10b-46b9-bf7c-635c3b92a50f --- openair-cn/S1AP/s1ap_eNB.c | 78 +++++---- openair-cn/S1AP/s1ap_eNB_defs.h | 6 + openair-cn/S1AP/s1ap_eNB_handlers.c | 33 ++++ openair-cn/S1AP/s1ap_eNB_handlers.h | 2 + openair-cn/SCTP/sctp_eNB_task.c | 4 +- openair2/COMMON/s1ap_messages_def.h | 7 +- openair2/COMMON/s1ap_messages_types.h | 174 ++++++++++--------- targets/SIMU/USER/oaisim.c | 231 ++++++++++++++++++-------- targets/SIMU/USER/oaisim.h | 2 +- 9 files changed, 351 insertions(+), 186 deletions(-) diff --git a/openair-cn/S1AP/s1ap_eNB.c b/openair-cn/S1AP/s1ap_eNB.c index 2e18f7ccbd..6a74c6e24d 100644 --- a/openair-cn/S1AP/s1ap_eNB.c +++ b/openair-cn/S1AP/s1ap_eNB.c @@ -66,7 +66,7 @@ static int s1ap_eNB_generate_s1_setup_request( s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p); static -void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_eNB_t *s1ap_register_eNB); +void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB); static void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp); @@ -126,47 +126,56 @@ static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p, * but not yet associated. */ RB_INSERT(s1ap_mme_map, &instance_p->s1ap_mme_head, s1ap_mme_data_p); + s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING; + instance_p->s1ap_mme_nb ++; + instance_p->s1ap_mme_pending_nb ++; itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p); } static -void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_eNB_t *s1ap_register_eNB) +void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB) { s1ap_eNB_instance_t *new_instance; uint8_t index; DevAssert(s1ap_register_eNB != NULL); - /* Look if the provided instance already exists - * If so notify user... - */ + /* Look if the provided instance already exists */ new_instance = s1ap_eNB_get_instance(instance); - 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->instance = instance; - 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; - - /* Add the new instance to the list of eNB (meaningfull in virtual mode) */ - s1ap_eNB_insert_new_instance(new_instance); - - S1AP_DEBUG("Registered new eNB[%d] and %s eNB id %u\n", - instance, - s1ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home", - s1ap_register_eNB->eNB_id); + if (new_instance != NULL) { + /* Checks if it is a retry on the same eNB */ + DevCheck(new_instance->eNB_id == s1ap_register_eNB->eNB_id, new_instance->eNB_id, s1ap_register_eNB->eNB_id, 0); + DevCheck(new_instance->cell_type == s1ap_register_eNB->cell_type, new_instance->cell_type, s1ap_register_eNB->cell_type, 0); + DevCheck(new_instance->tac == s1ap_register_eNB->tac, new_instance->tac, s1ap_register_eNB->tac, 0); + DevCheck(new_instance->mcc == s1ap_register_eNB->mcc, new_instance->mcc, s1ap_register_eNB->mcc, 0); + DevCheck(new_instance->mnc == s1ap_register_eNB->mnc, new_instance->mnc, s1ap_register_eNB->mnc, 0); + DevCheck(new_instance->default_drx == s1ap_register_eNB->default_drx, new_instance->default_drx, s1ap_register_eNB->default_drx, 0); + } else { + 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->instance = instance; + 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; + + /* Add the new instance to the list of eNB (meaningfull in virtual mode) */ + s1ap_eNB_insert_new_instance(new_instance); + + S1AP_DEBUG("Registered new eNB[%d] and %s eNB id %u\n", + instance, + 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); @@ -198,6 +207,9 @@ void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_associa sctp_new_association_resp->sctp_state, instance, sctp_new_association_resp->ulp_cnx_id); + + s1ap_handle_s1_setup_message(s1ap_mme_data_p); + return; } @@ -238,14 +250,14 @@ void *s1ap_eNB_task(void *arg) case TERMINATE_MESSAGE: itti_exit_task(); break; - case S1AP_REGISTER_ENB: { + case S1AP_REGISTER_ENB_REQ: { /* 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(ITTI_MESSAGE_GET_INSTANCE(received_msg), - &received_msg->ittiMsg.s1ap_register_eNB); + &S1AP_REGISTER_ENB_REQ(received_msg)); } break; case SCTP_NEW_ASSOCIATION_RESP: { s1ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg), @@ -318,6 +330,8 @@ static int s1ap_eNB_generate_s1_setup_request( MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, &s1SetupRequest_p->global_ENB_ID.pLMNidentity); + S1AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[0], s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[1], s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[2]); + INT16_TO_OCTET_STRING(instance_p->tac, &ta.tAC); MCC_MNC_TO_TBCD(instance_p->mcc, instance_p->mnc, &plmnIdentity); diff --git a/openair-cn/S1AP/s1ap_eNB_defs.h b/openair-cn/S1AP/s1ap_eNB_defs.h index 8c2f2530b8..1a1609d0ce 100644 --- a/openair-cn/S1AP/s1ap_eNB_defs.h +++ b/openair-cn/S1AP/s1ap_eNB_defs.h @@ -172,6 +172,12 @@ typedef struct s1ap_eNB_instance_s { */ STAILQ_ENTRY(s1ap_eNB_instance_s) s1ap_eNB_entries; + /* Number of MME requested by eNB (tree size) */ + uint32_t s1ap_mme_nb; + /* Number of MME for which association is pending */ + uint32_t s1ap_mme_pending_nb; + /* Number of MME successfully associated to eNB */ + uint32_t s1ap_mme_associated_nb; /* Tree of S1AP MME associations ordered by association ID */ RB_HEAD(s1ap_mme_map, s1ap_eNB_mme_data_s) s1ap_mme_head; diff --git a/openair-cn/S1AP/s1ap_eNB_handlers.c b/openair-cn/S1AP/s1ap_eNB_handlers.c index 52bbbf807b..c24cb96cc5 100644 --- a/openair-cn/S1AP/s1ap_eNB_handlers.c +++ b/openair-cn/S1AP/s1ap_eNB_handlers.c @@ -55,6 +55,7 @@ #include "s1ap_eNB_default_values.h" +#include "assertions.h" #include "conversions.h" static @@ -132,6 +133,24 @@ static const char *direction2String[] = { "UnSuccessfull outcome", /* successfull outcome */ }; +void s1ap_handle_s1_setup_message(s1ap_eNB_mme_data_t *mme_desc_p) { + /* Check that at least one setup message is pending */ + DevCheck(mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb > 0, mme_desc_p->s1ap_eNB_instance->instance, + mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb, 0); + /* Decrease pending messages number */ + mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb --; + + /* If there are no more pending messages, inform eNB app */ + if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb == 0) + { + MessageDef *message_p; + + message_p = itti_alloc_new_message(TASK_S1AP, S1AP_REGISTER_ENB_CNF); + S1AP_REGISTER_ENB_CNF(message_p).nb_mme = mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb; + itti_send_msg_to_task(TASK_ENB_APP, mme_desc_p->s1ap_eNB_instance->instance, message_p); + } +} + int s1ap_eNB_handle_message(uint32_t assoc_id, int32_t stream, const uint8_t * const data, const uint32_t data_length) { @@ -173,13 +192,25 @@ int s1ap_eNB_handle_s1_setup_failure(uint32_t assoc_id, uint32_t stream, struct s1ap_message_s *message_p) { + s1ap_eNB_mme_data_t *mme_desc_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); } + + 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", assoc_id); + return -1; + } + S1AP_ERROR("Received s1 setup failure for MME... please check your parameters\n"); + mme_desc_p->state = S1AP_ENB_STATE_WAITING; + s1ap_handle_s1_setup_message(mme_desc_p); + return 0; } @@ -278,6 +309,8 @@ int s1ap_eNB_handle_s1_setup_response(uint32_t assoc_id, * Mark the association as UP to enable UE contexts creation. */ mme_desc_p->state = S1AP_ENB_STATE_CONNECTED; + mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb ++; + s1ap_handle_s1_setup_message(mme_desc_p); #if 0 /* We call back our self diff --git a/openair-cn/S1AP/s1ap_eNB_handlers.h b/openair-cn/S1AP/s1ap_eNB_handlers.h index 0ae1cb2fcb..c708517b73 100644 --- a/openair-cn/S1AP/s1ap_eNB_handlers.h +++ b/openair-cn/S1AP/s1ap_eNB_handlers.h @@ -31,6 +31,8 @@ #ifndef S1AP_ENB_HANDLERS_H_ #define S1AP_ENB_HANDLERS_H_ +void s1ap_handle_s1_setup_message(s1ap_eNB_mme_data_t *mme_desc_p); + int s1ap_eNB_handle_message(uint32_t assoc_id, int32_t stream, const uint8_t * const data, const uint32_t data_length); diff --git a/openair-cn/SCTP/sctp_eNB_task.c b/openair-cn/SCTP/sctp_eNB_task.c index f7427a9dfa..cc1d8dd950 100644 --- a/openair-cn/SCTP/sctp_eNB_task.c +++ b/openair-cn/SCTP/sctp_eNB_task.c @@ -237,7 +237,7 @@ void sctp_handle_new_association_req( close(sd); return; } else { - SCTP_DEBUG("connectx in progress...\n"); + SCTP_DEBUG("connectx %d in progress...\n", assoc_id); } } } else { @@ -270,6 +270,7 @@ void sctp_handle_new_association_req( sctp_cnx->cnx_id = sctp_new_association_req_p->ulp_cnx_id; sctp_cnx->ppid = sctp_new_association_req_p->ppid; sctp_cnx->instance = instance; + sctp_cnx->assoc_id = assoc_id; /* Insert new element at end of list */ STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries); @@ -412,6 +413,7 @@ inline void sctp_eNB_read_from_socket(struct sctp_cnx_list_elm_s *sctp_cnx) sctp_cnx->cnx_id, SCTP_STATE_UNREACHABLE, 0, 0); close(sctp_cnx->sd); + STAILQ_REMOVE(&sctp_cnx_list, sctp_cnx, sctp_cnx_list_elm_s, entries); sctp_nb_cnx--; free(sctp_cnx); } else { diff --git a/openair2/COMMON/s1ap_messages_def.h b/openair2/COMMON/s1ap_messages_def.h index 019dc21066..3e41dae2a9 100644 --- a/openair2/COMMON/s1ap_messages_def.h +++ b/openair2/COMMON/s1ap_messages_def.h @@ -1,9 +1,12 @@ /* eNB application layer -> S1AP messages */ -MESSAGE_DEF(S1AP_REGISTER_ENB , MESSAGE_PRIORITY_MED, s1ap_register_eNB_t , s1ap_register_eNB ) +MESSAGE_DEF(S1AP_REGISTER_ENB_REQ , MESSAGE_PRIORITY_MED, s1ap_register_enb_req_t , s1ap_register_enb_req) + +/* S1AP -> eNB application layer messages */ +MESSAGE_DEF(S1AP_REGISTER_ENB_CNF , MESSAGE_PRIORITY_MED, s1ap_register_enb_cnf_t , s1ap_register_enb_cnf) /* RRC -> S1AP messages */ MESSAGE_DEF(S1AP_NAS_FIRST_REQ , MESSAGE_PRIORITY_MED, s1ap_nas_first_req_t , s1ap_nas_first_req) -MESSAGE_DEF(S1AP_UPLINK_NAS , MESSAGE_PRIORITY_MED, s1ap_uplink_nas_t , s1ap_uplink_nas ) +MESSAGE_DEF(S1AP_UPLINK_NAS , MESSAGE_PRIORITY_MED, s1ap_uplink_nas_t , s1ap_uplink_nas) MESSAGE_DEF(S1AP_UE_CAPABILITIES_IND , MESSAGE_PRIORITY_MED, s1ap_ue_cap_info_ind_t , s1ap_ue_cap_info_ind) MESSAGE_DEF(S1AP_INITIAL_CONTEXT_SETUP_RESP, MESSAGE_PRIORITY_MED, s1ap_initial_context_setup_resp_t, s1ap_initial_context_setup_resp) MESSAGE_DEF(S1AP_INITIAL_CONTEXT_SETUP_FAIL, MESSAGE_PRIORITY_MED, s1ap_initial_context_setup_fail_t, s1ap_initial_context_setup_fail) diff --git a/openair2/COMMON/s1ap_messages_types.h b/openair2/COMMON/s1ap_messages_types.h index 223b69a7bb..898f5989ef 100644 --- a/openair2/COMMON/s1ap_messages_types.h +++ b/openair2/COMMON/s1ap_messages_types.h @@ -4,6 +4,10 @@ //-------------------------------------------------------------------------------------------// // Defines to access message fields. +#define S1AP_REGISTER_ENB_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_register_enb_req + +#define S1AP_REGISTER_ENB_CNF(mSGpTR) (mSGpTR)->ittiMsg.s1ap_register_enb_cnf + #define S1AP_NAS_FIRST_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_nas_first_req #define S1AP_UPLINK_NAS(mSGpTR) (mSGpTR)->ittiMsg.s1ap_uplink_nas #define S1AP_UE_CAPABILITIES_IND(mSGpTR) (mSGpTR)->ittiMsg.s1ap_ue_cap_info_ind @@ -22,6 +26,24 @@ #define S1AP_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_ue_release_req //-------------------------------------------------------------------------------------------// +/* Maximum number of e-rabs to be setup/deleted in a single message. + * Even if only one bearer will be modified by message. + */ +#define S1AP_MAX_E_RAB 11 + +/* Length of the transport layer address string + * 160 bits / 8 bits by char. + */ +#define S1AP_TRANSPORT_LAYER_ADDRESS_SIZE (160 / 8) + +#define S1AP_MAX_NB_MME_IP_ADDRESS 10 +#define S1AP_IMSI_LENGTH 16 + +/* Security key length used within eNB + * Even if only 16 bytes will be effectively used, + * the key length is 32 bytes (256 bits) + */ +#define SECURITY_KEY_LENGTH 32 typedef enum cell_type_e { CELL_MACRO_ENB, @@ -63,7 +85,7 @@ typedef struct net_ip_address_s { typedef uint64_t bitrate_t; -typedef struct { +typedef struct ambr_s { bitrate_t br_ul; bitrate_t br_dl; } ambr_t; @@ -75,19 +97,19 @@ typedef enum priority_level_s { PRIORITY_LEVEL_NO_PRIORITY = 15 } priority_level_t; -typedef enum { +typedef enum pre_emp_capability_e { PRE_EMPTION_CAPABILITY_ENABLED = 0, PRE_EMPTION_CAPABILITY_DISABLED = 1, PRE_EMPTION_CAPABILITY_MAX, } pre_emp_capability_t; -typedef enum { +typedef enum pre_emp_vulnerability_e { PRE_EMPTION_VULNERABILITY_ENABLED = 0, PRE_EMPTION_VULNERABILITY_DISABLED = 1, PRE_EMPTION_VULNERABILITY_MAX, } pre_emp_vulnerability_t; -typedef struct { +typedef struct allocation_retention_priority_s { priority_level_t priority_level; pre_emp_capability_t pre_emp_capability; pre_emp_vulnerability_t pre_emp_vulnerability; @@ -98,25 +120,6 @@ typedef struct security_capabilities_s { uint16_t integrity_algorithms; } security_capabilities_t; -/* Maximum number of e-rabs to be setup/deleted in a single message. - * Even if only one bearer will be modified by message. - */ -#define S1AP_MAX_E_RAB 11 - -/* Length of the transport layer address string - * 160 bits / 8 bits by char. - */ -#define S1AP_TRANSPORT_LAYER_ADDRESS_SIZE (160 / 8) - -#define S1AP_MAX_NB_MME_IP_ADDRESS 10 -#define S1AP_IMSI_LENGTH 16 - -/* Security key length used within eNB - * Even if only 16 bytes will be effectively used, - * the key length is 32 bytes (256 bits) - */ -#define SECURITY_KEY_LENGTH 32 - /* Provides the establishment cause for the RRC connection request as provided * by the upper layers. W.r.t. the cause value names: highPriorityAccess * concerns AC11..AC15, ‘mt’ stands for ‘Mobile Terminating’ and ‘mo’ for @@ -226,7 +229,20 @@ typedef struct e_rab_failed_s { // cause_t cause; } e_rab_failed_t; -typedef struct s1ap_register_eNB_s { +typedef enum s1ap_ue_ctxt_modification_present_s { + S1AP_UE_CONTEXT_MODIFICATION_SECURITY_KEY = (1 << 0), + S1AP_UE_CONTEXT_MODIFICATION_UE_AMBR = (1 << 1), + S1AP_UE_CONTEXT_MODIFICATION_UE_SECU_CAP = (1 << 2), +} s1ap_ue_ctxt_modification_present_t; + +typedef enum s1ap_paging_ind_present_s { + S1AP_PAGING_IND_PAGING_DRX = (1 << 0), + S1AP_PAGING_IND_PAGING_PRIORITY = (1 << 1), +} s1ap_paging_ind_present_t; + +//-------------------------------------------------------------------------------------------// +// eNB application layer -> S1AP messages +typedef struct s1ap_register_enb_req_s { /* 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. @@ -260,7 +276,18 @@ typedef struct s1ap_register_eNB_s { 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; +} s1ap_register_enb_req_t; + +//-------------------------------------------------------------------------------------------// +// S1AP -> eNB application layer messages +typedef struct s1ap_register_enb_cnf_s { + /* Nb of MME connected */ + uint8_t nb_mme; + +} s1ap_register_enb_cnf_t; + +//-------------------------------------------------------------------------------------------// +// RRC -> S1AP messages /* The NAS First Req is the first message exchanged between RRC and S1AP * for an UE. @@ -291,38 +318,10 @@ typedef struct s1ap_uplink_nas_s { nas_pdu_t nas_pdu; } s1ap_uplink_nas_t; -typedef struct s1ap_downlink_nas_s { - /* UE id for initial connection to S1AP */ - uint16_t ue_initial_id; - - /* Unique UE identifier within an eNB */ - unsigned eNB_ue_s1ap_id:24; - - /* NAS pdu */ - nas_pdu_t nas_pdu; -} s1ap_downlink_nas_t; - -typedef struct s1ap_initial_context_setup_req_s { - /* UE id for initial connection to S1AP */ - uint16_t ue_initial_id; - - /* eNB ue s1ap id as initialized by S1AP layer */ - unsigned eNB_ue_s1ap_id:24; - - /* UE aggregate maximum bitrate */ - ambr_t ue_ambr; - - /* Security algorithms */ - security_capabilities_t security_capabilities; - - /* Security key */ - uint8_t security_key[SECURITY_KEY_LENGTH]; - - /* 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_MAX_E_RAB]; -} s1ap_initial_context_setup_req_t; +typedef struct s1ap_ue_cap_info_ind_s { + unsigned eNB_ue_s1ap_id:24; + ue_radio_cap_t ue_radio_cap; +} s1ap_ue_cap_info_ind_t; typedef struct s1ap_initial_context_setup_resp_s { unsigned eNB_ue_s1ap_id:24; @@ -344,21 +343,11 @@ typedef struct s1ap_initial_context_setup_fail_s { /* TODO add cause */ } s1ap_initial_context_setup_fail_t, s1ap_ue_ctxt_modification_fail_t; -typedef struct s1ap_ue_cap_info_ind_s { - unsigned eNB_ue_s1ap_id:24; - ue_radio_cap_t ue_radio_cap; -} s1ap_ue_cap_info_ind_t; - -typedef struct s1ap_ue_release_req_s { +typedef struct s1ap_nas_non_delivery_ind_s { unsigned eNB_ue_s1ap_id:24; + nas_pdu_t nas_pdu; /* TODO: add cause */ -} s1ap_ue_release_req_t, s1ap_ue_release_resp_t; - -typedef enum s1ap_ue_ctxt_modification_present_s { - S1AP_UE_CONTEXT_MODIFICATION_SECURITY_KEY = (1 << 0), - S1AP_UE_CONTEXT_MODIFICATION_UE_AMBR = (1 << 1), - S1AP_UE_CONTEXT_MODIFICATION_UE_SECU_CAP = (1 << 2), -} s1ap_ue_ctxt_modification_present_t; +} s1ap_nas_non_delivery_ind_t; typedef struct s1ap_ue_ctxt_modification_req_s { unsigned eNB_ue_s1ap_id:24; @@ -382,10 +371,40 @@ typedef struct s1ap_ue_ctxt_modification_resp_s { unsigned eNB_ue_s1ap_id:24; } s1ap_ue_ctxt_modification_resp_t; -typedef enum s1ap_paging_ind_present_s { - S1AP_PAGING_IND_PAGING_DRX = (1 << 0), - S1AP_PAGING_IND_PAGING_PRIORITY = (1 << 1), -} s1ap_paging_ind_present_t; +//-------------------------------------------------------------------------------------------// +// S1AP -> RRC messages +typedef struct s1ap_downlink_nas_s { + /* UE id for initial connection to S1AP */ + uint16_t ue_initial_id; + + /* Unique UE identifier within an eNB */ + unsigned eNB_ue_s1ap_id:24; + + /* NAS pdu */ + nas_pdu_t nas_pdu; +} s1ap_downlink_nas_t; + +typedef struct s1ap_initial_context_setup_req_s { + /* UE id for initial connection to S1AP */ + uint16_t ue_initial_id; + + /* eNB ue s1ap id as initialized by S1AP layer */ + unsigned eNB_ue_s1ap_id:24; + + /* UE aggregate maximum bitrate */ + ambr_t ue_ambr; + + /* Security algorithms */ + security_capabilities_t security_capabilities; + + /* Security key */ + uint8_t security_key[SECURITY_KEY_LENGTH]; + + /* 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_MAX_E_RAB]; +} s1ap_initial_context_setup_req_t; typedef struct s1ap_paging_ind_s { /* UE identity index value. @@ -405,10 +424,11 @@ typedef struct s1ap_paging_ind_s { paging_priority_t paging_priority; } s1ap_paging_ind_t; -typedef struct s1ap_nas_non_delivery_ind_s { +//-------------------------------------------------------------------------------------------// +// S1AP <-> RRC messages +typedef struct s1ap_ue_release_req_s { unsigned eNB_ue_s1ap_id:24; - nas_pdu_t nas_pdu; /* TODO: add cause */ -} s1ap_nas_non_delivery_ind_t; +} s1ap_ue_release_req_t, s1ap_ue_release_resp_t; #endif /* S1AP_MESSAGES_TYPES_H_ */ diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index a2b57c5e6f..07cb090b13 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -69,6 +69,7 @@ char smbv_ip[16]; #include "UTIL/LOG/vcd_signal_dumper.h" #include "UTIL/OTG/otg_kpi.h" +#include "assertions.h" #if defined(ENABLE_ITTI) # include "intertask_interface_init.h" @@ -372,9 +373,8 @@ static s32 UE_id = 0, eNB_id = 0; static s32 RN_id=0; #endif -int itti_create_task_successful(void){ - #if defined(ENABLE_ITTI) +int itti_create_task_successful(void){ # if defined(ENABLE_USE_MME) if (itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0) { LOG_E(EMU, "Create task failed"); @@ -388,103 +388,180 @@ int itti_create_task_successful(void){ } # endif - if (itti_create_task(TASK_ENB_APP, eNB_app_task, NULL) < 0) { + if (itti_create_task(TASK_L2L1, l2l1_task, NULL) < 0) { LOG_E(EMU, "Create task failed"); - LOG_D(EMU, "Initializing eNB APP task interface: FAILED\n"); + LOG_D(EMU, "Initializing L2L1 task interface: FAILED\n"); return -1; } - if (itti_create_task(TASK_L2L1, l2l1_task, NULL) < 0) { + /* Last task to create, others task must be ready before its start */ + if (itti_create_task(TASK_ENB_APP, eNB_app_task, NULL) < 0) { LOG_E(EMU, "Create task failed"); - LOG_D(EMU, "Initializing L2L1 task interface: FAILED\n"); + LOG_D(EMU, "Initializing eNB APP task interface: FAILED\n"); return -1; } - -#endif return 1; } +#endif +#if defined(ENABLE_ITTI) /* - * later, the enb task will be moved from here + * later, the eNB task will be moved from here */ -void *eNB_app_task(void *args_p) { -#if defined(ENABLE_ITTI) - MessageDef *message_p; # if defined(ENABLE_USE_MME) - /* Trying to register each eNB */ + +#define ENB_REGISTER_RETRY_DELAY 10 + +uint32_t eNB_app_register() +{ + MessageDef *msg_p; + uint32_t register_enb_pending = 0; 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++) { - char *mme_address_v4; - - if (EPC_MODE_ENABLED){ - mme_address_v4 = EPC_MODE_MME_ADDRESS; - }else { - 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; - uint32_t hash; - - //note: there is an implicit relationship between the data struct and the message name - message_p = itti_alloc_new_message(TASK_ENB_APP, S1AP_REGISTER_ENB); - - s1ap_register_eNB = &message_p->ittiMsg.s1ap_register_eNB; - - hash = s1ap_generate_eNB_id(); - - /* Some default/random parameters */ - s1ap_register_eNB->eNB_id = eNB_id + (hash & 0xFFFF8); - s1ap_register_eNB->cell_type = CELL_MACRO_ENB; - s1ap_register_eNB->tac = 0; - s1ap_register_eNB->mcc = 208; - s1ap_register_eNB->mnc = 34; - 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, eNB_id, message_p); + (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++) { + char *mme_address_v4; + + if (EPC_MODE_ENABLED){ + mme_address_v4 = EPC_MODE_MME_ADDRESS; + } else { + mme_address_v4 = "192.168.12.87"; } + char *mme_address_v6 = "2001:660:5502:12:30da:829a:2343:b6cf"; + s1ap_register_enb_req_t *s1ap_register_eNB; + uint32_t hash; + + //note: there is an implicit relationship between the data struct and the message name + msg_p = itti_alloc_new_message(TASK_ENB_APP, S1AP_REGISTER_ENB_REQ); + + s1ap_register_eNB = &S1AP_REGISTER_ENB_REQ(msg_p); + + hash = s1ap_generate_eNB_id(); + + /* Some default/random parameters */ + s1ap_register_eNB->eNB_id = eNB_id + (hash & 0xFFFF8); + s1ap_register_eNB->cell_type = CELL_MACRO_ENB; + s1ap_register_eNB->tac = 0; + s1ap_register_eNB->mcc = 208; + s1ap_register_eNB->mnc = 34; + 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)); + +# if defined ENB_APP_ENB_REGISTER_2_MME + s1ap_register_eNB->nb_mme = 2; + s1ap_register_eNB->mme_ip_address[1].ipv4 = 1; + s1ap_register_eNB->mme_ip_address[1].ipv6 = 0; + mme_address_v4 = "192.168.12.88"; + memcpy(s1ap_register_eNB->mme_ip_address[1].ipv4_address, mme_address_v4, strlen(mme_address_v4)); + memcpy(s1ap_register_eNB->mme_ip_address[1].ipv6_address, mme_address_v6, strlen(mme_address_v6)); +# endif + + itti_send_msg_to_task(TASK_S1AP, eNB_id, msg_p); + + register_enb_pending ++; + } + + return register_enb_pending; +} # endif +#endif - itti_mark_task_ready (TASK_ENB_APP); // at the end of init for the current task +void *eNB_app_task(void *args_p) { +#if defined(ENABLE_ITTI) +# if defined(ENABLE_USE_MME) + static uint32_t register_enb_pending; + static uint32_t registered_enb; + static long enb_register_retry_timer_id; +# endif + MessageDef *msg_p; + const char *msg_name; + instance_t instance; + itti_mark_task_ready (TASK_ENB_APP); + +# if defined(ENABLE_USE_MME) + /* Try to register each eNB */ + registered_enb = 0; + register_enb_pending = eNB_app_register(); +# else + msg_p = itti_alloc_new_message(TASK_ENB_APP, INITIALIZE_MESSAGE); + itti_send_msg_to_task(TASK_L2L1, INSTANCE_DEFAULT, msg_p); +# endif do { - // Checks if a message has been sent to L2L1 task - itti_receive_msg (TASK_ENB_APP, &message_p); + // Wait for a message + itti_receive_msg (TASK_ENB_APP, &msg_p); - if (message_p != NULL) { - switch (ITTI_MSG_ID(message_p)) { + msg_name = ITTI_MSG_NAME (msg_p); + instance = ITTI_MSG_INSTANCE (msg_p); + + switch (ITTI_MSG_ID(msg_p)) { case TERMINATE_MESSAGE: - itti_exit_task (); - break; - + itti_exit_task (); + break; + case MESSAGE_TEST: - LOG_D(EMU, "Received %s\n", ITTI_MSG_NAME(message_p)); - break; - - /* case MME_REGISTERED: - LOG_D(EMU, "Received %s\n", ITTI_MSG_NAME(message_p)); - itti_mark_task_ready (TASK_L2L1); - break; - */ + LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(msg_p)); + break; + +# if defined(ENABLE_USE_MME) + case S1AP_REGISTER_ENB_CNF: + LOG_I(EMU, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name, S1AP_REGISTER_ENB_CNF(msg_p).nb_mme); + + DevAssert(register_enb_pending > 0); + register_enb_pending--; + + /* Check if at least eNB is registered with one MME */ + if (S1AP_REGISTER_ENB_CNF(msg_p).nb_mme > 0) { + registered_enb ++; + } + + /* Check if all register eNB requests have been processed */ + if (register_enb_pending == 0) { + if (registered_enb == oai_emulation.info.nb_enb_local) { + /* If all eNB are registered, start L2L1 task */ + MessageDef *msg_init_p; + + msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE); + itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p); + } + else { + uint32_t not_associated = oai_emulation.info.nb_enb_local - registered_enb; + + LOG_W(EMU, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n", + not_associated, not_associated > 1 ? "are" : "is", ENB_REGISTER_RETRY_DELAY); + + /* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */ + if (timer_setup (ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL, &enb_register_retry_timer_id) < 0) { + LOG_E(EMU, " Can not start eNB register retry timer!\n"); + } + } + } + break; + + case TIMER_HAS_EXPIRED: + LOG_I(EMU, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id); + + if (TIMER_HAS_EXPIRED(msg_p).timer_id == enb_register_retry_timer_id) { + /* Restart the registration process */ + registered_enb = 0; + register_enb_pending = eNB_app_register(); + } + break; +# endif + default: - LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); - break; - } - - free (message_p); + LOG_E(EMU, "Received unexpected message %s\n", msg_name); + break; } - } while(1); - itti_terminate_tasks(TASK_ENB_APP); + free (msg_p); + } while(1); #endif return NULL; @@ -503,10 +580,18 @@ void *l2l1_task(void *args_p) { char fname[64], vname[64]; #if defined(ENABLE_ITTI) - MessageDef *message_p; + MessageDef *message_p = NULL; itti_mark_task_ready (TASK_L2L1); + /* Wait for the initialize message */ + do { + if (message_p != NULL) { + free (message_p); + } + itti_receive_msg (TASK_L2L1, &message_p); + } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE); + free (message_p); #endif for (frame = 0; frame < oai_emulation.info.n_frames; frame++) { diff --git a/targets/SIMU/USER/oaisim.h b/targets/SIMU/USER/oaisim.h index 2fe5cf8d90..71b56dc8b4 100644 --- a/targets/SIMU/USER/oaisim.h +++ b/targets/SIMU/USER/oaisim.h @@ -42,9 +42,9 @@ void calc_path_loss(node_desc_t* node_tx, node_desc_t* node_rx, channel_desc_t * void do_OFDM_mod(mod_sym_t **txdataF, s32 **txdata, uint32_t frame, u16 next_slot, LTE_DL_FRAME_PARMS *frame_parms); +void *eNB_app_task(void *args_p); #ifdef ENABLE_ITTI int itti_create_task_successful(void); -void *eNB_app_task(void *args_p); void *l2l1_task(void *args_p); #endif #ifdef OPENAIR2 -- GitLab