[AMF] Handle am-data/subscribedUeAmbr change notification

When such a notification arrives from UDM, notify the GNB of the new values
AMBR uplink/downlink values.
This commit is contained in:
mitmitmitm 2022-11-23 12:49:37 +01:00 committed by Sukchan Lee
parent 3b043b082a
commit ea09a7921a
5 changed files with 388 additions and 5 deletions

View File

@ -725,6 +725,86 @@ static int update_rat_res(OpenAPI_change_item_t *item_change,
}
static int update_ambr_check_one(cJSON *obj, uint64_t *limit,
bool *ambr_changed)
{
if (!cJSON_IsString(obj)) {
ogs_error("Invalid type of subscribedUeAmbr");
return OGS_ERROR;
}
*limit = ogs_sbi_bitrate_from_string(obj->valuestring);
*ambr_changed = true;
return OGS_OK;
}
static int update_ambr_check_obj(cJSON *obj, ogs_bitrate_t *ambr,
bool *ambr_changed)
{
if (!cJSON_IsObject(obj)) {
if (obj == NULL || cJSON_IsNull(obj)) {
/* Limit of 0 means unlimited. */
ambr->uplink = 0;
ambr->downlink = 0;
*ambr_changed = true;
return OGS_OK;
} else {
ogs_error("Invalid type of subscribedUeAmbr");
return OGS_ERROR;
}
}
if (update_ambr_check_one(
cJSON_GetObjectItemCaseSensitive(obj, "uplink"),
&ambr->uplink, ambr_changed)) {
return OGS_ERROR;
}
if (update_ambr_check_one(
cJSON_GetObjectItemCaseSensitive(obj, "downlink"),
&ambr->downlink, ambr_changed)) {
return OGS_ERROR;
}
return OGS_OK;
}
static int update_ambr(OpenAPI_change_item_t *item_change,
ogs_bitrate_t *ambr, bool *ambr_changed)
{
cJSON* json = item_change->new_value->json;
if (!item_change->path) {
return OGS_ERROR;
}
switch (item_change->op) {
case OpenAPI_change_type_REPLACE:
case OpenAPI_change_type_ADD:
if (!strcmp(item_change->path, "")) {
if (!cJSON_IsObject(json)) {
ogs_error("Invalid type of am-data");
}
return update_ambr_check_obj(
cJSON_GetObjectItemCaseSensitive(json, "subscribedUeAmbr"),
ambr, ambr_changed);
} else if (!strcmp(item_change->path, "/subscribedUeAmbr")) {
return update_ambr_check_obj(json, ambr, ambr_changed);
} else if (!strcmp(item_change->path, "/subscribedUeAmbr/uplink")) {
return update_ambr_check_one(json, &ambr->uplink, ambr_changed);
} else if (!strcmp(item_change->path, "/subscribedUeAmbr/downlink")) {
return update_ambr_check_one(json, &ambr->downlink, ambr_changed);
}
return OGS_OK;
case OpenAPI_change_type__REMOVE:
if (!strcmp(item_change->path, "/subscribedUeAmbr")) {
update_ambr_check_obj(NULL, ambr, ambr_changed);
}
return OGS_OK;
default:
return OGS_OK;
}
}
int amf_namf_callback_handle_sdm_data_change_notify(
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
{
@ -741,6 +821,8 @@ int amf_namf_callback_handle_sdm_data_change_notify(
char *ueid = NULL;
char *res_name = NULL;
bool ambr_changed = false;
ogs_assert(stream);
ogs_assert(recvmsg);
@ -786,7 +868,9 @@ int amf_namf_callback_handle_sdm_data_change_notify(
OpenAPI_list_for_each(item->changes, node_ci)
{
OpenAPI_change_item_t *change_item = node_ci->data;
if (update_rat_res(change_item, amf_ue->rat_restrictions)) {
if (update_rat_res(change_item, amf_ue->rat_restrictions)
|| update_ambr(change_item, &amf_ue->ue_ambr,
&ambr_changed)) {
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
goto cleanup;
}
@ -816,6 +900,14 @@ int amf_namf_callback_handle_sdm_data_change_notify(
amf_ue_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NUDM_SDM, NULL,
amf_nudm_sdm_build_subscription_delete, amf_ue, NULL));
} else if (ambr_changed) {
ogs_pkbuf_t *ngapbuf;
ngapbuf = ngap_build_ue_context_modification_request(amf_ue);
ogs_assert(ngapbuf);
if (nas_5gs_send_to_gnb(amf_ue, ngapbuf) != OGS_OK)
ogs_error("nas_5gs_send_to_gnb() failed");
}
cleanup:

View File

@ -764,6 +764,146 @@ ogs_pkbuf_t *ngap_ue_build_initial_context_setup_request(
return ogs_ngap_encode(&pdu);
}
ogs_pkbuf_t *ngap_build_ue_context_modification_request(amf_ue_t *amf_ue)
{
ran_ue_t *ran_ue = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_InitiatingMessage_t *initiatingMessage = NULL;
NGAP_UEContextModificationRequest_t *UEContextModificationRequest = NULL;
NGAP_UEContextModificationRequestIEs_t *ie = NULL;
NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL;
NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL;
NGAP_UEAggregateMaximumBitRate_t *UEAggregateMaximumBitRate = NULL;
NGAP_UESecurityCapabilities_t *UESecurityCapabilities = NULL;
NGAP_SecurityKey_t *SecurityKey = NULL;
amf_ue = amf_ue_cycle(amf_ue);
ogs_assert(amf_ue);
ran_ue = ran_ue_cycle(amf_ue->ran_ue);
ogs_assert(ran_ue);
ogs_debug("UEContextModificationRequest(UE)");
memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t));
initiatingMessage = pdu.choice.initiatingMessage;
initiatingMessage->procedureCode =
NGAP_ProcedureCode_id_UEContextModification;
initiatingMessage->criticality = NGAP_Criticality_reject;
initiatingMessage->value.present =
NGAP_InitiatingMessage__value_PR_UEContextModificationRequest;
UEContextModificationRequest =
&initiatingMessage->value.choice.UEContextModificationRequest;
ie = CALLOC(1, sizeof(NGAP_UEContextModificationRequestIEs_t));
ASN_SEQUENCE_ADD(&UEContextModificationRequest->protocolIEs, ie);
ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present =
NGAP_UEContextModificationRequestIEs__value_PR_AMF_UE_NGAP_ID;
AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID;
ie = CALLOC(1, sizeof(NGAP_UEContextModificationRequestIEs_t));
ASN_SEQUENCE_ADD(&UEContextModificationRequest->protocolIEs, ie);
ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present =
NGAP_UEContextModificationRequestIEs__value_PR_RAN_UE_NGAP_ID;
RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID;
ie = CALLOC(1, sizeof(NGAP_UEContextModificationRequestIEs_t));
ASN_SEQUENCE_ADD(&UEContextModificationRequest->protocolIEs, ie);
ie->id = NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UEContextModificationRequestIEs__value_PR_UEAggregateMaximumBitRate;
UEAggregateMaximumBitRate = &ie->value.choice.UEAggregateMaximumBitRate;
asn_uint642INTEGER(
&UEAggregateMaximumBitRate->uEAggregateMaximumBitRateUL,
amf_ue->ue_ambr.uplink == 0 ? MAX_BIT_RATE : amf_ue->ue_ambr.uplink);
asn_uint642INTEGER(
&UEAggregateMaximumBitRate->uEAggregateMaximumBitRateDL,
amf_ue->ue_ambr.downlink == 0 ? MAX_BIT_RATE : amf_ue->ue_ambr.downlink);
ran_ue->ue_ambr_sent = true;
ie = CALLOC(1, sizeof(NGAP_UEContextModificationRequestIEs_t));
ASN_SEQUENCE_ADD(&UEContextModificationRequest->protocolIEs, ie);
ie->id = NGAP_ProtocolIE_ID_id_UESecurityCapabilities;
ie->criticality = NGAP_Criticality_reject;
ie->value.present =
NGAP_UEContextModificationRequestIEs__value_PR_UESecurityCapabilities;
UESecurityCapabilities = &ie->value.choice.UESecurityCapabilities;
ie = CALLOC(1, sizeof(NGAP_UEContextModificationRequestIEs_t));
ASN_SEQUENCE_ADD(&UEContextModificationRequest->protocolIEs, ie);
ie->id = NGAP_ProtocolIE_ID_id_SecurityKey;
ie->criticality = NGAP_Criticality_reject;
ie->value.present =
NGAP_UEContextModificationRequestIEs__value_PR_SecurityKey;
SecurityKey = &ie->value.choice.SecurityKey;
ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]",
ran_ue->ran_ue_ngap_id, (long long)ran_ue->amf_ue_ngap_id);
asn_uint642INTEGER(AMF_UE_NGAP_ID, ran_ue->amf_ue_ngap_id);
*RAN_UE_NGAP_ID = ran_ue->ran_ue_ngap_id;
UESecurityCapabilities->nRencryptionAlgorithms.size = 2;
UESecurityCapabilities->nRencryptionAlgorithms.buf =
CALLOC(UESecurityCapabilities->
nRencryptionAlgorithms.size, sizeof(uint8_t));
UESecurityCapabilities->nRencryptionAlgorithms.bits_unused = 0;
UESecurityCapabilities->nRencryptionAlgorithms.buf[0] =
(amf_ue->ue_security_capability.nr_ea << 1);
UESecurityCapabilities->nRintegrityProtectionAlgorithms.size = 2;
UESecurityCapabilities->nRintegrityProtectionAlgorithms.buf =
CALLOC(UESecurityCapabilities->
nRintegrityProtectionAlgorithms.size, sizeof(uint8_t));
UESecurityCapabilities->nRintegrityProtectionAlgorithms.bits_unused = 0;
UESecurityCapabilities->nRintegrityProtectionAlgorithms.buf[0] =
(amf_ue->ue_security_capability.nr_ia << 1);
UESecurityCapabilities->eUTRAencryptionAlgorithms.size = 2;
UESecurityCapabilities->eUTRAencryptionAlgorithms.buf =
CALLOC(UESecurityCapabilities->
eUTRAencryptionAlgorithms.size, sizeof(uint8_t));
UESecurityCapabilities->eUTRAencryptionAlgorithms.bits_unused = 0;
UESecurityCapabilities->eUTRAencryptionAlgorithms.buf[0] =
(amf_ue->ue_security_capability.eutra_ea << 1);
UESecurityCapabilities->eUTRAintegrityProtectionAlgorithms.size = 2;
UESecurityCapabilities->eUTRAintegrityProtectionAlgorithms.buf =
CALLOC(UESecurityCapabilities->
eUTRAintegrityProtectionAlgorithms.size, sizeof(uint8_t));
UESecurityCapabilities->eUTRAintegrityProtectionAlgorithms.bits_unused = 0;
UESecurityCapabilities->eUTRAintegrityProtectionAlgorithms.buf[0] =
(amf_ue->ue_security_capability.eutra_ia << 1);
SecurityKey->size = OGS_SHA256_DIGEST_SIZE;
SecurityKey->buf = CALLOC(SecurityKey->size, sizeof(uint8_t));
SecurityKey->bits_unused = 0;
memcpy(SecurityKey->buf, amf_ue->kgnb, SecurityKey->size);
return ogs_ngap_encode(&pdu);
}
ogs_pkbuf_t *ngap_sess_build_initial_context_setup_request(
amf_sess_t *sess, ogs_pkbuf_t *gmmbuf, ogs_pkbuf_t *n2smbuf)
{

View File

@ -39,6 +39,7 @@ ogs_pkbuf_t *ngap_build_downlink_nas_transport(
ogs_pkbuf_t *ngap_ue_build_initial_context_setup_request(
amf_ue_t *amf_ue, ogs_pkbuf_t *gmmbuf);
ogs_pkbuf_t *ngap_build_ue_context_modification_request(amf_ue_t *amf_ue);
ogs_pkbuf_t *ngap_sess_build_initial_context_setup_request(
amf_sess_t *sess, ogs_pkbuf_t *gmmbuf, ogs_pkbuf_t *n2smbuf);
ogs_pkbuf_t *ngap_build_ue_context_release_command(

View File

@ -1145,6 +1145,160 @@ void ngap_handle_initial_context_setup_failure(
}
}
void ngap_handle_ue_context_modification_response(
amf_gnb_t *gnb, ogs_ngap_message_t *message)
{
int i;
char buf[OGS_ADDRSTRLEN];
uint64_t amf_ue_ngap_id;
ran_ue_t *ran_ue = NULL;
NGAP_SuccessfulOutcome_t *SuccessfulOutcome = NULL;
NGAP_UEContextModificationResponse_t *UEContextModificationResponse = NULL;
NGAP_UEContextModificationResponseIEs_t *ie = NULL;
NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL;
NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL;
/* NGAP_RRCState_t *RRCState = NULL; */
/* NGAP_UserLocationInformation_t *UserLocationInformation = NULL; */
/* NGAP_CriticalityDiagnostics_t *CriticalityDiagnostics = NULL; */
ogs_assert(gnb);
ogs_assert(gnb->sctp.sock);
ogs_assert(message);
SuccessfulOutcome = message->choice.successfulOutcome;
ogs_assert(SuccessfulOutcome);
UEContextModificationResponse = &SuccessfulOutcome->value.choice.UEContextModificationResponse;
ogs_assert(UEContextModificationResponse);
ogs_warn("UEContextModificationResponse");
for (i = 0; i < UEContextModificationResponse->protocolIEs.list.count; i++) {
ie = UEContextModificationResponse->protocolIEs.list.array[i];
switch (ie->id) {
case NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID:
RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID;
break;
case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID:
AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID;
break;
/* case NGAP_ProtocolIE_ID_id_RRCState: */
/* RRCState = &ie->value.choice.RRCState; */
/* break; */
/* case NGAP_ProtocolIE_ID_id_UserLocationInformation: */
/* UserLocationInformation = &ie->value.choice.UserLocationInformation; */
/* case NGAP_ProtocolIE_ID_id_CriticalityDiagnostics: */
/* CriticalityDiagnostics = &ie->value.choice.CriticalityDiagnostics; */
default:
break;
}
}
ogs_debug(" IP[%s] RAN_ID[%d]",
OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id);
if (AMF_UE_NGAP_ID) {
if (asn_INTEGER2ulong(AMF_UE_NGAP_ID,
(unsigned long *)&amf_ue_ngap_id) != 0) {
ogs_warn("Invalid AMF_UE_NGAP_ID");
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue)
ogs_warn("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
(long long)amf_ue_ngap_id);
} else if (RAN_UE_NGAP_ID) {
ran_ue = ran_ue_find_by_ran_ue_ngap_id(gnb, *RAN_UE_NGAP_ID);
if (!ran_ue)
ogs_warn("No RAN UE Context : RAN_UE_NGAP_ID[%d]",
(int)*RAN_UE_NGAP_ID);
}
}
void ngap_handle_ue_context_modification_failure(
amf_gnb_t *gnb, ogs_ngap_message_t *message)
{
int i;
char buf[OGS_ADDRSTRLEN];
uint64_t amf_ue_ngap_id;
ran_ue_t *ran_ue = NULL;
NGAP_UnsuccessfulOutcome_t *UnsuccessfulOutcome = NULL;
NGAP_UEContextModificationFailure_t *UEContextModificationFailiure = NULL;
NGAP_UEContextModificationFailureIEs_t *ie = NULL;
NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL;
NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL;
NGAP_Cause_t *Cause = NULL;
ogs_assert(gnb);
ogs_assert(gnb->sctp.sock);
ogs_assert(message);
UnsuccessfulOutcome = message->choice.unsuccessfulOutcome;
ogs_assert(UnsuccessfulOutcome);
UEContextModificationFailiure = &UnsuccessfulOutcome->value.choice.UEContextModificationFailure;
ogs_assert(UEContextModificationFailiure);
ogs_warn("UEContextModificationFailiure");
for (i = 0; i < UEContextModificationFailiure->protocolIEs.list.count; i++) {
ie = UEContextModificationFailiure->protocolIEs.list.array[i];
switch (ie->id) {
case NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID:
RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID;
break;
case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID:
AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID;
break;
case NGAP_ProtocolIE_ID_id_Cause:
Cause = &ie->value.choice.Cause;
break;
default:
break;
}
}
ogs_warn(" IP[%s] RAN_ID[%d]",
OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id);
if (AMF_UE_NGAP_ID) {
if (asn_INTEGER2ulong(AMF_UE_NGAP_ID,
(unsigned long *)&amf_ue_ngap_id) != 0) {
ogs_warn("Invalid AMF_UE_NGAP_ID");
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue)
ogs_warn("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
(long long)amf_ue_ngap_id);
else
ogs_warn(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]",
ran_ue->ran_ue_ngap_id, (long long)ran_ue->amf_ue_ngap_id);
} else if (RAN_UE_NGAP_ID) {
ran_ue = ran_ue_find_by_ran_ue_ngap_id(gnb, *RAN_UE_NGAP_ID);
if (!ran_ue)
ogs_warn("No RAN UE Context : RAN_UE_NGAP_ID[%d]",
(int)*RAN_UE_NGAP_ID);
else
ogs_warn(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]",
ran_ue->ran_ue_ngap_id, (long long)ran_ue->amf_ue_ngap_id);
}
if (Cause) {
ogs_warn(" Cause[Group:%d Cause:%d]",
Cause->present, (int)Cause->choice.radioNetwork);
}
}
void ngap_handle_ue_context_release_request(
amf_gnb_t *gnb, ogs_ngap_message_t *message)
{

View File

@ -145,11 +145,9 @@ void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e)
case NGAP_ProcedureCode_id_PDUSessionResourceRelease:
ngap_handle_pdu_session_resource_release_response(gnb, pdu);
break;
#if 0
case NGAP_ProcedureCode_id_UEContextModification:
ngap_handle_ue_context_modification_response(gnb, pdu);
break;
#endif
case NGAP_ProcedureCode_id_UEContextRelease:
ngap_handle_ue_context_release_complete(gnb, pdu);
break;
@ -170,11 +168,9 @@ void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e)
case NGAP_ProcedureCode_id_InitialContextSetup :
ngap_handle_initial_context_setup_failure(gnb, pdu);
break;
#if 0
case NGAP_ProcedureCode_id_UEContextModification:
ngap_handle_ue_context_modification_failure(gnb, pdu);
break;
#endif
case NGAP_ProcedureCode_id_HandoverResourceAllocation :
ngap_handle_handover_failure(gnb, pdu);
break;