[AMF] Follow-up on Context transfer (#3052)

This commit is contained in:
Sukchan Lee 2024-05-26 14:40:11 +09:00
parent 2a4d8db72e
commit 7062b9c0d6
18 changed files with 1216 additions and 613 deletions

View file

@ -1082,21 +1082,3 @@ cleanup:
return (int)(rule-first);
}
bool ogs_nas_5gs_guti_is_valid(ogs_nas_5gs_guti_t *guti)
{
if ((guti->amf_id.region !=0) &&
(guti->amf_id.set2 !=0) &&
(guti->m_tmsi != 0) &&
((guti->nas_plmn_id.mcc1) !=0 ||
(guti->nas_plmn_id.mcc2) !=0 ||
(guti->nas_plmn_id.mcc3) !=0) &&
((guti->nas_plmn_id.mnc1) !=0 ||
(guti->nas_plmn_id.mnc2) !=0 ||
(guti->nas_plmn_id.mnc3) !=0)) {
return true;
}
return false;
}

View file

@ -1192,8 +1192,6 @@ typedef struct ogs_nas_rsn_s {
uint8_t value;
} __attribute__ ((packed)) ogs_nas_rsn_t;
bool ogs_nas_5gs_guti_is_valid(ogs_nas_5gs_guti_t *guti);
#ifdef __cplusplus
}
#endif

View file

@ -1983,9 +1983,9 @@ bool ogs_sbi_discovery_option_is_matched(
switch (nf_info->nf_type) {
case OpenAPI_nf_type_AMF:
if (requester_nf_type == OpenAPI_nf_type_AMF &&
discovery_option->target_guami &&
discovery_option->guami_presence &&
ogs_sbi_check_amf_info_guami(&nf_info->amf,
discovery_option->target_guami) == false)
&discovery_option->guami) == false)
return false;
break;
case OpenAPI_nf_type_SMF:

View file

