[MME] Implement ENBConfigurationUpdate (#2589)

This commit is contained in:
Sukchan Lee 2023-09-16 20:58:10 +09:00
parent aa746794e7
commit a3a683e5a6
11 changed files with 366 additions and 2 deletions

View File

@ -217,8 +217,13 @@ int emm_handle_attach_request(mme_ue_t *mme_ue,
switch (eps_mobile_identity->imsi.type) {
case OGS_NAS_EPS_MOBILE_IDENTITY_IMSI:
ogs_assert(sizeof(ogs_nas_mobile_identity_imsi_t) ==
eps_mobile_identity->length);
if (sizeof(ogs_nas_mobile_identity_imsi_t) !=
eps_mobile_identity->length) {
ogs_error("mobile_identity length (%d != %d)",
(int)sizeof(ogs_nas_mobile_identity_imsi_t),
eps_mobile_identity->length);
return OGS_ERROR;
}
memcpy(&mme_ue->nas_mobile_identity_imsi,
&eps_mobile_identity->imsi, eps_mobile_identity->length);
ogs_nas_eps_imsi_to_bcd(

View File

@ -188,6 +188,88 @@ ogs_pkbuf_t *s1ap_build_setup_failure(
return ogs_s1ap_encode(&pdu);
}
ogs_pkbuf_t *s1ap_build_enb_configuration_update_ack(void)
{
S1AP_S1AP_PDU_t pdu;
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
ogs_debug("ENBConfigurationUpdateAcknowledge");
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
pdu.present = S1AP_S1AP_PDU_PR_successfulOutcome;
pdu.choice.successfulOutcome = CALLOC(1, sizeof(S1AP_SuccessfulOutcome_t));
successfulOutcome = pdu.choice.successfulOutcome;
successfulOutcome->procedureCode =
S1AP_ProcedureCode_id_ENBConfigurationUpdate;
successfulOutcome->criticality = S1AP_Criticality_reject;
successfulOutcome->value.present =
S1AP_SuccessfulOutcome__value_PR_ENBConfigurationUpdateAcknowledge;
return ogs_s1ap_encode(&pdu);
}
ogs_pkbuf_t *s1ap_build_enb_configuration_update_failure(
S1AP_Cause_PR group, long cause, long time_to_wait)
{
S1AP_S1AP_PDU_t pdu;
S1AP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL;
S1AP_ENBConfigurationUpdateFailure_t *ENBConfigurationUpdateFailure = NULL;
S1AP_ENBConfigurationUpdateFailureIEs_t *ie = NULL;
S1AP_Cause_t *Cause = NULL;
S1AP_TimeToWait_t *TimeToWait = NULL;
ogs_debug("ENBConfigurationUpdateFailure");
ogs_debug(" Group[%d] Cause[%d] TimeToWait[%ld]",
group, (int)cause, time_to_wait);
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
pdu.present = S1AP_S1AP_PDU_PR_unsuccessfulOutcome;
pdu.choice.unsuccessfulOutcome =
CALLOC(1, sizeof(S1AP_UnsuccessfulOutcome_t));
unsuccessfulOutcome = pdu.choice.unsuccessfulOutcome;
unsuccessfulOutcome->procedureCode =
S1AP_ProcedureCode_id_ENBConfigurationUpdate;
unsuccessfulOutcome->criticality = S1AP_Criticality_reject;
unsuccessfulOutcome->value.present =
S1AP_UnsuccessfulOutcome__value_PR_ENBConfigurationUpdateFailure;
ENBConfigurationUpdateFailure =
&unsuccessfulOutcome->value.choice.ENBConfigurationUpdateFailure;
ie = CALLOC(1, sizeof(S1AP_ENBConfigurationUpdateFailureIEs_t));
ASN_SEQUENCE_ADD(&ENBConfigurationUpdateFailure->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_Cause;
ie->criticality = S1AP_Criticality_ignore;
ie->value.present = S1AP_ENBConfigurationUpdateFailureIEs__value_PR_Cause;
Cause = &ie->value.choice.Cause;
if (time_to_wait > -1) {
ie = CALLOC(1, sizeof(S1AP_ENBConfigurationUpdateFailureIEs_t));
ASN_SEQUENCE_ADD(&ENBConfigurationUpdateFailure->protocolIEs, ie);
ie->id = S1AP_ProtocolIE_ID_id_TimeToWait;
ie->criticality = S1AP_Criticality_ignore;
ie->value.present =
S1AP_ENBConfigurationUpdateFailureIEs__value_PR_TimeToWait;
TimeToWait = &ie->value.choice.TimeToWait;
}
Cause->present = group;
Cause->choice.radioNetwork = cause;
if (TimeToWait)
*TimeToWait = time_to_wait;
return ogs_s1ap_encode(&pdu);
}
ogs_pkbuf_t *s1ap_build_downlink_nas_transport(
enb_ue_t *enb_ue, ogs_pkbuf_t *emmbuf)
{

View File

@ -32,6 +32,10 @@ ogs_pkbuf_t *s1ap_build_setup_rsp(void);
ogs_pkbuf_t *s1ap_build_setup_failure(
S1AP_Cause_PR group, long cause, long time_to_wait);
ogs_pkbuf_t *s1ap_build_enb_configuration_update_ack(void);
ogs_pkbuf_t *s1ap_build_enb_configuration_update_failure(
S1AP_Cause_PR group, long cause, long time_to_wait);
ogs_pkbuf_t *s1ap_build_downlink_nas_transport(
enb_ue_t *enb_ue, ogs_pkbuf_t *emmbuf);

View File

@ -246,6 +246,129 @@ void s1ap_handle_s1_setup_request(mme_enb_t *enb, ogs_s1ap_message_t *message)
ogs_assert(r != OGS_ERROR);
}
void s1ap_handle_enb_configuration_update(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
int i, j, r;
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
S1AP_ENBConfigurationUpdate_t *ENBConfigurationUpdate = NULL;
S1AP_ENBConfigurationUpdateIEs_t *ie = NULL;
S1AP_SupportedTAs_t *SupportedTAs = NULL;
S1AP_PagingDRX_t *PagingDRX = NULL;
ogs_assert(enb);
ogs_assert(enb->sctp.sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
ENBConfigurationUpdate =
&initiatingMessage->value.choice.ENBConfigurationUpdate;
ogs_assert(ENBConfigurationUpdate);
ogs_debug("ENBConfigurationUpdate");
for (i = 0; i < ENBConfigurationUpdate->protocolIEs.list.count; i++) {
ie = ENBConfigurationUpdate->protocolIEs.list.array[i];
switch (ie->id) {
case S1AP_ProtocolIE_ID_id_SupportedTAs:
SupportedTAs = &ie->value.choice.SupportedTAs;
break;
case S1AP_ProtocolIE_ID_id_DefaultPagingDRX:
PagingDRX = &ie->value.choice.PagingDRX;
break;
default:
break;
}
}
/* Parse Supported TA */
if (SupportedTAs) {
S1AP_Cause_PR group = S1AP_Cause_PR_NOTHING;
long cause = 0;
enb->num_of_supported_ta_list = 0;
for (i = 0; i < SupportedTAs->list.count; i++) {
S1AP_SupportedTAs_Item_t *SupportedTAs_Item = NULL;
S1AP_TAC_t *tAC = NULL;
SupportedTAs_Item =
(S1AP_SupportedTAs_Item_t *)SupportedTAs->list.array[i];
ogs_assert(SupportedTAs_Item);
tAC = &SupportedTAs_Item->tAC;
ogs_assert(tAC);
for (j = 0; j < SupportedTAs_Item->broadcastPLMNs.list.count; j++) {
S1AP_PLMNidentity_t *pLMNidentity = NULL;
pLMNidentity = (S1AP_PLMNidentity_t *)
SupportedTAs_Item->broadcastPLMNs.list.array[j];
ogs_assert(pLMNidentity);
memcpy(&enb->supported_ta_list[
enb->num_of_supported_ta_list].tac,
tAC->buf, sizeof(uint16_t));
enb->supported_ta_list[enb->num_of_supported_ta_list].tac =
be16toh(enb->supported_ta_list
[enb->num_of_supported_ta_list].tac);
memcpy(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id,
pLMNidentity->buf, sizeof(ogs_plmn_id_t));
ogs_debug(" PLMN_ID[MCC:%d MNC:%d] TAC[%d]",
ogs_plmn_id_mcc(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id),
ogs_plmn_id_mnc(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id),
enb->supported_ta_list[enb->num_of_supported_ta_list].tac);
enb->num_of_supported_ta_list++;
}
}
/*
* TS36.413
* Section 8.7.3.4 Abnormal Conditions
*
* If the eNB initiates the procedure by sending a S1 SETUP REQUEST
* message including the PLMN Identity IEs and none of the PLMNs
* provided by the eNB is identified by the MME, then the MME shall
* reject the eNB S1 Setup Request procedure with the appropriate cause
* value, e.g., Unknown PLMN.
*/
if (enb_plmn_id_is_foreign(enb)) {
ogs_warn("S1-Setup failure:");
ogs_warn(" Global-ENB-ID PLMN-ID is foreign");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unknown_PLMN;
r = s1ap_send_enb_configuration_update_failure(enb, group, cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
if (!served_tai_is_found(enb)) {
ogs_warn("S1-Setup failure:");
ogs_warn(" Cannot find Served TAI. "
"Check 'mme.tai' configuration");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unknown_PLMN;
r = s1ap_send_enb_configuration_update_failure(enb, group, cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
}
if (PagingDRX)
ogs_debug(" PagingDRX[%ld]", *PagingDRX);
r = s1ap_send_enb_configuration_update_ack(enb);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
}
void s1ap_handle_initial_ue_message(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
int i, r;

View File

@ -28,6 +28,8 @@ extern "C" {
void s1ap_handle_s1_setup_request(
mme_enb_t *enb, ogs_s1ap_message_t *message);
void s1ap_handle_enb_configuration_update(
mme_enb_t *enb, ogs_s1ap_message_t *message);
void s1ap_handle_initial_ue_message(
mme_enb_t *enb, ogs_s1ap_message_t *message);
void s1ap_handle_uplink_nas_transport(

View File

@ -309,6 +309,56 @@ int s1ap_send_s1_setup_failure(
return rv;
}
int s1ap_send_enb_configuration_update_ack(mme_enb_t *enb)
{
int rv;
ogs_pkbuf_t *s1ap_buffer;
ogs_debug("ENBConfigurationUpdateAcknowledge");
if (!mme_enb_cycle(enb)) {
ogs_error("eNB has already been removed");
return OGS_NOTFOUND;
}
s1ap_buffer = s1ap_build_enb_configuration_update_ack();
if (!s1ap_buffer) {
ogs_error("s1ap_build_setup_rsp() failed");
return OGS_ERROR;
}
rv = s1ap_send_to_enb(enb, s1ap_buffer, S1AP_NON_UE_SIGNALLING);
ogs_expect(rv == OGS_OK);
return rv;
}
int s1ap_send_enb_configuration_update_failure(
mme_enb_t *enb, S1AP_Cause_PR group, long cause)
{
int rv;
ogs_pkbuf_t *s1ap_buffer;
ogs_debug("ENBConfigurationUpdateFailure");
if (!mme_enb_cycle(enb)) {
ogs_error("eNB has already been removed");
return OGS_NOTFOUND;
}
s1ap_buffer = s1ap_build_enb_configuration_update_failure(
group, cause, S1AP_TimeToWait_v10s);
if (!s1ap_buffer) {
ogs_error("s1ap_build_setup_failure() failed");
return OGS_ERROR;
}
rv = s1ap_send_to_enb(enb, s1ap_buffer, S1AP_NON_UE_SIGNALLING);
ogs_expect(rv == OGS_OK);
return rv;
}
int s1ap_send_initial_context_setup_request(mme_ue_t *mme_ue)
{
int rv;

View File

@ -52,6 +52,10 @@ int s1ap_send_s1_setup_response(mme_enb_t *enb);
int s1ap_send_s1_setup_failure(
mme_enb_t *enb, S1AP_Cause_PR group, long cause);
int s1ap_send_enb_configuration_update_ack(mme_enb_t *enb);
int s1ap_send_enb_configuration_update_failure(
mme_enb_t *enb, S1AP_Cause_PR group, long cause);
int s1ap_send_initial_context_setup_request(mme_ue_t *mme_ue);
int s1ap_send_ue_context_modification_request(mme_ue_t *mme_ue);
int s1ap_send_ue_context_release_command(

View File

@ -87,6 +87,9 @@ void s1ap_state_operational(ogs_fsm_t *s, mme_event_t *e)
case S1AP_ProcedureCode_id_S1Setup :
s1ap_handle_s1_setup_request(enb, pdu);
break;
case S1AP_ProcedureCode_id_ENBConfigurationUpdate:
s1ap_handle_enb_configuration_update(enb, pdu);
break;
case S1AP_ProcedureCode_id_initialUEMessage :
s1ap_handle_initial_ue_message(enb, pdu);
break;

View File

@ -97,12 +97,60 @@ static void s1setup_test2(abts_case *tc, void *data)
}
}
static void s1setup_test3(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *node[NUM_OF_TEST_ENB];
ogs_pkbuf_t *sendbuf;
ogs_pkbuf_t *recvbuf;
ogs_s1ap_message_t message;
int i;
i = 0;
node[i] = tests1ap_client(AF_INET);
ABTS_PTR_NOTNULL(tc, node[i]);
sendbuf = test_s1ap_build_s1_setup_request(
S1AP_ENB_ID_PR_macroENB_ID, 0x54f64+i);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(node[i], sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
recvbuf = testenb_s1ap_read(node[i]);
ABTS_PTR_NOTNULL(tc, recvbuf);
rv = ogs_s1ap_decode(&message, recvbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
ogs_s1ap_free(&message);
ogs_pkbuf_free(recvbuf);
sendbuf = test_s1ap_build_enb_configuration_update(0);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(node[i], sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
recvbuf = testenb_s1ap_read(node[i]);
ABTS_PTR_NOTNULL(tc, recvbuf);
rv = ogs_s1ap_decode(&message, recvbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
ogs_s1ap_free(&message);
ogs_pkbuf_free(recvbuf);
testenb_s1ap_close(node[i]);
}
abts_suite *test_s1setup(abts_suite *suite)
{
suite = ADD_SUITE(suite)
abts_run_test(suite, s1setup_test1, NULL);
abts_run_test(suite, s1setup_test2, NULL);
abts_run_test(suite, s1setup_test3, NULL);
return suite;
}

View File

@ -2041,6 +2041,48 @@ ogs_pkbuf_t *test_s1ap_build_enb_configuration_transfer(int i)
return pkbuf;
}
ogs_pkbuf_t *test_s1ap_build_enb_configuration_update(int i)
{
ogs_pkbuf_t *pkbuf = NULL;
const char *payload[TEST_S1AP_MAX_MESSAGE] = {
"001d002a0000"
"04003c4003000031 0040000700000040 34f2990089400140 0124400c00004ced"
"a80000004034f299",
"",
"",
"",
"",
"",
"",
"",
"",
};
uint16_t len[TEST_S1AP_MAX_MESSAGE] = {
46,
0,
0,
0,
0,
0,
0,
0,
0,
};
char hexbuf[OGS_HUGE_LEN];
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
ogs_assert(pkbuf);
ogs_pkbuf_put_data(pkbuf,
ogs_hex_from_string(payload[i], hexbuf, sizeof(hexbuf)), len[i]);
return pkbuf;
}
ogs_pkbuf_t *test_s1ap_build_malformed_s1_setup_request(int i)
{
ogs_pkbuf_t *pkbuf = NULL;

View File

@ -67,6 +67,7 @@ ogs_pkbuf_t *test_s1ap_build_handover_failure(test_ue_t *test_ue,
S1AP_Cause_PR group, long cause);
ogs_pkbuf_t *test_s1ap_build_enb_configuration_transfer(int i);
ogs_pkbuf_t *test_s1ap_build_enb_configuration_update(int i);
ogs_pkbuf_t *test_s1ap_build_malformed_s1_setup_request(int i);
ogs_pkbuf_t *test_s1ap_build_malformed_enb_status_transfer(int i);