forked from acouzens/open5gs
UE context transfer (#3052)
* [SBI] Handle and store AMF info * [SBI] Add "target GUAMI" discovery option * [SBI] Handle UeContextTransfer request and response messages * [AMF] Handle NF discovery from AMF to AMF * [AMF] Add UE Context Transfer Request/Response from AMF to AMF * [SCP] Handle UeContextTransfer * Follow-up on #3052 * [AMF] force authentication after 'Ue context transfer' for now * [AMF] force authentication after 'Ue context transfer' for now --------- Co-authored-by: Sukchan Lee <acetcom@gmail.com>
This commit is contained in:
parent
ea122da9fc
commit
e1820e4e54
|
@ -968,3 +968,21 @@ int ogs_nas_parse_qos_rules(
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1192,6 +1192,8 @@ 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
|
||||
|
|
|
@ -85,6 +85,8 @@ extern "C" {
|
|||
|
||||
#define OGS_MAX_NUM_OF_ALGORITHM 8
|
||||
|
||||
#define OGS_MAX_5G_GUTI_LEN 28
|
||||
|
||||
#define OGS_MAX_NUM_OF_SERVED_GUMMEI 8 /* maxnoofRATs: 8 */
|
||||
#define OGS_MAX_NUM_OF_SERVED_GUAMI 256 /* maxnoofServedGUAMIs: 256 */
|
||||
#define OGS_MAX_NUM_OF_SUPPORTED_TA 256 /* maxnoofTACs: 256 */
|
||||
|
@ -271,10 +273,11 @@ ogs_amf_id_t *ogs_amf_id_build(ogs_amf_id_t *amf_id,
|
|||
#define OGS_PROTECTION_SCHEME_PROFILE_B 2
|
||||
|
||||
/************************************
|
||||
* SUPI/GPSI */
|
||||
* SUPI/GPSI/GUTI */
|
||||
#define OGS_ID_SUPI_TYPE_IMSI "imsi"
|
||||
#define OGS_ID_GPSI_TYPE_MSISDN "msisdn"
|
||||
#define OGS_ID_SUPI_TYPE_IMEISV "imeisv"
|
||||
#define OGS_ID_5G_GUTI_TYPE "5g-guti"
|
||||
char *ogs_id_get_type(const char *str);
|
||||
char *ogs_id_get_value(const char *str);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ static OGS_POOL(xact_pool, ogs_sbi_xact_t);
|
|||
static OGS_POOL(subscription_spec_pool, ogs_sbi_subscription_spec_t);
|
||||
static OGS_POOL(subscription_data_pool, ogs_sbi_subscription_data_t);
|
||||
static OGS_POOL(smf_info_pool, ogs_sbi_smf_info_t);
|
||||
static OGS_POOL(amf_info_pool, ogs_sbi_amf_info_t);
|
||||
static OGS_POOL(nf_info_pool, ogs_sbi_nf_info_t);
|
||||
|
||||
void ogs_sbi_context_init(OpenAPI_nf_type_e nf_type)
|
||||
|
@ -61,6 +62,7 @@ void ogs_sbi_context_init(OpenAPI_nf_type_e nf_type)
|
|||
ogs_pool_init(&subscription_data_pool, ogs_app()->pool.subscription);
|
||||
|
||||
ogs_pool_init(&smf_info_pool, ogs_app()->pool.nf);
|
||||
ogs_pool_init(&amf_info_pool, ogs_app()->pool.nf);
|
||||
|
||||
ogs_pool_init(&nf_info_pool, ogs_app()->pool.nf * OGS_MAX_NUM_OF_NF_INFO);
|
||||
|
||||
|
@ -107,6 +109,7 @@ void ogs_sbi_context_final(void)
|
|||
ogs_pool_final(&nf_instance_pool);
|
||||
ogs_pool_final(&nf_service_pool);
|
||||
ogs_pool_final(&smf_info_pool);
|
||||
ogs_pool_final(&amf_info_pool);
|
||||
|
||||
ogs_pool_final(&nf_info_pool);
|
||||
|
||||
|
@ -1530,7 +1533,13 @@ ogs_sbi_nf_info_t *ogs_sbi_nf_info_add(
|
|||
|
||||
static void amf_info_free(ogs_sbi_amf_info_t *amf_info)
|
||||
{
|
||||
/* Nothing */
|
||||
ogs_assert(amf_info);
|
||||
|
||||
amf_info->num_of_guami = 0;
|
||||
amf_info->num_of_nr_tai = 0;
|
||||
amf_info->num_of_nr_tai_range = 0;
|
||||
|
||||
ogs_pool_free(&amf_info_pool, amf_info);
|
||||
}
|
||||
|
||||
static void smf_info_free(ogs_sbi_smf_info_t *smf_info)
|
||||
|
@ -1621,6 +1630,26 @@ ogs_sbi_nf_info_t *ogs_sbi_nf_info_find(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool ogs_sbi_check_amf_info_guami(
|
||||
ogs_sbi_amf_info_t *amf_info, ogs_guami_t *guami)
|
||||
{
|
||||
int i;
|
||||
|
||||
ogs_assert(amf_info);
|
||||
ogs_assert(guami);
|
||||
|
||||
for (i = 0; i < amf_info->num_of_guami; i++) {
|
||||
if ((memcmp(&amf_info->guami[i].amf_id, &guami->amf_id,
|
||||
sizeof(ogs_amf_id_t)) == 0) &&
|
||||
(memcmp(&amf_info->guami[i].plmn_id, &guami->plmn_id,
|
||||
OGS_PLMN_ID_LEN) == 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ogs_sbi_check_smf_info_slice(
|
||||
ogs_sbi_smf_info_t *smf_info, ogs_s_nssai_t *s_nssai, char *dnn)
|
||||
{
|
||||
|
@ -1964,6 +1993,13 @@ 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 &&
|
||||
ogs_sbi_check_amf_info_guami(&nf_info->amf,
|
||||
discovery_option->target_guami) == false)
|
||||
return false;
|
||||
break;
|
||||
case OpenAPI_nf_type_SMF:
|
||||
if (discovery_option->num_of_snssais && discovery_option->dnn &&
|
||||
ogs_sbi_check_smf_info_slice(&nf_info->smf,
|
||||
|
|
|
@ -341,8 +341,8 @@ typedef struct ogs_sbi_sepp_info_s {
|
|||
} ogs_sbi_sepp_info_t;
|
||||
|
||||
typedef struct ogs_sbi_amf_info_s {
|
||||
int amf_set_id;
|
||||
int amf_region_id;
|
||||
uint8_t amf_set_id;
|
||||
uint16_t amf_region_id;
|
||||
|
||||
int num_of_guami;
|
||||
ogs_guami_t guami[OGS_MAX_NUM_OF_SERVED_GUAMI];
|
||||
|
@ -437,6 +437,8 @@ void ogs_sbi_nf_info_remove_all(ogs_list_t *list);
|
|||
ogs_sbi_nf_info_t *ogs_sbi_nf_info_find(
|
||||
ogs_list_t *list, OpenAPI_nf_type_e nf_type);
|
||||
|
||||
bool ogs_sbi_check_amf_info_guami(
|
||||
ogs_sbi_amf_info_t *amf_info, ogs_guami_t *guami);
|
||||
bool ogs_sbi_check_smf_info_slice(
|
||||
ogs_sbi_smf_info_t *smf_info, ogs_s_nssai_t *s_nssai, char *dnn);
|
||||
bool ogs_sbi_check_smf_info_tai(
|
||||
|
|
|
@ -189,6 +189,10 @@ void ogs_sbi_message_free(ogs_sbi_message_t *message)
|
|||
OpenAPI_sec_negotiate_req_data_free(message->SecNegotiateReqData);
|
||||
if (message->SecNegotiateRspData)
|
||||
OpenAPI_sec_negotiate_rsp_data_free(message->SecNegotiateRspData);
|
||||
if (message->UeContextTransferReqData)
|
||||
OpenAPI_ue_context_transfer_req_data_free(message->UeContextTransferReqData);
|
||||
if (message->UeContextTransferRspData)
|
||||
OpenAPI_ue_context_transfer_rsp_data_free(message->UeContextTransferRspData);
|
||||
|
||||
/* HTTP Part */
|
||||
for (i = 0; i < message->num_of_part; i++) {
|
||||
|
@ -282,6 +286,7 @@ ogs_sbi_request_t *ogs_sbi_build_request(ogs_sbi_message_t *message)
|
|||
int i;
|
||||
ogs_sbi_request_t *request = NULL;
|
||||
OpenAPI_nf_type_e nf_type = OpenAPI_nf_type_NULL;
|
||||
|
||||
char sender_timestamp[OGS_SBI_RFC7231_DATE_LEN];
|
||||
char *max_rsp_time = NULL;
|
||||
|
||||
|
@ -389,6 +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) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
if (ogs_sbi_self()->discovery_config.no_service_names == false &&
|
||||
discovery_option->num_of_service_names) {
|
||||
|
||||
|
@ -817,9 +834,14 @@ int ogs_sbi_parse_request(
|
|||
ogs_sbi_discovery_option_parse_snssais(discovery_option, v);
|
||||
discovery_option_presence = true;
|
||||
}
|
||||
} else if (!strcmp(ogs_hash_this_key(hi), OGS_SBI_PARAM_GUAMI)) {
|
||||
char *v = ogs_hash_this_val(hi);
|
||||
if (v) {
|
||||
ogs_sbi_discovery_option_parse_guami(discovery_option, v);
|
||||
discovery_option_presence = true;
|
||||
}
|
||||
} else if (!strcmp(ogs_hash_this_key(hi), OGS_SBI_PARAM_DNN)) {
|
||||
char *v = ogs_hash_this_val(hi);
|
||||
|
||||
if (v) {
|
||||
ogs_sbi_discovery_option_set_dnn(discovery_option, v);
|
||||
discovery_option_presence = true;
|
||||
|
@ -1340,6 +1362,14 @@ static char *build_json(ogs_sbi_message_t *message)
|
|||
item = OpenAPI_sec_negotiate_rsp_data_convertToJSON(
|
||||
message->SecNegotiateRspData);
|
||||
ogs_assert(item);
|
||||
} else if (message->UeContextTransferReqData) {
|
||||
item = OpenAPI_ue_context_transfer_req_data_convertToJSON(
|
||||
message->UeContextTransferReqData);
|
||||
ogs_assert(item);
|
||||
} else if (message->UeContextTransferRspData) {
|
||||
item = OpenAPI_ue_context_transfer_rsp_data_convertToJSON(
|
||||
message->UeContextTransferRspData);
|
||||
ogs_assert(item);
|
||||
}
|
||||
|
||||
if (item) {
|
||||
|
@ -2082,6 +2112,27 @@ static int parse_json(ogs_sbi_message_t *message,
|
|||
}
|
||||
break;
|
||||
|
||||
CASE(OGS_SBI_RESOURCE_NAME_TRANSFER)
|
||||
if (message->res_status == 0) {
|
||||
message->UeContextTransferReqData =
|
||||
OpenAPI_ue_context_transfer_req_data_parseFromJSON(item);
|
||||
if (!message->UeContextTransferReqData) {
|
||||
rv = OGS_ERROR;
|
||||
ogs_error("JSON parse error");
|
||||
}
|
||||
} else if (message->res_status == OGS_SBI_HTTP_STATUS_OK) {
|
||||
message->UeContextTransferRspData =
|
||||
OpenAPI_ue_context_transfer_rsp_data_parseFromJSON(item);
|
||||
if (!message->UeContextTransferRspData) {
|
||||
rv = OGS_ERROR;
|
||||
ogs_error("JSON parse error");
|
||||
}
|
||||
} else {
|
||||
ogs_error("HTTP ERROR Status : %d",
|
||||
message->res_status);
|
||||
}
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
rv = OGS_ERROR;
|
||||
ogs_error("Unknown resource name [%s]",
|
||||
|
@ -2889,6 +2940,8 @@ 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]);
|
||||
|
@ -3129,6 +3182,71 @@ void ogs_sbi_discovery_option_parse_snssais(
|
|||
ogs_free(v);
|
||||
}
|
||||
|
||||
char *ogs_sbi_discovery_option_build_guami(
|
||||
ogs_sbi_discovery_option_t *discovery_option)
|
||||
{
|
||||
OpenAPI_guami_t *Guami = NULL;
|
||||
cJSON *guamiItem = NULL;
|
||||
char *v = NULL;
|
||||
|
||||
ogs_assert(discovery_option);
|
||||
ogs_assert(discovery_option->target_guami);
|
||||
|
||||
Guami = ogs_sbi_build_guami(discovery_option->target_guami);
|
||||
ogs_assert(Guami);
|
||||
guamiItem = OpenAPI_guami_convertToJSON(Guami);
|
||||
ogs_assert(guamiItem);
|
||||
ogs_sbi_free_guami(Guami);
|
||||
|
||||
v = cJSON_PrintUnformatted(guamiItem);
|
||||
ogs_expect(v);
|
||||
cJSON_Delete(guamiItem);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void ogs_sbi_discovery_option_parse_guami(
|
||||
ogs_sbi_discovery_option_t *discovery_option, char *guami)
|
||||
{
|
||||
OpenAPI_guami_t *Guami = NULL;
|
||||
cJSON *guamItem = NULL;
|
||||
char *v = NULL;
|
||||
|
||||
ogs_assert(discovery_option);
|
||||
ogs_assert(guami);
|
||||
|
||||
v = ogs_sbi_url_decode(guami);
|
||||
if (!v) {
|
||||
ogs_error("ogs_sbi_url_decode() failed : guami[%s]", guami);
|
||||
return;
|
||||
}
|
||||
|
||||
guamItem = cJSON_Parse(v);
|
||||
if (!guamItem) {
|
||||
ogs_error("Cannot parse guami[%s]", guami);
|
||||
ogs_free(v);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
OpenAPI_guami_free(Guami);
|
||||
} else {
|
||||
ogs_error("OpenAPI_guami_parseFromJSON() failed : guami[%s]",
|
||||
guami);
|
||||
}
|
||||
cJSON_Delete(guamItem);
|
||||
|
||||
ogs_free(v);
|
||||
}
|
||||
|
||||
void ogs_sbi_discovery_option_set_tai(
|
||||
ogs_sbi_discovery_option_t *discovery_option, ogs_5gs_tai_t *tai)
|
||||
{
|
||||
|
|
|
@ -124,6 +124,7 @@ extern "C" {
|
|||
|
||||
#define OGS_SBI_RESOURCE_NAME_UE_CONTEXTS "ue-contexts"
|
||||
#define OGS_SBI_RESOURCE_NAME_N1_N2_MESSAGES "n1-n2-messages"
|
||||
#define OGS_SBI_RESOURCE_NAME_TRANSFER "transfer"
|
||||
|
||||
#define OGS_SBI_RESOURCE_NAME_SM_CONTEXT_STATUS "sm-context-status"
|
||||
#define OGS_SBI_RESOURCE_NAME_AM_POLICY_NOTIFY "am-policy-notify"
|
||||
|
@ -295,6 +296,8 @@ extern "C" {
|
|||
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_REQUESTER_PLMN_LIST
|
||||
#define OGS_SBI_CUSTOM_DISCOVERY_REQUESTER_FEATURES \
|
||||
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_REQUESTER_FEATURES
|
||||
#define OGS_SBI_CUSTOM_DISCOVERY_GUAMI \
|
||||
OGS_SBI_CUSTOM_DISCOVERY_COMMON OGS_SBI_PARAM_GUAMI
|
||||
#define OGS_SBI_CUSTOM_PRODUCER_ID \
|
||||
OGS_SBI_CUSTOM_3GPP_COMMON "Producer-Id"
|
||||
#define OGS_SBI_CUSTOM_OCI \
|
||||
|
@ -330,6 +333,7 @@ extern "C" {
|
|||
#define OGS_SBI_PARAM_PLMN_ID "plmn-id"
|
||||
#define OGS_SBI_PARAM_SINGLE_NSSAI "single-nssai"
|
||||
#define OGS_SBI_PARAM_SNSSAI "snssai"
|
||||
#define OGS_SBI_PARAM_GUAMI "guami"
|
||||
#define OGS_SBI_PARAM_SNSSAIS "snssais"
|
||||
#define OGS_SBI_PARAM_TAI "tai"
|
||||
#define OGS_SBI_PARAM_SLICE_INFO_REQUEST_FOR_PDU_SESSION \
|
||||
|
@ -431,6 +435,8 @@ typedef struct ogs_sbi_discovery_option_s {
|
|||
bool tai_presence;
|
||||
ogs_5gs_tai_t tai;
|
||||
|
||||
ogs_guami_t *target_guami;
|
||||
|
||||
int num_of_target_plmn_list;
|
||||
ogs_plmn_id_t target_plmn_list[OGS_MAX_NUM_OF_PLMN];
|
||||
int num_of_requester_plmn_list;
|
||||
|
@ -542,6 +548,8 @@ typedef struct ogs_sbi_message_s {
|
|||
OpenAPI_smf_registration_t *SmfRegistration;
|
||||
OpenAPI_sec_negotiate_req_data_t *SecNegotiateReqData;
|
||||
OpenAPI_sec_negotiate_rsp_data_t *SecNegotiateRspData;
|
||||
OpenAPI_ue_context_transfer_req_data_t *UeContextTransferReqData;
|
||||
OpenAPI_ue_context_transfer_rsp_data_t *UeContextTransferRspData;
|
||||
|
||||
ogs_sbi_links_t *links;
|
||||
|
||||
|
@ -641,6 +649,11 @@ char *ogs_sbi_discovery_option_build_snssais(
|
|||
void ogs_sbi_discovery_option_parse_snssais(
|
||||
ogs_sbi_discovery_option_t *discovery_option, char *snssais);
|
||||
|
||||
char *ogs_sbi_discovery_option_build_guami(
|
||||
ogs_sbi_discovery_option_t *discovery_option);
|
||||
void ogs_sbi_discovery_option_parse_guami(
|
||||
ogs_sbi_discovery_option_t *discovery_option, char *guami);
|
||||
|
||||
void ogs_sbi_discovery_option_set_tai(
|
||||
ogs_sbi_discovery_option_t *discovery_option, ogs_5gs_tai_t *tai);
|
||||
char *ogs_sbi_discovery_option_build_tai(
|
||||
|
|
|
@ -27,6 +27,8 @@ static void handle_scp_info(
|
|||
ogs_sbi_nf_instance_t *nf_instance, OpenAPI_scp_info_t *ScpInfo);
|
||||
static void handle_sepp_info(
|
||||
ogs_sbi_nf_instance_t *nf_instance, OpenAPI_sepp_info_t *SeppInfo);
|
||||
static void handle_amf_info(
|
||||
ogs_sbi_nf_instance_t *nf_instance, OpenAPI_amf_info_t *AmfInfo);
|
||||
|
||||
void ogs_nnrf_nfm_handle_nf_register(
|
||||
ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_message_t *recvmsg)
|
||||
|
@ -256,7 +258,14 @@ void ogs_nnrf_nfm_handle_nf_profile(
|
|||
if (SmfInfoMap && SmfInfoMap->value)
|
||||
handle_smf_info(nf_instance, SmfInfoMap->value);
|
||||
}
|
||||
if (NFProfile->amf_info)
|
||||
handle_amf_info(nf_instance, NFProfile->amf_info);
|
||||
|
||||
OpenAPI_list_for_each(NFProfile->amf_info_list, node) {
|
||||
OpenAPI_map_t *AmfInfoMap = node->data;
|
||||
if (AmfInfoMap && AmfInfoMap->value)
|
||||
handle_amf_info(nf_instance, AmfInfoMap->value);
|
||||
}
|
||||
if (NFProfile->scp_info)
|
||||
handle_scp_info(nf_instance, NFProfile->scp_info);
|
||||
if (NFProfile->sepp_info)
|
||||
|
@ -653,6 +662,100 @@ static void handle_sepp_info(
|
|||
}
|
||||
}
|
||||
|
||||
static void handle_amf_info(
|
||||
ogs_sbi_nf_instance_t *nf_instance, OpenAPI_amf_info_t *AmfInfo)
|
||||
{
|
||||
ogs_sbi_nf_info_t *nf_info = NULL;
|
||||
OpenAPI_list_t *GuamiList = NULL;
|
||||
OpenAPI_guami_t *GuamiAmfInfoItem = NULL;
|
||||
OpenAPI_list_t *TaiList = NULL;
|
||||
OpenAPI_tai_t *TaiItem = NULL;
|
||||
OpenAPI_list_t *TaiRangeList = NULL;
|
||||
OpenAPI_tai_range_t *TaiRangeItem = NULL;
|
||||
OpenAPI_list_t *TacRangeList = NULL;
|
||||
OpenAPI_tac_range_t *TacRangeItem = NULL;
|
||||
OpenAPI_lnode_t *node = NULL, *node2 = NULL;
|
||||
|
||||
ogs_assert(nf_instance);
|
||||
ogs_assert(AmfInfo);
|
||||
|
||||
nf_info = ogs_sbi_nf_info_add(
|
||||
&nf_instance->nf_info_list, OpenAPI_nf_type_AMF);
|
||||
ogs_assert(nf_info);
|
||||
|
||||
nf_info->amf.amf_set_id = ogs_uint64_from_string(AmfInfo->amf_set_id);
|
||||
nf_info->amf.amf_region_id = ogs_uint64_from_string(AmfInfo->amf_region_id);
|
||||
GuamiList = AmfInfo->guami_list;
|
||||
|
||||
OpenAPI_list_for_each(GuamiList, node) {
|
||||
GuamiAmfInfoItem = node->data;
|
||||
if (GuamiAmfInfoItem) {
|
||||
ogs_assert(nf_info->amf.num_of_guami < OGS_MAX_NUM_OF_SERVED_GUAMI);
|
||||
|
||||
if (GuamiAmfInfoItem->amf_id && GuamiAmfInfoItem->plmn_id &&
|
||||
GuamiAmfInfoItem->plmn_id->mnc &&
|
||||
GuamiAmfInfoItem->plmn_id->mcc) {
|
||||
|
||||
ogs_sbi_parse_guami(
|
||||
&nf_info->amf.guami[nf_info->amf.num_of_guami],
|
||||
GuamiAmfInfoItem);
|
||||
nf_info->amf.num_of_guami++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TaiList = AmfInfo->tai_list;
|
||||
OpenAPI_list_for_each(TaiList, node) {
|
||||
TaiItem = node->data;
|
||||
if (TaiItem && TaiItem->plmn_id && TaiItem->tac) {
|
||||
ogs_5gs_tai_t *nr_tai = NULL;
|
||||
ogs_assert(nf_info->amf.num_of_nr_tai < OGS_MAX_NUM_OF_TAI);
|
||||
nr_tai = &nf_info->amf.nr_tai[nf_info->amf.num_of_nr_tai];
|
||||
ogs_assert(nr_tai);
|
||||
ogs_sbi_parse_plmn_id(&nr_tai->plmn_id, TaiItem->plmn_id);
|
||||
nr_tai->tac = ogs_uint24_from_string(TaiItem->tac);
|
||||
nf_info->amf.num_of_nr_tai++;
|
||||
}
|
||||
}
|
||||
|
||||
TaiRangeList = AmfInfo->tai_range_list;
|
||||
OpenAPI_list_for_each(TaiRangeList, node) {
|
||||
TaiRangeItem = node->data;
|
||||
if (TaiRangeItem && TaiRangeItem->plmn_id &&
|
||||
TaiRangeItem->tac_range_list) {
|
||||
ogs_assert(nf_info->amf.num_of_nr_tai_range <
|
||||
OGS_MAX_NUM_OF_TAI);
|
||||
|
||||
ogs_sbi_parse_plmn_id(
|
||||
&nf_info->amf.nr_tai_range
|
||||
[nf_info->amf.num_of_nr_tai_range].plmn_id,
|
||||
TaiRangeItem->plmn_id);
|
||||
|
||||
TacRangeList = TaiRangeItem->tac_range_list;
|
||||
OpenAPI_list_for_each(TacRangeList, node2) {
|
||||
TacRangeItem = node2->data;
|
||||
if (TacRangeItem &&
|
||||
TacRangeItem->start && TacRangeItem->end) {
|
||||
int tac_index = nf_info->amf.nr_tai_range
|
||||
[nf_info->amf.num_of_nr_tai_range].num_of_tac_range;
|
||||
ogs_assert(tac_index < OGS_MAX_NUM_OF_TAI);
|
||||
|
||||
nf_info->amf.nr_tai_range
|
||||
[nf_info->amf.num_of_nr_tai_range].start[tac_index] =
|
||||
ogs_uint24_from_string(TacRangeItem->start);
|
||||
nf_info->amf.nr_tai_range
|
||||
[nf_info->amf.num_of_nr_tai_range].end[tac_index] =
|
||||
ogs_uint24_from_string(TacRangeItem->end);
|
||||
|
||||
nf_info->amf.nr_tai_range
|
||||
[nf_info->amf.num_of_nr_tai_range].num_of_tac_range++;
|
||||
}
|
||||
}
|
||||
nf_info->amf.num_of_nr_tai_range++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_validity_time(
|
||||
ogs_sbi_subscription_data_t *subscription_data,
|
||||
char *validity_time, const char *action)
|
||||
|
|
|
@ -84,6 +84,8 @@
|
|||
#include "model/sec_negotiate_rsp_data.h"
|
||||
#include "model/patch_item.h"
|
||||
#include "model/ue_authentication_ctx.h"
|
||||
#include "model/ue_context_transfer_req_data.h"
|
||||
#include "model/ue_context_transfer_rsp_data.h"
|
||||
|
||||
#include "custom/links.h"
|
||||
|
||||
|
|
|
@ -422,6 +422,33 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
|
|||
discovery_option->tai.tac.v);
|
||||
}
|
||||
|
||||
if (discovery_option && discovery_option->target_guami) {
|
||||
bool rc = false;
|
||||
char *v = ogs_sbi_discovery_option_build_guami(discovery_option);
|
||||
ogs_expect(v);
|
||||
|
||||
if (v) {
|
||||
char *encoded = ogs_sbi_url_encode(v);
|
||||
ogs_expect(encoded);
|
||||
|
||||
if (encoded) {
|
||||
ogs_sbi_header_set(request->http.headers,
|
||||
OGS_SBI_CUSTOM_DISCOVERY_GUAMI, encoded);
|
||||
ogs_free(encoded);
|
||||
|
||||
rc = true;
|
||||
}
|
||||
ogs_free(v);
|
||||
}
|
||||
|
||||
if (rc == false)
|
||||
ogs_error("build failed: guami[PLMN_ID:%06x,AMF_ID:%x]",
|
||||
ogs_plmn_id_hexdump(
|
||||
&discovery_option->target_guami->plmn_id),
|
||||
ogs_amf_id_hexdump(
|
||||
&discovery_option->target_guami->amf_id));
|
||||
}
|
||||
|
||||
if (discovery_option &&
|
||||
discovery_option->requester_features) {
|
||||
char *v = ogs_uint64_to_string(
|
||||
|
|
|
@ -180,6 +180,22 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e)
|
|||
END
|
||||
break;
|
||||
|
||||
CASE(OGS_SBI_RESOURCE_NAME_TRANSFER)
|
||||
SWITCH(sbi_message.h.method)
|
||||
CASE(OGS_SBI_HTTP_METHOD_POST)
|
||||
amf_namf_comm_handle_ue_context_transfer_request(
|
||||
stream, &sbi_message);
|
||||
break;
|
||||
DEFAULT
|
||||
ogs_error("Invalid HTTP method [%s]",
|
||||
sbi_message.h.method);
|
||||
ogs_assert(true ==
|
||||
ogs_sbi_server_send_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_FORBIDDEN, &sbi_message,
|
||||
"Invalid HTTP method", sbi_message.h.method));
|
||||
END
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid resource name [%s]",
|
||||
sbi_message.h.resource.component[2]);
|
||||
|
@ -375,6 +391,7 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e)
|
|||
CASE(OGS_SBI_SERVICE_NAME_NUDM_UECM)
|
||||
CASE(OGS_SBI_SERVICE_NAME_NUDM_SDM)
|
||||
CASE(OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL)
|
||||
CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM)
|
||||
sbi_xact = e->h.sbi.data;
|
||||
ogs_assert(sbi_xact);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ static void stats_add_ran_ue(void);
|
|||
static void stats_remove_ran_ue(void);
|
||||
static void stats_add_amf_session(void);
|
||||
static void stats_remove_amf_session(void);
|
||||
static bool amf_namf_comm_parse_guti(ogs_nas_5gs_guti_t *guti, char *ue_context_id);
|
||||
|
||||
void amf_context_init(void)
|
||||
{
|
||||
|
@ -1955,6 +1956,105 @@ amf_ue_t *amf_ue_find_by_message(ogs_nas_5gs_message_t *message)
|
|||
return amf_ue;
|
||||
}
|
||||
|
||||
static bool amf_namf_comm_parse_guti(ogs_nas_5gs_guti_t *guti, char *ue_context_id)
|
||||
{
|
||||
#define MIN_LENGTH_OF_MNC 2
|
||||
#define MAX_LENGTH_OF_MNC 3
|
||||
#define LENGTH_OF_MCC 3
|
||||
#define LENGTH_OF_AMF_ID 6
|
||||
#define LENGTH_OF_TMSI 8
|
||||
|
||||
char amf_id_string[LENGTH_OF_AMF_ID + 1];
|
||||
char tmsi_string[LENGTH_OF_TMSI + 1];
|
||||
char mcc_string[LENGTH_OF_MCC + 1];
|
||||
char mnc_string[MAX_LENGTH_OF_MNC + 1];
|
||||
OpenAPI_plmn_id_t Plmn_id;
|
||||
ogs_plmn_id_t plmn_id;
|
||||
|
||||
/* TS29.518 6.1.3.2.2 Guti pattern (27 or 28 characters):
|
||||
"5g-guti-[0-9]{5,6}[0-9a-fA-F]{14}" */
|
||||
|
||||
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';
|
||||
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);
|
||||
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);
|
||||
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';
|
||||
index += LENGTH_OF_AMF_ID;
|
||||
|
||||
strncpy(tmsi_string, &ue_context_id[index], LENGTH_OF_TMSI);
|
||||
tmsi_string[LENGTH_OF_TMSI] = '\0';
|
||||
|
||||
memset(&Plmn_id, 0, sizeof(Plmn_id));
|
||||
Plmn_id.mcc = mcc_string;
|
||||
Plmn_id.mnc = mnc_string;
|
||||
|
||||
memset(&plmn_id, 0, sizeof(plmn_id));
|
||||
ogs_sbi_parse_plmn_id(&plmn_id, &Plmn_id);
|
||||
ogs_nas_from_plmn_id(&guti->nas_plmn_id, &plmn_id);
|
||||
ogs_amf_id_from_string(&guti->amf_id, amf_id_string);
|
||||
|
||||
guti->m_tmsi = (u_int32_t)strtol(tmsi_string, NULL, 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
amf_ue_t *amf_ue_find_by_ue_context_id(char *ue_context_id)
|
||||
{
|
||||
amf_ue_t *amf_ue = NULL;
|
||||
|
||||
ogs_assert(ue_context_id);
|
||||
|
||||
if (strncmp(ue_context_id, OGS_ID_SUPI_TYPE_IMSI,
|
||||
strlen(OGS_ID_SUPI_TYPE_IMSI)) == 0) {
|
||||
|
||||
amf_ue = amf_ue_find_by_supi(ue_context_id);
|
||||
if (!amf_ue) {
|
||||
ogs_info("[%s] Unknown UE by SUPI", ue_context_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else if (strncmp(ue_context_id, OGS_ID_5G_GUTI_TYPE,
|
||||
strlen(OGS_ID_5G_GUTI_TYPE)) == 0) {
|
||||
|
||||
ogs_nas_5gs_guti_t guti;
|
||||
memset(&guti, 0, sizeof(guti));
|
||||
|
||||
if (amf_namf_comm_parse_guti(&guti, ue_context_id) == false) {
|
||||
ogs_error("amf_namf_comm_parse_guti() failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
amf_ue = amf_ue_find_by_guti(&guti);
|
||||
if (!amf_ue) {
|
||||
ogs_info("[%s] Unknown UE by GUTI", ue_context_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
ogs_error("Unsupported UE context ID type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return amf_ue;
|
||||
}
|
||||
|
||||
void amf_ue_set_suci(amf_ue_t *amf_ue,
|
||||
ogs_nas_5gs_mobile_identity_t *mobile_identity)
|
||||
{
|
||||
|
|
|
@ -749,6 +749,7 @@ void amf_ue_fsm_fini(amf_ue_t *amf_ue);
|
|||
amf_ue_t *amf_ue_find_by_guti(ogs_nas_5gs_guti_t *nas_guti);
|
||||
amf_ue_t *amf_ue_find_by_suci(char *suci);
|
||||
amf_ue_t *amf_ue_find_by_supi(char *supi);
|
||||
amf_ue_t *amf_ue_find_by_ue_context_id(char *ue_context_id);
|
||||
|
||||
amf_ue_t *amf_ue_find_by_message(ogs_nas_5gs_message_t *message);
|
||||
void amf_ue_set_suci(amf_ue_t *amf_ue,
|
||||
|
|
|
@ -1520,6 +1520,243 @@ 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;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define GMM_HANDLER_H
|
||||
|
||||
#include "context.h"
|
||||
#include "namf-handler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
121
src/amf/gmm-sm.c
121
src/amf/gmm-sm.c
|
@ -27,8 +27,10 @@
|
|||
#include "nsmf-handler.h"
|
||||
#include "nudm-handler.h"
|
||||
#include "npcf-handler.h"
|
||||
#include "namf-handler.h"
|
||||
#include "sbi-path.h"
|
||||
#include "amf-sm.h"
|
||||
#include "namf-build.h"
|
||||
|
||||
#undef OGS_LOG_DOMAIN
|
||||
#define OGS_LOG_DOMAIN __gmm_log_domain
|
||||
|
@ -62,6 +64,7 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
{
|
||||
amf_ue_t *amf_ue = NULL;
|
||||
amf_sess_t *sess = NULL;
|
||||
ran_ue_t *ran_ue = NULL;
|
||||
|
||||
ogs_sbi_message_t *sbi_message = NULL;
|
||||
|
||||
|
@ -546,6 +549,61 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
END
|
||||
break;
|
||||
|
||||
CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM)
|
||||
SWITCH(sbi_message->h.resource.component[0])
|
||||
CASE(OGS_SBI_RESOURCE_NAME_UE_CONTEXTS)
|
||||
SWITCH(sbi_message->h.resource.component[2])
|
||||
CASE(OGS_SBI_RESOURCE_NAME_TRANSFER)
|
||||
|
||||
ran_ue = ran_ue_cycle(amf_ue->ran_ue);
|
||||
ogs_assert(ran_ue);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
r = amf_ue_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NAUSF_AUTH, NULL,
|
||||
amf_nausf_auth_build_authenticate,
|
||||
amf_ue, 0, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
}
|
||||
|
||||
OGS_FSM_TRAN(s, &gmm_state_authentication);
|
||||
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid resource name [%s]",
|
||||
sbi_message->h.resource.component[2]);
|
||||
ogs_assert_if_reached();
|
||||
END
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid resource name [%s]",
|
||||
sbi_message->h.resource.component[0]);
|
||||
ogs_assert_if_reached();
|
||||
END
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid service name [%s]", sbi_message->h.service.name);
|
||||
ogs_assert_if_reached();
|
||||
|
@ -1136,6 +1194,9 @@ 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);
|
||||
|
||||
|
@ -1194,6 +1255,66 @@ 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;
|
||||
|
||||
/* 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)) {
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
int state = e->h.sbi.state;
|
||||
bool serving_guami = false;
|
||||
int i;
|
||||
|
||||
/* 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)) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AMF_UE_HAVE_SUCI(amf_ue)) {
|
||||
CLEAR_AMF_UE_TIMER(amf_ue->t3570);
|
||||
r = nas_5gs_send_identity_request(amf_ue);
|
||||
|
|
|
@ -40,6 +40,7 @@ libamf_sources = files('''
|
|||
nnrf-build.c
|
||||
nnrf-handler.c
|
||||
|
||||
namf-build.c
|
||||
namf-handler.c
|
||||
sbi-path.c
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "namf-build.h"
|
||||
|
||||
static char* ogs_guti_to_string(amf_ue_t *amf_ue)
|
||||
{
|
||||
ogs_plmn_id_t plmn_id;
|
||||
char plmn_id_buff[OGS_PLMNIDSTRLEN];
|
||||
char *amf_id = NULL;
|
||||
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);
|
||||
|
||||
amf_id = ogs_amf_id_to_string(&amf_ue->current.guti.amf_id);
|
||||
tmsi = ogs_uint32_to_0string(*(amf_ue->current.m_tmsi));
|
||||
|
||||
guti = ogs_msprintf("5g-guti-%s%s%s",
|
||||
ogs_plmn_id_to_string(&plmn_id, plmn_id_buff),
|
||||
amf_id,
|
||||
tmsi);
|
||||
|
||||
/* TS29.518 6.1.3.2.2 Guti pattern (27 or 28 characters):
|
||||
"5g-guti-[0-9]{5,6}[0-9a-fA-F]{14}" */
|
||||
ogs_assert(strlen(guti) == (OGS_MAX_5G_GUTI_LEN - 1) ||
|
||||
(strlen(guti)) == OGS_MAX_5G_GUTI_LEN);
|
||||
|
||||
ogs_free(amf_id);
|
||||
ogs_free(tmsi);
|
||||
|
||||
return guti;
|
||||
}
|
||||
|
||||
static char* amf_ue_to_context_id(amf_ue_t *amf_ue)
|
||||
{
|
||||
char *ue_context_id = NULL;
|
||||
|
||||
if (amf_ue->supi) {
|
||||
ue_context_id = ogs_strdup(amf_ue->supi);
|
||||
} else {
|
||||
ue_context_id = ogs_guti_to_string(amf_ue);
|
||||
}
|
||||
|
||||
return ue_context_id;
|
||||
}
|
||||
|
||||
ogs_sbi_request_t *amf_namf_comm_build_ue_context_transfer(
|
||||
amf_ue_t *amf_ue, void *data)
|
||||
{
|
||||
ogs_sbi_message_t message;
|
||||
ogs_sbi_request_t *request = NULL;
|
||||
OpenAPI_ue_context_transfer_req_data_t UeContextTransferReqData;
|
||||
char *ue_context_id = NULL;
|
||||
|
||||
ogs_assert(amf_ue);
|
||||
|
||||
ue_context_id = amf_ue_to_context_id(amf_ue);
|
||||
ogs_assert(ue_context_id);
|
||||
|
||||
memset(&UeContextTransferReqData, 0, sizeof(UeContextTransferReqData));
|
||||
UeContextTransferReqData.access_type = amf_ue->nas.access_type;
|
||||
UeContextTransferReqData.reason = amf_ue->nas.registration.value;
|
||||
|
||||
memset(&message, 0, sizeof(message));
|
||||
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[1] = ue_context_id;
|
||||
message.h.resource.component[2] =
|
||||
(char *)OGS_SBI_RESOURCE_NAME_TRANSFER;
|
||||
message.UeContextTransferReqData = &UeContextTransferReqData;
|
||||
|
||||
request = ogs_sbi_build_request(&message);
|
||||
ogs_expect(request);
|
||||
|
||||
if (ue_context_id)
|
||||
ogs_free(ue_context_id);
|
||||
|
||||
return request;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AMF_NAMF_BUILD_H
|
||||
#define AMF_NAMF_BUILD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "context.h"
|
||||
|
||||
ogs_sbi_request_t *amf_namf_comm_build_ue_context_transfer(
|
||||
amf_ue_t *amf_ue, void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AMF_NAMF_BUILD_H */
|
|
@ -1079,3 +1079,396 @@ cleanup:
|
|||
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
int amf_namf_comm_handle_ue_context_transfer_request(
|
||||
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
||||
{
|
||||
ogs_sbi_response_t *response = NULL;
|
||||
ogs_sbi_message_t sendmsg;
|
||||
amf_ue_t *amf_ue = NULL;
|
||||
|
||||
OpenAPI_ambr_t *UeAmbr = NULL;
|
||||
OpenAPI_list_t *MmContextList = NULL;
|
||||
OpenAPI_mm_context_t *MmContext = NULL;
|
||||
OpenAPI_list_t *SessionContextList = NULL;
|
||||
OpenAPI_pdu_session_context_t *PduSessionContext = NULL;
|
||||
OpenAPI_lnode_t *node = NULL;
|
||||
OpenAPI_ue_context_t UeContext;
|
||||
OpenAPI_seaf_data_t SeafData;
|
||||
OpenAPI_ng_ksi_t Ng_ksi;
|
||||
OpenAPI_key_amf_t Key_amf;
|
||||
OpenAPI_sc_type_e Tsc_type;
|
||||
|
||||
OpenAPI_ue_context_transfer_rsp_data_t UeContextTransferRspData;
|
||||
|
||||
char *ue_context_id = NULL;
|
||||
char *encoded_gmm_capability = NULL;
|
||||
int status = OGS_SBI_HTTP_STATUS_OK;
|
||||
char hxkamf_string[OGS_KEYSTRLEN(OGS_SHA256_DIGEST_SIZE)];
|
||||
char *strerror = NULL;
|
||||
|
||||
ogs_assert(stream);
|
||||
ogs_assert(recvmsg);
|
||||
|
||||
memset(&UeContextTransferRspData, 0, sizeof(UeContextTransferRspData));
|
||||
memset(&UeContext, 0, sizeof(UeContext));
|
||||
UeContextTransferRspData.ue_context = &UeContext;
|
||||
|
||||
memset(&sendmsg, 0, sizeof(sendmsg));
|
||||
sendmsg.UeContextTransferRspData = &UeContextTransferRspData;
|
||||
|
||||
ue_context_id = recvmsg->h.resource.component[1];
|
||||
if (!ue_context_id) {
|
||||
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
||||
strerror = ogs_msprintf("No UE context ID");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
amf_ue = amf_ue_find_by_ue_context_id(ue_context_id);
|
||||
if (!amf_ue) {
|
||||
status = OGS_SBI_HTTP_STATUS_NOT_FOUND;
|
||||
strerror = ogs_msprintf("CONTEXT_NOT_FOUND");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (amf_ue->supi) {
|
||||
UeContext.supi = amf_ue->supi;
|
||||
if (amf_ue->auth_result !=
|
||||
OpenAPI_auth_result_AUTHENTICATION_SUCCESS) {
|
||||
UeContext.is_supi_unauth_ind = true;
|
||||
UeContext.supi_unauth_ind = amf_ue->auth_result;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO UeContext.gpsi_list */
|
||||
|
||||
if (amf_ue->pei) {
|
||||
UeContext.pei = amf_ue->pei;
|
||||
}
|
||||
|
||||
if ((amf_ue->ue_ambr.uplink > 0) || (amf_ue->ue_ambr.downlink > 0)) {
|
||||
UeAmbr = ogs_malloc(sizeof(*UeAmbr));
|
||||
ogs_assert(UeAmbr);
|
||||
memset(UeAmbr, 0, sizeof(*UeAmbr));
|
||||
|
||||
if (amf_ue->ue_ambr.uplink > 0)
|
||||
UeAmbr->uplink = ogs_sbi_bitrate_to_string(
|
||||
amf_ue->ue_ambr.uplink, OGS_SBI_BITRATE_KBPS);
|
||||
if (amf_ue->ue_ambr.downlink > 0)
|
||||
UeAmbr->downlink = ogs_sbi_bitrate_to_string(
|
||||
amf_ue->ue_ambr.downlink, OGS_SBI_BITRATE_KBPS);
|
||||
UeContext.sub_ue_ambr = UeAmbr;
|
||||
}
|
||||
|
||||
if ((amf_ue->nas.ue.ksi != 0) && (amf_ue->nas.ue.tsc != 0)) {
|
||||
memset(&SeafData, 0, sizeof(SeafData));
|
||||
Tsc_type = (amf_ue->nas.ue.tsc == 0) ?
|
||||
OpenAPI_sc_type_NATIVE : OpenAPI_sc_type_MAPPED;
|
||||
|
||||
memset(&Ng_ksi, 0, sizeof(Ng_ksi));
|
||||
SeafData.ng_ksi = &Ng_ksi;
|
||||
Ng_ksi.tsc = Tsc_type;
|
||||
Ng_ksi.ksi = (int)amf_ue->nas.ue.ksi;
|
||||
|
||||
memset(&Key_amf, 0, sizeof(Key_amf));
|
||||
SeafData.key_amf = &Key_amf;
|
||||
OpenAPI_key_amf_type_e temp_key_type =
|
||||
(OpenAPI_key_amf_type_e)OpenAPI_key_amf_type_KAMF;
|
||||
Key_amf.key_type = temp_key_type;
|
||||
ogs_hex_to_ascii(amf_ue->kamf, sizeof(amf_ue->kamf),
|
||||
hxkamf_string, sizeof(hxkamf_string));
|
||||
Key_amf.key_val = hxkamf_string;
|
||||
UeContext.seaf_data = &SeafData;
|
||||
}
|
||||
|
||||
encoded_gmm_capability = amf_namf_comm_base64_encode_5gmm_capability(amf_ue);
|
||||
UeContext._5g_mm_capability = encoded_gmm_capability;
|
||||
|
||||
UeContext.pcf_id = amf_ue->sbi.service_type_array[
|
||||
OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL].nf_instance->id;
|
||||
|
||||
/* TODO UeContext.pcfAmPolicyUri */
|
||||
/* TODO UeContext.pcfUePolicyUri */
|
||||
|
||||
MmContextList = amf_namf_comm_encode_ue_mm_context_list(amf_ue);
|
||||
UeContext.mm_context_list = MmContextList;
|
||||
|
||||
if (recvmsg->UeContextTransferReqData->reason ==
|
||||
OpenAPI_transfer_reason_MOBI_REG) {
|
||||
SessionContextList = amf_namf_comm_encode_ue_session_context_list(amf_ue);
|
||||
UeContext.session_context_list = SessionContextList;
|
||||
}
|
||||
|
||||
/* TODO ueRadioCapability */
|
||||
|
||||
response = ogs_sbi_build_response(&sendmsg, status);
|
||||
ogs_assert(response);
|
||||
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
||||
|
||||
if (encoded_gmm_capability)
|
||||
ogs_free(encoded_gmm_capability);
|
||||
if (UeAmbr)
|
||||
OpenAPI_ambr_free(UeAmbr);
|
||||
|
||||
if (SessionContextList) {
|
||||
OpenAPI_list_for_each(SessionContextList, node) {
|
||||
PduSessionContext = node->data;
|
||||
OpenAPI_pdu_session_context_free(PduSessionContext);
|
||||
}
|
||||
OpenAPI_list_free(SessionContextList);
|
||||
}
|
||||
|
||||
if (MmContextList) {
|
||||
OpenAPI_list_for_each(MmContextList, node) {
|
||||
MmContext = node->data;
|
||||
OpenAPI_mm_context_free(MmContext);
|
||||
}
|
||||
OpenAPI_list_free(MmContextList);
|
||||
}
|
||||
|
||||
return OGS_OK;
|
||||
|
||||
cleanup:
|
||||
ogs_assert(strerror);
|
||||
ogs_error("%s", strerror);
|
||||
|
||||
ogs_assert(true ==
|
||||
ogs_sbi_server_send_error(stream, status, NULL, strerror, NULL));
|
||||
ogs_free(strerror);
|
||||
|
||||
return OGS_ERROR;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,10 @@ int amf_namf_callback_handle_dereg_notify(
|
|||
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
|
||||
int amf_namf_callback_handle_sdm_data_change_notify(
|
||||
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
|
||||
int amf_namf_comm_handle_ue_context_transfer_request(
|
||||
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
|
||||
int amf_namf_comm_handle_ue_context_transfer_response(
|
||||
ogs_sbi_message_t *recvmsg, amf_ue_t *amf_ue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ int amf_sbi_open(void)
|
|||
ogs_sbi_nf_instance_build_default(nf_instance);
|
||||
ogs_sbi_nf_instance_add_allowed_nf_type(nf_instance, OpenAPI_nf_type_SCP);
|
||||
ogs_sbi_nf_instance_add_allowed_nf_type(nf_instance, OpenAPI_nf_type_SMF);
|
||||
ogs_sbi_nf_instance_add_allowed_nf_type(nf_instance, OpenAPI_nf_type_AMF);
|
||||
|
||||
/* Build NF service information. It will be transmitted to NRF. */
|
||||
if (ogs_sbi_nf_service_is_available(OGS_SBI_SERVICE_NAME_NAMF_COMM)) {
|
||||
|
@ -45,6 +46,7 @@ int amf_sbi_open(void)
|
|||
ogs_sbi_nf_service_add_version(
|
||||
service, OGS_SBI_API_V1, OGS_SBI_API_V1_0_0, NULL);
|
||||
ogs_sbi_nf_service_add_allowed_nf_type(service, OpenAPI_nf_type_SMF);
|
||||
ogs_sbi_nf_service_add_allowed_nf_type(service, OpenAPI_nf_type_AMF);
|
||||
}
|
||||
|
||||
/* Initialize NRF NF Instance */
|
||||
|
|
|
@ -830,6 +830,13 @@ bool nrf_nnrf_handle_nf_discover(
|
|||
&discovery_option->tai.plmn_id),
|
||||
discovery_option->tai.tac.v);
|
||||
}
|
||||
if (discovery_option->target_guami) {
|
||||
ogs_debug("guami[PLMN_ID:%06x,AMF_ID:%x]",
|
||||
ogs_plmn_id_hexdump(
|
||||
&discovery_option->target_guami->plmn_id),
|
||||
ogs_amf_id_hexdump(
|
||||
&discovery_option->target_guami->amf_id));
|
||||
}
|
||||
if (discovery_option->num_of_target_plmn_list) {
|
||||
for (i = 0; i < discovery_option->num_of_target_plmn_list; i++)
|
||||
ogs_debug("[%d] target-plmn-list[MCC:%03d,MNC:%03d]", i,
|
||||
|
|
|
@ -225,6 +225,9 @@ static int request_handler(ogs_sbi_request_t *request, void *data)
|
|||
} else if (!strcasecmp(key, OGS_SBI_CUSTOM_DISCOVERY_SNSSAIS)) {
|
||||
if (val)
|
||||
ogs_sbi_discovery_option_parse_snssais(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_DNN)) {
|
||||
ogs_sbi_discovery_option_set_dnn(discovery_option, val);
|
||||
} else if (!strcasecmp(key, OGS_SBI_CUSTOM_DISCOVERY_TAI)) {
|
||||
|
|
Loading…
Reference in New Issue