Added AMF-initiated AM Policy Termination

This commit is contained in:
Sukchan Lee 2021-12-04 19:31:36 +09:00
parent aab8286401
commit a5a5c424c1
14 changed files with 268 additions and 143 deletions

View File

@ -35,14 +35,6 @@ extern "C" {
(__dATA) = NULL; \
} \
} while(0)
#define OGS_MEM_STORE(__dST, __sRC) \
do { \
ogs_assert((__sRC)); \
OGS_MEM_CLEAR(__dST); \
(__dST) = ogs_calloc(sizeof(*(__sRC)), sizeof(uint8_t)); \
ogs_assert((__dST)); \
memcpy((__dST), (__sRC), sizeof(*(__sRC))*sizeof(uint8_t)); \
} while(0)
#define ogs_malloc(size) ogs_malloc_debug(size, OGS_FILE_LINE, false)
#define ogs_malloc_or_assert(size) \

View File

@ -75,6 +75,13 @@ char *ogs_vslprintf(char *str, char *last, const char *format, va_list ap)
char *ogs_slprintf(char *str, char *last, const char *format, ...)
OGS_GNUC_PRINTF(3, 4);
#define OGS_STRING_DUP(__dST, __sRC) \
do { \
OGS_MEM_CLEAR(__dST); \
__dST = ogs_strdup(__sRC); \
ogs_assert(__dST); \
} while(0)
#define ogs_strdup(s) ogs_strdup_debug(s, OGS_FILE_LINE, false)
#define ogs_strdup_or_assert(s) ogs_strdup_debug(s, OGS_FILE_LINE, true)
char *ogs_strdup_debug(const char *s, const char *file_line, bool abort);

View File

