nr: improve x2/rrc for ENDC
This commit introduces several enhancements in X2AP and RRC to deal
with ENDC. The main goal is to deal with UE's on/off and with various
errors.
The following work is included:
- DC prep and DC overall X2 timers
- X2 messages for UE release and DC timers' timeout
Open problems:
- what to do when the UE sends an scg Failure? This commit removes
the UE. And this removal may not be correctly done
- UE removal in the gNB's PHY layer (a next commit is coming,
but it is hackish and will need a rework)
This commit is contained in:
+64
-38
@@ -305,7 +305,9 @@ void x2ap_eNB_handle_register_eNB(instance_t instance,
|
||||
x2ap_id_manager_init(&new_instance->id_manager);
|
||||
x2ap_timers_init(&new_instance->timers,
|
||||
x2ap_register_eNB->t_reloc_prep,
|
||||
x2ap_register_eNB->tx2_reloc_overall);
|
||||
x2ap_register_eNB->tx2_reloc_overall,
|
||||
x2ap_register_eNB->t_dc_prep,
|
||||
x2ap_register_eNB->t_dc_overall);
|
||||
|
||||
for (int i = 0; i< x2ap_register_eNB->num_cc; i++) {
|
||||
new_instance->eutra_band[i] = x2ap_register_eNB->eutra_band[i];
|
||||
@@ -476,7 +478,10 @@ void x2ap_eNB_handle_sgNB_add_req(instance_t instance,
|
||||
}
|
||||
/* id_source is ue_id, id_target is unknown yet */
|
||||
x2ap_set_ids(id_manager, ue_id, x2ap_ENDC_sgnb_addition_req->rnti, ue_id, -1);
|
||||
x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_NSA_PREPARE);
|
||||
x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_NSA_ENB_PREPARE);
|
||||
x2ap_set_dc_prep_timer(id_manager, ue_id,
|
||||
x2ap_timer_get_tti(&instance_p->timers));
|
||||
x2ap_id_set_target(id_manager, ue_id, x2ap_eNB_data);
|
||||
|
||||
x2ap_eNB_generate_ENDC_x2_SgNB_addition_request(instance_p, x2ap_ENDC_sgnb_addition_req,
|
||||
x2ap_eNB_data, ue_id);
|
||||
@@ -498,9 +503,6 @@ void x2ap_gNB_trigger_sgNB_add_req_ack(instance_t instance,
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *target;
|
||||
int ue_id;
|
||||
/*int source_assoc_id = x2ap_ENDC_sgnb_addition_req_ACK->source_assoc_id;
|
||||
int id_source;
|
||||
int id_target;*/
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
@@ -514,22 +516,15 @@ void x2ap_gNB_trigger_sgNB_add_req_ack(instance_t instance,
|
||||
X2AP_ERROR("could not allocate a new X2AP UE ID\n");
|
||||
exit(1);
|
||||
}
|
||||
/* id_source is ue_id, id_target is unknown yet */
|
||||
x2ap_set_ids(id_manager, ue_id, x2ap_ENDC_sgnb_addition_req_ACK->rnti, ue_id,
|
||||
x2ap_ENDC_sgnb_addition_req_ACK->MeNB_ue_x2_id);
|
||||
x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_SOURCE_OVERALL);
|
||||
|
||||
|
||||
/*target = x2ap_get_eNB(NULL, source_assoc_id, 0);
|
||||
DevAssert(target != NULL);*/
|
||||
|
||||
// rnti is a new information, save it
|
||||
|
||||
/*ue_id = x2ap_handover_req_ack->x2_id_target;
|
||||
id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
|
||||
id_target = ue_id;
|
||||
x2ap_set_ids(&instance_p->id_manager, ue_id, x2ap_handover_req_ack->rnti, id_source, id_target);*/
|
||||
|
||||
/* id_Source is MeNB_ue_x2_id, id_target is rnti (rnti is SgNB_ue_x2_id) */
|
||||
x2ap_set_ids(id_manager, ue_id,
|
||||
x2ap_ENDC_sgnb_addition_req_ACK->SgNB_ue_x2_id,
|
||||
x2ap_ENDC_sgnb_addition_req_ACK->MeNB_ue_x2_id,
|
||||
x2ap_ENDC_sgnb_addition_req_ACK->SgNB_ue_x2_id);
|
||||
x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_NSA_GNB_OVERALL);
|
||||
x2ap_set_dc_overall_timer(id_manager, ue_id,
|
||||
x2ap_timer_get_tti(&instance_p->timers));
|
||||
x2ap_id_set_target(id_manager, ue_id, target);
|
||||
|
||||
x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK(instance_p, target,
|
||||
x2ap_ENDC_sgnb_addition_req_ACK, ue_id);
|
||||
@@ -540,27 +535,24 @@ void x2ap_gNB_trigger_sgNB_add_req_ack(instance_t instance,
|
||||
* @param : IN instance, IN x2ap_reconf_complete
|
||||
**/
|
||||
static
|
||||
void x2ap_eNB_trigger_sgnb_reconfiguration_complete(instance_t instance,
|
||||
x2ap_ENDC_reconf_complete_t *x2ap_reconf_complete)
|
||||
void x2ap_eNB_trigger_sgnb_reconfiguration_complete(instance_t instance,
|
||||
x2ap_ENDC_reconf_complete_t *x2ap_reconf_complete)
|
||||
{
|
||||
x2ap_eNB_instance_t *instance_p = NULL;
|
||||
x2ap_eNB_data_t *target = NULL;
|
||||
int id_source = -1;
|
||||
int id_target = -1;
|
||||
LTE_PhysCellId_t target_pci;
|
||||
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *target;
|
||||
int id_source;
|
||||
int id_target;
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_reconf_complete != NULL);
|
||||
|
||||
target_pci = x2ap_reconf_complete->target_physCellId;
|
||||
target = x2ap_is_eNB_pci_in_list(target_pci);
|
||||
|
||||
target = x2ap_get_eNB(NULL,x2ap_reconf_complete->gnb_x2_assoc_id, 0);
|
||||
DevAssert(target != NULL);
|
||||
|
||||
|
||||
id_source = x2ap_reconf_complete->MeNB_ue_x2_id;
|
||||
id_target = x2ap_reconf_complete->SgNB_ue_x2_id;
|
||||
x2ap_eNB_generate_ENDC_x2_SgNB_reconfiguration_complete(instance_p, target, id_source, id_target);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -589,6 +581,34 @@ void x2ap_eNB_ue_context_release(instance_t instance,
|
||||
x2ap_release_id(&instance_p->id_manager, ue_id);
|
||||
}
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_sgNB_release_request(instance_t instance,
|
||||
x2ap_ENDC_sgnb_release_request_t *x2ap_release_req)
|
||||
{
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *target;
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_release_req != NULL);
|
||||
|
||||
if (x2ap_release_req->rnti == -1 ||
|
||||
x2ap_release_req->assoc_id == -1) {
|
||||
X2AP_WARN("x2ap_eNB_handle_sgNB_release_request: bad rnti or assoc_id, do not send release request to gNB\n");
|
||||
return;
|
||||
}
|
||||
|
||||
target = x2ap_get_eNB(NULL, x2ap_release_req->assoc_id, 0);
|
||||
DevAssert(target != NULL);
|
||||
|
||||
/* id_source is not used by oai's gNB so it's not big deal. For
|
||||
* interoperability with other gNBs things may need to be refined.
|
||||
*/
|
||||
x2ap_eNB_generate_ENDC_x2_SgNB_release_request(instance_p, target,
|
||||
0, x2ap_release_req->rnti,
|
||||
x2ap_release_req->cause);
|
||||
}
|
||||
|
||||
void *x2ap_task(void *arg) {
|
||||
MessageDef *received_msg = NULL;
|
||||
int result;
|
||||
@@ -640,10 +660,16 @@ void *x2ap_task(void *arg) {
|
||||
LOG_I(X2AP, "Received elements for X2AP_ENDC_SGNB_ADDITION_REQ_ACK \n");
|
||||
break;
|
||||
|
||||
case X2AP_ENDC_SGNB_RECONF_COMPLETE:
|
||||
x2ap_eNB_trigger_sgnb_reconfiguration_complete(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&X2AP_ENDC_SGNB_RECONF_COMPLETE(received_msg));
|
||||
break;
|
||||
case X2AP_ENDC_SGNB_RECONF_COMPLETE:
|
||||
x2ap_eNB_trigger_sgnb_reconfiguration_complete(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&X2AP_ENDC_SGNB_RECONF_COMPLETE(received_msg));
|
||||
break;
|
||||
|
||||
case X2AP_ENDC_SGNB_RELEASE_REQUEST:
|
||||
x2ap_eNB_handle_sgNB_release_request(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&X2AP_ENDC_SGNB_RELEASE_REQUEST(received_msg));
|
||||
break;
|
||||
|
||||
case SCTP_INIT_MSG_MULTI_CNF:
|
||||
x2ap_eNB_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&received_msg->ittiMsg.sctp_init_msg_multi_cnf);
|
||||
|
||||
@@ -69,6 +69,14 @@ static int x2ap_eNB_decode_initiating_message(X2AP_X2AP_PDU_t *pdu)
|
||||
X2AP_INFO("X2AP_ProcedureCode_id_sgNBReconfigurationCompletion message!\n");
|
||||
break;
|
||||
|
||||
case X2AP_ProcedureCode_id_meNBinitiatedSgNBRelease:
|
||||
X2AP_INFO("X2AP_ProcedureCode_id_meNBinitiatedSgNBRelease message!\n");
|
||||
break;
|
||||
|
||||
case X2AP_ProcedureCode_id_sgNBinitiatedSgNBRelease:
|
||||
X2AP_INFO("X2AP_ProcedureCode_id_sgNBinitiatedSgNBRelease message!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("Unknown procedure ID (%d) for initiating message\n",
|
||||
(int)pdu->choice.initiatingMessage.procedureCode);
|
||||
@@ -103,6 +111,10 @@ static int x2ap_eNB_decode_successful_outcome(X2AP_X2AP_PDU_t *pdu)
|
||||
X2AP_INFO("x2ap_eNB_decode_successfuloutcome_message!\n");
|
||||
break;
|
||||
|
||||
case X2AP_ProcedureCode_id_meNBinitiatedSgNBRelease:
|
||||
X2AP_INFO("meNBinitiatedSgNBRelease successful outcome!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n",
|
||||
(int)pdu->choice.successfulOutcome.procedureCode);
|
||||
|
||||
@@ -1668,8 +1668,6 @@ int x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK( x2ap_eNB_instance_t *in
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
int MeNB_UE_X2AP_id = x2ap_sgnb_addition_req_ACK->MeNB_ue_x2_id;
|
||||
int SgNB_UE_X2AP_id = ue_id;
|
||||
int e_rabs_admitted_tobeadded = x2ap_sgnb_addition_req_ACK->nb_e_rabs_admitted_tobeadded;
|
||||
long int pDCPatSgNB = X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present;
|
||||
long int mCGresources = X2AP_EN_DC_ResourceConfiguration__mCGresources_not_present;
|
||||
@@ -1694,7 +1692,7 @@ int x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK( x2ap_eNB_instance_t *in
|
||||
ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_SgNBAdditionRequestAcknowledge_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = MeNB_UE_X2AP_id; //x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
|
||||
ie->value.choice.UE_X2AP_ID = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
// SgNB_UE_X2AP_id
|
||||
@@ -1702,7 +1700,7 @@ int x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK( x2ap_eNB_instance_t *in
|
||||
ie->id = X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_SgNBAdditionRequestAcknowledge_IEs__value_PR_SgNB_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = SgNB_UE_X2AP_id; //x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
|
||||
ie->value.choice.UE_X2AP_ID = x2ap_id_get_id_target(&instance_p->id_manager, ue_id);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
ie = (X2AP_SgNBAdditionRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequestAcknowledge_IEs_t));
|
||||
@@ -1792,7 +1790,7 @@ int x2ap_eNB_generate_ENDC_x2_SgNB_reconfiguration_complete(
|
||||
ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_SgNBReconfigurationComplete_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = ue_id; //x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
|
||||
ie->value.choice.UE_X2AP_ID = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
ie = (X2AP_SgNBReconfigurationComplete_IEs_t *)calloc(1, sizeof(X2AP_SgNBReconfigurationComplete_IEs_t));
|
||||
@@ -1821,3 +1819,226 @@ int x2ap_eNB_generate_ENDC_x2_SgNB_reconfiguration_complete(
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_ENDC_x2_SgNB_release_request(
|
||||
x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int x2_id_source, int x2_id_target, x2ap_cause_t cause)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_SgNBReleaseRequest_t *out;
|
||||
X2AP_SgNBReleaseRequest_IEs_t *ie;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage.procedureCode = X2AP_ProcedureCode_id_meNBinitiatedSgNBRelease;
|
||||
pdu.choice.initiatingMessage.criticality = X2AP_Criticality_ignore;
|
||||
pdu.choice.initiatingMessage.value.present = X2AP_InitiatingMessage__value_PR_SgNBReleaseRequest;
|
||||
out = &pdu.choice.initiatingMessage.value.choice.SgNBReleaseRequest;
|
||||
|
||||
ie = (X2AP_SgNBReleaseRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_SgNBReleaseRequest_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = x2_id_source;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2_id_target != -1) {
|
||||
ie = (X2AP_SgNBReleaseRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_SgNBReleaseRequest_IEs__value_PR_SgNB_UE_X2AP_ID;
|
||||
ie->value.choice.SgNB_UE_X2AP_ID = x2_id_target;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
}
|
||||
|
||||
ie = (X2AP_SgNBReleaseRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Cause;
|
||||
ie->criticality= X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_SgNBReleaseRequest_IEs__value_PR_Cause;
|
||||
switch (cause) {
|
||||
case X2AP_CAUSE_T_DC_PREP_TIMEOUT:
|
||||
ie->value.choice.Cause.present = X2AP_Cause_PR_radioNetwork;
|
||||
ie->value.choice.Cause.choice.radioNetwork = X2AP_CauseRadioNetwork_tDCprep_expiry;
|
||||
break;
|
||||
case X2AP_CAUSE_RADIO_CONNECTION_WITH_UE_LOST:
|
||||
ie->value.choice.Cause.present = X2AP_Cause_PR_radioNetwork;
|
||||
ie->value.choice.Cause.choice.radioNetwork = X2AP_CauseRadioNetwork_radio_connection_with_UE_lost;
|
||||
break;
|
||||
default:
|
||||
X2AP_ERROR("%s: unhandled cause %d\n", __FUNCTION__, cause);
|
||||
exit(1);
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode ENDC X2 SgNB_release_request message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_gNB_generate_ENDC_x2_SgNB_release_request_acknowledge(
|
||||
x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int menb_ue_x2ap_id, int sgnb_ue_x2ap_id)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_SgNBReleaseRequestAcknowledge_t *out;
|
||||
X2AP_SgNBReleaseRequestAcknowledge_IEs_t *ie;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
x2ap_eNB_data_p->state = X2AP_ENB_STATE_WAITING;
|
||||
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome;
|
||||
pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_meNBinitiatedSgNBRelease;
|
||||
pdu.choice.successfulOutcome.criticality = X2AP_Criticality_ignore;
|
||||
pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_SgNBReleaseRequestAcknowledge;
|
||||
out = &pdu.choice.successfulOutcome.value.choice.SgNBReleaseRequestAcknowledge;
|
||||
|
||||
ie = (X2AP_SgNBReleaseRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseRequestAcknowledge_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_SgNBReleaseRequestAcknowledge_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = menb_ue_x2ap_id;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
ie = (X2AP_SgNBReleaseRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseRequestAcknowledge_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_SgNBReleaseRequestAcknowledge_IEs__value_PR_SgNB_UE_X2AP_ID;
|
||||
ie->value.choice.SgNB_UE_X2AP_ID = sgnb_ue_x2ap_id;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode ENDC X2 SgNB Release Request Acknowledge\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_ENDC_x2_SgNB_release_required(
|
||||
x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int x2_id_source, int x2_id_target, x2ap_cause_t cause)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_SgNBReleaseRequired_t *out;
|
||||
X2AP_SgNBReleaseRequired_IEs_t *ie;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
/* Prepare the X2AP message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage.procedureCode = X2AP_ProcedureCode_id_sgNBinitiatedSgNBRelease;
|
||||
pdu.choice.initiatingMessage.criticality = X2AP_Criticality_reject;
|
||||
pdu.choice.initiatingMessage.value.present = X2AP_InitiatingMessage__value_PR_SgNBReleaseRequired;
|
||||
out = &pdu.choice.initiatingMessage.value.choice.SgNBReleaseRequired;
|
||||
|
||||
ie = (X2AP_SgNBReleaseRequired_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseRequired_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_SgNBReleaseRequired_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = x2_id_source;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
ie = (X2AP_SgNBReleaseRequired_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseRequired_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_SgNBReleaseRequired_IEs__value_PR_SgNB_UE_X2AP_ID;
|
||||
ie->value.choice.SgNB_UE_X2AP_ID = x2_id_target;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
ie = (X2AP_SgNBReleaseRequired_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseRequired_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Cause;
|
||||
ie->criticality= X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_SgNBReleaseRequired_IEs__value_PR_Cause;
|
||||
switch (cause) {
|
||||
case X2AP_CAUSE_T_DC_OVERALL_TIMEOUT:
|
||||
ie->value.choice.Cause.present = X2AP_Cause_PR_radioNetwork;
|
||||
ie->value.choice.Cause.choice.radioNetwork = X2AP_CauseRadioNetwork_tDCoverall_expiry;
|
||||
break;
|
||||
default:
|
||||
X2AP_ERROR("%s: unhandled cause %d\n", __FUNCTION__, cause);
|
||||
exit(1);
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode ENDC X2 SgNB_release_request message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_gNB_generate_ENDC_x2_SgNB_release_confirm(
|
||||
x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int menb_ue_x2ap_id, int sgnb_ue_x2ap_id)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_SgNBReleaseConfirm_t *out;
|
||||
X2AP_SgNBReleaseConfirm_IEs_t *ie;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome;
|
||||
pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_sgNBinitiatedSgNBRelease;
|
||||
pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject;
|
||||
pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_SgNBReleaseConfirm;
|
||||
out = &pdu.choice.successfulOutcome.value.choice.SgNBReleaseConfirm;
|
||||
|
||||
ie = (X2AP_SgNBReleaseConfirm_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseConfirm_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_SgNBReleaseConfirm_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = menb_ue_x2ap_id;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
ie = (X2AP_SgNBReleaseConfirm_IEs_t *)calloc(1, sizeof(X2AP_SgNBReleaseConfirm_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID;
|
||||
ie->criticality= X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_SgNBReleaseConfirm_IEs__value_PR_SgNB_UE_X2AP_ID;
|
||||
ie->value.choice.SgNB_UE_X2AP_ID = sgnb_ue_x2ap_id;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode ENDC X2 SgNB Release Request Acknowledge\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -77,4 +77,16 @@ int x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK( x2ap_eNB_instance_t *in
|
||||
int x2ap_eNB_generate_ENDC_x2_SgNB_reconfiguration_complete(
|
||||
x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, int ue_id, int SgNB_ue_id);
|
||||
|
||||
int x2ap_eNB_generate_ENDC_x2_SgNB_release_request(x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int x2_id_source, int x2_id_target, x2ap_cause_t cause);
|
||||
|
||||
int x2ap_gNB_generate_ENDC_x2_SgNB_release_request_acknowledge(x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int menb_ue_x2ap_id, int sgnb_ue_x2ap_id);
|
||||
|
||||
int x2ap_eNB_generate_ENDC_x2_SgNB_release_required(x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int x2_id_source, int x2_id_target, x2ap_cause_t cause);
|
||||
|
||||
int x2ap_gNB_generate_ENDC_x2_SgNB_release_confirm(x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int menb_ue_x2ap_id, int sgnb_ue_x2ap_id);
|
||||
|
||||
#endif /* X2AP_ENB_GENERATE_MESSAGES_H_ */
|
||||
|
||||
@@ -132,6 +132,29 @@ int x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete (instance_t instance,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_release_request(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_release_request_acknowledge(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_release_required(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_release_confirm(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
/* Handlers matrix. Only eNB related procedure present here. Placement of callback functions according to X2AP_ProcedureCode.h */
|
||||
x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
|
||||
@@ -166,8 +189,9 @@ x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
|
||||
{ x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete, 0, 0 }, /*X2AP_ProcedureCode_id_sgNBReconfigurationCompletion*/
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ x2ap_gNB_handle_ENDC_sGNB_release_request, x2ap_gNB_handle_ENDC_sGNB_release_request_acknowledge, 0 }, /* meNBinitiatedSgNBRelease */
|
||||
{ x2ap_gNB_handle_ENDC_sGNB_release_required, x2ap_gNB_handle_ENDC_sGNB_release_confirm, 0 }, /* sgNBinitiatedSgNBRelease */
|
||||
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
@@ -1641,8 +1665,6 @@ int x2ap_gNB_handle_ENDC_sGNB_addition_request (instance_t instance,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
|
||||
|
||||
X2AP_SgNBAdditionRequest_t *x2SgNBAdditionRequest;
|
||||
X2AP_SgNBAdditionRequest_IEs_t *ie;
|
||||
|
||||
@@ -1823,6 +1845,8 @@ int x2ap_eNB_handle_ENDC_sGNB_addition_response (instance_t instance,
|
||||
//Allocate an ITTI X2AP_SGNB_ADDITION_REQ message instead
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_SGNB_ADDITION_REQ_ACK);
|
||||
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).gnb_x2_assoc_id = assoc_id;
|
||||
|
||||
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack,
|
||||
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
||||
@@ -1923,6 +1947,9 @@ int x2ap_eNB_handle_ENDC_sGNB_addition_response (instance_t instance,
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
||||
|
||||
/* remove UE from x2, DC preparation is over */
|
||||
x2ap_release_id(&instance_p->id_manager, ue_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1930,78 +1957,289 @@ static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu) {
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
X2AP_SgNBReconfigurationComplete_t *x2SgNBReconfigurationComplete;
|
||||
X2AP_SgNBReconfigurationComplete_IEs_t *ie;
|
||||
|
||||
X2AP_SgNBReconfigurationComplete_t *x2SgNBReconfigurationComplete;
|
||||
X2AP_SgNBReconfigurationComplete_IEs_t *ie;
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
MessageDef *msg;
|
||||
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
MessageDef *msg;
|
||||
int id_target;
|
||||
int ue_id;
|
||||
|
||||
DevAssert (pdu != NULL);
|
||||
x2SgNBReconfigurationComplete = &pdu->choice.initiatingMessage.value.choice.SgNBReconfigurationComplete;
|
||||
DevAssert (pdu != NULL);
|
||||
x2SgNBReconfigurationComplete = &pdu->choice.initiatingMessage.value.choice.SgNBReconfigurationComplete;
|
||||
|
||||
/*if (stream == 0) {
|
||||
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
||||
// TODO: send a x2 failure response
|
||||
return 0;
|
||||
}*/
|
||||
/*if (stream == 0) {
|
||||
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
||||
// TODO: send a x2 failure response
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
X2AP_DEBUG ("Received X2 SgNB Reconfiguration complete message\n");
|
||||
X2AP_DEBUG ("Received X2 SgNB Reconfiguration complete message\n");
|
||||
|
||||
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
||||
DevAssert(x2ap_eNB_data != NULL);
|
||||
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
||||
DevAssert(x2ap_eNB_data != NULL);
|
||||
|
||||
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
||||
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
//Allocate an ITTI X2AP_sGNB_reconfiguration_complete message
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_SGNB_RECONF_COMPLETE);
|
||||
//Allocate an ITTI X2AP_sGNB_reconfiguration_complete message
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_SGNB_RECONF_COMPLETE);
|
||||
|
||||
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
||||
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
||||
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).MeNB_ue_x2_id = ie->value.choice.UE_X2AP_ID;
|
||||
X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).MeNB_ue_x2_id = ie->value.choice.UE_X2AP_ID;
|
||||
|
||||
|
||||
/* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
||||
X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
/* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
||||
X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).SgNB_ue_x2_id = ie->value.choice.SgNB_UE_X2AP_ID;
|
||||
id_target = ie->value.choice.SgNB_UE_X2AP_ID;
|
||||
X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).SgNB_ue_x2_id = id_target;
|
||||
|
||||
ue_id = x2ap_find_id_from_id_target(&instance_p->id_manager, id_target);
|
||||
if (ue_id == -1) {
|
||||
X2AP_WARN("incorrect/unknown X2AP IDs for UE (SgNB_UE_X2AP_ID %d), ignoring sGNB reconfiguration complete\n",
|
||||
id_target);
|
||||
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
||||
X2AP_ProtocolIE_ID_id_ResponseInformationSgNBReconfComp, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
||||
X2AP_ProtocolIE_ID_id_ResponseInformationSgNBReconfComp, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ie->value.choice.ResponseInformationSgNBReconfComp.present == X2AP_ResponseInformationSgNBReconfComp_PR_success_SgNBReconfComp){
|
||||
X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).reconf_response = X2AP_RECONF_RESPONSE_SUCCESS;
|
||||
}
|
||||
else {
|
||||
X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).reconf_response = X2AP_RECONF_RESPONSE_REJECT;
|
||||
}
|
||||
if (ie->value.choice.ResponseInformationSgNBReconfComp.present != X2AP_ResponseInformationSgNBReconfComp_PR_success_SgNBReconfComp){
|
||||
X2AP_ERROR("%s %d: fatal: unsuccessfulSgNB Reconfiguration Complete\n",__FILE__,__LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg);
|
||||
x2ap_release_id(&instance_p->id_manager, ue_id);
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_release_request(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
/* the logic in this function is the following: when receiving a release
|
||||
* request, the UE may exist in X2. Or not. If it's not in X2, it can
|
||||
* nevertheless be in RRC.
|
||||
* The release request message may contain the gNB id. Or not. It's better
|
||||
* to look for the UE using the gNB rather than the eNB id. So if we have
|
||||
* the gNB id we use it. If not, we use the eNB id.
|
||||
*/
|
||||
X2AP_SgNBReleaseRequest_t *req;
|
||||
X2AP_SgNBReleaseRequest_IEs_t *ie;
|
||||
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
MessageDef *msg;
|
||||
|
||||
int id_source;
|
||||
int id_target;
|
||||
int rnti;
|
||||
int ue_id;
|
||||
|
||||
DevAssert (pdu != NULL);
|
||||
req = &pdu->choice.initiatingMessage.value.choice.SgNBReleaseRequest;
|
||||
|
||||
/*if (stream == 0) {
|
||||
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
||||
// TODO: send a x2 failure response
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
X2AP_DEBUG ("Received X2 SgNB Release Request message\n");
|
||||
|
||||
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
||||
DevAssert(x2ap_eNB_data != NULL);
|
||||
|
||||
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReleaseRequest_IEs_t, ie, req,
|
||||
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
id_source = ie->value.choice.UE_X2AP_ID;
|
||||
|
||||
/* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReleaseRequest_IEs_t, ie, req,
|
||||
X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, false);
|
||||
if (ie != NULL)
|
||||
id_target = ie->value.choice.SgNB_UE_X2AP_ID;
|
||||
else
|
||||
id_target = -1;
|
||||
|
||||
/* find ue_id, preferably from id_target if id_target is known */
|
||||
ue_id = -1;
|
||||
if (id_target != -1)
|
||||
ue_id = x2ap_find_id_from_id_target(&instance_p->id_manager, id_target);
|
||||
if (ue_id == -1)
|
||||
ue_id = x2ap_find_id_from_id_source(&instance_p->id_manager, id_source);
|
||||
|
||||
if (ue_id == -1) {
|
||||
X2AP_WARN("%s %d: no UE found for id_source %d id_target %d\n",
|
||||
__FILE__, __LINE__, id_source, id_target);
|
||||
}
|
||||
|
||||
/* the UE may not exist in X2 anymore but exist in RRC
|
||||
* in which case its rnti is simply the id_target
|
||||
*/
|
||||
if (ue_id != -1) {
|
||||
rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
||||
|
||||
/* remove ue_id */
|
||||
x2ap_release_id(&instance_p->id_manager, ue_id);
|
||||
} else {
|
||||
rnti = id_target;
|
||||
}
|
||||
|
||||
if (rnti != -1) {
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_SGNB_RELEASE_REQUEST);
|
||||
|
||||
X2AP_ENDC_SGNB_RELEASE_REQUEST(msg).rnti = rnti;
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg);
|
||||
}
|
||||
|
||||
/* this call should maybe not be here, we should check that the
|
||||
* SgNB Release Request message has been executed properly
|
||||
*/
|
||||
x2ap_gNB_generate_ENDC_x2_SgNB_release_request_acknowledge(instance_p, x2ap_eNB_data,
|
||||
id_source,
|
||||
rnti != -1 ? rnti : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_release_request_acknowledge(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
/* nothing to do - may change at some point */
|
||||
X2AP_INFO("received release request acknowledge\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_release_required(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
/* the logic in this function is the following: when receiving a release
|
||||
* required we don't care about the UE in X2. We simply send a message
|
||||
* to RRC with the SgNB id (which is SgNB's RNTI). RRC will look for the
|
||||
* UE using this RNTI and deal with it. In the meanwhile the X2 layer
|
||||
* immediately replies with "release confirm" no matter what happens
|
||||
* in RRC.
|
||||
*/
|
||||
X2AP_SgNBReleaseRequired_t *req;
|
||||
X2AP_SgNBReleaseRequired_IEs_t *ie;
|
||||
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
MessageDef *msg;
|
||||
|
||||
int id_source;
|
||||
int id_target;
|
||||
int gnb_rnti;
|
||||
|
||||
DevAssert (pdu != NULL);
|
||||
req = &pdu->choice.initiatingMessage.value.choice.SgNBReleaseRequired;
|
||||
|
||||
/*if (stream == 0) {
|
||||
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
||||
// TODO: send a x2 failure response
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
X2AP_DEBUG ("Received X2 SgNB Release Required message\n");
|
||||
|
||||
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
||||
DevAssert(x2ap_eNB_data != NULL);
|
||||
|
||||
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReleaseRequired_IEs_t, ie, req,
|
||||
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
id_source = ie->value.choice.UE_X2AP_ID;
|
||||
|
||||
/* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReleaseRequired_IEs_t, ie, req,
|
||||
X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, true);
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
id_target = ie->value.choice.SgNB_UE_X2AP_ID;
|
||||
|
||||
gnb_rnti = id_target;
|
||||
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_SGNB_RELEASE_REQUIRED);
|
||||
X2AP_ENDC_SGNB_RELEASE_REQUIRED(msg).gnb_rnti = gnb_rnti;
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
||||
|
||||
/* this call should maybe not be here, we should check that the
|
||||
* SgNB Release Required message has been executed properly
|
||||
*/
|
||||
x2ap_gNB_generate_ENDC_x2_SgNB_release_confirm(instance_p, x2ap_eNB_data,
|
||||
id_source, id_target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_gNB_handle_ENDC_sGNB_release_confirm(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
/* nothing to do - may change at some point */
|
||||
X2AP_INFO("received release confirm\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,16 @@ int x2ap_find_id_from_id_source(x2ap_id_manager *m, int id_source)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int x2ap_find_id_from_id_target(x2ap_id_manager *m, int id_target)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < X2AP_MAX_IDS; i++)
|
||||
if (m->ids[i].rnti != -1 &&
|
||||
m->ids[i].id_target == id_target)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int x2ap_find_id_from_rnti(x2ap_id_manager *m, int rnti)
|
||||
{
|
||||
int i;
|
||||
@@ -107,6 +117,16 @@ void x2ap_set_reloc_overall_timer(x2ap_id_manager *m, int ue_id, uint64_t time)
|
||||
m->ids[ue_id].tx2_reloc_overall_start = time;
|
||||
}
|
||||
|
||||
void x2ap_set_dc_prep_timer(x2ap_id_manager *m, int ue_id, uint64_t time)
|
||||
{
|
||||
m->ids[ue_id].t_dc_prep_start = time;
|
||||
}
|
||||
|
||||
void x2ap_set_dc_overall_timer(x2ap_id_manager *m, int ue_id, uint64_t time)
|
||||
{
|
||||
m->ids[ue_id].t_dc_overall_start = time;
|
||||
}
|
||||
|
||||
int x2ap_id_get_id_source(x2ap_id_manager *m, int ue_id)
|
||||
{
|
||||
return m->ids[ue_id].id_source;
|
||||
|
||||
@@ -38,7 +38,8 @@ typedef enum {
|
||||
X2ID_STATE_SOURCE_PREPARE,
|
||||
X2ID_STATE_SOURCE_OVERALL,
|
||||
X2ID_STATE_TARGET,
|
||||
X2ID_STATE_NSA_PREPARE,
|
||||
X2ID_STATE_NSA_ENB_PREPARE,
|
||||
X2ID_STATE_NSA_GNB_OVERALL,
|
||||
} x2id_state_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -55,6 +56,8 @@ typedef struct {
|
||||
/* timers */
|
||||
uint64_t t_reloc_prep_start;
|
||||
uint64_t tx2_reloc_overall_start;
|
||||
uint64_t t_dc_prep_start;
|
||||
uint64_t t_dc_overall_start;
|
||||
} x2ap_id;
|
||||
|
||||
typedef struct {
|
||||
@@ -66,6 +69,7 @@ int x2ap_allocate_new_id(x2ap_id_manager *m);
|
||||
void x2ap_release_id(x2ap_id_manager *m, int id);
|
||||
int x2ap_find_id(x2ap_id_manager *, int id_source, int id_target);
|
||||
int x2ap_find_id_from_id_source(x2ap_id_manager *, int id_source);
|
||||
int x2ap_find_id_from_id_target(x2ap_id_manager *, int id_source);
|
||||
int x2ap_find_id_from_rnti(x2ap_id_manager *, int rnti);
|
||||
void x2ap_set_ids(x2ap_id_manager *m, int ue_id, int rnti, int id_source, int id_target);
|
||||
void x2ap_id_set_state(x2ap_id_manager *m, int ue_id, x2id_state_t state);
|
||||
@@ -73,6 +77,8 @@ void x2ap_id_set_state(x2ap_id_manager *m, int ue_id, x2id_state_t state);
|
||||
void x2ap_id_set_target(x2ap_id_manager *m, int ue_id, void *target);
|
||||
void x2ap_set_reloc_prep_timer(x2ap_id_manager *m, int ue_id, uint64_t time);
|
||||
void x2ap_set_reloc_overall_timer(x2ap_id_manager *m, int ue_id, uint64_t time);
|
||||
void x2ap_set_dc_prep_timer(x2ap_id_manager *m, int ue_id, uint64_t time);
|
||||
void x2ap_set_dc_overall_timer(x2ap_id_manager *m, int ue_id, uint64_t time);
|
||||
int x2ap_id_get_id_source(x2ap_id_manager *m, int ue_id);
|
||||
int x2ap_id_get_id_target(x2ap_id_manager *m, int ue_id);
|
||||
int x2ap_id_get_rnti(x2ap_id_manager *m, int ue_id);
|
||||
|
||||
@@ -28,11 +28,17 @@
|
||||
#include "x2ap_eNB_management_procedures.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
|
||||
void x2ap_timers_init(x2ap_timers_t *t, int t_reloc_prep, int tx2_reloc_overall)
|
||||
void x2ap_timers_init(x2ap_timers_t *t,
|
||||
int t_reloc_prep,
|
||||
int tx2_reloc_overall,
|
||||
int t_dc_prep,
|
||||
int t_dc_overall)
|
||||
{
|
||||
t->tti = 0;
|
||||
t->t_reloc_prep = t_reloc_prep;
|
||||
t->tx2_reloc_overall = tx2_reloc_overall;
|
||||
t->t_dc_prep = t_dc_prep;
|
||||
t->t_dc_overall = t_dc_overall;
|
||||
}
|
||||
|
||||
void x2ap_check_timers(instance_t instance)
|
||||
@@ -59,14 +65,17 @@ void x2ap_check_timers(instance_t instance)
|
||||
|
||||
for (i = 0; i < X2AP_MAX_IDS; i++) {
|
||||
if (m->ids[i].rnti == -1) continue;
|
||||
x2_ongoing++;
|
||||
|
||||
if (m->ids[i].state == X2ID_STATE_SOURCE_PREPARE ||
|
||||
m->ids[i].state == X2ID_STATE_SOURCE_OVERALL)
|
||||
x2_ongoing++;
|
||||
|
||||
if (m->ids[i].state == X2ID_STATE_SOURCE_PREPARE &&
|
||||
t->tti > m->ids[i].t_reloc_prep_start + t->t_reloc_prep) {
|
||||
LOG_I(X2AP, "X2 timeout reloc prep\n");
|
||||
/* t_reloc_prep timed out */
|
||||
cause = X2AP_T_RELOC_PREP_TIMEOUT;
|
||||
goto timeout;
|
||||
goto lte_handover_timeout;
|
||||
}
|
||||
|
||||
if (m->ids[i].state == X2ID_STATE_SOURCE_OVERALL &&
|
||||
@@ -74,13 +83,62 @@ void x2ap_check_timers(instance_t instance)
|
||||
LOG_I(X2AP, "X2 timeout reloc overall\n");
|
||||
/* tx2_reloc_overall timed out */
|
||||
cause = X2AP_TX2_RELOC_OVERALL_TIMEOUT;
|
||||
goto timeout;
|
||||
goto lte_handover_timeout;
|
||||
}
|
||||
|
||||
if (m->ids[i].state == X2ID_STATE_NSA_ENB_PREPARE &&
|
||||
t->tti > m->ids[i].t_dc_prep_start + t->t_dc_prep) {
|
||||
int id_source;
|
||||
int id_target;
|
||||
|
||||
LOG_I(X2AP, "X2 timeout DC prep\n");
|
||||
/* t_dc_prep timed out */
|
||||
target = x2ap_id_get_target(m, i);
|
||||
id_source = x2ap_id_get_id_source(m, i);
|
||||
id_target = x2ap_id_get_id_target(m, i);
|
||||
x2ap_eNB_generate_ENDC_x2_SgNB_release_request(instance_p, target,
|
||||
id_source, id_target,
|
||||
X2AP_CAUSE_T_DC_PREP_TIMEOUT);
|
||||
|
||||
/* inform RRC of timeout */
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_DC_PREP_TIMEOUT);
|
||||
X2AP_ENDC_DC_PREP_TIMEOUT(msg).rnti = x2ap_id_get_rnti(m, i);
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
||||
|
||||
/* remove UE from X2AP */
|
||||
x2ap_release_id(m, i);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m->ids[i].state == X2ID_STATE_NSA_GNB_OVERALL &&
|
||||
t->tti > m->ids[i].t_dc_overall_start + t->t_dc_overall) {
|
||||
int id_source;
|
||||
int id_target;
|
||||
|
||||
LOG_I(X2AP, "X2 timeout DC overall\n");
|
||||
/* t_dc_overall timed out */
|
||||
target = x2ap_id_get_target(m, i);
|
||||
id_source = x2ap_id_get_id_source(m, i);
|
||||
id_target = x2ap_id_get_id_target(m, i);
|
||||
x2ap_eNB_generate_ENDC_x2_SgNB_release_required(instance_p, target,
|
||||
id_source, id_target, X2AP_CAUSE_T_DC_OVERALL_TIMEOUT);
|
||||
|
||||
/* inform RRC of timeout */
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_ENDC_DC_OVERALL_TIMEOUT);
|
||||
X2AP_ENDC_DC_OVERALL_TIMEOUT(msg).rnti = x2ap_id_get_rnti(m, i);
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg);
|
||||
|
||||
/* remove UE from X2AP */
|
||||
x2ap_release_id(m, i);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* no timeout -> check next UE */
|
||||
continue;
|
||||
|
||||
timeout:
|
||||
lte_handover_timeout:
|
||||
/* inform target about timeout */
|
||||
target = x2ap_id_get_target(m, i);
|
||||
x2ap_eNB_generate_x2_handover_cancel(instance_p, target, i, cause);
|
||||
|
||||
@@ -36,9 +36,15 @@ typedef struct {
|
||||
/* timer values (unit: TTI, ie. millisecond when in realtime) */
|
||||
int t_reloc_prep;
|
||||
int tx2_reloc_overall;
|
||||
int t_dc_prep;
|
||||
int t_dc_overall;
|
||||
} x2ap_timers_t;
|
||||
|
||||
void x2ap_timers_init(x2ap_timers_t *t, int t_reloc_prep, int tx2_reloc_overall);
|
||||
void x2ap_timers_init(x2ap_timers_t *t,
|
||||
int t_reloc_prep,
|
||||
int tx2_reloc_overall,
|
||||
int t_dc_prep,
|
||||
int t_dc_overall);
|
||||
void x2ap_check_timers(instance_t instance);
|
||||
uint64_t x2ap_timer_get_tti(x2ap_timers_t *t);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user