@ -394,16 +394,18 @@ ogs_sbi_request_t *ogs_sbi_build_request(ogs_sbi_message_t *message)
OGS_SBI_PARAM_REQUESTER_NF_INSTANCE_ID,
discovery_option->requester_nf_instance_id);
}
if (discovery_option->target_guami) {
if (discovery_option->guami_presence) {
char *v = ogs_sbi_discovery_option_build_guami(discovery_option);
if (v) {
ogs_sbi_header_set(request->http.params,
OGS_SBI_PARAM_GUAMI, v);
ogs_free(v);
} else {
ogs_warn("build failed: service-names[%d:%s]",
discovery_option->num_of_service_names,
discovery_option->service_names[0]);
ogs_error("build failed: guami[PLMN_ID:%06x,AMF_ID:%d]",
ogs_plmn_id_hexdump(
&discovery_option->guami.plmn_id),
ogs_amf_id_hexdump(
&discovery_option->guami.amf_id));
}
}
if (ogs_sbi_self()->discovery_config.no_service_names == false &&
@ -2940,8 +2942,6 @@ void ogs_sbi_discovery_option_free(
ogs_free(discovery_option->requester_nf_instance_id);
if (discovery_option->dnn)
ogs_free(discovery_option->dnn);
if (discovery_option->target_guami)
ogs_free(discovery_option->target_guami);
for (i = 0; i < discovery_option->num_of_service_names; i++)
ogs_free(discovery_option->service_names[i]);
@ -3182,6 +3182,18 @@ void ogs_sbi_discovery_option_parse_snssais(
ogs_free(v);
}
void ogs_sbi_discovery_option_set_guami(
ogs_sbi_discovery_option_t *discovery_option, ogs_guami_t *guami)
{
ogs_assert(discovery_option);
ogs_assert(guami);
ogs_assert(discovery_option->guami_presence == false);
memcpy(&discovery_option->guami, guami, sizeof(ogs_guami_t));
discovery_option->guami_presence = true;
}
char *ogs_sbi_discovery_option_build_guami(
ogs_sbi_discovery_option_t *discovery_option)
{
@ -3190,9 +3202,9 @@ char *ogs_sbi_discovery_option_build_guami(
char *v = NULL;
ogs_assert(discovery_option);
ogs_assert(discovery_option->target_guami);
ogs_assert(discovery_option->guami_presence);
Guami = ogs_sbi_build_guami(discovery_option->target_guami);
Guami = ogs_sbi_build_guami(&discovery_option->guami);
ogs_assert(Guami);
guamiItem = OpenAPI_guami_convertToJSON(Guami);
ogs_assert(guamiItem);
@ -3231,12 +3243,9 @@ void ogs_sbi_discovery_option_parse_guami(
Guami = OpenAPI_guami_parseFromJSON(guamItem);
if (Guami) {
ogs_guami_t *ogs_guami = NULL;
discovery_option->target_guami = ogs_malloc(sizeof(*ogs_guami));
ogs_assert(discovery_option->target_guami);
ogs_sbi_parse_guami(discovery_option->target_guami, Guami);
ogs_guami_t guami;
ogs_sbi_parse_guami(&guami, Guami);
ogs_sbi_discovery_option_set_guami(discovery_option, &guami);
OpenAPI_guami_free(Guami);
} else {
ogs_error("OpenAPI_guami_parseFromJSON() failed : guami[%s]",

View file

@ -435,7 +435,8 @@ typedef struct ogs_sbi_discovery_option_s {
bool tai_presence;
ogs_5gs_tai_t tai;
ogs_guami_t *target_guami;
bool guami_presence;
ogs_guami_t guami;
int num_of_target_plmn_list;
ogs_plmn_id_t target_plmn_list[OGS_MAX_NUM_OF_PLMN];
@ -649,6 +650,8 @@ char *ogs_sbi_discovery_option_build_snssais(
void ogs_sbi_discovery_option_parse_snssais(
ogs_sbi_discovery_option_t *discovery_option, char *snssais);
void ogs_sbi_discovery_option_set_guami(
ogs_sbi_discovery_option_t *discovery_option, ogs_guami_t *guami);
char *ogs_sbi_discovery_option_build_guami(
ogs_sbi_discovery_option_t *discovery_option);
void ogs_sbi_discovery_option_parse_guami(

View file

@ -284,9 +284,14 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
/* Target NF-Instance */
nf_instance = OGS_SBI_GET_NF_INSTANCE(
sbi_object->service_type_array[service_type]);
ogs_debug("OGS_SBI_GET_NF_INSTANCE [nf_instance:%p,service_name:%s]",
nf_instance, ogs_sbi_service_type_to_name(service_type));
if (!nf_instance) {
nf_instance = ogs_sbi_nf_instance_find_by_discovery_param(
target_nf_type, requester_nf_type, discovery_option);
ogs_debug("ogs_sbi_nf_instance_find_by_discovery_param() "
"[nf_instance:%p,service_name:%s]",
nf_instance, ogs_sbi_service_type_to_name(service_type));
if (nf_instance)
OGS_SBI_SETUP_NF_INSTANCE(
sbi_object->service_type_array[service_type], nf_instance);
@ -337,6 +342,7 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
apiroot = ogs_sbi_client_apiroot(client);
ogs_assert(apiroot);
ogs_debug("apiroot [%s]", apiroot);
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_TARGET_APIROOT, apiroot);
@ -355,6 +361,8 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
*/
if (discovery_option &&
discovery_option->target_nf_instance_id) {
ogs_debug("target_nf_instance_id [%s]",
discovery_option->target_nf_instance_id);
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_DISCOVERY_TARGET_NF_INSTANCE_ID,
discovery_option->target_nf_instance_id);
@ -362,6 +370,7 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_DISCOVERY_TARGET_NF_INSTANCE_ID,
nf_instance->id);
ogs_debug("nf_instance->id [%s]", nf_instance->id);
}
if (discovery_option && discovery_option->num_of_snssais) {
@ -373,6 +382,7 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
if (v) {
char *encoded = ogs_sbi_url_encode(v);
ogs_expect(encoded);
ogs_debug("snssai [%s]", v);
if (encoded) {
/*
@ -399,6 +409,7 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
}
if (discovery_option && discovery_option->dnn) {
ogs_debug("dnn [%s]", discovery_option->dnn);
ogs_sbi_header_set(request->http.headers,
OGS_SBI_CUSTOM_DISCOVERY_DNN, discovery_option->dnn);
}
@ -408,9 +419,11 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
char *v = ogs_sbi_discovery_option_build_tai(discovery_option);
ogs_expect(v);
if (v) {
char *encoded = ogs_sbi_url_encode(v);
ogs_expect(encoded);
ogs_debug("tai [%s]", v);
if (encoded) {
ogs_sbi_header_set(request->http.headers,
@ -429,7 +442,7 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
discovery_option->tai.tac.v);
}
if (discovery_option && discovery_option->target_guami) {
if (discovery_option && discovery_option->guami_presence) {
bool rc = false;
char *v = ogs_sbi_discovery_option_build_guami(discovery_option);
ogs_expect(v);
@ -437,6 +450,7 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
if (v) {
char *encoded = ogs_sbi_url_encode(v);
ogs_expect(encoded);
ogs_debug("guami [%s]", v);
if (encoded) {
ogs_sbi_header_set(request->http.headers,
@ -451,9 +465,9 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
if (rc == false)
ogs_error("build failed: guami[PLMN_ID:%06x,AMF_ID:%x]",
ogs_plmn_id_hexdump(
&discovery_option->target_guami->plmn_id),
&discovery_option->guami.plmn_id),
ogs_amf_id_hexdump(
&discovery_option->target_guami->amf_id));
&discovery_option->guami.amf_id));
}
if (discovery_option &&

View file

@ -1980,31 +1980,26 @@ static bool amf_namf_comm_parse_guti(ogs_nas_5gs_guti_t *guti, char *ue_context_
short index = 8; /* start parsing guti after "5g-guti-" */
strncpy(mcc_string, &ue_context_id[index], LENGTH_OF_MCC);
mcc_string[LENGTH_OF_MCC] = '\0';
ogs_cpystrn(mcc_string, &ue_context_id[index], LENGTH_OF_MCC+1);
index += LENGTH_OF_MCC;
if (strlen(ue_context_id) == OGS_MAX_5G_GUTI_LEN - 1) {
/* mnc is 2 characters long */
mnc_string[MIN_LENGTH_OF_MNC] = '\0';
strncpy(mnc_string, &ue_context_id[index], MIN_LENGTH_OF_MNC);
ogs_cpystrn(mnc_string, &ue_context_id[index], MIN_LENGTH_OF_MNC+1);
index += MIN_LENGTH_OF_MNC;
} else if (strlen(ue_context_id) == OGS_MAX_5G_GUTI_LEN) {
/* mnc is 3 characters long */
mnc_string[MAX_LENGTH_OF_MNC] = '\0';
strncpy(mnc_string, &ue_context_id[index], MAX_LENGTH_OF_MNC);
ogs_cpystrn(mnc_string, &ue_context_id[index], MAX_LENGTH_OF_MNC+1);
index += MAX_LENGTH_OF_MNC;
} else {
ogs_error("Invalid Ue context id");
return false;
}
strncpy(amf_id_string, &ue_context_id[index], LENGTH_OF_AMF_ID);
amf_id_string[LENGTH_OF_AMF_ID] = '\0';
ogs_cpystrn(amf_id_string, &ue_context_id[index], LENGTH_OF_AMF_ID+1);
index += LENGTH_OF_AMF_ID;
strncpy(tmsi_string, &ue_context_id[index], LENGTH_OF_TMSI);
tmsi_string[LENGTH_OF_TMSI] = '\0';
ogs_cpystrn(tmsi_string, &ue_context_id[index], LENGTH_OF_TMSI+1);
memset(&Plmn_id, 0, sizeof(Plmn_id));
Plmn_id.mcc = mcc_string;

View file

@ -268,6 +268,8 @@ struct amf_ue_s {
ogs_nas_5gs_guti_t guti;
} current, next;
ogs_nas_5gs_guti_t old_guti;
/* UE Info */
ogs_guami_t *guami;
uint16_t gnb_ostream_id;

View file

@ -48,7 +48,6 @@ ogs_nas_5gmm_cause_t gmm_handle_registration_request(amf_ue_t *amf_ue,
ogs_nas_5gs_mobile_identity_suci_t *mobile_identity_suci = NULL;
ogs_nas_5gs_mobile_identity_guti_t *mobile_identity_guti = NULL;
ogs_nas_ue_security_capability_t *ue_security_capability = NULL;
ogs_nas_5gs_guti_t nas_guti;
ogs_assert(amf_ue);
ran_ue = ran_ue_cycle(amf_ue->ran_ue);
@ -139,6 +138,8 @@ ogs_nas_5gmm_cause_t gmm_handle_registration_request(amf_ue_t *amf_ue,
mobile_identity_header =
(ogs_nas_5gs_mobile_identity_header_t *)mobile_identity->buffer;
memset(&amf_ue->old_guti, 0, sizeof(ogs_nas_5gs_guti_t));
switch (mobile_identity_header->type) {
case OGS_NAS_5GS_MOBILE_IDENTITY_SUCI:
mobile_identity_suci =
@ -180,11 +181,12 @@ ogs_nas_5gmm_cause_t gmm_handle_registration_request(amf_ue_t *amf_ue,
}
ogs_nas_5gs_mobile_identity_guti_to_nas_guti(
mobile_identity_guti, &nas_guti);
mobile_identity_guti, &amf_ue->old_guti);
ogs_info("[%s] 5G-S_GUTI[AMF_ID:0x%x,M_TMSI:0x%x]",
AMF_UE_HAVE_SUCI(amf_ue) ? amf_ue->suci : "Unknown ID",
ogs_amf_id_hexdump(&nas_guti.amf_id), nas_guti.m_tmsi);
ogs_amf_id_hexdump(&amf_ue->old_guti.amf_id),
amf_ue->old_guti.m_tmsi);
break;
default:
ogs_error("Unknown SUCI type [%d]", mobile_identity_header->type);
@ -540,6 +542,86 @@ ogs_nas_5gmm_cause_t gmm_handle_registration_update(
return OGS_5GMM_CAUSE_REQUEST_ACCEPTED;
}
bool gmm_registration_request_from_old_amf(amf_ue_t *amf_ue,
ogs_nas_5gs_registration_request_t *registration_request)
{
ogs_nas_5gs_mobile_identity_t *mobile_identity = NULL;
ogs_nas_5gs_mobile_identity_header_t *mobile_identity_header = NULL;
int i;
ogs_plmn_id_t plmn_id;
ogs_assert(amf_ue);
ogs_assert(registration_request);
mobile_identity = &registration_request->mobile_identity;
mobile_identity_header =
(ogs_nas_5gs_mobile_identity_header_t *)mobile_identity->buffer;
if (mobile_identity_header->type != OGS_NAS_5GS_MOBILE_IDENTITY_GUTI) {
return false;
}
/*
* TODO : FIXME
*
* Typically, UEs send 5G-GUTIs with all 0. In such cases,
* we need to prevent context transfer betwen AMFs by the N14 interface
* because they are not included in served_guami.
*
* We don't yet know how to check for 5G GUTI conformance,
* so we've implemented the following as a temporary solution.
*/
if ((amf_ue->old_guti.amf_id.region == 0 &&
amf_ue->old_guti.amf_id.set2 == 0) &&
(amf_ue->old_guti.nas_plmn_id.mcc1 == 0 &&
amf_ue->old_guti.nas_plmn_id.mcc2 == 0 &&
amf_ue->old_guti.nas_plmn_id.mcc3 == 0) &&
(amf_ue->old_guti.nas_plmn_id.mnc1 == 0 &&
amf_ue->old_guti.nas_plmn_id.mnc2 == 0 &&
amf_ue->old_guti.nas_plmn_id.mnc3 == 0)) {
return false;
}
/*
* TS 23.502
* 4.2.2.2.2 General Registration
* (Without UDSF Deployment): If the UE's 5G-GUTI was included in the
* Registration Request and the serving AMF has changed since last
* Registration procedure, the new AMF may invoke the
* Namf_Communication_UEContextTransfer service operation on the
* old AMF including the complete Registration Request NAS message,
* which may be integrity protected, as well as the Access Type,
* to request the UE's SUPI and UE Context. See clause 5.2.2.2.2
* for details of this service operation.
*/
ogs_nas_to_plmn_id(&plmn_id, &amf_ue->old_guti.nas_plmn_id);
ogs_info("[%s] 5G-S_GUTI[PLMN_ID:0x%x,AMF_ID:0x%x,M_TMSI:0x%x]",
AMF_UE_HAVE_SUCI(amf_ue) ? amf_ue->suci : "Unknown ID",
ogs_plmn_id_hexdump(&plmn_id),
ogs_amf_id_hexdump(&amf_ue->old_guti.amf_id),
amf_ue->old_guti.m_tmsi);
for (i = 0; i < amf_self()->num_of_served_guami; i++) {
if (memcmp(&amf_self()->served_guami[i].plmn_id,
&plmn_id, OGS_PLMN_ID_LEN) == 0 &&
memcmp(&amf_self()->served_guami[i].amf_id,
&amf_ue->old_guti.amf_id, sizeof(ogs_amf_id_t)) == 0) {
return false;
}
}
ogs_info("Serving AMF Changed [NumberOfServedGuami:%d]",
amf_self()->num_of_served_guami);
for (i = 0; i < amf_self()->num_of_served_guami; i++) {
ogs_info("Served Guami[PLMN_ID:0x%x,AMF_ID:0x%x]",
ogs_plmn_id_hexdump(&amf_self()->served_guami[i].plmn_id),
ogs_amf_id_hexdump(&amf_self()->served_guami[i].amf_id));
}
return true;
}
ogs_nas_5gmm_cause_t gmm_handle_service_request(amf_ue_t *amf_ue,
ogs_nas_security_header_type_t h, NGAP_ProcedureCode_t ngap_code,
ogs_nas_5gs_service_request_t *service_request)
@ -1540,243 +1622,6 @@ static ogs_nas_5gmm_cause_t gmm_handle_nas_message_container(
return gmm_cause;
}
static ogs_nas_5gmm_capability_t
amf_namf_comm_base64_decode_5gmm_capability(char *encoded)
{
ogs_nas_5gmm_capability_t gmm_capability;
char *gmm_capability_octets_string = NULL;
uint8_t gmm_capability_iei = 0;
memset(&gmm_capability, 0, sizeof(gmm_capability));
gmm_capability_octets_string =
(char*) ogs_calloc(sizeof(gmm_capability) + 1, sizeof(char));
ogs_assert(gmm_capability_octets_string);
int len = ogs_base64_decode(gmm_capability_octets_string, encoded);
if (len == 0)
ogs_error("Gmm capability not decoded");
ogs_assert(sizeof(gmm_capability_octets_string) <=
sizeof(gmm_capability) + 1);
gmm_capability_iei = // not copied anywhere for now
gmm_capability_octets_string[0];
if (gmm_capability_iei !=
OGS_NAS_5GS_REGISTRATION_REQUEST_5GMM_CAPABILITY_TYPE) {
ogs_error("Type of 5GMM capability IEI is incorrect");
}
memcpy(&gmm_capability,
gmm_capability_octets_string + 1,
sizeof(gmm_capability));
if (gmm_capability_octets_string) {
ogs_free(gmm_capability_octets_string);
}
return gmm_capability;
}
static ogs_nas_ue_security_capability_t
amf_namf_comm_base64_decode_ue_security_capability(char *encoded)
{
ogs_nas_ue_security_capability_t ue_security_capability;
char *ue_security_capability_octets_string = NULL;
uint8_t ue_security_capability_iei = 0;
memset(&ue_security_capability, 0, sizeof(ue_security_capability));
ue_security_capability_octets_string =
(char*) ogs_calloc(sizeof(ue_security_capability), sizeof(char));
ogs_assert(ue_security_capability_octets_string);
ogs_base64_decode(ue_security_capability_octets_string, encoded);
ogs_assert(sizeof(ue_security_capability_octets_string) <=
sizeof(ogs_nas_ue_security_capability_t) + 1);
ue_security_capability_iei = // not copied anywhere for now
ue_security_capability_octets_string[0];
if (ue_security_capability_iei !=
OGS_NAS_5GS_REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_TYPE) {
ogs_error("UE security capability IEI is incorrect");
}
memcpy(&ue_security_capability, ue_security_capability_octets_string + 1,
sizeof(ue_security_capability));
if (ue_security_capability_octets_string) {
ogs_free(ue_security_capability_octets_string);
}
return ue_security_capability;
}
static void amf_namf_comm_decode_ue_mm_context_list(
amf_ue_t *amf_ue, OpenAPI_list_t *MmContextList) {
OpenAPI_lnode_t *node = NULL;
OpenAPI_list_for_each(MmContextList, node) {
OpenAPI_mm_context_t *MmContext = NULL;
OpenAPI_list_t *AllowedNssaiList = NULL;
OpenAPI_lnode_t *node1 = NULL;
OpenAPI_list_t *NssaiMappingList = NULL;
int num_of_s_nssai = 0;
int num_of_nssai_mapping = 0;
MmContext = node->data;
AllowedNssaiList = MmContext->allowed_nssai;
NssaiMappingList = MmContext->nssai_mapping_list;
OpenAPI_list_for_each(AllowedNssaiList, node1) {
OpenAPI_snssai_t *AllowedNssai = node1->data;
ogs_assert(num_of_s_nssai < OGS_MAX_NUM_OF_SLICE);
amf_ue->allowed_nssai.s_nssai[num_of_s_nssai].sst =
(uint8_t)AllowedNssai->sst;
amf_ue->allowed_nssai.s_nssai[num_of_s_nssai].sd =
ogs_s_nssai_sd_from_string(AllowedNssai->sd);
num_of_s_nssai++;
amf_ue->allowed_nssai.num_of_s_nssai = num_of_s_nssai;
}
OpenAPI_list_for_each(NssaiMappingList, node1) {
OpenAPI_nssai_mapping_t *NssaiMapping = node1->data;
OpenAPI_snssai_t *HSnssai = NssaiMapping->h_snssai;
ogs_assert(num_of_nssai_mapping < OGS_MAX_NUM_OF_SLICE);
amf_ue->allowed_nssai.s_nssai[num_of_nssai_mapping].
mapped_hplmn_sst = HSnssai->sst;
amf_ue->allowed_nssai.s_nssai[num_of_nssai_mapping].
mapped_hplmn_sd = ogs_s_nssai_sd_from_string(HSnssai->sd);
num_of_nssai_mapping++;
}
if (MmContext->ue_security_capability) {
amf_ue->ue_security_capability =
amf_namf_comm_base64_decode_ue_security_capability(
MmContext->ue_security_capability);
}
}
}
static void amf_namf_comm_decode_ue_session_context_list(
amf_ue_t *amf_ue, OpenAPI_list_t *SessionContextList)
{
OpenAPI_lnode_t *node = NULL;
OpenAPI_list_for_each(SessionContextList, node) {
OpenAPI_pdu_session_context_t *PduSessionContext;
PduSessionContext = node->data;
amf_sess_t *sess = NULL;
sess = amf_sess_add(amf_ue, PduSessionContext->pdu_session_id);
ogs_assert(sess);
sess->sm_context.ref = PduSessionContext->sm_context_ref;
if (PduSessionContext->s_nssai) {
memset(&sess->s_nssai, 0, sizeof(sess->s_nssai));
sess->s_nssai.sst = PduSessionContext->s_nssai->sst;
sess->s_nssai.sd = ogs_s_nssai_sd_from_string(
PduSessionContext->s_nssai->sd);
}
if (PduSessionContext->dnn)
sess->dnn = ogs_strdup(PduSessionContext->dnn);
if (PduSessionContext->access_type)
amf_ue->nas.access_type = (int)PduSessionContext->access_type;
}
}
int amf_namf_comm_handle_ue_context_transfer_response(
ogs_sbi_message_t *recvmsg, amf_ue_t *amf_ue)
{
OpenAPI_ue_context_t *UeContext = NULL;
ogs_error("V funkciji amf_namf_comm_handle_ue_context_transfer_response");
if (!recvmsg->UeContextTransferRspData) {
ogs_error("No UeContextTransferRspData");
return OGS_ERROR;
}
if (!recvmsg->UeContextTransferRspData->ue_context) {
ogs_error("No UE context");
return OGS_ERROR;
}
UeContext = recvmsg->UeContextTransferRspData->ue_context;
if (UeContext->supi) {
amf_ue_set_supi(amf_ue, UeContext->supi);
if (!UeContext->supi_unauth_ind){
amf_ue->auth_result = OpenAPI_auth_result_AUTHENTICATION_SUCCESS;
}
}
if (UeContext->pei) {
if (amf_ue->pei)
ogs_free(amf_ue->pei);
amf_ue->pei = ogs_strdup(UeContext->pei);
}
if (UeContext->sub_ue_ambr) {
amf_ue->ue_ambr.downlink =
ogs_sbi_bitrate_from_string(UeContext->sub_ue_ambr->downlink);
amf_ue->ue_ambr.uplink =
ogs_sbi_bitrate_from_string(UeContext->sub_ue_ambr->uplink);
}
if (UeContext->seaf_data) {
if (UeContext->seaf_data->ng_ksi->tsc != OpenAPI_sc_type_NULL) {
amf_ue->nas.ue.tsc =
(UeContext->seaf_data->ng_ksi->tsc == OpenAPI_sc_type_NATIVE) ? 0 : 1;
amf_ue->nas.ue.ksi = (uint8_t)UeContext->seaf_data->ng_ksi->ksi;
ogs_ascii_to_hex(
UeContext->seaf_data->key_amf->key_val,
strlen(UeContext->seaf_data->key_amf->key_val),
amf_ue->kamf,
sizeof(amf_ue->kamf));
}
}
if (UeContext->_5g_mm_capability) {
ogs_nas_5gmm_capability_t gmm_capability;
gmm_capability = amf_namf_comm_base64_decode_5gmm_capability(
UeContext->_5g_mm_capability);
amf_ue->gmm_capability.lte_positioning_protocol_capability =
(bool)gmm_capability.lte_positioning_protocol_capability;
amf_ue->gmm_capability.ho_attach = (bool)gmm_capability.ho_attach;
amf_ue->gmm_capability.s1_mode = (bool)gmm_capability.s1_mode;
}
if (UeContext->pcf_id) {
/* TODO */
}
/* TODO UeContext->pcfAmPolicyUri */
/* TODO UeContext->pcfUePolicyUri */
if (UeContext->mm_context_list)
amf_namf_comm_decode_ue_mm_context_list(amf_ue, UeContext->mm_context_list);
if (UeContext->session_context_list)
amf_namf_comm_decode_ue_session_context_list(amf_ue, UeContext->session_context_list);
/* TODO ueRadioCapability */
return OGS_OK;
}
static uint8_t gmm_cause_from_access_control(ogs_plmn_id_t *plmn_id)
{
int i;

View file

@ -33,6 +33,8 @@ ogs_nas_5gmm_cause_t gmm_handle_registration_request(amf_ue_t *amf_ue,
ogs_nas_5gmm_cause_t gmm_handle_registration_update(
ran_ue_t *ran_ue, amf_ue_t *amf_ue,
ogs_nas_5gs_registration_request_t *registration_request);
bool gmm_registration_request_from_old_amf(amf_ue_t *amf_ue,
ogs_nas_5gs_registration_request_t *registration_request);
ogs_nas_5gmm_cause_t gmm_handle_service_request(amf_ue_t *amf_ue,
ogs_nas_security_header_type_t h, NGAP_ProcedureCode_t ngap_code,

View file

@ -67,7 +67,7 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
ogs_sbi_message_t *sbi_message = NULL;
int r, state = 0;
int r, state = 0, xact_count;
ogs_assert(s);
ogs_assert(e);
@ -298,7 +298,7 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
state ==
AMF_NETWORK_INITIATED_EXPLICIT_DE_REGISTERED) {
int xact_count = amf_sess_xact_count(amf_ue);
xact_count = amf_sess_xact_count(amf_ue);
amf_sbi_send_release_all_sessions(NULL, amf_ue, state);
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
@ -549,21 +549,31 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
SWITCH(sbi_message->h.resource.component[2])
CASE(OGS_SBI_RESOURCE_NAME_TRANSFER)
r = OGS_ERROR;
if (sbi_message->res_status == OGS_SBI_HTTP_STATUS_OK) {
r = amf_namf_comm_handle_ue_context_transfer_response(sbi_message, amf_ue);
ogs_expect(r == OGS_OK);
r = amf_namf_comm_handle_ue_context_transfer_response(
sbi_message, amf_ue);
if (r != OGS_OK) {
ogs_error("failed to handle "
"UE_CONTEXT_TRANSFER response");
}
} else {
ogs_error("[%s] HTTP response error [%d]",
amf_ue->suci, sbi_message->res_status);
}
int xact_count = amf_sess_xact_count(amf_ue);
if (!AMF_UE_HAVE_SUCI(amf_ue)) {
CLEAR_AMF_UE_TIMER(amf_ue->t3570);
r = nas_5gs_send_identity_request(amf_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
break;
if (r != OGS_OK) {
if (!AMF_UE_HAVE_SUCI(amf_ue)) {
CLEAR_AMF_UE_TIMER(amf_ue->t3570);
r = nas_5gs_send_identity_request(amf_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
break;
}
}
xact_count = amf_sess_xact_count(amf_ue);
amf_sbi_send_release_all_sessions(
amf_ue->ran_ue, amf_ue,
AMF_RELEASE_SM_CONTEXT_NO_STATE);
@ -579,7 +589,6 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
}
OGS_FSM_TRAN(s, &gmm_state_authentication);
break;
DEFAULT
@ -1182,9 +1191,6 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
amf_sess_t *sess = NULL;
ogs_nas_5gs_message_t *nas_message = NULL;
ogs_nas_security_header_type_t h;
ogs_nas_5gs_registration_request_t *registration_request = NULL;
ogs_nas_5gs_mobile_identity_header_t *mobile_identity_header = NULL;
ogs_nas_5gs_mobile_identity_t *mobile_identity = NULL;
ogs_assert(e);
@ -1243,64 +1249,32 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
break;
}
registration_request = &nas_message->gmm.registration_request;
mobile_identity = &registration_request->mobile_identity;
mobile_identity_header =
(ogs_nas_5gs_mobile_identity_header_t *)mobile_identity->buffer;
if (gmm_registration_request_from_old_amf(amf_ue,
&nas_message->gmm.registration_request) == true) {
ogs_sbi_discovery_option_t *discovery_option = NULL;
ogs_guami_t guami;
/* Check if registration is done with GUTI */
if (mobile_identity_header && mobile_identity_header->type ==
OGS_NAS_5GS_MOBILE_IDENTITY_GUTI &&
ogs_nas_5gs_guti_is_valid(&amf_ue->current.guti)) {
discovery_option = ogs_sbi_discovery_option_new();
ogs_assert(discovery_option);
/*
* TS 23.502
* 4.2.2.2.2 General Registration
* (Without UDSF Deployment): If the UE's 5G-GUTI was included in the
* Registration Request and the serving AMF has changed since last
* Registration procedure, the new AMF may invoke the
* Namf_Communication_UEContextTransfer service operation on the
* old AMF including the complete Registration Request NAS message,
* which may be integrity protected, as well as the Access Type,
* to request the UE's SUPI and UE Context. See clause 5.2.2.2.2
* for details of this service operation.
*/
/* Configure Home PLMN ID */
ogs_nas_to_plmn_id(
&amf_ue->home_plmn_id, &amf_ue->old_guti.nas_plmn_id);
int state = e->h.sbi.state;
bool serving_guami = false;
int i;
memcpy(&guami.plmn_id, &amf_ue->home_plmn_id,
sizeof(ogs_plmn_id_t));
memcpy(&guami.amf_id, &amf_ue->old_guti.amf_id,
sizeof(ogs_amf_id_t));
/* Compare all serving guamis with guami from UE's GUTI */
for (i = 0; i < amf_self()->num_of_served_guami; i++) {
if ((memcmp(&amf_self()->served_guami[i].amf_id,
&amf_ue->current.guti.amf_id,
sizeof(ogs_amf_id_t)) == 0) &&
(memcmp(&amf_self()->served_guami[i].plmn_id,
&amf_ue->current.guti.nas_plmn_id,
OGS_PLMN_ID_LEN) == 0)) {
ogs_sbi_discovery_option_set_guami(discovery_option, &guami);
serving_guami = true;
break;
}
}
if (!serving_guami) {
/* Guami from UE is not this AMF's serving guami - send UEContextTransfer */
ogs_sbi_discovery_option_t *discovery_option = NULL;
discovery_option = ogs_sbi_discovery_option_new();
ogs_assert(discovery_option);
memcpy(discovery_option->target_guami,
amf_ue->guami, sizeof(ogs_guami_t));
int r = amf_ue_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NAMF_COMM, discovery_option,
amf_namf_comm_build_ue_context_transfer,
amf_ue, state, nas_message);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
break;
}
r = amf_ue_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NAMF_COMM, discovery_option,
amf_namf_comm_build_ue_context_transfer,
amf_ue, state, nas_message);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
break;
}
if (!AMF_UE_HAVE_SUCI(amf_ue)) {

View file

@ -19,7 +19,7 @@
#include "namf-build.h"
static char* ogs_guti_to_string(amf_ue_t *amf_ue)
static char* ogs_guti_to_string(ogs_nas_5gs_guti_t *nas_guti)
{
ogs_plmn_id_t plmn_id;
char plmn_id_buff[OGS_PLMNIDSTRLEN];
@ -27,11 +27,13 @@ static char* ogs_guti_to_string(amf_ue_t *amf_ue)
char *tmsi = NULL;
char *guti = NULL;
memset(&plmn_id, 0, sizeof(plmn_id));
ogs_nas_to_plmn_id(&plmn_id, &amf_ue->current.guti.nas_plmn_id);
ogs_assert(nas_guti);
amf_id = ogs_amf_id_to_string(&amf_ue->current.guti.amf_id);
tmsi = ogs_uint32_to_0string(*(amf_ue->current.m_tmsi));
memset(&plmn_id, 0, sizeof(plmn_id));
ogs_nas_to_plmn_id(&plmn_id, &nas_guti->nas_plmn_id);
amf_id = ogs_amf_id_to_string(&nas_guti->amf_id);
tmsi = ogs_uint32_to_0string(nas_guti->m_tmsi);
guti = ogs_msprintf("5g-guti-%s%s%s",
ogs_plmn_id_to_string(&plmn_id, plmn_id_buff),
@ -56,7 +58,7 @@ static char* amf_ue_to_context_id(amf_ue_t *amf_ue)
if (amf_ue->supi) {
ue_context_id = ogs_strdup(amf_ue->supi);
} else {
ue_context_id = ogs_guti_to_string(amf_ue);
ue_context_id = ogs_guti_to_string(&amf_ue->old_guti);
}
return ue_context_id;
@ -83,11 +85,9 @@ ogs_sbi_request_t *amf_namf_comm_build_ue_context_transfer(
message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST;
message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NAMF_COMM;
message.h.api.version = (char *)OGS_SBI_API_V1;
message.h.resource.component[0] =
(char *)OGS_SBI_RESOURCE_NAME_UE_CONTEXTS;
message.h.resource.component[0] = (char *)OGS_SBI_RESOURCE_NAME_UE_CONTEXTS;
message.h.resource.component[1] = ue_context_id;
message.h.resource.component[2] =
(char *)OGS_SBI_RESOURCE_NAME_TRANSFER;
message.h.resource.component[2] = (char *)OGS_SBI_RESOURCE_NAME_TRANSFER;
message.UeContextTransferReqData = &UeContextTransferReqData;
request = ogs_sbi_build_request(&message);

View file

@ -1079,238 +1079,12 @@ cleanup:
}
static char *amf_namf_comm_base64_encode_ue_security_capability(
ogs_nas_ue_security_capability_t ue_security_capability)
{
char *enc = NULL;
int enc_len = 0;
char num_of_octets =
ue_security_capability.length +
sizeof(ue_security_capability.length) +
sizeof((uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_TYPE);
/* Security guarantee */
num_of_octets = ogs_min(
num_of_octets, sizeof(ue_security_capability) + 1);
/*
* size [sizeof(ue_security_capability) + 1] is a sum of lengths:
* ue_security_capability (9 octets) +
* type (1 octet)
*/
char security_octets_string[sizeof(ue_security_capability) + 1];
enc_len = ogs_base64_encode_len(num_of_octets);
enc = ogs_malloc(enc_len);
ogs_assert(enc);
memset(enc, 0, sizeof(*enc));
security_octets_string[0] =
(uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_TYPE;
memcpy(security_octets_string + 1, &ue_security_capability, num_of_octets);
ogs_base64_encode(enc , security_octets_string, num_of_octets);
return enc;
}
static char *amf_namf_comm_base64_encode_5gmm_capability(amf_ue_t *amf_ue)
{
ogs_nas_5gmm_capability_t nas_gmm_capability;
int enc_len = 0;
char *enc = NULL;
memset(&nas_gmm_capability, 0, sizeof(nas_gmm_capability));
/* 1 octet is mandatory, n.3 from TS 24.501 V16.12.0, 9.11.3.1 */
nas_gmm_capability.length = 1;
nas_gmm_capability.lte_positioning_protocol_capability =
amf_ue->gmm_capability.lte_positioning_protocol_capability;
nas_gmm_capability.ho_attach = amf_ue->gmm_capability.ho_attach;
nas_gmm_capability.s1_mode = amf_ue->gmm_capability.s1_mode;
uint8_t num_of_octets =
nas_gmm_capability.length +
sizeof(nas_gmm_capability.length) +
sizeof((uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_5GMM_CAPABILITY_TYPE);
/* Security guarantee. + 1 stands for 5GMM capability IEI */
num_of_octets = ogs_min(
num_of_octets, sizeof(ogs_nas_5gmm_capability_t) + 1);
char gmm_capability_octets_string[sizeof(ogs_nas_5gmm_capability_t) + 1];
enc_len = ogs_base64_encode_len(num_of_octets);
enc = ogs_malloc(enc_len);
ogs_assert(enc);
memset(enc, 0, sizeof(*enc));
/* Fill the bytes of data */
gmm_capability_octets_string[0] =
(uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_5GMM_CAPABILITY_TYPE;
memcpy(gmm_capability_octets_string + 1, &nas_gmm_capability, num_of_octets);
ogs_base64_encode(enc, gmm_capability_octets_string, num_of_octets);
return enc;
}
static OpenAPI_list_t *amf_namf_comm_encode_ue_session_context_list(amf_ue_t *amf_ue)
{
ogs_assert(amf_ue);
amf_sess_t *sess = NULL;
OpenAPI_list_t *PduSessionList = NULL;
OpenAPI_pdu_session_context_t *PduSessionContext = NULL;
OpenAPI_snssai_t *sNSSAI = NULL;
PduSessionList = OpenAPI_list_create();
ogs_assert(PduSessionList);
ogs_list_for_each(&amf_ue->sess_list, sess) {
PduSessionContext = ogs_calloc(1, sizeof(*PduSessionContext));
ogs_assert(PduSessionContext);
sNSSAI = ogs_calloc(1, sizeof(*sNSSAI));
ogs_assert(sNSSAI);
PduSessionContext->pdu_session_id = sess->psi;
PduSessionContext->sm_context_ref = sess->sm_context.ref;
sNSSAI->sst = sess->s_nssai.sst;
sNSSAI->sd = ogs_s_nssai_sd_to_string(sess->s_nssai.sd);
PduSessionContext->s_nssai = sNSSAI;
PduSessionContext->dnn = sess->dnn;
PduSessionContext->access_type = (OpenAPI_access_type_e)amf_ue->nas.access_type;
OpenAPI_list_add(PduSessionList, PduSessionContext);
}
return PduSessionList;
}
static OpenAPI_list_t *amf_namf_comm_encode_ue_mm_context_list(amf_ue_t *amf_ue)
{
OpenAPI_list_t *MmContextList = NULL;
OpenAPI_mm_context_t *MmContext = NULL;
int i;
ogs_assert(amf_ue);
MmContextList = OpenAPI_list_create();
ogs_assert(MmContextList);
MmContext = ogs_malloc(sizeof(*MmContext));
ogs_assert(MmContext);
memset(MmContext, 0, sizeof(*MmContext));
MmContext->access_type = (OpenAPI_access_type_e)amf_ue->nas.access_type;
if ((OpenAPI_ciphering_algorithm_e)amf_ue->selected_enc_algorithm &&
(OpenAPI_integrity_algorithm_e)amf_ue->selected_int_algorithm) {
OpenAPI_nas_security_mode_t *NasSecurityMode;
NasSecurityMode = ogs_calloc(1, sizeof(*NasSecurityMode));
ogs_assert(NasSecurityMode);
NasSecurityMode->ciphering_algorithm =
(OpenAPI_ciphering_algorithm_e)amf_ue->selected_enc_algorithm;
NasSecurityMode->integrity_algorithm =
(OpenAPI_integrity_algorithm_e)amf_ue->selected_int_algorithm;
MmContext->nas_security_mode = NasSecurityMode;
}
if (amf_ue->dl_count > 0) {
MmContext->is_nas_downlink_count = true;
MmContext->nas_downlink_count = amf_ue->dl_count;
}
if (amf_ue->ul_count.i32 > 0) {
MmContext->is_nas_uplink_count = true;
MmContext->nas_uplink_count = amf_ue->ul_count.i32;
}
if (amf_ue->ue_security_capability.length > 0) {
MmContext->ue_security_capability =
amf_namf_comm_base64_encode_ue_security_capability(
amf_ue->ue_security_capability);
}
if (amf_ue->allowed_nssai.num_of_s_nssai) {
OpenAPI_list_t *AllowedNssaiList;
OpenAPI_list_t *NssaiMappingList;
/* This IE shall be present if the source AMF and the target AMF are
* in the same PLMN and if available. When present, this IE shall
* contain the allowed NSSAI for the access type.
*/
AllowedNssaiList = OpenAPI_list_create();
/* This IE shall be present if the source AMF and the target AMF are
* in the same PLMN and if available. When present, this IE shall
* contain the mapping of the allowed NSSAI for the UE.
*/
NssaiMappingList = OpenAPI_list_create();
ogs_assert(AllowedNssaiList);
ogs_assert(NssaiMappingList);
for (i = 0; i < amf_ue->allowed_nssai.num_of_s_nssai; i++) {
OpenAPI_snssai_t *AllowedNssai;
AllowedNssai = ogs_calloc(1, sizeof(*AllowedNssai));
ogs_assert(AllowedNssai);
AllowedNssai->sst = amf_ue->allowed_nssai.s_nssai[i].sst;
AllowedNssai->sd = ogs_s_nssai_sd_to_string(
amf_ue->allowed_nssai.s_nssai[i].sd);
OpenAPI_list_add(AllowedNssaiList, AllowedNssai);
}
for (i = 0; i < amf_ue->allowed_nssai.num_of_s_nssai; i++) {
OpenAPI_nssai_mapping_t *NssaiMapping;
OpenAPI_snssai_t *HSnssai;
OpenAPI_snssai_t *MappedSnssai;
NssaiMapping = ogs_calloc(1, sizeof(*NssaiMapping));
ogs_assert(NssaiMapping);
/* Indicates the S-NSSAI in home PLMN */
HSnssai = ogs_calloc(1, sizeof(*HSnssai));
ogs_assert(HSnssai);
HSnssai->sst =
amf_ue->allowed_nssai.s_nssai[i].mapped_hplmn_sst;
HSnssai->sd =
ogs_s_nssai_sd_to_string(
amf_ue->allowed_nssai.s_nssai[i].mapped_hplmn_sd);
NssaiMapping->h_snssai = HSnssai;
/* Indicates the mapped S-NSSAI in the serving PLMN */
MappedSnssai = ogs_calloc(1, sizeof(*MappedSnssai));
ogs_assert(MappedSnssai);
/* MappedSnssai must be defined, else
"nssaiMappingList" will not convert to json*/
MappedSnssai->sst = 0;
MappedSnssai->sd = ogs_strdup("");
NssaiMapping->mapped_snssai = MappedSnssai;
OpenAPI_list_add(NssaiMappingList, NssaiMapping);
}
MmContext->allowed_nssai = AllowedNssaiList;
MmContext->nssai_mapping_list = NssaiMappingList;
}
OpenAPI_list_add(MmContextList, MmContext);
return MmContextList;
}
ogs_nas_ue_security_capability_t ue_security_capability);
static char *amf_namf_comm_base64_encode_5gmm_capability(amf_ue_t *amf_ue);
static OpenAPI_list_t *amf_namf_comm_encode_ue_session_context_list(
amf_ue_t *amf_ue);
static OpenAPI_list_t *amf_namf_comm_encode_ue_mm_context_list(
amf_ue_t *amf_ue);
int amf_namf_comm_handle_ue_context_transfer_request(
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
@ -1381,9 +1155,8 @@ int amf_namf_comm_handle_ue_context_transfer_request(
}
if ((amf_ue->ue_ambr.uplink > 0) || (amf_ue->ue_ambr.downlink > 0)) {
UeAmbr = ogs_malloc(sizeof(*UeAmbr));
UeAmbr = ogs_calloc(1, sizeof(*UeAmbr));
ogs_assert(UeAmbr);
memset(UeAmbr, 0, sizeof(*UeAmbr));
if (amf_ue->ue_ambr.uplink > 0)
UeAmbr->uplink = ogs_sbi_bitrate_to_string(
@ -1415,7 +1188,8 @@ int amf_namf_comm_handle_ue_context_transfer_request(
UeContext.seaf_data = &SeafData;
}
encoded_gmm_capability = amf_namf_comm_base64_encode_5gmm_capability(amf_ue);
encoded_gmm_capability =
amf_namf_comm_base64_encode_5gmm_capability(amf_ue);
UeContext._5g_mm_capability = encoded_gmm_capability;
pcf_nf_instance = OGS_SBI_GET_NF_INSTANCE(
@ -1435,7 +1209,8 @@ int amf_namf_comm_handle_ue_context_transfer_request(
if (recvmsg->UeContextTransferReqData->reason ==
OpenAPI_transfer_reason_MOBI_REG) {
SessionContextList = amf_namf_comm_encode_ue_session_context_list(amf_ue);
SessionContextList =
amf_namf_comm_encode_ue_session_context_list(amf_ue);
UeContext.session_context_list = SessionContextList;
}
@ -1447,6 +1222,7 @@ int amf_namf_comm_handle_ue_context_transfer_request(
if (encoded_gmm_capability)
ogs_free(encoded_gmm_capability);
if (UeAmbr)
OpenAPI_ambr_free(UeAmbr);
@ -1466,6 +1242,14 @@ int amf_namf_comm_handle_ue_context_transfer_request(
OpenAPI_list_free(MmContextList);
}
/*
* Context TRANSFERRED !!!
* So, we removed UE context.
*/
if (amf_ue->ran_ue)
ran_ue_remove(amf_ue->ran_ue);
amf_ue_remove(amf_ue);
return OGS_OK;
cleanup:
@ -1478,3 +1262,500 @@ cleanup:
return OGS_ERROR;
}
static ogs_nas_5gmm_capability_t
amf_namf_comm_base64_decode_5gmm_capability(char *encoded);
static ogs_nas_ue_security_capability_t
amf_namf_comm_base64_decode_ue_security_capability(char *encoded);
static void amf_namf_comm_decode_ue_mm_context_list(
amf_ue_t *amf_ue, OpenAPI_list_t *MmContextList);
static void amf_namf_comm_decode_ue_session_context_list(
amf_ue_t *amf_ue, OpenAPI_list_t *SessionContextList);
int amf_namf_comm_handle_ue_context_transfer_response(
ogs_sbi_message_t *recvmsg, amf_ue_t *amf_ue)
{
OpenAPI_ue_context_t *UeContext = NULL;
if (!recvmsg->UeContextTransferRspData) {
ogs_error("No UeContextTransferRspData");
return OGS_ERROR;
}
if (!recvmsg->UeContextTransferRspData->ue_context) {
ogs_error("No UE context");
return OGS_ERROR;
}
UeContext = recvmsg->UeContextTransferRspData->ue_context;
if (!UeContext->supi) {
ogs_error("No SUPI");
return OGS_ERROR;
}
amf_ue_set_supi(amf_ue, UeContext->supi);
if (!UeContext->supi_unauth_ind){
amf_ue->auth_result = OpenAPI_auth_result_AUTHENTICATION_SUCCESS;
}
if (UeContext->pei) {
if (amf_ue->pei)
ogs_free(amf_ue->pei);
amf_ue->pei = ogs_strdup(UeContext->pei);
}
if (UeContext->sub_ue_ambr) {
amf_ue->ue_ambr.downlink =
ogs_sbi_bitrate_from_string(UeContext->sub_ue_ambr->downlink);
amf_ue->ue_ambr.uplink =
ogs_sbi_bitrate_from_string(UeContext->sub_ue_ambr->uplink);
}
if (UeContext->seaf_data) {
if (UeContext->seaf_data->ng_ksi->tsc != OpenAPI_sc_type_NULL) {
amf_ue->nas.ue.tsc =
(UeContext->seaf_data->ng_ksi->tsc ==
OpenAPI_sc_type_NATIVE) ? 0 : 1;
amf_ue->nas.ue.ksi = (uint8_t)UeContext->seaf_data->ng_ksi->ksi;
ogs_ascii_to_hex(
UeContext->seaf_data->key_amf->key_val,
strlen(UeContext->seaf_data->key_amf->key_val),
amf_ue->kamf,
sizeof(amf_ue->kamf));
}
}
if (UeContext->_5g_mm_capability) {
ogs_nas_5gmm_capability_t gmm_capability;
gmm_capability = amf_namf_comm_base64_decode_5gmm_capability(
UeContext->_5g_mm_capability);
amf_ue->gmm_capability.lte_positioning_protocol_capability =
(bool)gmm_capability.lte_positioning_protocol_capability;
amf_ue->gmm_capability.ho_attach = (bool)gmm_capability.ho_attach;
amf_ue->gmm_capability.s1_mode = (bool)gmm_capability.s1_mode;
}
if (UeContext->pcf_id) {
/* TODO */
}
/* TODO UeContext->pcfAmPolicyUri */
/* TODO UeContext->pcfUePolicyUri */
if (UeContext->mm_context_list)
amf_namf_comm_decode_ue_mm_context_list(
amf_ue, UeContext->mm_context_list);
if (UeContext->session_context_list)
amf_namf_comm_decode_ue_session_context_list(
amf_ue, UeContext->session_context_list);
/* TODO ueRadioCapability */
return OGS_OK;
}
static char *amf_namf_comm_base64_encode_ue_security_capability(
ogs_nas_ue_security_capability_t ue_security_capability)
{
char *enc = NULL;
int enc_len = 0;
char num_of_octets =
ue_security_capability.length +
sizeof(ue_security_capability.length) +
sizeof((uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_TYPE);
/*
* size [sizeof(ue_security_capability) + 1] is a sum of lengths:
* ue_security_capability (9 octets) +
* type (1 octet)
*/
char security_octets_string[sizeof(ue_security_capability) + 1];
/* Security guarantee */
num_of_octets = ogs_min(
num_of_octets, sizeof(ue_security_capability) + 1);
enc_len = ogs_base64_encode_len(num_of_octets);
enc = ogs_calloc(1, enc_len);
ogs_assert(enc);
security_octets_string[0] = (uint8_t)
OGS_NAS_5GS_REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_TYPE;
memcpy(security_octets_string + 1, &ue_security_capability, num_of_octets);
ogs_base64_encode(enc , security_octets_string, num_of_octets);
return enc;
}
static char *amf_namf_comm_base64_encode_5gmm_capability(amf_ue_t *amf_ue)
{
ogs_nas_5gmm_capability_t nas_gmm_capability;
int enc_len = 0;
char *enc = NULL;
memset(&nas_gmm_capability, 0, sizeof(nas_gmm_capability));
/* 1 octet is mandatory, n.3 from TS 24.501 V16.12.0, 9.11.3.1 */
nas_gmm_capability.length = 1;
nas_gmm_capability.lte_positioning_protocol_capability =
amf_ue->gmm_capability.lte_positioning_protocol_capability;
nas_gmm_capability.ho_attach = amf_ue->gmm_capability.ho_attach;
nas_gmm_capability.s1_mode = amf_ue->gmm_capability.s1_mode;
uint8_t num_of_octets;
char gmm_capability_octets_string[sizeof(ogs_nas_5gmm_capability_t) + 1];
num_of_octets =
nas_gmm_capability.length +
sizeof(nas_gmm_capability.length) +
sizeof((uint8_t)
OGS_NAS_5GS_REGISTRATION_REQUEST_5GMM_CAPABILITY_TYPE);
/* Security guarantee. + 1 stands for 5GMM capability IEI */
num_of_octets = ogs_min(
num_of_octets, sizeof(ogs_nas_5gmm_capability_t) + 1);
enc_len = ogs_base64_encode_len(num_of_octets);
enc = ogs_calloc(1, enc_len);
ogs_assert(enc);
/* Fill the bytes of data */
gmm_capability_octets_string[0] =
(uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_5GMM_CAPABILITY_TYPE;
memcpy(gmm_capability_octets_string + 1,
&nas_gmm_capability, num_of_octets);
ogs_base64_encode(enc, gmm_capability_octets_string, num_of_octets);
return enc;
}
static OpenAPI_list_t *amf_namf_comm_encode_ue_session_context_list(
amf_ue_t *amf_ue)
{
ogs_assert(amf_ue);
amf_sess_t *sess = NULL;
OpenAPI_list_t *PduSessionList = NULL;
OpenAPI_pdu_session_context_t *PduSessionContext = NULL;
OpenAPI_snssai_t *sNSSAI = NULL;
PduSessionList = OpenAPI_list_create();
ogs_assert(PduSessionList);
ogs_list_for_each(&amf_ue->sess_list, sess) {
PduSessionContext = ogs_calloc(1, sizeof(*PduSessionContext));
ogs_assert(PduSessionContext);
sNSSAI = ogs_calloc(1, sizeof(*sNSSAI));
ogs_assert(sNSSAI);
PduSessionContext->pdu_session_id = sess->psi;
ogs_assert(sess->sm_context.resource_uri);
PduSessionContext->sm_context_ref =
ogs_strdup(sess->sm_context.resource_uri);
sNSSAI->sst = sess->s_nssai.sst;
sNSSAI->sd = ogs_s_nssai_sd_to_string(sess->s_nssai.sd);
PduSessionContext->s_nssai = sNSSAI;
ogs_assert(sess->dnn);
PduSessionContext->dnn = ogs_strdup(sess->dnn);
PduSessionContext->access_type =
(OpenAPI_access_type_e)amf_ue->nas.access_type;
OpenAPI_list_add(PduSessionList, PduSessionContext);
}
return PduSessionList;
}
static OpenAPI_list_t *amf_namf_comm_encode_ue_mm_context_list(amf_ue_t *amf_ue)
{
OpenAPI_list_t *MmContextList = NULL;
OpenAPI_mm_context_t *MmContext = NULL;
int i;
ogs_assert(amf_ue);
MmContextList = OpenAPI_list_create();
ogs_assert(MmContextList);
MmContext = ogs_malloc(sizeof(*MmContext));
ogs_assert(MmContext);
memset(MmContext, 0, sizeof(*MmContext));
MmContext->access_type = (OpenAPI_access_type_e)amf_ue->nas.access_type;
if ((OpenAPI_ciphering_algorithm_e)amf_ue->selected_enc_algorithm &&
(OpenAPI_integrity_algorithm_e)amf_ue->selected_int_algorithm) {
OpenAPI_nas_security_mode_t *NasSecurityMode;
NasSecurityMode = ogs_calloc(1, sizeof(*NasSecurityMode));
ogs_assert(NasSecurityMode);
NasSecurityMode->ciphering_algorithm =
(OpenAPI_ciphering_algorithm_e)amf_ue->selected_enc_algorithm;
NasSecurityMode->integrity_algorithm =
(OpenAPI_integrity_algorithm_e)amf_ue->selected_int_algorithm;
MmContext->nas_security_mode = NasSecurityMode;
}
if (amf_ue->dl_count > 0) {
MmContext->is_nas_downlink_count = true;
MmContext->nas_downlink_count = amf_ue->dl_count;
}
if (amf_ue->ul_count.i32 > 0) {
MmContext->is_nas_uplink_count = true;
MmContext->nas_uplink_count = amf_ue->ul_count.i32;
}
if (amf_ue->ue_security_capability.length > 0) {
MmContext->ue_security_capability =
amf_namf_comm_base64_encode_ue_security_capability(
amf_ue->ue_security_capability);
}
if (amf_ue->allowed_nssai.num_of_s_nssai) {
OpenAPI_list_t *AllowedNssaiList;
/* This IE shall be present if the source AMF and the target AMF are
* in the same PLMN and if available. When present, this IE shall
* contain the allowed NSSAI for the access type.
*/
AllowedNssaiList = OpenAPI_list_create();
ogs_assert(AllowedNssaiList);
for (i = 0; i < amf_ue->allowed_nssai.num_of_s_nssai; i++) {
OpenAPI_snssai_t *AllowedNssai;
AllowedNssai = ogs_calloc(1, sizeof(*AllowedNssai));
ogs_assert(AllowedNssai);
AllowedNssai->sst = amf_ue->allowed_nssai.s_nssai[i].sst;
AllowedNssai->sd = ogs_s_nssai_sd_to_string(
amf_ue->allowed_nssai.s_nssai[i].sd);
OpenAPI_list_add(AllowedNssaiList, AllowedNssai);
}
MmContext->allowed_nssai = AllowedNssaiList;
}
OpenAPI_list_add(MmContextList, MmContext);
return MmContextList;
}
static ogs_nas_5gmm_capability_t
amf_namf_comm_base64_decode_5gmm_capability(char *encoded)
{
ogs_nas_5gmm_capability_t gmm_capability;
char *gmm_capability_octets_string = NULL;
uint8_t gmm_capability_iei = 0;
int len;
memset(&gmm_capability, 0, sizeof(gmm_capability));
gmm_capability_octets_string =
(char*) ogs_calloc(sizeof(gmm_capability) + 1, sizeof(char));
ogs_assert(gmm_capability_octets_string);
len = ogs_base64_decode(gmm_capability_octets_string, encoded);
if (len == 0)
ogs_error("Gmm capability not decoded");
ogs_assert(sizeof(gmm_capability_octets_string) <=
sizeof(gmm_capability) + 1);
gmm_capability_iei = // not copied anywhere for now
gmm_capability_octets_string[0];
if (gmm_capability_iei !=
OGS_NAS_5GS_REGISTRATION_REQUEST_5GMM_CAPABILITY_TYPE) {
ogs_error("Type of 5GMM capability IEI is incorrect");
}
memcpy(&gmm_capability,
gmm_capability_octets_string + 1,
sizeof(gmm_capability));
if (gmm_capability_octets_string) {
ogs_free(gmm_capability_octets_string);
}
return gmm_capability;
}
static ogs_nas_ue_security_capability_t
amf_namf_comm_base64_decode_ue_security_capability(char *encoded)
{
ogs_nas_ue_security_capability_t ue_security_capability;
char *ue_security_capability_octets_string = NULL;
uint8_t ue_security_capability_iei = 0;
memset(&ue_security_capability, 0, sizeof(ue_security_capability));
ue_security_capability_octets_string =
(char*) ogs_calloc(sizeof(ue_security_capability), sizeof(char));
ogs_assert(ue_security_capability_octets_string);
ogs_base64_decode(ue_security_capability_octets_string, encoded);
ogs_assert(sizeof(ue_security_capability_octets_string) <=
sizeof(ogs_nas_ue_security_capability_t) + 1);
ue_security_capability_iei = // not copied anywhere for now
ue_security_capability_octets_string[0];
if (ue_security_capability_iei !=
OGS_NAS_5GS_REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_TYPE) {
ogs_error("UE security capability IEI is incorrect");
}
memcpy(&ue_security_capability, ue_security_capability_octets_string + 1,
sizeof(ue_security_capability));
if (ue_security_capability_octets_string) {
ogs_free(ue_security_capability_octets_string);
}
return ue_security_capability;
}
static void amf_namf_comm_decode_ue_mm_context_list(
amf_ue_t *amf_ue, OpenAPI_list_t *MmContextList) {
OpenAPI_lnode_t *node = NULL;
OpenAPI_list_for_each(MmContextList, node) {
OpenAPI_mm_context_t *MmContext = NULL;
OpenAPI_list_t *AllowedNssaiList = NULL;
OpenAPI_lnode_t *node1 = NULL;
OpenAPI_list_t *NssaiMappingList = NULL;
int num_of_s_nssai = 0;
int num_of_nssai_mapping = 0;
MmContext = node->data;
AllowedNssaiList = MmContext->allowed_nssai;
NssaiMappingList = MmContext->nssai_mapping_list;
OpenAPI_list_for_each(AllowedNssaiList, node1) {
OpenAPI_snssai_t *AllowedNssai = node1->data;
ogs_assert(num_of_s_nssai < OGS_MAX_NUM_OF_SLICE);
amf_ue->allowed_nssai.s_nssai[num_of_s_nssai].sst =
(uint8_t)AllowedNssai->sst;
amf_ue->allowed_nssai.s_nssai[num_of_s_nssai].sd =
ogs_s_nssai_sd_from_string(AllowedNssai->sd);
num_of_s_nssai++;
amf_ue->allowed_nssai.num_of_s_nssai = num_of_s_nssai;
}
OpenAPI_list_for_each(NssaiMappingList, node1) {
OpenAPI_nssai_mapping_t *NssaiMapping = node1->data;
OpenAPI_snssai_t *HSnssai = NssaiMapping->h_snssai;
ogs_assert(num_of_nssai_mapping < OGS_MAX_NUM_OF_SLICE);
amf_ue->allowed_nssai.s_nssai[num_of_nssai_mapping].
mapped_hplmn_sst = HSnssai->sst;
amf_ue->allowed_nssai.s_nssai[num_of_nssai_mapping].
mapped_hplmn_sd = ogs_s_nssai_sd_from_string(HSnssai->sd);
num_of_nssai_mapping++;
}
if (MmContext->ue_security_capability) {
amf_ue->ue_security_capability =
amf_namf_comm_base64_decode_ue_security_capability(
MmContext->ue_security_capability);
}
}
}
static void amf_namf_comm_decode_ue_session_context_list(
amf_ue_t *amf_ue, OpenAPI_list_t *SessionContextList)
{
OpenAPI_lnode_t *node = NULL;
OpenAPI_list_for_each(SessionContextList, node) {
OpenAPI_pdu_session_context_t *PduSessionContext;
PduSessionContext = node->data;
amf_sess_t *sess = NULL;
int rv;
ogs_sbi_message_t message;
ogs_sbi_header_t header;
if (!PduSessionContext->sm_context_ref) {
ogs_error("No smContextRef [PSI:%d]",
PduSessionContext->pdu_session_id);
continue;
}
if (!PduSessionContext->s_nssai) {
ogs_error("No sNSSI [PSI:%d]", PduSessionContext->pdu_session_id);
continue;
}
if (!PduSessionContext->dnn) {
ogs_error("No DNN [PSI:%d]", PduSessionContext->pdu_session_id);
continue;
}
if (!PduSessionContext->access_type) {
ogs_error("No accessType [PSI:%d]",
PduSessionContext->pdu_session_id);
continue;
}
memset(&header, 0, sizeof(header));
header.uri = PduSessionContext->sm_context_ref;
rv = ogs_sbi_parse_header(&message, &header);
if (rv != OGS_OK) {
ogs_error("[%d] Cannot parse sm_context_ref [%s]",
PduSessionContext->pdu_session_id,
PduSessionContext->sm_context_ref);
continue;
}
if (!message.h.resource.component[1]) {
ogs_error("[%d] No SmContextRef [%s]",
PduSessionContext->pdu_session_id,
PduSessionContext->sm_context_ref);
ogs_sbi_header_free(&header);
continue;
}
sess = amf_sess_add(amf_ue, PduSessionContext->pdu_session_id);
ogs_assert(sess);
sess->sm_context.resource_uri =
ogs_strdup(PduSessionContext->sm_context_ref);
sess->sm_context.ref =
ogs_strdup(message.h.resource.component[1]);
memset(&sess->s_nssai, 0, sizeof(sess->s_nssai));
sess->s_nssai.sst = PduSessionContext->s_nssai->sst;
sess->s_nssai.sd = ogs_s_nssai_sd_from_string(
PduSessionContext->s_nssai->sd);
sess->dnn = ogs_strdup(PduSessionContext->dnn);
amf_ue->nas.access_type = (int)PduSessionContext->access_type;
ogs_sbi_header_free(&header);
}
}

View file

@ -46,8 +46,18 @@ ogs_sbi_request_t *amf_nausf_auth_build_authenticate(
memset(&AuthenticationInfo, 0, sizeof(AuthenticationInfo));
ogs_assert(amf_ue->suci);
AuthenticationInfo.supi_or_suci = amf_ue->suci;
if (amf_ue->suci)
AuthenticationInfo.supi_or_suci = amf_ue->suci;
else
AuthenticationInfo.supi_or_suci = amf_ue->supi;
if (!AuthenticationInfo.supi_or_suci) {
ogs_error("No SUPI[%s] or SUCI[%s]",
amf_ue->supi ? amf_ue->supi : "NULL",
amf_ue->suci ? amf_ue->suci : "NULL");
goto end;
}
AuthenticationInfo.serving_network_name =
ogs_serving_network_name_from_plmn_id(&amf_ue->nr_tai.plmn_id);
if (!AuthenticationInfo.serving_network_name) {

View file

@ -125,7 +125,7 @@ void ausf_state_operational(ogs_fsm_t *s, ausf_event_t *e)
CASE(OGS_SBI_HTTP_METHOD_POST)
if (message.AuthenticationInfo &&
message.AuthenticationInfo->supi_or_suci) {
ausf_ue = ausf_ue_find_by_suci(
ausf_ue = ausf_ue_find_by_suci_or_supi(
message.AuthenticationInfo->supi_or_suci);
if (!ausf_ue) {
ausf_ue = ausf_ue_add(

View file

@ -835,12 +835,12 @@ bool nrf_nnrf_handle_nf_discover(
&discovery_option->tai.plmn_id),
discovery_option->tai.tac.v);
}
if (discovery_option->target_guami) {
if (discovery_option->guami_presence) {
ogs_debug("guami[PLMN_ID:%06x,AMF_ID:%x]",
ogs_plmn_id_hexdump(
&discovery_option->target_guami->plmn_id),
&discovery_option->guami.plmn_id),
ogs_amf_id_hexdump(
&discovery_option->target_guami->amf_id));
&discovery_option->guami.amf_id));
}
if (discovery_option->num_of_target_plmn_list) {
for (i = 0; i < discovery_option->num_of_target_plmn_list; i++)

View file

@ -233,6 +233,9 @@ static int request_handler(ogs_sbi_request_t *request, void *data)
} else if (!strcasecmp(key, OGS_SBI_CUSTOM_DISCOVERY_TAI)) {
if (val)
ogs_sbi_discovery_option_parse_tai(discovery_option, val);
} else if (!strcasecmp(key, OGS_SBI_CUSTOM_DISCOVERY_GUAMI)) {
if (val)
ogs_sbi_discovery_option_parse_guami(discovery_option, val);
} else if (!strcasecmp(key, OGS_SBI_CUSTOM_DISCOVERY_TARGET_PLMN_LIST)) {
if (val)
discovery_option->num_of_target_plmn_list =

View file

@ -497,7 +497,7 @@ static void test1_func(abts_case *tc, void *data)
static void test2_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *ngap;
ogs_socknode_t *ngap, *ngap2;
ogs_socknode_t *gtpu;
ogs_pkbuf_t *gmmbuf;
ogs_pkbuf_t *gsmbuf;
@ -539,7 +539,7 @@ static void test2_func(abts_case *tc, void *data)
test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc";
test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca";
/* gNB connects to AMF */
/* gNB connects to AMF(default configuration) */
ngap = testngap_client(AF_INET);
ABTS_PTR_NOTNULL(tc, ngap);
@ -1517,14 +1517,499 @@ static void test4_issues2839_func(abts_case *tc, void *data)
test_ue_remove(test_ue);
}
#define CONTEXT_TRANSFER_TEST 0
#define OLD_AMF_NOT_FOUND 0
#if CONTEXT_TRANSFER_TEST
static void context_transfer_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *ngap, *ngap2;
ogs_socknode_t *gtpu;
ogs_pkbuf_t *gmmbuf;
ogs_pkbuf_t *gsmbuf;
ogs_pkbuf_t *nasbuf;
ogs_pkbuf_t *sendbuf;
ogs_pkbuf_t *recvbuf;
ogs_ngap_message_t message;
int i;
ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci;
test_ue_t *test_ue = NULL;
test_sess_t *sess = NULL;
test_bearer_t *qos_flow = NULL;
bson_t *doc = NULL;
/* Setup Test UE & Session Context */
memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci));
mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI;
mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI;
mobile_identity_suci.routing_indicator1 = 0;
mobile_identity_suci.routing_indicator2 = 0xf;
mobile_identity_suci.routing_indicator3 = 0xf;
mobile_identity_suci.routing_indicator4 = 0xf;
mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL;
mobile_identity_suci.home_network_pki_value = 0;
test_ue = test_ue_add_by_suci(&mobile_identity_suci, "0000203190");
ogs_assert(test_ue);
test_ue->nr_cgi.cell_id = 0x40001;
test_ue->nas.registration.tsc = 0;
test_ue->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE;
test_ue->nas.registration.follow_on_request = 1;
test_ue->nas.registration.value = OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL;
test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc";
test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca";
/* gNB connects to AMF(default configuration) */
ngap = testngap_client(AF_INET);
ABTS_PTR_NOTNULL(tc, ngap);
/* gNB connects to AMF(127.0.1.5) */
ngap2 = testsctp_client("127.0.1.5", OGS_NGAP_SCTP_PORT);
ABTS_PTR_NOTNULL(tc, ngap2);
/* gNB connects to UPF */
gtpu = test_gtpu_server(1, AF_INET);
ABTS_PTR_NOTNULL(tc, gtpu);
/* Send NG-Setup Reqeust */
sendbuf = testngap_build_ng_setup_request(0x4000, 22);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive NG-Setup Response */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send NG-Setup Reqeust */
sendbuf = testngap_build_ng_setup_request(0x4000, 22);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive NG-Setup Response */
recvbuf = testgnb_ngap_read(ngap2);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/********** Insert Subscriber in Database */
doc = test_db_new_simple(test_ue);
ABTS_PTR_NOTNULL(tc, doc);
ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc));
/* Send Registration request */
test_ue->registration_request_param.guti = 1;
gmmbuf = testgmm_build_registration_request(test_ue, NULL, false, false);
ABTS_PTR_NOTNULL(tc, gmmbuf);
test_ue->registration_request_param.gmm_capability = 1;
test_ue->registration_request_param.s1_ue_network_capability = 1;
test_ue->registration_request_param.requested_nssai = 1;
test_ue->registration_request_param.last_visited_registered_tai = 1;
test_ue->registration_request_param.ue_usage_setting = 1;
nasbuf = testgmm_build_registration_request(test_ue, NULL, false, false);
ABTS_PTR_NOTNULL(tc, nasbuf);
sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf,
NGAP_RRCEstablishmentCause_mo_Signalling, false, true);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Identity request */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Identity response */
gmmbuf = testgmm_build_identity_response(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Authentication request */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Authentication response */
gmmbuf = testgmm_build_authentication_response(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Security mode command */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Security mode complete */
gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive InitialContextSetupRequest +
* Registration accept */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_InitialContextSetup,
test_ue->ngap_procedure_code);
/* Send UERadioCapabilityInfoIndication */
sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send InitialContextSetupResponse */
sendbuf = testngap_build_initial_context_setup_response(test_ue, false);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Registration complete */
gmmbuf = testgmm_build_registration_complete(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Configuration update command */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send PDU session establishment request */
sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5);
ogs_assert(sess);
sess->ul_nas_transport_param.request_type =
OGS_NAS_5GS_REQUEST_TYPE_INITIAL;
sess->ul_nas_transport_param.dnn = 1;
sess->ul_nas_transport_param.s_nssai = 1;
sess->pdu_session_establishment_param.ssc_mode = 1;
sess->pdu_session_establishment_param.epco = 1;
gsmbuf = testgsm_build_pdu_session_establishment_request(sess);
ABTS_PTR_NOTNULL(tc, gsmbuf);
gmmbuf = testgmm_build_ul_nas_transport(sess,
OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive PDUSessionResourceSetupRequest +
* DL NAS transport +
* PDU session establishment accept */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_PDUSessionResourceSetup,
test_ue->ngap_procedure_code);
/* Send GTP-U ICMP Packet */
qos_flow = test_qos_flow_find_by_qfi(sess, 1);
ogs_assert(qos_flow);
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send PDUSessionResourceSetupResponse */
sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = testgnb_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = testgnb_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send GTP-U Router Solicitation */
rv = test_gtpu_send_slacc_rs(gtpu, qos_flow);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U Router Advertisement */
recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
testgtpu_recv(test_ue, recvbuf);
#if !defined(__FreeBSD__)
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV6);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
#endif
ogs_msleep(300);
/* Send Registration request
* - Update Registration request type
* - Uplink Data Status */
test_ue->nas.registration.value =
OGS_NAS_5GS_REGISTRATION_TYPE_MOBILITY_UPDATING;
test_ue->registration_request_param.uplink_data_status = 1;
test_ue->registration_request_param.psimask.uplink_data_status =
1 << sess->psi;
nasbuf = testgmm_build_registration_request(test_ue, NULL, false, false);
ABTS_PTR_NOTNULL(tc, nasbuf);
memset(&test_ue->registration_request_param, 0,
sizeof(test_ue->registration_request_param));
test_ue->registration_request_param.guti = 1;
#if OLD_AMF_NOT_FOUND
test_ue->nas_5gs_guti.amf_id.pointer = 2;
#endif
gmmbuf = testgmm_build_registration_request(test_ue, NULL, true, false);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf,
NGAP_RRCEstablishmentCause_mo_Signalling, true, true);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
#if OLD_AMF_NOT_FOUND
/* Receive Identity request */
recvbuf = testgnb_ngap_read(ngap2);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Identity response */
gmmbuf = testgmm_build_identity_response(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
#endif
/* Receive Authentication request */
recvbuf = testgnb_ngap_read(ngap2);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Authentication response */
gmmbuf = testgmm_build_authentication_response(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Security mode command */
recvbuf = testgnb_ngap_read(ngap2);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Security mode complete */
gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive InitialContextSetupRequest +
* Registration accept */
recvbuf = testgnb_ngap_read(ngap2);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_InitialContextSetup,
test_ue->ngap_procedure_code);
/* Send UERadioCapabilityInfoIndication */
sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send InitialContextSetupResponse */
sendbuf = testngap_build_initial_context_setup_response(test_ue, false);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Registration complete */
gmmbuf = testgmm_build_registration_complete(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Configuration update command */
recvbuf = testgnb_ngap_read(ngap2);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send PDU session establishment request */
sess = test_sess_find_by_psi(test_ue, 5);
ogs_assert(sess);
sess->ul_nas_transport_param.request_type =
OGS_NAS_5GS_REQUEST_TYPE_INITIAL;
sess->ul_nas_transport_param.dnn = 1;
sess->ul_nas_transport_param.s_nssai = 0;
sess->pdu_session_establishment_param.ssc_mode = 1;
sess->pdu_session_establishment_param.epco = 1;
gsmbuf = testgsm_build_pdu_session_establishment_request(sess);
ABTS_PTR_NOTNULL(tc, gsmbuf);
gmmbuf = testgmm_build_ul_nas_transport(sess,
OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive PDUSessionResourceSetupRequest +
* DL NAS transport +
* PDU session establishment accept */
recvbuf = testgnb_ngap_read(ngap2);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_PDUSessionResourceSetup,
test_ue->ngap_procedure_code);
/* Send GTP-U ICMP Packet */
qos_flow = test_qos_flow_find_by_qfi(sess, 1);
ogs_assert(qos_flow);
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send PDUSessionResourceSetupResponse */
sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = testgnb_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = testgnb_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send GTP-U Router Solicitation */
rv = test_gtpu_send_slacc_rs(gtpu, qos_flow);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U Router Advertisement */
recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
testgtpu_recv(test_ue, recvbuf);
#if !defined(__FreeBSD__)
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV6);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
#endif
/* Send UEContextReleaseRequest */
sendbuf = testngap_build_ue_context_release_request(test_ue,
NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity,
true);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive UEContextReleaseCommand */
recvbuf = testgnb_ngap_read(ngap2);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_UEContextRelease,
test_ue->ngap_procedure_code);
/* Send UEContextReleaseComplete */
sendbuf = testngap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap2, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
ogs_msleep(300);
/********** Remove Subscriber in Database */
ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue));
/* gNB disonncect from UPF */
testgnb_gtpu_close(gtpu);
/* gNB disonncect from AMF(127.0.1.5) */
testgnb_ngap_close(ngap2);
/* gNB disonncect from AMF */
testgnb_ngap_close(ngap);
/* Clear Test UE Context */
test_ue_remove(test_ue);
}
#endif
abts_suite *test_guti(abts_suite *suite)
{
suite = ADD_SUITE(suite)
#if !CONTEXT_TRANSFER_TEST
abts_run_test(suite, test1_func, NULL);
abts_run_test(suite, test2_func, NULL);
abts_run_test(suite, test3_func, NULL);
abts_run_test(suite, test4_issues2839_func, NULL);
#else
abts_run_test(suite, context_transfer_func, NULL);
#endif
return suite;
}