diff --git a/lib/nas/5gs/types.c b/lib/nas/5gs/types.c index cf576a64c..f8a049deb 100644 --- a/lib/nas/5gs/types.c +++ b/lib/nas/5gs/types.c @@ -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; -} diff --git a/lib/nas/5gs/types.h b/lib/nas/5gs/types.h index 8262f616b..cc35611db 100644 --- a/lib/nas/5gs/types.h +++ b/lib/nas/5gs/types.h @@ -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 diff --git a/lib/sbi/context.c b/lib/sbi/context.c index 9f3d3e8c2..12ab90234 100644 --- a/lib/sbi/context.c +++ b/lib/sbi/context.c @@ -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: diff --git a/lib/sbi/message.c b/lib/sbi/message.c index 07f5ce309..322ca594b 100644 --- a/lib/sbi/message.c +++ b/lib/sbi/message.c @@ -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]", diff --git a/lib/sbi/message.h b/lib/sbi/message.h index 7f5cd9109..281066bab 100644 --- a/lib/sbi/message.h +++ b/lib/sbi/message.h @@ -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( diff --git a/lib/sbi/path.c b/lib/sbi/path.c index 11462873e..76ff33d3a 100644 --- a/lib/sbi/path.c +++ b/lib/sbi/path.c @@ -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 && diff --git a/src/amf/context.c b/src/amf/context.c index c6ba6f387..57a19aea3 100644 --- a/src/amf/context.c +++ b/src/amf/context.c @@ -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; diff --git a/src/amf/context.h b/src/amf/context.h index 4b3ab39e4..b61fce88b 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -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; diff --git a/src/amf/gmm-handler.c b/src/amf/gmm-handler.c index 790326edc..d8a734c61 100644 --- a/src/amf/gmm-handler.c +++ b/src/amf/gmm-handler.c @@ -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 = ®istration_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; diff --git a/src/amf/gmm-handler.h b/src/amf/gmm-handler.h index 3e735aa9e..f750b86bd 100644 --- a/src/amf/gmm-handler.h +++ b/src/amf/gmm-handler.h @@ -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, diff --git a/src/amf/gmm-sm.c b/src/amf/gmm-sm.c index 69e1f85e3..3832d44a7 100644 --- a/src/amf/gmm-sm.c +++ b/src/amf/gmm-sm.c @@ -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 = ®istration_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)) { diff --git a/src/amf/namf-build.c b/src/amf/namf-build.c index 72d423de6..ca6c46c9d 100644 --- a/src/amf/namf-build.c +++ b/src/amf/namf-build.c @@ -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); diff --git a/src/amf/namf-handler.c b/src/amf/namf-handler.c index c6d63ac46..e31c313db 100644 --- a/src/amf/namf-handler.c +++ b/src/amf/namf-handler.c @@ -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); + } +} diff --git a/src/amf/nausf-build.c b/src/amf/nausf-build.c index f3d69bf17..5330744bc 100644 --- a/src/amf/nausf-build.c +++ b/src/amf/nausf-build.c @@ -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) { diff --git a/src/ausf/ausf-sm.c b/src/ausf/ausf-sm.c index f17bb4348..a6ac432c2 100644 --- a/src/ausf/ausf-sm.c +++ b/src/ausf/ausf-sm.c @@ -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( diff --git a/src/nrf/nnrf-handler.c b/src/nrf/nnrf-handler.c index 593cfeb10..5dc81ef20 100644 --- a/src/nrf/nnrf-handler.c +++ b/src/nrf/nnrf-handler.c @@ -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++) diff --git a/src/scp/sbi-path.c b/src/scp/sbi-path.c index 98f0a233b..9c6eb6aea 100644 --- a/src/scp/sbi-path.c +++ b/src/scp/sbi-path.c @@ -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 = diff --git a/tests/registration/guti-test.c b/tests/registration/guti-test.c index c3c536e39..54065d16c 100644 --- a/tests/registration/guti-test.c +++ b/tests/registration/guti-test.c @@ -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; }