@ -1466,24 +1466,34 @@ static int parse_json(ogs_sbi_message_t *message,
CASE(OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL)
SWITCH(message->h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_POLICIES)
if (message->res_status == 0) {
message->PolicyAssociationRequest =
OpenAPI_policy_association_request_parseFromJSON(
item);
if (!message->PolicyAssociationRequest) {
rv = OGS_ERROR;
ogs_error("JSON parse error");
SWITCH(message->h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
if (message->res_status == 0) {
message->PolicyAssociationRequest =
OpenAPI_policy_association_request_parseFromJSON(
item);
if (!message->PolicyAssociationRequest) {
rv = OGS_ERROR;
ogs_error("JSON parse error");
}
} else if (message->res_status ==
OGS_SBI_HTTP_STATUS_CREATED) {
message->PolicyAssociation =
OpenAPI_policy_association_parseFromJSON(item);
if (!message->PolicyAssociation) {
rv = OGS_ERROR;
ogs_error("JSON parse error");
}
}
} else if (message->res_status == OGS_SBI_HTTP_STATUS_CREATED) {
message->PolicyAssociation =
OpenAPI_policy_association_parseFromJSON(item);
if (!message->PolicyAssociation) {
rv = OGS_ERROR;
ogs_error("JSON parse error");
}
}
break;
CASE(OGS_SBI_HTTP_METHOD_DELETE)
/* Nothing */
break;
DEFAULT
rv = OGS_ERROR;
ogs_error("Unknown method [%s]", message->h.method);
END
break;
DEFAULT
rv = OGS_ERROR;
ogs_error("Unknown resource name [%s]",
@ -1529,7 +1539,6 @@ static int parse_json(ogs_sbi_message_t *message,
ogs_error("Unknown resource name [%s]",
message->h.resource.component[2]);
END
break;
}
break;

View File

@ -2144,7 +2144,7 @@ static bool check_smf_info_nr_tai(
return false;
}
void amf_update_allowed_nssai(amf_ue_t *amf_ue)
bool amf_update_allowed_nssai(amf_ue_t *amf_ue)
{
int i;
ogs_assert(amf_ue);
@ -2285,4 +2285,37 @@ void amf_update_allowed_nssai(amf_ue_t *amf_ue)
}
}
}
if (!amf_ue->allowed_nssai.num_of_s_nssai) {
ogs_error("No Allowed-NSSAI");
ogs_error(" Number of Subscribed S-NSSAI [%d]",
amf_ue->num_of_slice);
for (i = 0; i < amf_ue->num_of_slice; i++) {
ogs_slice_data_t *slice = &amf_ue->slice[i];
if (slice->default_indicator == true) {
ogs_error(
" Default S_NSSAI[SST:%d SD:0x%x]",
slice->s_nssai.sst, slice->s_nssai.sd.v);
} else {
ogs_error(
" S_NSSAI[SST:%d SD:0x%x]",
slice->s_nssai.sst, slice->s_nssai.sd.v);
}
}
ogs_error(" Number of Requested NSSAI [%d]",
amf_ue->requested_nssai.num_of_s_nssai);
for (i = 0; i < amf_ue->requested_nssai.
num_of_s_nssai; i++) {
ogs_error(" PLMN_ID[MCC:%d MNC:%d]",
ogs_plmn_id_mcc(&amf_ue->nr_tai.plmn_id),
ogs_plmn_id_mnc(&amf_ue->nr_tai.plmn_id));
ogs_error(" S_NSSAI[SST:%d SD:0x%x]",
amf_ue->requested_nssai.s_nssai[i].sst,
amf_ue->requested_nssai.s_nssai[i].sd.v);
}
return false;
}
return true;
}

View File

@ -282,6 +282,13 @@ struct amf_ue_s {
/* PCF sends the RESPONSE
* of [POST] /npcf-am-polocy-control/v1/policies */
#define PCF_AM_POLICY_ASSOCIATED(__aMF) \
((__aMF) && ((__aMF)->policy_association_id))
#define PCF_AM_POLICY_CLEAR(__aMF) \
OGS_MEM_CLEAR((__aMF)->policy_association_id);
#define PCF_AM_POLICY_STORE(__aMF, __iD) \
OGS_STRING_DUP((__aMF)->policy_association_id, __iD);
char *policy_association_id;
/* 5GMM Capability */
@ -760,7 +767,7 @@ uint8_t amf_selected_enc_algorithm(amf_ue_t *amf_ue);
void amf_clear_subscribed_info(amf_ue_t *amf_ue);
void amf_update_allowed_nssai(amf_ue_t *amf_ue);
bool amf_update_allowed_nssai(amf_ue_t *amf_ue);
#ifdef __cplusplus
}

View File

@ -98,6 +98,9 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e)
ogs_nas_5gs_message_t *nas_message = NULL;
ogs_nas_security_header_type_t h;
ogs_sbi_response_t *sbi_response = NULL;
ogs_sbi_message_t *sbi_message = NULL;
ogs_assert(e);
if (e->sess) {
@ -157,42 +160,22 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e)
if (amf_sess_xact_count(amf_ue) == xact_count) {
amf_update_allowed_nssai(amf_ue);
if (!amf_ue->allowed_nssai.num_of_s_nssai) {
int i;
if (amf_update_allowed_nssai(amf_ue) == false) {
ogs_error("No Allowed-NSSAI");
ogs_error(" Number of Subscribed S-NSSAI [%d]",
amf_ue->num_of_slice);
for (i = 0; i < amf_ue->num_of_slice; i++) {
ogs_slice_data_t *slice = &amf_ue->slice[i];
if (slice->default_indicator == true) {
ogs_error(
" Default S_NSSAI[SST:%d SD:0x%x]",
slice->s_nssai.sst, slice->s_nssai.sd.v);
} else {
ogs_error(
" S_NSSAI[SST:%d SD:0x%x]",
slice->s_nssai.sst, slice->s_nssai.sd.v);
}
}
ogs_error(" Number of Requested NSSAI [%d]",
amf_ue->requested_nssai.num_of_s_nssai);
for (i = 0; i < amf_ue->requested_nssai.
num_of_s_nssai; i++) {
ogs_error(" PLMN_ID[MCC:%d MNC:%d]",
ogs_plmn_id_mcc(&amf_ue->nr_tai.plmn_id),
ogs_plmn_id_mnc(&amf_ue->nr_tai.plmn_id));
ogs_error(" S_NSSAI[SST:%d SD:0x%x]",
amf_ue->requested_nssai.s_nssai[i].sst,
amf_ue->requested_nssai.s_nssai[i].sd.v);
}
OGS_FSM_TRAN(s, gmm_state_exception);
break;
}
if (!PCF_AM_POLICY_ASSOCIATED(amf_ue)) {
ogs_assert(true ==
amf_ue_sbi_discover_and_send(
OpenAPI_nf_type_PCF, amf_ue, NULL,
amf_npcf_am_policy_control_build_create));
OGS_FSM_TRAN(s, &gmm_state_initial_context_setup);
break;
}
CLEAR_AMF_UE_TIMER(amf_ue->t3550);
ogs_assert(OGS_OK ==
nas_5gs_send_registration_accept(amf_ue));
@ -436,6 +419,43 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e)
amf_timer_get_name(e->timer_id), e->timer_id);
}
break;
case AMF_EVT_SBI_CLIENT:
sbi_response = e->sbi.response;
ogs_assert(sbi_response);
sbi_message = e->sbi.message;
ogs_assert(sbi_message);
SWITCH(sbi_message->h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL)
SWITCH(sbi_message->h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_POLICIES)
SWITCH(sbi_message->h.method)
CASE(OGS_SBI_HTTP_METHOD_DELETE)
ogs_assert(OGS_OK ==
nas_5gs_send_de_registration_accept(amf_ue));
PCF_AM_POLICY_CLEAR(amf_ue);
break;
DEFAULT
ogs_error("Unknown method [%s]", sbi_message->h.method);
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();
END
break;
default:
ogs_error("Unknown event[%s]", amf_event_get_name(e));
}
@ -978,22 +998,45 @@ void gmm_state_initial_context_setup(ogs_fsm_t *s, amf_event_t *e)
CASE(OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL)
SWITCH(sbi_message->h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_POLICIES)
rv = amf_npcf_am_policy_control_handle_create(
amf_ue, sbi_message);
if (rv != OGS_OK) {
ogs_error("[%s] amf_npcf_am_policy_control_handle_create() "
"failed", amf_ue->supi);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
SWITCH(sbi_message->h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
rv = amf_npcf_am_policy_control_handle_create(
amf_ue, sbi_message);
if (rv != OGS_OK) {
ogs_error("[%s] amf_npcf_am_policy_control"
"_handle_create() failed", amf_ue->supi);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
break;
}
ogs_assert(amf_ue->nas.message_type ==
OGS_NAS_5GS_REGISTRATION_REQUEST);
CLEAR_AMF_UE_TIMER(amf_ue->t3550);
ogs_assert(OGS_OK ==
nas_5gs_send_registration_accept(amf_ue));
/* In nsmf-handler.c
*
* 1. AMF_SESS_STORE_N2_TRANSFER
* 2. if PCF_AM_POLICY is NOT associated
* 3. AMF sends npcf-am-policy-control/create to PCF
*
* In gmm-sm.c
* 4. Send Registration Accept
* 5. We should clear N2 transfer
* (PDUSessionResourceSetupRequest)
*/
AMF_UE_CLEAR_N2_TRANSFER(
amf_ue, pdu_session_resource_setup_request);
if (!amf_ue->next.m_tmsi)
OGS_FSM_TRAN(s, &gmm_state_registered);
break;
}
ogs_assert(amf_ue->nas.message_type ==
OGS_NAS_5GS_REGISTRATION_REQUEST);
CLEAR_AMF_UE_TIMER(amf_ue->t3550);
ogs_assert(OGS_OK == nas_5gs_send_registration_accept(amf_ue));
if (!amf_ue->next.m_tmsi)
OGS_FSM_TRAN(s, &gmm_state_registered);
DEFAULT
ogs_error("Unknown method [%s]", sbi_message->h.method);
ogs_assert_if_reached();
END
break;
DEFAULT
@ -1245,39 +1288,17 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e)
if (amf_sess_xact_count(amf_ue) == xact_count) {
amf_update_allowed_nssai(amf_ue);
if (!amf_ue->allowed_nssai.num_of_s_nssai) {
int i;
if (amf_update_allowed_nssai(amf_ue) == false) {
ogs_error("No Allowed-NSSAI");
ogs_error(" Number of Subscribed S-NSSAI [%d]",
amf_ue->num_of_slice);
for (i = 0; i < amf_ue->num_of_slice; i++) {
ogs_slice_data_t *slice = &amf_ue->slice[i];
if (slice->default_indicator == true) {
ogs_error(
" Default S_NSSAI[SST:%d SD:0x%x]",
slice->s_nssai.sst, slice->s_nssai.sd.v);
} else {
ogs_error(
" S_NSSAI[SST:%d SD:0x%x]",
slice->s_nssai.sst, slice->s_nssai.sd.v);
}
}
ogs_error(" Number of Requested NSSAI [%d]",
amf_ue->requested_nssai.num_of_s_nssai);
for (i = 0; i < amf_ue->requested_nssai.
num_of_s_nssai; i++) {
ogs_error(" PLMN_ID[MCC:%d MNC:%d]",
ogs_plmn_id_mcc(&amf_ue->nr_tai.plmn_id),
ogs_plmn_id_mnc(&amf_ue->nr_tai.plmn_id));
ogs_error(" S_NSSAI[SST:%d SD:0x%x]",
amf_ue->requested_nssai.s_nssai[i].sst,
amf_ue->requested_nssai.s_nssai[i].sd.v);
}
break;
}
OGS_FSM_TRAN(s, gmm_state_exception);
if (!PCF_AM_POLICY_ASSOCIATED(amf_ue)) {
ogs_assert(true ==
amf_ue_sbi_discover_and_send(
OpenAPI_nf_type_PCF, amf_ue, NULL,
amf_npcf_am_policy_control_build_create));
OGS_FSM_TRAN(s, &gmm_state_initial_context_setup);
break;
}

View File

@ -179,3 +179,27 @@ ogs_sbi_request_t *amf_npcf_am_policy_control_build_create(
return request;
}
ogs_sbi_request_t *amf_npcf_am_policy_control_build_delete(
amf_ue_t *amf_ue, void *data)
{
ogs_sbi_message_t message;
ogs_sbi_request_t *request = NULL;
ogs_assert(amf_ue);
ogs_assert(amf_ue->supi);
ogs_assert(amf_ue->policy_association_id);
memset(&message, 0, sizeof(message));
message.h.method = (char *)OGS_SBI_HTTP_METHOD_DELETE;
message.h.service.name =
(char *)OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL;
message.h.api.version = (char *)OGS_SBI_API_V1;
message.h.resource.component[0] = (char *)OGS_SBI_RESOURCE_NAME_POLICIES;
message.h.resource.component[1] = amf_ue->policy_association_id;
request = ogs_sbi_build_request(&message);
ogs_expect(request);
return request;
}

View File

@ -28,6 +28,8 @@ extern "C" {
ogs_sbi_request_t *amf_npcf_am_policy_control_build_create(
amf_ue_t *amf_ue, void *data);
ogs_sbi_request_t *amf_npcf_am_policy_control_build_delete(
amf_ue_t *amf_ue, void *data);
#ifdef __cplusplus
}

View File

@ -96,10 +96,7 @@ int amf_npcf_am_policy_control_handle_create(
supported_features = ogs_uint64_from_string(PolicyAssociation->supp_feat);
amf_ue->am_policy_control_features &= supported_features;
if (amf_ue->policy_association_id)
ogs_free(amf_ue->policy_association_id);
amf_ue->policy_association_id = ogs_strdup(message.h.resource.component[1]);
ogs_assert(amf_ue->policy_association_id);
PCF_AM_POLICY_STORE(amf_ue, message.h.resource.component[1]);
OpenAPI_list_for_each(PolicyAssociation->triggers, node) {
if (node->data) {

View File

@ -216,12 +216,19 @@ int amf_nsmf_pdusession_handle_update_sm_context(
SESSION_SYNC_DONE(amf_ue,
AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST)) {
CLEAR_AMF_UE_TIMER(amf_ue->t3550);
ogs_assert(OGS_OK ==
nas_5gs_send_registration_accept(amf_ue));
if (!PCF_AM_POLICY_ASSOCIATED(amf_ue)) {
ogs_assert(true ==
amf_ue_sbi_discover_and_send(
OpenAPI_nf_type_PCF, amf_ue, NULL,
amf_npcf_am_policy_control_build_create));
} else {
CLEAR_AMF_UE_TIMER(amf_ue->t3550);
ogs_assert(OGS_OK ==
nas_5gs_send_registration_accept(amf_ue));
AMF_UE_CLEAR_N2_TRANSFER(
amf_ue, pdu_session_resource_setup_request);
AMF_UE_CLEAR_N2_TRANSFER(
amf_ue, pdu_session_resource_setup_request);
}
}
} else if (state == AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST) {
AMF_SESS_STORE_N2_TRANSFER(
@ -767,11 +774,19 @@ int amf_nsmf_pdusession_handle_release_sm_context(amf_sess_t *sess, int state)
if (SESSION_SYNC_DONE(
amf_ue, AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) &&
SESSION_SYNC_DONE(
amf_ue, AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST))
amf_ue, AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST)) {
CLEAR_AMF_UE_TIMER(amf_ue->t3550);
ogs_assert(OGS_OK ==
nas_5gs_send_registration_accept(amf_ue));
if (!PCF_AM_POLICY_ASSOCIATED(amf_ue)) {
ogs_assert(true ==
amf_ue_sbi_discover_and_send(
OpenAPI_nf_type_PCF, amf_ue, NULL,
amf_npcf_am_policy_control_build_create));
} else {
CLEAR_AMF_UE_TIMER(amf_ue->t3550);
ogs_assert(OGS_OK ==
nas_5gs_send_registration_accept(amf_ue));
}
}
} else if (state == AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) {
/*
@ -833,8 +848,10 @@ int amf_nsmf_pdusession_handle_release_sm_context(amf_sess_t *sess, int state)
* 7. UEContextReleaseComplete
*/
ogs_assert(OGS_OK ==
nas_5gs_send_de_registration_accept(amf_ue));
ogs_assert(true ==
amf_ue_sbi_discover_and_send(
OpenAPI_nf_type_PCF, amf_ue,
NULL, amf_npcf_am_policy_control_build_delete));
} else if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered)) {
/*

View File

@ -134,32 +134,8 @@ int amf_nudm_sdm_handle_provisioned(
}
}
amf_update_allowed_nssai(amf_ue);
if (!amf_ue->allowed_nssai.num_of_s_nssai) {
if (amf_update_allowed_nssai(amf_ue) == false) {
ogs_error("No Allowed-NSSAI");
ogs_error(" Number of Subscribed S-NSSAI [%d]",
amf_ue->num_of_slice);
for (i = 0; i < amf_ue->num_of_slice; i++) {
ogs_slice_data_t *slice = &amf_ue->slice[i];
if (slice->default_indicator == true) {
ogs_error(" Default S_NSSAI[SST:%d SD:0x%x]",
slice->s_nssai.sst, slice->s_nssai.sd.v);
} else {
ogs_error(" S_NSSAI[SST:%d SD:0x%x]",
slice->s_nssai.sst, slice->s_nssai.sd.v);
}
}
ogs_error(" Number of Requested NSSAI [%d]",
amf_ue->requested_nssai.num_of_s_nssai);
for (i = 0; i < amf_ue->requested_nssai.num_of_s_nssai; i++) {
ogs_error(" PLMN_ID[MCC:%d MNC:%d]",
ogs_plmn_id_mcc(&amf_ue->nr_tai.plmn_id),
ogs_plmn_id_mnc(&amf_ue->nr_tai.plmn_id));
ogs_error(" S_NSSAI[SST:%d SD:0x%x]",
amf_ue->requested_nssai.s_nssai[i].sst,
amf_ue->requested_nssai.s_nssai[i].sd.v);
}
return OGS_ERROR;
}

View File

@ -73,6 +73,11 @@ void pcf_am_state_operational(ogs_fsm_t *s, pcf_event_t *e)
}
break;
CASE(OGS_SBI_HTTP_METHOD_DELETE)
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
OGS_FSM_TRAN(s, pcf_am_state_deleted);
break;
DEFAULT
ogs_error("[%s] Invalid HTTP method [%s]",
pcf_ue->supi, message->h.method);
@ -145,6 +150,30 @@ void pcf_am_state_operational(ogs_fsm_t *s, pcf_event_t *e)
}
}
void pcf_am_state_deleted(ogs_fsm_t *s, pcf_event_t *e)
{
pcf_ue_t *pcf_ue = NULL;
ogs_assert(s);
ogs_assert(e);
pcf_sm_debug(e);
pcf_ue = e->pcf_ue;
ogs_assert(pcf_ue);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
break;
case OGS_FSM_EXIT_SIG:
break;
default:
ogs_error("[%s] Unknown event %s", pcf_ue->supi, pcf_event_get_name(e));
break;
}
}
void pcf_am_state_exception(ogs_fsm_t *s, pcf_event_t *e)
{
pcf_ue_t *pcf_ue = NULL;

View File

@ -137,7 +137,14 @@ void pcf_state_operational(ogs_fsm_t *s, pcf_event_t *e)
}
}
break;
CASE(OGS_SBI_HTTP_METHOD_DELETE)
if (message.h.resource.component[1]) {
pcf_ue = pcf_ue_find_by_association_id(
message.h.resource.component[1]);
} else {
ogs_error("No Policy Association Id");
}
break;
DEFAULT
END
@ -158,6 +165,9 @@ void pcf_state_operational(ogs_fsm_t *s, pcf_event_t *e)
if (OGS_FSM_CHECK(&pcf_ue->sm, pcf_am_state_exception)) {
ogs_error("[%s] State machine exception", pcf_ue->supi);
pcf_ue_remove(pcf_ue);
} else if (OGS_FSM_CHECK(&pcf_ue->sm, pcf_am_state_deleted)) {
ogs_debug("[%s] PCF-AM removed", pcf_ue->supi);
pcf_ue_remove(pcf_ue);
}
break;

View File

@ -43,6 +43,7 @@ void pcf_nf_state_exception(ogs_fsm_t *s, pcf_event_t *e);
void pcf_am_state_initial(ogs_fsm_t *s, pcf_event_t *e);
void pcf_am_state_final(ogs_fsm_t *s, pcf_event_t *e);
void pcf_am_state_operational(ogs_fsm_t *s, pcf_event_t *e);
void pcf_am_state_deleted(ogs_fsm_t *s, pcf_event_t *e);
void pcf_am_state_exception(ogs_fsm_t *s, pcf_event_t *e);
void pcf_sm_state_initial(ogs_fsm_t *s, pcf_event_t *e);