[HR] Implement handling of UE-initiated PDU Session Modification (#2194)

This commit consolidates the entire ue-mod feature branch
into a single update on top of the latest home-routed code.
This commit is contained in:
Sukchan Lee 2025-06-30 10:07:06 +09:00
parent 932101b919
commit 94cf8ee0e0
32 changed files with 2989 additions and 870 deletions

View file

@ -332,7 +332,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.2.200:7777
udr:
sbi:

View file

@ -332,7 +332,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.3.200:7777
udr:
sbi:

View file

@ -327,7 +327,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.1.200:7777
udr:
sbi:

View file

@ -332,7 +332,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.2.200:7777
udr:
sbi:

View file

@ -327,7 +327,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.3.200:7777
udr:
sbi:

View file

@ -332,7 +332,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.1.200:7777
udr:
sbi:

View file

@ -332,7 +332,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.2.200:7777
udr:
sbi:

View file

@ -332,7 +332,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.3.200:7777
udr:
sbi:

View file

@ -327,7 +327,7 @@ af:
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
- uri: http://127.0.1.200:7777
udr:
sbi:

View file

@ -102,21 +102,22 @@ typedef struct ogs_pfcp_xact_s {
#define OGS_PFCP_MODIFY_QOS_DELETE ((uint64_t)1<<16)
#define OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL ((uint64_t)1<<17)
#define OGS_PFCP_MODIFY_ACTIVATE ((uint64_t)1<<18)
#define OGS_PFCP_MODIFY_DEACTIVATE ((uint64_t)1<<19)
#define OGS_PFCP_MODIFY_END_MARKER ((uint64_t)1<<20)
#define OGS_PFCP_MODIFY_ERROR_INDICATION ((uint64_t)1<<21)
#define OGS_PFCP_MODIFY_XN_HANDOVER ((uint64_t)1<<22)
#define OGS_PFCP_MODIFY_N2_HANDOVER ((uint64_t)1<<23)
#define OGS_PFCP_MODIFY_HANDOVER_CANCEL ((uint64_t)1<<24)
#define OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING ((uint64_t)1<<25)
#define OGS_PFCP_MODIFY_URR ((uint64_t)1<<26) /* type of trigger */
#define OGS_PFCP_MODIFY_URR_MEAS_METHOD ((uint64_t)1<<27)
#define OGS_PFCP_MODIFY_URR_REPORT_TRIGGER ((uint64_t)1<<28)
#define OGS_PFCP_MODIFY_URR_QUOTA_VALIDITY_TIME ((uint64_t)1<<29)
#define OGS_PFCP_MODIFY_URR_VOLUME_QUOTA ((uint64_t)1<<30)
#define OGS_PFCP_MODIFY_URR_TIME_QUOTA ((uint64_t)1<<31)
#define OGS_PFCP_MODIFY_URR_VOLUME_THRESH ((uint64_t)1<<32)
#define OGS_PFCP_MODIFY_URR_TIME_THRESH ((uint64_t)1<<33)
#define OGS_PFCP_MODIFY_FROM_ACTIVATING ((uint64_t)1<<19)
#define OGS_PFCP_MODIFY_DEACTIVATE ((uint64_t)1<<20)
#define OGS_PFCP_MODIFY_END_MARKER ((uint64_t)1<<21)
#define OGS_PFCP_MODIFY_ERROR_INDICATION ((uint64_t)1<<22)
#define OGS_PFCP_MODIFY_XN_HANDOVER ((uint64_t)1<<23)
#define OGS_PFCP_MODIFY_N2_HANDOVER ((uint64_t)1<<24)
#define OGS_PFCP_MODIFY_HANDOVER_CANCEL ((uint64_t)1<<25)
#define OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING ((uint64_t)1<<26)
#define OGS_PFCP_MODIFY_URR ((uint64_t)1<<27) /* type of trigger */
#define OGS_PFCP_MODIFY_URR_MEAS_METHOD ((uint64_t)1<<28)
#define OGS_PFCP_MODIFY_URR_REPORT_TRIGGER ((uint64_t)1<<29)
#define OGS_PFCP_MODIFY_URR_QUOTA_VALIDITY_TIME ((uint64_t)1<<30)
#define OGS_PFCP_MODIFY_URR_VOLUME_QUOTA ((uint64_t)1<<31)
#define OGS_PFCP_MODIFY_URR_TIME_QUOTA ((uint64_t)1<<32)
#define OGS_PFCP_MODIFY_URR_VOLUME_THRESH ((uint64_t)1<<33)
#define OGS_PFCP_MODIFY_URR_TIME_THRESH ((uint64_t)1<<34)
uint64_t modify_flags;
#define OGS_PFCP_DELETE_TRIGGER_LOCAL_INITIATED 1

View file

@ -92,12 +92,9 @@ ogs_sbi_request_t *amf_npcf_am_policy_control_build_create(
ogs_error("No ueLocation.nr_location");
goto end;
}
if (amf_ue->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(amf_ue->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("No ueLocation.nr_location->ue_location_timestamp");
goto end;
}
PolicyAssociationRequest.user_loc = &ueLocation;
PolicyAssociationRequest.time_zone =

View file

@ -160,12 +160,9 @@ ogs_sbi_request_t *amf_nsmf_pdusession_build_create_sm_context(
ogs_error("No ueLocation.nr_location");
goto end;
}
if (amf_ue->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(amf_ue->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("No ue_location_timestamp");
goto end;
}
SmContextCreateData.ue_location = &ueLocation;
SmContextCreateData.ue_time_zone = ogs_sbi_timezone_string(ogs_timezone());
@ -391,12 +388,9 @@ ogs_sbi_request_t *amf_nsmf_pdusession_build_update_sm_context(
ogs_error("No ueLocation.nr_location");
goto end;
}
if (amf_ue->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(amf_ue->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("No ueLocation.nr_location->ue_location_timestamp");
goto end;
}
SmContextUpdateData.ue_location = &ueLocation;
}
@ -490,12 +484,9 @@ ogs_sbi_request_t *amf_nsmf_pdusession_build_release_sm_context(
ogs_error("No ueLocation.nr_location");
goto end;
}
if (amf_ue->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(amf_ue->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("No ueLocation.nr_location->ue_location_timestamp");
goto end;
}
SmContextReleaseData.ue_location = &ueLocation;
}

View file

@ -90,10 +90,6 @@ bool nssf_nnrf_nsselection_handle_get_from_amf_or_vnssf(
nssf_home_t *home = nssf_home_find(
&recvmsg->param.home_plmn_id, &recvmsg->param.home_snssai);
if (!home) {
int r, i;
nssf_nnssf_nsselection_param_t param;
ogs_sbi_discovery_option_t *h_discovery_option = NULL;
home = nssf_home_add(
&recvmsg->param.home_plmn_id, &recvmsg->param.home_snssai);
if (!home) {
@ -105,6 +101,12 @@ bool nssf_nnrf_nsselection_handle_get_from_amf_or_vnssf(
recvmsg->param.home_snssai.sd.v);
goto cleanup;
}
}
if (!home->nrf_id || !home->nsi_id) {
int r, i;
nssf_nnssf_nsselection_param_t param;
ogs_sbi_discovery_option_t *h_discovery_option = NULL;
h_discovery_option = ogs_sbi_discovery_option_new();
ogs_assert(h_discovery_option);

View file

@ -1867,8 +1867,8 @@ void smf_sess_remove(smf_sess_t *sess)
if (sess->v_smf.client)
ogs_sbi_client_remove(sess->v_smf.client);
if (sess->n1smbuf)
ogs_pkbuf_free(sess->n1smbuf);
if (sess->n1SmBufFromUe)
ogs_pkbuf_free(sess->n1SmBufFromUe);
OGS_NAS_CLEAR_DATA(&sess->h_smf_extended_protocol_configuration_options);
sess->h_smf_gsm_cause = 0;
@ -1876,6 +1876,10 @@ void smf_sess_remove(smf_sess_t *sess)
CLEAR_QOS_FLOWS_SETUP_LIST(sess->h_smf_qos_flows_setup_list);
CLEAR_QOS_FLOWS_ADD_MOD_REQUEST_LIST(
sess->h_smf_qos_flows_add_mod_request_list);
CLEAR_QOS_FLOWS_REL_REQUEST_LIST(sess->h_smf_qos_flows_rel_request_list);
if (sess->pending_modification_xact)
ogs_sbi_xact_remove(sess->pending_modification_xact);
/* Free SBI object memory */
ogs_sbi_object_free(&sess->sbi);

View file

@ -78,14 +78,25 @@ typedef struct smf_nsmf_pdusession_param_s {
int gsm_cause;
struct {
ED3(uint8_t ue_location:1;,
ED4(uint8_t serving_network:1;,
uint8_t ue_location:1;,
uint8_t ue_timezone:1;,
uint8_t spare:6;)
uint8_t spare:4;)
};
uint32_t dl_teid;
ogs_ip_t dl_ip;
OpenAPI_access_type_e an_type;
OpenAPI_rat_type_e rat_type;
OpenAPI_up_cnx_state_e up_cnx_state;
#define QOS_RULE_CODE_FROM_PFCP_FLAGS(pfcp_flags) \
(pfcp_flags & OGS_PFCP_MODIFY_CREATE) ? \
OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE : \
(pfcp_flags & OGS_PFCP_MODIFY_REMOVE) ? \
OGS_NAS_QOS_CODE_DELETE_EXISTING_QOS_RULE : \
(pfcp_flags & OGS_PFCP_MODIFY_TFT_NEW) ? \
OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE : \
(pfcp_flags & OGS_PFCP_MODIFY_TFT_ADD) ? \
@ -98,46 +109,16 @@ typedef struct smf_nsmf_pdusession_param_s {
#define QOS_RULE_FLOW_DESCRIPTION_CODE_FROM_PFCP_FLAGS(pfcp_flags) \
(pfcp_flags & OGS_PFCP_MODIFY_CREATE) ? \
OGS_NAS_CREATE_NEW_QOS_FLOW_DESCRIPTION : \
(pfcp_flags & OGS_PFCP_MODIFY_REMOVE) ? \
OGS_NAS_DELETE_NEW_QOS_FLOW_DESCRIPTION : \
(pfcp_flags & OGS_PFCP_MODIFY_QOS_MODIFY) ? \
OGS_NAS_MODIFY_NEW_QOS_FLOW_DESCRIPTION : 0
uint8_t qos_flow_description_code;
uint64_t pfcp_flags;
} smf_nsmf_pdusession_param_t;
/* HR flag bit */
#define SMF_UECM_FLAG_HR (1 << 7)
/* Base states (low bits only) */
#define SMF_UECM_STATE_NONE 0
#define SMF_UECM_STATE_REGISTERED 1
#define SMF_UECM_STATE_DEREG_BY_AMF 2
#define SMF_UECM_STATE_DEREG_BY_N1N2 3
/* HR variants (OR base state with HR flag) */
#define SMF_UECM_STATE_REGISTERED_HR \
(SMF_UECM_STATE_REGISTERED | SMF_UECM_FLAG_HR)
#define SMF_UECM_STATE_DEREG_BY_AMF_HR \
(SMF_UECM_STATE_DEREG_BY_AMF | SMF_UECM_FLAG_HR)
#define SMF_UECM_STATE_DEREG_BY_N1N2_HR \
(SMF_UECM_STATE_DEREG_BY_N1N2 | SMF_UECM_FLAG_HR)
/**
* Return true if the PDU session anchor SMF is in the HPLMN
* (Home-Routed Roaming, HR)
*/
static inline bool smf_uecm_anchor_in_hplmn(int state)
{
return !!(state & SMF_UECM_FLAG_HR);
}
/**
* Return true if the PDU session anchor SMF is in the VPLMN
* (Non-Roaming or Local Break-Out Roaming, LBO)
*/
static inline bool smf_uecm_anchor_in_vplmn(int state)
{
return !(state & SMF_UECM_FLAG_HR);
}
typedef struct smf_context_s {
smf_ctf_config_t ctf_config;
const char* diam_conf_path; /* SMF Diameter conf path */
@ -502,6 +483,7 @@ typedef struct smf_sess_s {
OpenAPI_qos_flow_setup_item_free(qosFlowSetupItem); \
} \
OpenAPI_list_free((__lIST)); \
(__lIST) = NULL; \
} while(0)
OpenAPI_list_t *h_smf_qos_flows_setup_list;
#define CLEAR_QOS_FLOWS_ADD_MOD_REQUEST_LIST(__lIST) \
@ -515,8 +497,23 @@ typedef struct smf_sess_s {
qosFlowAddModifyRequestItem); \
} \
OpenAPI_list_free((__lIST)); \
(__lIST) = NULL; \
} while(0)
OpenAPI_list_t *h_smf_qos_flows_add_mod_request_list;
#define CLEAR_QOS_FLOWS_REL_REQUEST_LIST(__lIST) \
do { \
OpenAPI_lnode_t *node = NULL; \
OpenAPI_list_for_each((__lIST), node) { \
OpenAPI_qos_flow_release_request_item_t \
*qosFlowReleaseRequestItem = node->data; \
if (qosFlowReleaseRequestItem) \
OpenAPI_qos_flow_release_request_item_free( \
qosFlowReleaseRequestItem); \
} \
OpenAPI_list_free((__lIST)); \
(__lIST) = NULL; \
} while(0)
OpenAPI_list_t *h_smf_qos_flows_rel_request_list;
#define HOME_ROUTED_ROAMING_IN_HSMF(__sESS) \
((__sESS) && (__sESS)->vsmf_pdu_session_uri)
@ -529,7 +526,7 @@ typedef struct smf_sess_s {
* Keeps the n1SmMsg Content (n1smbuf) in the context of the V-SMF
* for use when creating the n1SmBufFromUe to send to the H-SMF.
*/
ogs_pkbuf_t *n1smbuf;
ogs_pkbuf_t *n1SmBufFromUe;
/* PCF ID */
char *pcf_id;
@ -677,14 +674,43 @@ typedef struct smf_sess_s {
ogs_pool_id_t smf_ue_id;
OpenAPI_resource_status_e resource_status;
bool n1_released;
bool n2_released;
ogs_pool_id_t amf_update_request_stream_id;
ogs_pool_id_t n1_n2_modified_stream_id;
ogs_pool_id_t n1_n2_released_stream_id;
/*
* Section 4.3.3.3 'UE or network requested PDU Session Modification
* (home-routed roaming)'
* - Step 1a: Nsmf_PDUSession_UpdateSMContext Request (AMF -> V-SMF):
* - Step 4a: Nsmf_PDUSession_UpdateSMContext Response (V-SMF -> AMF):
*/
ogs_pool_id_t amf_to_vsmf_modify_stream_id;
/*
* Section 4.3.3.3 'UE or network requested PDU Session Modification
* (home-routed roaming)'
* - Step 3: Nsmf_PDUSession_UpdateSMContext Request (V-SMF -> H-SMF):
* - Step 15: Nsmf_PDUSession_UpdateSMContext Response (V-SMF -> H-SMF):
*/
ogs_pool_id_t vsmf_to_hsmf_modify_stream_id;
/*
* Section 4.3.4.3 'UE or network requested PDU Session Release for
* Home-routed Roaming'
* - Step 1a: Nsmf_PDUSession_UpdateSMContext Request (AMF -> V-SMF):
* - Step 5b: Nsmf_PDUSession_UpdateSMContext Response (V-SMF -> AMF):
*/
ogs_pool_id_t amf_to_vsmf_release_stream_id;
/*
* Section 4.3.4.3 'UE or network requested PDU Session Release for
* Home-routed Roaming'
* - Step 3a: Nsmf_PDUSession_UpdateSMContext Request (V-SMF -> H-SMF):
* - Step 14: Nsmf_PDUSession_UpdateSMContext Response (V-SMF -> H-SMF):
*/
ogs_pool_id_t vsmf_to_hsmf_release_stream_id;
smf_nsmf_pdusession_param_t nsmf_param;
bool establishment_accept_sent;
ogs_sbi_xact_t *pending_modification_xact;
} smf_sess_t;
void smf_context_init(void);

View file

@ -270,6 +270,8 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess)
pkbuf = ogs_nas_5gs_plain_encode(&message);
ogs_assert(pkbuf);
sess->establishment_accept_sent = true;
cleanup:
if (authorized_qos_rules->buffer)
ogs_free(authorized_qos_rules->buffer);
@ -326,8 +328,8 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
ogs_nas_qos_flow_description_t
qos_flow_description[OGS_NAS_MAX_NUM_OF_QOS_FLOW_DESCRIPTION];
OpenAPI_qos_flow_add_modify_request_item_t *qosFlowAddModifyRequestItem =
NULL;
OpenAPI_qos_flow_add_modify_request_item_t *qosFlowAddModRequestItem = NULL;
OpenAPI_qos_flow_release_request_item_t *qosFlowRelRequestItem = NULL;
OpenAPI_lnode_t *node = NULL;
int num, len;
@ -352,24 +354,44 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
num = 0;
OpenAPI_list_for_each(
sess->h_smf_qos_flows_add_mod_request_list, node) {
qosFlowAddModifyRequestItem = node->data;
if (qosFlowAddModifyRequestItem) {
qosFlowAddModRequestItem = node->data;
if (qosFlowAddModRequestItem &&
qosFlowAddModRequestItem->qos_rules) {
ogs_nas_qos_rules_t qos_rules;
len = ogs_base64_decode_len(
qosFlowAddModifyRequestItem->qos_rules);
qosFlowAddModRequestItem->qos_rules);
ogs_assert(len);
qos_rules.buffer = ogs_calloc(1, len);
ogs_assert(qos_rules.buffer);
qos_rules.length =
ogs_base64_decode_binary(
qos_rules.buffer,
qosFlowAddModifyRequestItem->qos_rules);
qos_rules.length = ogs_base64_decode_binary(
qos_rules.buffer, qosFlowAddModRequestItem->qos_rules);
ogs_assert(qos_rules.length);
ogs_assert(1 ==
ogs_nas_parse_qos_rules(
&qos_rule[num], &qos_rules));
ogs_nas_parse_qos_rules(&qos_rule[num], &qos_rules));
ogs_free(qos_rules.buffer);
num++;
}
}
OpenAPI_list_for_each(sess->h_smf_qos_flows_rel_request_list, node) {
qosFlowRelRequestItem = node->data;
if (qosFlowRelRequestItem && qosFlowRelRequestItem->qos_rules) {
ogs_nas_qos_rules_t qos_rules;
len = ogs_base64_decode_len(qosFlowRelRequestItem->qos_rules);
ogs_assert(len);
qos_rules.buffer = ogs_calloc(1, len);
ogs_assert(qos_rules.buffer);
qos_rules.length = ogs_base64_decode_binary(
qos_rules.buffer, qosFlowRelRequestItem->qos_rules);
ogs_assert(qos_rules.length);
ogs_assert(1 ==
ogs_nas_parse_qos_rules(&qos_rule[num], &qos_rules));
ogs_free(qos_rules.buffer);
@ -419,24 +441,53 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
num = 0;
OpenAPI_list_for_each(
sess->h_smf_qos_flows_add_mod_request_list, node) {
qosFlowAddModifyRequestItem = node->data;
if (qosFlowAddModifyRequestItem) {
qosFlowAddModRequestItem = node->data;
if (qosFlowAddModRequestItem &&
qosFlowAddModRequestItem->qos_flow_description) {
ogs_nas_qos_flow_descriptions_t qos_flow_descriptions;
len = ogs_base64_decode_len(
qosFlowAddModifyRequestItem->qos_flow_description);
qosFlowAddModRequestItem->qos_flow_description);
ogs_assert(len);
qos_flow_descriptions.buffer = ogs_calloc(1, len);
ogs_assert(qos_flow_descriptions.buffer);
qos_flow_descriptions.length =
ogs_base64_decode_binary(
qos_flow_descriptions.length = ogs_base64_decode_binary(
qos_flow_descriptions.buffer,
qosFlowAddModifyRequestItem->qos_flow_description);
qosFlowAddModRequestItem->qos_flow_description);
ogs_assert(qos_flow_descriptions.length);
ogs_assert(1 ==
ogs_nas_parse_qos_flow_descriptions(
&qos_flow_description[num], &qos_flow_descriptions));
&qos_flow_description[num],
&qos_flow_descriptions));
ogs_free(qos_flow_descriptions.buffer);
num++;
}
}
OpenAPI_list_for_each(
sess->h_smf_qos_flows_rel_request_list, node) {
qosFlowRelRequestItem = node->data;
if (qosFlowRelRequestItem &&
qosFlowRelRequestItem->qos_flow_description) {
ogs_nas_qos_flow_descriptions_t qos_flow_descriptions;
len = ogs_base64_decode_len(
qosFlowRelRequestItem->qos_flow_description);
ogs_assert(len);
qos_flow_descriptions.buffer = ogs_calloc(1, len);
ogs_assert(qos_flow_descriptions.buffer);
qos_flow_descriptions.length = ogs_base64_decode_binary(
qos_flow_descriptions.buffer,
qosFlowRelRequestItem->qos_flow_description);
ogs_assert(qos_flow_descriptions.length);
ogs_assert(1 ==
ogs_nas_parse_qos_flow_descriptions(
&qos_flow_description[num],
&qos_flow_descriptions));
ogs_free(qos_flow_descriptions.buffer);

View file

@ -211,57 +211,34 @@ static int reconfigure_packet_filter(
} \
} while(0);
int gsm_handle_pdu_session_modification_request(
smf_sess_t *sess, ogs_sbi_stream_t *stream,
ogs_nas_5gs_pdu_session_modification_request_t *
pdu_session_modification_request)
int gsm_handle_pdu_session_modification_qos_rules(
smf_sess_t *sess,
ogs_nas_qos_rules_t *requested_qos_rules,
uint64_t *pfcp_flags)
{
int i, j;
uint64_t pfcp_flags = 0;
smf_bearer_t *qos_flow = NULL;
smf_pf_t *pf = NULL;
smf_ue_t *smf_ue = NULL;
int i, j, num_of_rule = 0;
ogs_nas_qos_rule_t qos_rule[OGS_NAS_MAX_NUM_OF_QOS_RULE];
ogs_nas_qos_flow_description_t
qos_flow_description[OGS_NAS_MAX_NUM_OF_QOS_FLOW_DESCRIPTION];
ogs_nas_qos_rules_t *requested_qos_rules =
&pdu_session_modification_request->requested_qos_rules;
ogs_nas_qos_flow_descriptions_t *requested_qos_flow_descriptions =
&pdu_session_modification_request->requested_qos_flow_descriptions;
smf_ue_t *smf_ue = NULL;
ogs_pkbuf_t *n1smbuf = NULL;
ogs_assert(requested_qos_rules);
ogs_assert(pfcp_flags);
ogs_assert(sess);
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
ogs_assert(smf_ue);
ogs_assert(stream);
ogs_assert(pdu_session_modification_request);
ogs_list_init(&sess->qos_flow_to_modify_list);
if (pdu_session_modification_request->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_5GSM_CAUSE_PRESENT) {
/* Nothing to do */
}
if (pdu_session_modification_request->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_REQUESTED_QOS_RULES_PRESENT) {
int num_of_rule = 0;
num_of_rule = ogs_nas_parse_qos_rules(qos_rule, requested_qos_rules);
if (!num_of_rule) {
ogs_error("[%s:%d] Invalid modification request",
smf_ue->supi, sess->psi);
goto cleanup;
return OGS_ERROR;
}
for (i = 0; i < num_of_rule; i++) {
qos_flow = smf_qos_flow_find_by_qfi(
sess, qos_rule[i].identifier);
smf_pf_t *pf = NULL;
smf_bearer_t *qos_flow =
smf_qos_flow_find_by_qfi(sess, qos_rule[i].identifier);
if (!qos_flow) {
ogs_error("No Qos Flow");
continue;
@ -272,7 +249,7 @@ int gsm_handle_pdu_session_modification_request(
if (qos_rule[i].code == OGS_NAS_QOS_CODE_DELETE_EXISTING_QOS_RULE) {
smf_pf_remove_all(qos_flow);
pfcp_flags |= OGS_PFCP_MODIFY_REMOVE;
*pfcp_flags |= OGS_PFCP_MODIFY_REMOVE;
qos_flow_find_or_add(&sess->qos_flow_to_modify_list,
qos_flow, to_modify_node);
} else if (qos_rule[i].code ==
@ -343,13 +320,13 @@ int gsm_handle_pdu_session_modification_request(
if (qos_rule[i].code ==
OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE) {
pfcp_flags |= OGS_PFCP_MODIFY_TFT_NEW;
*pfcp_flags |= OGS_PFCP_MODIFY_TFT_NEW;
} else if (qos_rule[i].code ==
OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_ADD_PACKET_FILTERS) {
pfcp_flags |= OGS_PFCP_MODIFY_TFT_ADD;
*pfcp_flags |= OGS_PFCP_MODIFY_TFT_ADD;
} else if (qos_rule[i].code ==
OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_REPLACE_ALL_PACKET_FILTERS) {
pfcp_flags |= OGS_PFCP_MODIFY_TFT_REPLACE;
*pfcp_flags |= OGS_PFCP_MODIFY_TFT_REPLACE;
} else
ogs_assert_if_reached();
@ -377,32 +354,54 @@ int gsm_handle_pdu_session_modification_request(
}
if (ogs_list_count(&qos_flow->pf_list)) {
pfcp_flags |= OGS_PFCP_MODIFY_TFT_DELETE;
*pfcp_flags |= OGS_PFCP_MODIFY_TFT_DELETE;
qos_flow_find_or_add(&sess->qos_flow_to_modify_list,
qos_flow, to_modify_node);
} else {
pfcp_flags |= OGS_PFCP_MODIFY_REMOVE;
*pfcp_flags |= OGS_PFCP_MODIFY_REMOVE;
qos_flow_find_or_add(&sess->qos_flow_to_modify_list,
qos_flow, to_modify_node);
}
}
}
if (*pfcp_flags &
(OGS_PFCP_MODIFY_TFT_NEW|OGS_PFCP_MODIFY_TFT_ADD|
OGS_PFCP_MODIFY_TFT_REPLACE|OGS_PFCP_MODIFY_TFT_DELETE))
smf_bearer_tft_update(qos_flow);
}
if (pdu_session_modification_request->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_REQUESTED_QOS_FLOW_DESCRIPTIONS_PRESENT) {
int num_of_description = 0;
return OGS_OK;
}
int gsm_handle_pdu_session_modification_qos_flow_descriptions(
smf_sess_t *sess,
ogs_nas_qos_flow_descriptions_t *requested_qos_flow_descriptions,
uint64_t *pfcp_flags)
{
smf_ue_t *smf_ue = NULL;
int i, j, num_of_description = 0;
ogs_nas_qos_flow_description_t
qos_flow_description[OGS_NAS_MAX_NUM_OF_QOS_FLOW_DESCRIPTION];
ogs_assert(requested_qos_flow_descriptions);
ogs_assert(pfcp_flags);
ogs_assert(sess);
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
ogs_assert(smf_ue);
num_of_description = ogs_nas_parse_qos_flow_descriptions(
qos_flow_description, requested_qos_flow_descriptions);
if (!num_of_description) {
ogs_error("[%s:%d] Invalid modification request",
smf_ue->supi, sess->psi);
goto cleanup;
return OGS_ERROR;
}
for (i = 0; i < num_of_description; i++) {
qos_flow = smf_qos_flow_find_by_qfi(
smf_bearer_t *qos_flow =
smf_qos_flow_find_by_qfi(
sess, qos_flow_description[i].identifier);
if (!qos_flow) {
ogs_error("No Qos Flow");
@ -437,9 +436,64 @@ int gsm_handle_pdu_session_modification_request(
}
}
pfcp_flags |= OGS_PFCP_MODIFY_QOS_MODIFY;
*pfcp_flags |= OGS_PFCP_MODIFY_QOS_MODIFY;
qos_flow_find_or_add(&sess->qos_flow_to_modify_list,
qos_flow, to_modify_node);
if (*pfcp_flags & OGS_PFCP_MODIFY_QOS_MODIFY)
smf_bearer_qos_update(qos_flow);
}
return OGS_OK;
}
int gsm_handle_pdu_session_modification_request(
smf_sess_t *sess, ogs_sbi_stream_t *stream,
ogs_nas_5gs_pdu_session_modification_request_t *
pdu_session_modification_request)
{
int rv;
uint64_t pfcp_flags = 0;
ogs_nas_qos_rules_t *requested_qos_rules =
&pdu_session_modification_request->requested_qos_rules;
ogs_nas_qos_flow_descriptions_t *requested_qos_flow_descriptions =
&pdu_session_modification_request->requested_qos_flow_descriptions;
smf_ue_t *smf_ue = NULL;
ogs_pkbuf_t *n1smbuf = NULL;
ogs_assert(sess);
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
ogs_assert(smf_ue);
ogs_assert(stream);
ogs_assert(pdu_session_modification_request);
ogs_list_init(&sess->qos_flow_to_modify_list);
if (pdu_session_modification_request->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_5GSM_CAUSE_PRESENT) {
/* Nothing to do */
}
if (pdu_session_modification_request->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_REQUESTED_QOS_RULES_PRESENT) {
rv = gsm_handle_pdu_session_modification_qos_rules(
sess, requested_qos_rules, &pfcp_flags);
if (rv != OGS_OK) {
ogs_error("gsm_handle_pdu_session_modification_qos_rules() failed");
goto cleanup;
}
}
if (pdu_session_modification_request->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_REQUESTED_QOS_FLOW_DESCRIPTIONS_PRESENT) {
rv = gsm_handle_pdu_session_modification_qos_flow_descriptions(
sess, requested_qos_flow_descriptions, &pfcp_flags);
if (rv != OGS_OK) {
ogs_error("gsm_handle_pdu_session_modification_"
"qos_flow_descriptions() failed");
goto cleanup;
}
}
@ -463,14 +517,6 @@ int gsm_handle_pdu_session_modification_request(
ogs_assert((pfcp_flags & OGS_PFCP_MODIFY_REMOVE) == 0);
if (pfcp_flags &
(OGS_PFCP_MODIFY_TFT_NEW|OGS_PFCP_MODIFY_TFT_ADD|
OGS_PFCP_MODIFY_TFT_REPLACE|OGS_PFCP_MODIFY_TFT_DELETE))
smf_bearer_tft_update(qos_flow);
if (pfcp_flags & OGS_PFCP_MODIFY_QOS_MODIFY)
smf_bearer_qos_update(qos_flow);
} else {
ogs_fatal("Unknown PFCP-Flags : [0x%llx]", (long long)pfcp_flags);
ogs_assert_if_reached();

View file

@ -31,6 +31,15 @@ int gsm_handle_pdu_session_establishment_request(
ogs_nas_5gs_pdu_session_establishment_request_t *
pdu_session_establishment_request);
int gsm_handle_pdu_session_modification_qos_rules(
smf_sess_t *sess,
ogs_nas_qos_rules_t *requested_qos_rules,
uint64_t *pfcp_flags);
int gsm_handle_pdu_session_modification_qos_flow_descriptions(
smf_sess_t *sess,
ogs_nas_qos_flow_descriptions_t *requested_qos_flow_descriptions,
uint64_t *pfcp_flags);
int gsm_handle_pdu_session_modification_request(
smf_sess_t *sess, ogs_sbi_stream_t *stream,
ogs_nas_5gs_pdu_session_modification_request_t *

File diff suppressed because it is too large Load diff

View file

@ -410,14 +410,93 @@ void smf_5gc_n4_handle_session_modification_response(
if (flags & OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING) {
if (flags & OGS_PFCP_MODIFY_ACTIVATE) {
if (flags & OGS_PFCP_MODIFY_DL_ONLY) {
if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING) {
sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
smf_sbi_send_sm_context_updated_data_up_cnx_state(
sess, stream, OpenAPI_up_cnx_state_ACTIVATED);
} else {
/*
* UE-requested PDU Session Modification(ACTIVATED)
*
* 1. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY|
* OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL|OGS_PFCP_MODIFY_ACTIVATE
* 2. V: if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING)
* pfcp_flags |= OGS_PFCP_MODIFY_FROM_ACTIVATING;
* 3. V*: flags & OGS_PFCP_MODIFY_FROM_ACTIVATING ?
* SMF_UPDATE_STATE_HR_ACTIVATED_FROM_ACTIVATING :
* SMF_UPDATE_STATE_HR_ACTIVATED_FROM_NON_ACTIVATING,
* 4. V*: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 5. V*: smf_nsmf_pdusession_build_hsmf_update_data
* 6. H: smf_nsmf_handle_update_data_in_hsmf
* 7. H: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 8. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY|
* OGS_PFCP_MODIFY_ACTIVATE
* 9. H*: ogs_sbi_send_http_status_no_content
* 10. V: case SMF_UPDATE_STATE_HR_ACTIVATED_FROM_ACTIVATING:
* sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
* smf_sbi_send_sm_context_updated_data_up_cnx_state(
* OpenAPI_up_cnx_state_ACTIVATED);
* case SMF_UPDATE_STATE_HR_ACTIVATED_FROM_NON_ACTIVATING:
* ogs_sbi_send_http_status_no_content
*/
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
ogs_assert(stream);
sess->nsmf_param.request_indication =
OpenAPI_request_indication_UE_REQ_PDU_SES_MOD;
sess->nsmf_param.up_cnx_state =
OpenAPI_up_cnx_state_ACTIVATED;
sess->nsmf_param.serving_network = true;
ogs_assert(OGS_OK ==
ogs_sockaddr_to_ip(
sess->local_dl_addr, sess->local_dl_addr6,
&sess->nsmf_param.dl_ip));
sess->nsmf_param.dl_teid = sess->local_dl_teid;
sess->nsmf_param.an_type = sess->an_type;
sess->nsmf_param.rat_type = sess->sbi_rat_type;
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
smf_nsmf_pdusession_build_hsmf_update_data,
sess, stream,
flags & OGS_PFCP_MODIFY_FROM_ACTIVATING ?
SMF_UPDATE_STATE_ACTIVATED_FROM_ACTIVATING :
SMF_UPDATE_STATE_ACTIVATED_FROM_NON_ACTIVATING,
NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else if (HOME_ROUTED_ROAMING_IN_HSMF(sess)) {
/*
* Network-requested PDU Session Modification
*
* 1. H: OpenAPI_request_indication_NW_REQ_PDU_SES_MOD
* QOS_RULE_CODE_FROM_PFCP_FLAGS
* QOS_RULE_FLOW_DESCRIPTION_CODE_FROM_PFCP_FLAGS
* 2. H: smf_nsmf_pdusession_build_vsmf_update_data
* 3. V: smf_nsmf_handle_update_data_in_vsmf
* 4. V: gsm_build_pdu_session_modification_command+
* ngap_build_pdu_session_resource_modify_request_transfer
* 5. V: OpenAPI_n2_sm_info_type_PDU_RES_MOD_RSP
* if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING)
* sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
* smf_sbi_send_sm_context_updated_data_up_cnx_state(
* OpenAPI_up_cnx_state_ACTIVATED)
* else
* ogs_sbi_send_http_status_no_content(stream)
* 6. V: ogs_sbi_send_http_status_no_content(stream)
* OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMPLETE:
* ogs_sbi_send_http_status_no_content(n1_n2_modified_stream));
* 7. V: case OGS_EVENT_SBI_CLIENT
* CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
* 8. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|
* OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE
* 9. H*: ogs_sbi_send_http_status_no_content
*/
if (stream)
ogs_assert(true ==
ogs_sbi_send_http_status_no_content(stream));
} else {
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
ogs_assert_if_reached();
}
} else if (flags & OGS_PFCP_MODIFY_UL_ONLY) {
smf_n1_n2_message_transfer_param_t param;
@ -433,14 +512,85 @@ void smf_5gc_n4_handle_session_modification_response(
ogs_assert(param.n2smbuf);
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, &param);
if (sess->pending_modification_xact) {
if (ogs_sbi_discover_and_send(
sess->pending_modification_xact) != OGS_OK) {
ogs_error("ogs_sbi_discover_and_send() failed");
ogs_sbi_xact_remove(sess->pending_modification_xact);
}
sess->pending_modification_xact = NULL;
}
} else {
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
ogs_assert_if_reached();
}
} else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) {
if (flags & OGS_PFCP_MODIFY_DL_ONLY) {
/*
* UE-requested PDU Session Modification(DEACTIVATED)
*
* For Home Routed Roaming, delegate PFCP deactivation to H-SMF by
* sending UP_CNX_STATE=DEACTIVATED via HsmfUpdateData.
*
* 1. V: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 2. V: smf_nsmf_pdusession_build_hsmf_update_data
* SMF_UPDATE_STATE_HR_DEACTIVATED
* 3. H: smf_nsmf_handle_update_data_in_hsmf
* 4. H: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 5. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 6. H*: ogs_sbi_send_http_status_no_content
* 7. V: case SMF_UPDATE_STATE_HR_DEACTIVATED:
* 8. V: smf_sbi_send_sm_context_updated_data_up_cnx_state(
* OpenAPI_up_cnx_state_DEACTIVATED)
*/
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
} else if (flags & OGS_PFCP_MODIFY_UL_ONLY) {
ogs_assert(trigger);
if (trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED) {
/*
* UE-requested PDU Session Release
*
* 1. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_UL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 2. V: OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED
* 3. V*: OpenAPI_request_indication_UE_REQ_PDU_SES_REL
* 4. V*: smf_nsmf_pdusession_build_hsmf_update_data
* 5. H: smf_nsmf_handle_update_data_in_hsmf
* 6. H: OpenAPI_request_indication_UE_REQ_PDU_SES_REL
* 6. H: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED
* 7. H: ogs_sbi_send_http_status_no_content
* 8. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 9. H: smf_nsmf_pdusession_build_vsmf_update_data
* 10. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_5gc_n1_n2_release);
* 11. V: smf_nsmf_handle_update_data_in_vsmf
* 12. V: OpenAPI_request_indication_UE_REQ_PDU_SES_REL
* 13. V: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED
* 14. V: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 15. V: ngap_build_pdu_session_resource_release_command_transfer+
* gsm_build_pdu_session_release_command
* 16 V: OGS_FSM_TRAN(&sess->sm, smf_gsm_state_wait_5gc_n1_n2_release)
17. V: case OpenAPI_n2_sm_info_type_PDU_RES_REL_RSP:
case OGS_NAS_5GS_PDU_SESSION_RELEASE_COMPLETE:
* 18. V: ogs_sbi_send_http_status_no_content(n1_n2_released_stream)
* 19. V: OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister);
* 20. H: case OGS_EVENT_SBI_CLIENT:
* 21. H: CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
* 22. H: smf_sbi_cleanup_session(SMF_UECM_STATE_DEREG_BY_N1N2_HR
* SMF_SBI_CLEANUP_MODE_POLICY_FIRST);
* 23. H: smf_sbi_send_status_notify+SMF_SESS_CLEAR(sess)
* 24. V: case OGS_EVENT_SBI_SERVER:
* 25. V: CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
* 26. V: ogs_sbi_send_http_status_no_content+
* smf_sbi_send_sm_context_status_notify
* 27. V: OGS_FSM_TRAN(s, smf_gsm_state_session_will_release);
*/
sess->nsmf_param.request_indication =
OpenAPI_request_indication_UE_REQ_PDU_SES_REL;
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
smf_nsmf_pdusession_build_hsmf_update_data,
@ -449,6 +599,31 @@ void smf_5gc_n4_handle_session_modification_response(
ogs_assert(r != OGS_ERROR);
} else if (trigger ==
OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT) {
/*
* Network-requested PDU Session Release(DUPLICATED)
*
* 1. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_UL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 2. V: OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT,
* 3. V*: OpenAPI_request_indication_NW_REQ_PDU_SES_REL
* 4. V*: smf_nsmf_pdusession_build_hsmf_update_data
* 5. H: smf_nsmf_handle_update_data_in_hsmf
* 6. H: OpenAPI_request_indication_NW_REQ_PDU_SES_REL
* 6. H: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT
* 7. H: ogs_sbi_send_http_status_no_content
* 8. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 9. H: smf_sbi_cleanup_session(SMF_UECM_STATE_DEREG_BY_AMF_HR
* SMF_SBI_CLEANUP_MODE_POLICY_FIRST);
* 10. H: OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister);
* 11. H: SMF_SESS_CLEAR(sess)
* 12. V: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT
* 13. V: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 14. V: ogs_sbi_send_http_status_no_content
* 15. V: OGS_FSM_TRAN(s, smf_gsm_state_session_will_release);
*/
sess->nsmf_param.request_indication =
OpenAPI_request_indication_NW_REQ_PDU_SES_REL;
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
smf_nsmf_pdusession_build_hsmf_update_data,
@ -457,6 +632,28 @@ void smf_5gc_n4_handle_session_modification_response(
ogs_assert(r != OGS_ERROR);
} else if (trigger ==
OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT) {
/*
* Network-requested PDU Session Release
*
* 1. V: smf_nsmf_handle_release_sm_context
* 2. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_UL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 3. V: OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT
* 4. V*: smf_nsmf_pdusession_build_release_data
* 5. H: smf_nsmf_handle_release_data_in_hsmf
* 6. H: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT
* 7. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 8. H: ogs_sbi_send_http_status_no_content
* 9. H: smf_sbi_cleanup_session(SMF_UECM_STATE_DEREG_BY_AMF_HR
* SMF_SBI_CLEANUP_MODE_POLICY_FIRST);
* 10. H: OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister);
* 11. H: SMF_SESS_CLEAR(sess)
* 12. V: smf_nsmf_handle_release_data_in_hsmf
* 13. V: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT
* 14. V: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 15. V: ogs_sbi_send_http_status_no_content
* 16. V: OGS_FSM_TRAN(s, smf_gsm_state_session_will_release);
*/
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
smf_nsmf_pdusession_build_release_data,
@ -467,32 +664,100 @@ void smf_5gc_n4_handle_session_modification_response(
ogs_fatal("Invalid delete trigger[%d]", trigger);
ogs_assert_if_reached();
}
} else if (flags & OGS_PFCP_MODIFY_CREATE) {
if (flags & OGS_PFCP_MODIFY_NETWORK_REQUESTED) {
memset(&sess->nsmf_param, 0, sizeof(sess->nsmf_param));
} else {
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
ogs_assert_if_reached();
}
} else if (
(flags & OGS_PFCP_MODIFY_REMOVE) ||
(flags & OGS_PFCP_MODIFY_CREATE) ||
(flags &
(OGS_PFCP_MODIFY_TFT_NEW|OGS_PFCP_MODIFY_TFT_ADD|
OGS_PFCP_MODIFY_TFT_REPLACE|OGS_PFCP_MODIFY_TFT_DELETE|
OGS_PFCP_MODIFY_QOS_MODIFY))) {
/*
* UE or Network requested PDU Session Modification
*
* 1. H*: OpenAPI_request_indication_NW_REQ_PDU_SES_MOD
* QOS_RULE_CODE_FROM_PFCP_FLAGS
* QOS_RULE_FLOW_DESCRIPTION_CODE_FROM_PFCP_FLAGS
* 2. H*: smf_nsmf_pdusession_build_vsmf_update_data
* 3. V: smf_nsmf_handle_update_data_in_vsmf
* 4. V: gsm_build_pdu_session_modification_command+
* ngap_build_pdu_session_resource_modify_request_transfer
* 5. V: OpenAPI_n2_sm_info_type_PDU_RES_MOD_RSP
* if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING)
* sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
* smf_sbi_send_sm_context_updated_data_up_cnx_state(
* OpenAPI_up_cnx_state_ACTIVATED)
* else
* ogs_sbi_send_http_status_no_content(stream)
* 6. V: ogs_sbi_send_http_status_no_content(stream)
* OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMPLETE:
* ogs_sbi_send_http_status_no_content(n1_n2_modified_stream));
* 7. V: case OGS_EVENT_SBI_CLIENT
* CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
* 8. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|
* OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE
*/
int state = 0;
/* Network Requested PDU Session Modification */
memset(&sess->nsmf_param, 0, sizeof(sess->nsmf_param));
if (flags & OGS_PFCP_MODIFY_NETWORK_REQUESTED) {
sess->nsmf_param.request_indication =
OpenAPI_request_indication_NW_REQ_PDU_SES_MOD;
} else if (flags & OGS_PFCP_MODIFY_UE_REQUESTED) {
sess->nsmf_param.request_indication =
OpenAPI_request_indication_UE_REQ_PDU_SES_MOD;
} else {
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
ogs_assert_if_reached();
}
sess->nsmf_param.qos_rule_code =
QOS_RULE_CODE_FROM_PFCP_FLAGS(flags);
sess->nsmf_param.qos_flow_description_code =
QOS_RULE_FLOW_DESCRIPTION_CODE_FROM_PFCP_FLAGS(flags);
if (flags & OGS_PFCP_MODIFY_REMOVE) {
if (flags & OGS_PFCP_MODIFY_INDIRECT) {
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
ogs_assert_if_reached();
}
state = SMF_REMOVE_STATE_NONE;
} else if (flags & OGS_PFCP_MODIFY_CREATE) {
state = SMF_CREATE_STATE_NONE;
} else if (flags &
(OGS_PFCP_MODIFY_TFT_NEW|OGS_PFCP_MODIFY_TFT_ADD|
OGS_PFCP_MODIFY_TFT_REPLACE|OGS_PFCP_MODIFY_TFT_DELETE|
OGS_PFCP_MODIFY_QOS_MODIFY)) {
state = SMF_UPDATE_STATE_NONE;
}
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
smf_nsmf_pdusession_build_vsmf_update_data,
sess, NULL, 0, NULL);
sess, NULL, state, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else {
ogs_fatal("Invalid PDR-Create flags [0x%llx]",
(long long)flags);
ogs_assert_if_reached();
if (state == SMF_REMOVE_STATE_NONE) {
smf_bearer_t *next = NULL;
ogs_list_for_each_entry_safe(&sess->qos_flow_to_modify_list,
next, qos_flow, to_modify_node) {
smf_sess_t *sess = smf_sess_find_by_id(qos_flow->sess_id);
ogs_assert(sess);
smf_metrics_inst_by_5qi_add(
&sess->serving_plmn_id,
&sess->s_nssai,
sess->session.qos.index,
SMF_METR_GAUGE_SM_QOSFLOWNBR, -1);
smf_bearer_remove(qos_flow);
}
}
} else {
ogs_fatal("Invalid flags [%lld]", (long long)flags);
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
ogs_assert_if_reached();
}
} else if (flags & OGS_PFCP_MODIFY_ACTIVATE) {

View file

@ -66,9 +66,17 @@ bool smf_namf_comm_handle_n1_n2_message_transfer(
if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) {
if (N1N2MessageTransferRspData->cause ==
OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED) {
if (stream)
sess->n1_n2_modified_stream_id =
if (stream) {
if (sess->vsmf_to_hsmf_modify_stream_id >=
OGS_MIN_POOL_ID &&
sess->vsmf_to_hsmf_modify_stream_id <=
OGS_MAX_POOL_ID)
ogs_error("N1 N2 modified stream ID [%d]"
"has not been used yet",
sess->vsmf_to_hsmf_modify_stream_id);
sess->vsmf_to_hsmf_modify_stream_id =
ogs_sbi_id_from_stream(stream);
}
} else {
ogs_error("Not implemented [cause:%d]",
N1N2MessageTransferRspData->cause);
@ -82,6 +90,18 @@ bool smf_namf_comm_handle_n1_n2_message_transfer(
sess, recvmsg->http.location);
else
ogs_error("No HTTP Location");
if (stream) {
if (sess->vsmf_to_hsmf_modify_stream_id >=
OGS_MIN_POOL_ID &&
sess->vsmf_to_hsmf_modify_stream_id <=
OGS_MAX_POOL_ID)
ogs_error("N1 N2 modified stream ID [%d]"
"has not been used yet",
sess->vsmf_to_hsmf_modify_stream_id);
sess->vsmf_to_hsmf_modify_stream_id =
ogs_sbi_id_from_stream(stream);
}
} else {
ogs_error("Not implemented [cause:%d]",
N1N2MessageTransferRspData->cause);
@ -173,9 +193,16 @@ bool smf_namf_comm_handle_n1_n2_message_transfer(
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, &param);
} else if (N1N2MessageTransferRspData->cause ==
OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED) {
if (stream)
sess->n1_n2_released_stream_id =
if (stream) {
if (sess->vsmf_to_hsmf_release_stream_id >=
OGS_MIN_POOL_ID &&
sess->vsmf_to_hsmf_release_stream_id <= OGS_MAX_POOL_ID)
ogs_error("N1 N2 released stream ID [%d]"
"has not been used yet",
sess->vsmf_to_hsmf_release_stream_id);
sess->vsmf_to_hsmf_release_stream_id =
ogs_sbi_id_from_stream(stream);
}
} else {
ogs_error("Not implemented [cause:%d]",
N1N2MessageTransferRspData->cause);

View file

@ -399,10 +399,10 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_request_transfer(
OpenAPI_list_for_each(
sess->h_smf_qos_flows_add_mod_request_list, node) {
OpenAPI_qos_flow_add_modify_request_item_t
*qosFlowAddModifyRequestItem = node->data;
if (qosFlowAddModifyRequestItem) {
*qosFlowAddModRequestItem = node->data;
if (qosFlowAddModRequestItem) {
OpenAPI_qos_flow_profile_t *qosFlowProfile =
qosFlowAddModifyRequestItem->qos_flow_profile;
qosFlowAddModRequestItem->qos_flow_profile;
if (qosFlowProfile) {
ogs_qos_t qos;
@ -469,12 +469,12 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_request_transfer(
QosFlowAddOrModifyRequestItem);
QosFlowAddOrModifyRequestItem->qosFlowIdentifier =
qosFlowAddModifyRequestItem->qfi;
qosFlowAddModRequestItem->qfi;
QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters =
CALLOC(1, sizeof(NGAP_QosFlowLevelQosParameters_t));
ogs_assert(
QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters);
ogs_assert(QosFlowAddOrModifyRequestItem->
qosFlowLevelQosParameters);
fill_qos_level_parameters(
QosFlowAddOrModifyRequestItem->
@ -537,6 +537,28 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_release_request_transfer(
QosFlowListWithCause = &ie->value.choice.QosFlowListWithCause;
/* Home-Routed V-SMF: QoS flow */
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
OpenAPI_lnode_t *node = NULL;
OpenAPI_list_for_each(sess->h_smf_qos_flows_rel_request_list, node) {
OpenAPI_qos_flow_release_request_item_t
*qosFlowRelRequestItem = node->data;
if (qosFlowRelRequestItem) {
QosFlowWithCauseItem = CALLOC(1, sizeof(*QosFlowWithCauseItem));
ASN_SEQUENCE_ADD(&QosFlowListWithCause->list,
QosFlowWithCauseItem);
qosFlowIdentifier = &QosFlowWithCauseItem->qosFlowIdentifier;
*qosFlowIdentifier = qosFlowRelRequestItem->qfi;
Cause = &QosFlowWithCauseItem->cause;
Cause->present = group;
Cause->choice.radioNetwork = cause;
}
}
} else {
ogs_list_for_each_entry(
&sess->qos_flow_to_modify_list, qos_flow, to_modify_node) {
@ -552,6 +574,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_release_request_transfer(
Cause->choice.radioNetwork = cause;
}
}
return ogs_asn_encode(
&asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, &message);

View file

@ -28,7 +28,7 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
smf_ue_t *smf_ue = NULL;
smf_bearer_t *qos_flow = NULL;
int rv, i;
int rv, i, r;
uint32_t remote_dl_teid;
ogs_ip_t remote_dl_ip;
@ -162,20 +162,74 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
}
if (far_update) {
uint64_t pfcp_flags = OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE;
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
/*
* UE-requested PDU Session Modification(ACTIVATED)
*
* 1. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY|
* OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL|OGS_PFCP_MODIFY_ACTIVATE
* 2. V*: if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING)
* pfcp_flags |= OGS_PFCP_MODIFY_FROM_ACTIVATING;
* 3. V: flags & OGS_PFCP_MODIFY_FROM_ACTIVATING ?
* SMF_UPDATE_STATE_HR_ACTIVATED_FROM_ACTIVATING :
* SMF_UPDATE_STATE_HR_ACTIVATED_FROM_NON_ACTIVATING,
* 4. V: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 5. V: smf_nsmf_pdusession_build_hsmf_update_data
* 6. H: smf_nsmf_handle_update_data_in_hsmf
* 7. H: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 8. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY|
* OGS_PFCP_MODIFY_ACTIVATE
* 9. H: ogs_sbi_send_http_status_no_content
* 10. V: case SMF_UPDATE_STATE_HR_ACTIVATED_FROM_ACTIVATING:
* sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
* smf_sbi_send_sm_context_updated_data_up_cnx_state(
* OpenAPI_up_cnx_state_ACTIVATED);
* case SMF_UPDATE_STATE_HR_ACTIVATED_FROM_NON_ACTIVATING:
* ogs_sbi_send_http_status_no_content
*/
pfcp_flags |= OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING;
pfcp_flags |= OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL;
if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING)
pfcp_flags |= OGS_PFCP_MODIFY_FROM_ACTIVATING;
}
ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_all_pdr_modification_request(
sess, stream,
HOME_ROUTED_ROAMING_IN_VSMF(sess) ?
(OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|
OGS_PFCP_MODIFY_DL_ONLY|
OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL|
OGS_PFCP_MODIFY_ACTIVATE) :
(OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE), 0, 0));
sess, stream, pfcp_flags, 0, 0));
} else {
#if 0 /* Modified by pull request #1729 */
/* ACTIVATED Is NOT Included in RESPONSE */
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
#else
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
sess->nsmf_param.request_indication =
OpenAPI_request_indication_UE_REQ_PDU_SES_MOD;
sess->nsmf_param.up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
sess->nsmf_param.serving_network = true;
ogs_assert(OGS_OK ==
ogs_sockaddr_to_ip(
sess->local_dl_addr, sess->local_dl_addr6,
&sess->nsmf_param.dl_ip));
sess->nsmf_param.dl_teid = sess->local_dl_teid;
sess->nsmf_param.an_type = sess->an_type;
sess->nsmf_param.rat_type = sess->sbi_rat_type;
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
smf_nsmf_pdusession_build_hsmf_update_data, sess, stream,
sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING ?
SMF_UPDATE_STATE_ACTIVATED_FROM_ACTIVATING :
SMF_UPDATE_STATE_ACTIVATED_FROM_NON_ACTIVATING,
NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else {
if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING) {
sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
smf_sbi_send_sm_context_updated_data_up_cnx_state(
@ -183,6 +237,7 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
} else {
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
}
}
#endif
}

View file

@ -165,12 +165,9 @@ ogs_sbi_request_t *smf_npcf_smpolicycontrol_build_create(
ogs_error("ueLocation.nr_location");
goto end;
}
if (sess->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("ueLocation.nr_location->ue_location_timestamp");
goto end;
}
SmPolicyContextData.user_location_info = &ueLocation;
@ -405,12 +402,9 @@ ogs_sbi_request_t *smf_npcf_smpolicycontrol_build_delete(
ogs_error("ueLocation.nr_location");
goto end;
}
if (sess->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("ueLocation.nr_location->ue_location_timestamp");
goto end;
}
SmPolicyDeleteData.user_location_info = &ueLocation;
}

View file

@ -166,12 +166,9 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_create_data(
ogs_error("No ueLocation.nr_location");
goto end;
}
if (sess->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("No ue_location_timestamp");
goto end;
}
PduSessionCreateData.ue_location = &ueLocation;
PduSessionCreateData.ue_time_zone = ogs_sbi_timezone_string(ogs_timezone());
@ -211,8 +208,8 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_create_data(
goto end;
}
ogs_assert(sess->n1smbuf);
rv = ogs_nas_5gsm_decode(&nas_message, sess->n1smbuf);
ogs_assert(sess->n1SmBufFromUe);
rv = ogs_nas_5gsm_decode(&nas_message, sess->n1SmBufFromUe);
if (rv == OGS_OK) {
n1SmBufFromUe = gsmue_encode_n1_sm_info(&nas_message);
@ -275,11 +272,11 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_create_data(
} else {
ogs_error("gsm_encode_n1_sm_info() failed [%d]", rv);
ogs_log_hexdump(OGS_LOG_ERROR,
sess->n1smbuf->data, sess->n1smbuf->len);
sess->n1SmBufFromUe->data, sess->n1SmBufFromUe->len);
}
} else {
ogs_error("ogs_nas_5gsm_decode() failed [%d]", rv);
ogs_log_hexdump(OGS_LOG_ERROR, sess->n1smbuf->data, sess->n1smbuf->len);
ogs_log_hexdump(OGS_LOG_ERROR, sess->n1SmBufFromUe->data, sess->n1SmBufFromUe->len);
}
message.PduSessionCreateData = &PduSessionCreateData;
@ -324,9 +321,9 @@ end:
if (PduSessionCreateData.ue_time_zone)
ogs_free(PduSessionCreateData.ue_time_zone);
if (sess->n1smbuf) {
ogs_pkbuf_free(sess->n1smbuf);
sess->n1smbuf = NULL;
if (sess->n1SmBufFromUe) {
ogs_pkbuf_free(sess->n1SmBufFromUe);
sess->n1SmBufFromUe = NULL;
}
if (n1SmBufFromUe)
@ -348,6 +345,7 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
OpenAPI_hsmf_update_data_t HsmfUpdateData;
OpenAPI_ng_ap_cause_t ngApCause;
OpenAPI_tunnel_info_t vcnTunnelInfo;
OpenAPI_user_location_t ueLocation;
int rv;
@ -368,6 +366,7 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
memset(&HsmfUpdateData, 0, sizeof(HsmfUpdateData));
memset(&ngApCause, 0, sizeof(ngApCause));
memset(&vcnTunnelInfo, 0, sizeof(vcnTunnelInfo));
memset(&ueLocation, 0, sizeof(ueLocation));
HsmfUpdateData.request_indication = sess->nsmf_param.request_indication;
@ -375,6 +374,8 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
HsmfUpdateData.cause = sess->nsmf_param.cause;
HsmfUpdateData.up_cnx_state = sess->nsmf_param.up_cnx_state;
if (sess->nsmf_param.ngap_cause.group) {
HsmfUpdateData.ng_ap_cause = &ngApCause;
ngApCause.group = sess->nsmf_param.ngap_cause.group;
@ -386,6 +387,32 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
HsmfUpdateData._5g_mm_cause_value = sess->nsmf_param.gmm_cause;
}
if (sess->nsmf_param.serving_network) {
HsmfUpdateData.serving_network =
ogs_sbi_build_plmn_id_nid(&sess->nr_tai.plmn_id);
if (!HsmfUpdateData.serving_network) {
ogs_error("No serving_network");
goto end;
}
}
if (sess->nsmf_param.dl_ip.ipv4)
vcnTunnelInfo.ipv4_addr = ogs_ipv4_to_string(
sess->nsmf_param.dl_ip.addr);
if (sess->nsmf_param.dl_ip.ipv6)
vcnTunnelInfo.ipv6_addr = ogs_ipv6addr_to_string(
sess->nsmf_param.dl_ip.addr6);
if (vcnTunnelInfo.ipv4_addr || vcnTunnelInfo.ipv6_addr) {
vcnTunnelInfo.gtp_teid = ogs_uint32_to_0string(
sess->nsmf_param.dl_teid);
HsmfUpdateData.vcn_tunnel_info = &vcnTunnelInfo;
}
HsmfUpdateData.an_type = sess->nsmf_param.an_type;
HsmfUpdateData.rat_type = sess->nsmf_param.rat_type;
if (sess->nsmf_param.ue_location) {
ueLocation.nr_location = ogs_sbi_build_nr_location(
&sess->nr_tai, &sess->nr_cgi);
@ -393,12 +420,9 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
ogs_error("No ueLocation.nr_location");
goto end;
}
if (sess->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("No ue_location_timestamp");
goto end;
}
HsmfUpdateData.ue_location = &ueLocation;
}
@ -410,8 +434,8 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
}
}
if (sess->n1smbuf) {
rv = ogs_nas_5gsm_decode(&nas_message, sess->n1smbuf);
if (sess->n1SmBufFromUe) {
rv = ogs_nas_5gsm_decode(&nas_message, sess->n1SmBufFromUe);
if (rv == OGS_OK) {
n1SmBufFromUe = gsmue_encode_n1_sm_info(&nas_message);
@ -428,12 +452,12 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
} else {
ogs_error("gsm_encode_n1_sm_info() failed [%d]", rv);
ogs_log_hexdump(OGS_LOG_ERROR,
sess->n1smbuf->data, sess->n1smbuf->len);
sess->n1SmBufFromUe->data, sess->n1SmBufFromUe->len);
}
} else {
ogs_error("ogs_nas_5gsm_decode() failed [%d]", rv);
ogs_log_hexdump(OGS_LOG_ERROR,
sess->n1smbuf->data, sess->n1smbuf->len);
sess->n1SmBufFromUe->data, sess->n1SmBufFromUe->len);
}
}
@ -446,6 +470,16 @@ end:
if (message.h.uri)
ogs_free(message.h.uri);
if (HsmfUpdateData.serving_network)
ogs_sbi_free_plmn_id_nid(HsmfUpdateData.serving_network);
if (vcnTunnelInfo.ipv4_addr)
ogs_free(vcnTunnelInfo.ipv4_addr);
if (vcnTunnelInfo.ipv6_addr)
ogs_free(vcnTunnelInfo.ipv6_addr);
if (vcnTunnelInfo.gtp_teid)
ogs_free(vcnTunnelInfo.gtp_teid);
if (ueLocation.nr_location) {
if (ueLocation.nr_location->ue_location_timestamp)
ogs_free(ueLocation.nr_location->ue_location_timestamp);
@ -454,9 +488,9 @@ end:
if (HsmfUpdateData.ue_time_zone)
ogs_free(HsmfUpdateData.ue_time_zone);
if (sess->n1smbuf) {
ogs_pkbuf_free(sess->n1smbuf);
sess->n1smbuf = NULL;
if (sess->n1SmBufFromUe) {
ogs_pkbuf_free(sess->n1SmBufFromUe);
sess->n1SmBufFromUe = NULL;
}
return request;
@ -474,8 +508,10 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
ogs_pkbuf_t *n1SmBufToUe = NULL;
OpenAPI_list_t *qosFlowsAddModRequestList = NULL;
OpenAPI_qos_flow_add_modify_request_item_t *qosFlowAddModifyRequestItem =
OpenAPI_qos_flow_add_modify_request_item_t *qosFlowAddModRequestItem =
NULL;
OpenAPI_list_t *qosFlowsRelRequestList = NULL;
OpenAPI_qos_flow_release_request_item_t *qosFlowRelRequestItem = NULL;
smf_bearer_t *qos_flow = NULL;
@ -501,6 +537,8 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
qosFlowsAddModRequestList = OpenAPI_list_create();
ogs_assert(qosFlowsAddModRequestList);
qosFlowsRelRequestList = OpenAPI_list_create();
ogs_assert(qosFlowsRelRequestList);
int i = 0;
@ -513,14 +551,11 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
OpenAPI_arp_t *Arp = NULL;
OpenAPI_gbr_qos_flow_information_t *gbrQosFlowInfo = NULL;
char *encoded_qos_rules = NULL;
char *encoded_qos_flow_description = NULL;
ogs_assert(i < OGS_MAX_NUM_OF_BEARER);
qosFlowAddModifyRequestItem =
ogs_calloc(1, sizeof(*qosFlowAddModifyRequestItem));
ogs_assert(qosFlowAddModifyRequestItem);
qosFlowAddModifyRequestItem->qfi = qos_flow->qfi;
if (sess->nsmf_param.qos_rule_code) {
ogs_nas_qos_rules_t authorized_qos_rules;
ogs_nas_qos_rule_t qos_rule;
@ -541,10 +576,10 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
}
enc_len = ogs_base64_encode_len(authorized_qos_rules.length);
qosFlowAddModifyRequestItem->qos_rules = ogs_calloc(1, enc_len);
ogs_assert(qosFlowAddModifyRequestItem->qos_rules);
encoded_qos_rules = ogs_calloc(1, enc_len);
ogs_assert(encoded_qos_rules);
ogs_base64_encode(
qosFlowAddModifyRequestItem->qos_rules,
encoded_qos_rules,
authorized_qos_rules.buffer,
authorized_qos_rules.length);
@ -574,41 +609,53 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
enc_len = ogs_base64_encode_len(
authorized_qos_flow_descriptions.length);
qosFlowAddModifyRequestItem->qos_flow_description =
ogs_calloc(1, enc_len);
ogs_assert(qosFlowAddModifyRequestItem->qos_flow_description);
encoded_qos_flow_description = ogs_calloc(1, enc_len);
ogs_assert(encoded_qos_flow_description);
ogs_base64_encode(
qosFlowAddModifyRequestItem->qos_flow_description,
encoded_qos_flow_description,
authorized_qos_flow_descriptions.buffer,
authorized_qos_flow_descriptions.length);
ogs_free(authorized_qos_flow_descriptions.buffer);
if (qos_flow->qos.mbr.downlink && qos_flow->qos.mbr.uplink &&
qos_flow->qos.gbr.downlink && qos_flow->qos.gbr.uplink) {
gbrQosFlowInfo = ogs_calloc(1, sizeof(*gbrQosFlowInfo));
ogs_assert(gbrQosFlowInfo);
gbrQosFlowInfo->max_fbr_ul = ogs_sbi_bitrate_to_string(
qos_flow->qos.mbr.uplink, OGS_SBI_BITRATE_BPS);
gbrQosFlowInfo->max_fbr_dl = ogs_sbi_bitrate_to_string(
qos_flow->qos.mbr.downlink, OGS_SBI_BITRATE_BPS);
gbrQosFlowInfo->gua_fbr_ul = ogs_sbi_bitrate_to_string(
qos_flow->qos.gbr.uplink, OGS_SBI_BITRATE_BPS);
gbrQosFlowInfo->gua_fbr_dl = ogs_sbi_bitrate_to_string(
qos_flow->qos.gbr.downlink, OGS_SBI_BITRATE_BPS);
}
}
if (sess->nsmf_param.qos_rule_code ==
OGS_NAS_QOS_CODE_DELETE_EXISTING_QOS_RULE ||
sess->nsmf_param.qos_flow_description_code ==
OGS_NAS_DELETE_NEW_QOS_FLOW_DESCRIPTION) {
if (sess->nsmf_param.qos_rule_code !=
OGS_NAS_QOS_CODE_DELETE_EXISTING_QOS_RULE ||
sess->nsmf_param.qos_flow_description_code !=
OGS_NAS_DELETE_NEW_QOS_FLOW_DESCRIPTION)
ogs_error("Invalid qosRule[%d]/qosFlowDesc[%d]",
sess->nsmf_param.qos_rule_code,
sess->nsmf_param.qos_flow_description_code);
qosFlowRelRequestItem =
ogs_calloc(1, sizeof(*qosFlowRelRequestItem));
ogs_assert(qosFlowRelRequestItem);
qosFlowRelRequestItem->qfi = qos_flow->qfi;
qosFlowRelRequestItem->qos_rules = encoded_qos_rules;
qosFlowRelRequestItem->qos_flow_description =
encoded_qos_flow_description;
OpenAPI_list_add(qosFlowsRelRequestList, qosFlowRelRequestItem);
} else if (sess->nsmf_param.qos_rule_code ||
sess->nsmf_param.qos_flow_description_code) {
Arp = ogs_calloc(1, sizeof(*Arp));
ogs_assert(Arp);
if (qos_flow->qos.arp.pre_emption_capability ==
OGS_5GC_PRE_EMPTION_ENABLED)
Arp->preempt_cap = OpenAPI_preemption_capability_MAY_PREEMPT;
Arp->preempt_cap =
OpenAPI_preemption_capability_MAY_PREEMPT;
else if (qos_flow->qos.arp.pre_emption_capability ==
OGS_5GC_PRE_EMPTION_DISABLED)
Arp->preempt_cap = OpenAPI_preemption_capability_NOT_PREEMPT;
Arp->preempt_cap =
OpenAPI_preemption_capability_NOT_PREEMPT;
else {
ogs_error("No Arp->preempt_cap");
goto end;
@ -628,16 +675,50 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
}
Arp->priority_level = qos_flow->qos.arp.priority_level;
if (qos_flow->qos.mbr.downlink && qos_flow->qos.mbr.uplink &&
qos_flow->qos.gbr.downlink && qos_flow->qos.gbr.uplink) {
gbrQosFlowInfo = ogs_calloc(1, sizeof(*gbrQosFlowInfo));
ogs_assert(gbrQosFlowInfo);
gbrQosFlowInfo->max_fbr_ul = ogs_sbi_bitrate_to_string(
qos_flow->qos.mbr.uplink, OGS_SBI_BITRATE_BPS);
gbrQosFlowInfo->max_fbr_dl = ogs_sbi_bitrate_to_string(
qos_flow->qos.mbr.downlink, OGS_SBI_BITRATE_BPS);
gbrQosFlowInfo->gua_fbr_ul = ogs_sbi_bitrate_to_string(
qos_flow->qos.gbr.uplink, OGS_SBI_BITRATE_BPS);
gbrQosFlowInfo->gua_fbr_dl = ogs_sbi_bitrate_to_string(
qos_flow->qos.gbr.downlink, OGS_SBI_BITRATE_BPS);
}
qosFlowProfile = ogs_calloc(1, sizeof(*qosFlowProfile));
ogs_assert(qosFlowProfile);
qosFlowProfile->arp = Arp;
qosFlowProfile->_5qi = qos_flow->qos.index;
qosFlowProfile->gbr_qos_flow_info = gbrQosFlowInfo;
qosFlowAddModifyRequestItem->qos_flow_profile = qosFlowProfile;
qosFlowAddModRequestItem =
ogs_calloc(1, sizeof(*qosFlowAddModRequestItem));
ogs_assert(qosFlowAddModRequestItem);
qosFlowAddModRequestItem->qfi = qos_flow->qfi;
qosFlowAddModRequestItem->qos_rules = encoded_qos_rules;
qosFlowAddModRequestItem->qos_flow_description =
encoded_qos_flow_description;
qosFlowAddModRequestItem->qos_flow_profile = qosFlowProfile;
OpenAPI_list_add(qosFlowsAddModRequestList,
qosFlowAddModifyRequestItem);
qosFlowAddModRequestItem);
} else {
ogs_error("Invalid qosRule[%d]/qosFlowDesc[%d]",
sess->nsmf_param.qos_rule_code,
sess->nsmf_param.qos_flow_description_code);
}
i++;
}
if (qosFlowsAddModRequestList->count)
VsmfUpdateData.qos_flows_add_mod_request_list =
@ -645,8 +726,10 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
else
OpenAPI_list_free(qosFlowsAddModRequestList);
i++;
}
if (qosFlowsRelRequestList->count)
VsmfUpdateData.qos_flows_rel_request_list = qosFlowsRelRequestList;
else
OpenAPI_list_free(qosFlowsRelRequestList);
break;
case OpenAPI_request_indication_NW_REQ_PDU_SES_REL:
@ -681,6 +764,7 @@ end:
CLEAR_QOS_FLOWS_ADD_MOD_REQUEST_LIST(
VsmfUpdateData.qos_flows_add_mod_request_list);
CLEAR_QOS_FLOWS_REL_REQUEST_LIST(VsmfUpdateData.qos_flows_rel_request_list);
return request;
}
@ -732,12 +816,9 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_release_data(
ogs_error("No ueLocation.nr_location");
goto end;
}
if (sess->ue_location_timestamp)
ueLocation.nr_location->ue_location_timestamp =
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
if (!ueLocation.nr_location->ue_location_timestamp) {
ogs_error("No ue_location_timestamp");
goto end;
}
ReleaseData.ue_location = &ueLocation;
}

View file

@ -22,6 +22,7 @@
#include "ngap-path.h"
#include "pfcp-path.h"
#include "local-path.h"
#include "gsm-handler.h"
#include "nsmf-handler.h"
bool smf_nsmf_handle_create_sm_context(
@ -42,6 +43,7 @@ bool smf_nsmf_handle_create_sm_context(
char *fqdn = NULL;
uint16_t fqdn_port = 0;
ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
char *home_network_domain = NULL;
OpenAPI_sm_context_create_data_t *SmContextCreateData = NULL;
OpenAPI_nr_location_t *NrLocation = NULL;
@ -351,8 +353,7 @@ bool smf_nsmf_handle_create_sm_context(
* the full DNN in LBO and non-roaming scenarios. If the Operator Identifier
* is absent, the serving core network operator shall be assumed.
*/
if (SmContextCreateData->dnn) {
char *home_network_domain =
home_network_domain =
ogs_home_network_domain_from_fqdn(SmContextCreateData->dnn);
if (home_network_domain) {
@ -410,7 +411,6 @@ bool smf_nsmf_handle_create_sm_context(
ogs_free(sess->full_dnn);
sess->full_dnn = NULL;
}
}
ogs_assert(SmContextCreateData->serving_nf_id);
if (sess->amf_nf_id) ogs_free(sess->amf_nf_id);
@ -598,9 +598,9 @@ bool smf_nsmf_handle_create_sm_context(
ul_pdr->precedence = OGS_PFCP_DEFAULT_PDR_PRECEDENCE;
/* Save N1 SM Message and send it to H-SMF */
if (sess->n1smbuf) ogs_pkbuf_free(sess->n1smbuf);
sess->n1smbuf = ogs_pkbuf_copy(n1smbuf);
ogs_assert(sess->n1smbuf);
if (sess->n1SmBufFromUe) ogs_pkbuf_free(sess->n1SmBufFromUe);
sess->n1SmBufFromUe = ogs_pkbuf_copy(n1smbuf);
ogs_assert(sess->n1SmBufFromUe);
ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_session_establishment_request(sess, NULL, 0));
@ -611,7 +611,7 @@ bool smf_nsmf_handle_create_sm_context(
bool smf_nsmf_handle_update_sm_context(
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
{
int i;
int r;
smf_ue_t *smf_ue = NULL;
ogs_sbi_message_t sendmsg;
@ -644,6 +644,12 @@ bool smf_nsmf_handle_update_sm_context(
memset(&sess->nsmf_param, 0, sizeof(sess->nsmf_param));
/* Remove N1 SM Message From UE */
if (sess->n1SmBufFromUe) {
ogs_pkbuf_free(sess->n1SmBufFromUe);
sess->n1SmBufFromUe = NULL;
}
if (SmContextUpdateData->ue_location &&
SmContextUpdateData->ue_location->nr_location) {
OpenAPI_nr_location_t *NrLocation =
@ -703,46 +709,23 @@ bool smf_nsmf_handle_update_sm_context(
ogs_assert(gsm_header);
sess->pti = gsm_header->procedure_transaction_identity;
switch (gsm_header->message_type) {
case OGS_NAS_5GS_PDU_SESSION_RELEASE_REQUEST:
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
switch (gsm_header->message_type) {
case OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST:
case OGS_NAS_5GS_PDU_SESSION_RELEASE_REQUEST:
/* Save N1 SM Message and send it to H-SMF */
if (sess->n1smbuf) ogs_pkbuf_free(sess->n1smbuf);
sess->n1smbuf = ogs_pkbuf_copy(n1smbuf);
ogs_assert(sess->n1smbuf);
/* UE Requested PDU Session Release */
sess->nsmf_param.request_indication =
OpenAPI_request_indication_UE_REQ_PDU_SES_REL;
/* Store Stream ID */
sess->amf_update_request_stream_id =
ogs_sbi_id_from_stream(stream);
ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_all_pdr_modification_request(
sess, stream,
OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|
OGS_PFCP_MODIFY_UL_ONLY|
OGS_PFCP_MODIFY_DEACTIVATE,
OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED, 0));
} else {
n1smbuf = ogs_pkbuf_copy(n1smbuf);
ogs_assert(n1smbuf);
nas_5gs_send_to_gsm(sess, stream, n1smbuf);
}
sess->n1SmBufFromUe = ogs_pkbuf_copy(n1smbuf);
ogs_assert(sess->n1SmBufFromUe);
break;
default:
break;
}
}
/*
* Do not send PFCP Modification on PDU session release complete.
* PFCP Modification should only be sent on PDU session release request.
*/
n1smbuf = ogs_pkbuf_copy(n1smbuf);
ogs_assert(n1smbuf);
nas_5gs_send_to_gsm(sess, stream, n1smbuf);
}
return true;
@ -779,6 +762,37 @@ bool smf_nsmf_handle_update_sm_context(
return false;
}
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
/*
* UE-requested PDU Session Modification(ACTIVATED)
*
* 1. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY|
* OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL|OGS_PFCP_MODIFY_ACTIVATE
* 2. V: if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING)
* pfcp_flags |= OGS_PFCP_MODIFY_FROM_ACTIVATING;
* 3. V: flags & OGS_PFCP_MODIFY_FROM_ACTIVATING ?
* SMF_UPDATE_STATE_HR_ACTIVATED_FROM_ACTIVATING :
* SMF_UPDATE_STATE_HR_ACTIVATED_FROM_NON_ACTIVATING,
* 4. V: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 5. V: smf_nsmf_pdusession_build_hsmf_update_data
* 6. H: smf_nsmf_handle_update_data_in_hsmf
* 7. H: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 8. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY|
* OGS_PFCP_MODIFY_ACTIVATE
* 9. H: ogs_sbi_send_http_status_no_content
* 10. V: case SMF_UPDATE_STATE_HR_ACTIVATED_FROM_ACTIVATING:
* sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
* smf_sbi_send_sm_context_updated_data_up_cnx_state(
* OpenAPI_up_cnx_state_ACTIVATED);
* case SMF_UPDATE_STATE_HR_ACTIVATED_FROM_NON_ACTIVATING:
* ogs_sbi_send_http_status_no_content
*/
if (SmContextUpdateData->ue_location)
sess->nsmf_param.ue_location = true;
if (SmContextUpdateData->ue_time_zone)
sess->nsmf_param.ue_timezone = true;
}
/*
* NOTE : The pkbuf created in the SBI message will be removed
* from ogs_sbi_message_free().
@ -802,28 +816,77 @@ bool smf_nsmf_handle_update_sm_context(
if (sess->ngap_state.pdu_session_resource_release ==
SMF_NGAP_STATE_DELETE_TRIGGER_UE_REQUESTED) {
/*
* 1. UE->SMF: PDU session release request
* 2. PFCP Session Deletion Request/Response
* 3. AMF/SMF->UE : PDUSessionResourceReleaseCommand +
* PDU session release command
* sess->ngap_state.pdu_session_resource_release is set
* to SMF_NGAP_STATE_DELETE_TRIGGER_UE_REQUESTED
* 4. UE->AMF/SMF : PDUSessionResourceReleaseResponse
* If UE initiates PDU Session Release, PFCP context is already removed.
* In this case, skip PFCP deactivation and only send UP_CNX_STATE=DEACTIVATED.
*
* If UE sends UEContextReleaseRequest to the AMF/SMF,
* there is no PFCP context in the SMF/UPF.
* Typical flow:
* 1. UE -> SMF: PDU Session Release Request
* 2. SMF -> UPF: PFCP Session Deletion
* 3. SMF -> UE : ReleaseCommand (NAS + NGAP)
* 4. UE -> SMF: PDU Session Release Response
*
* So, PFCP deactivation is skipped.
* If UE sends UEContextReleaseRequest after step 4,
* PFCP session no longer exists in UPF.
*/
smf_sbi_send_sm_context_updated_data_up_cnx_state(
sess, stream, OpenAPI_up_cnx_state_DEACTIVATED);
} else {
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
/*
* UE-requested PDU Session Modification(DEACTIVATED)
*
* For Home Routed Roaming, delegate PFCP deactivation to H-SMF by
* sending UP_CNX_STATE=DEACTIVATED via HsmfUpdateData.
*
* 1. V*: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 2. V*: smf_nsmf_pdusession_build_hsmf_update_data
* SMF_UPDATE_STATE_HR_DEACTIVATED
* 3. H: smf_nsmf_handle_update_data_in_hsmf
* 4. H: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 5. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 6. H: ogs_sbi_send_http_status_no_content
* 7. V: case SMF_UPDATE_STATE_HR_DEACTIVATED:
* 8. V: smf_sbi_send_sm_context_updated_data_up_cnx_state(
* OpenAPI_up_cnx_state_DEACTIVATED)
*/
sess->nsmf_param.request_indication =
OpenAPI_request_indication_UE_REQ_PDU_SES_MOD;
sess->nsmf_param.up_cnx_state =
SmContextUpdateData->up_cnx_state;
if (SmContextUpdateData->ue_location)
sess->nsmf_param.ue_location = true;
if (SmContextUpdateData->ue_time_zone)
sess->nsmf_param.ue_timezone = true;
if (SmContextUpdateData->ng_ap_cause) {
OpenAPI_ng_ap_cause_t *ngApCause =
SmContextUpdateData->ng_ap_cause;
sess->nsmf_param.ngap_cause.group = ngApCause->group;
sess->nsmf_param.ngap_cause.value = ngApCause->value;
}
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
smf_nsmf_pdusession_build_hsmf_update_data,
sess, stream, SMF_UPDATE_STATE_DEACTIVATED, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else {
/*
* For non-HRR sessions, directly send PFCP PDR modification with
* DL-only deactivation to the local UPF.
*/
ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_all_pdr_modification_request(
sess, stream,
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE,
0, 0));
}
}
} else if (SmContextUpdateData->up_cnx_state ==
OpenAPI_up_cnx_state_ACTIVATING) {
@ -831,9 +894,6 @@ bool smf_nsmf_handle_update_sm_context(
/*********************************************************
* Handle ACTIVATING
********************************************************/
OpenAPI_sm_context_updated_data_t SmContextUpdatedData;
OpenAPI_ref_to_binary_data_t n2SmInfo;
if (!OGS_FSM_CHECK(&sess->sm, smf_gsm_state_operational)) {
/*
* TS29.502 5.2.2.3.2.2
@ -879,38 +939,45 @@ bool smf_nsmf_handle_update_sm_context(
return false;
}
memset(&sendmsg, 0, sizeof(sendmsg));
sendmsg.SmContextUpdatedData = &SmContextUpdatedData;
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
/*
* UE-requested PDU Session Modification(ACTIVATING)
*
* 1. V*: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 2. V*: smf_nsmf_pdusession_build_hsmf_update_data
* SMF_UPDATE_STATE_HR_ACTIVATING
* 3. H: smf_nsmf_handle_update_data_in_hsmf
* 4. H: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD
* 5. H: ogs_sbi_send_http_status_no_content
* 6. V: ngap_build_pdu_session_resource_setup_request_transfer
* 7. V: smf_sbi_send_sm_context_updated_data(
* OpenAPI_up_cnx_state_ACTIVATING,
* OpenAPI_n2_sm_info_type_PDU_RES_SETUP_REQ, n2smbuf)
*/
sess->nsmf_param.request_indication =
OpenAPI_request_indication_UE_REQ_PDU_SES_MOD;
memset(&SmContextUpdatedData, 0, sizeof(SmContextUpdatedData));
SmContextUpdatedData.up_cnx_state = OpenAPI_up_cnx_state_ACTIVATING;
SmContextUpdatedData.n2_sm_info_type =
OpenAPI_n2_sm_info_type_PDU_RES_SETUP_REQ;
SmContextUpdatedData.n2_sm_info = &n2SmInfo;
sess->nsmf_param.up_cnx_state =
SmContextUpdateData->up_cnx_state;
memset(&n2SmInfo, 0, sizeof(n2SmInfo));
n2SmInfo.content_id = (char *)OGS_SBI_CONTENT_NGAP_SM_ID;
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
smf_nsmf_pdusession_build_hsmf_update_data,
sess, stream, SMF_UPDATE_STATE_ACTIVATING, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
sendmsg.num_of_part = 0;
} else {
ogs_pkbuf_t *n2smbuf =
ngap_build_pdu_session_resource_setup_request_transfer(
sess);
ogs_assert(n2smbuf);
sendmsg.part[sendmsg.num_of_part].pkbuf =
ngap_build_pdu_session_resource_setup_request_transfer(sess);
if (sendmsg.part[sendmsg.num_of_part].pkbuf) {
sendmsg.part[sendmsg.num_of_part].content_id =
(char *)OGS_SBI_CONTENT_NGAP_SM_ID;
sendmsg.part[sendmsg.num_of_part].content_type =
(char *)OGS_SBI_CONTENT_NGAP_TYPE;
sendmsg.num_of_part++;
smf_sbi_send_sm_context_updated_data(
sess, stream,
OpenAPI_up_cnx_state_ACTIVATING, 0, NULL,
OpenAPI_n2_sm_info_type_PDU_RES_SETUP_REQ, n2smbuf);
}
response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_OK);
ogs_assert(response);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
for (i = 0; i < sendmsg.num_of_part; i++)
if (sendmsg.part[i].pkbuf)
ogs_pkbuf_free(sendmsg.part[i].pkbuf);
} else {
char *strerror = ogs_msprintf("[%s:%d] Invalid upCnxState [%d]",
smf_ue->supi, sess->psi, SmContextUpdateData->up_cnx_state);
@ -1037,16 +1104,28 @@ bool smf_nsmf_handle_update_sm_context(
} else {
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
/* Network Initiated PDU Session Release */
sess->nsmf_param.request_indication =
OpenAPI_request_indication_NW_REQ_PDU_SES_REL;
/* Remove N1 SM Message */
if (sess->n1smbuf) {
ogs_pkbuf_free(sess->n1smbuf);
sess->n1smbuf = NULL;
}
/*
* Network-requested PDU Session Release(DUPLICATED)
*
* 1. V*: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_UL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 2. V*: OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT,
* 3. V: OpenAPI_request_indication_NW_REQ_PDU_SES_REL
* 4. V: smf_nsmf_pdusession_build_hsmf_update_data
* 5. H: smf_nsmf_handle_update_data_in_hsmf
* 6. H: OpenAPI_request_indication_NW_REQ_PDU_SES_REL
* 6. H: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT
* 7. H: ogs_sbi_send_http_status_no_content
* 8. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 9. H: smf_sbi_cleanup_session(SMF_UECM_STATE_DEREG_BY_AMF_HR
* SMF_SBI_CLEANUP_MODE_POLICY_FIRST);
* 10. H: OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister);
* 11. H: SMF_SESS_CLEAR(sess)
* 12. V: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT
* 13. V: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 14. V: ogs_sbi_send_http_status_no_content
* 15. V: OGS_FSM_TRAN(s, smf_gsm_state_session_will_release);
*/
ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_all_pdr_modification_request(
sess, stream,
@ -1164,6 +1243,8 @@ bool smf_nsmf_handle_create_data_in_hsmf(
char *fqdn = NULL;
uint16_t fqdn_port = 0;
ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
char *home_network_domain = NULL;
OpenAPI_pdu_session_create_data_t *PduSessionCreateData = NULL;
OpenAPI_nr_location_t *NrLocation = NULL;
OpenAPI_snssai_t *sNssai = NULL;
@ -1232,6 +1313,38 @@ bool smf_nsmf_handle_create_data_in_hsmf(
return false;
}
home_network_domain =
ogs_home_network_domain_from_fqdn(PduSessionCreateData->dnn);
if (home_network_domain) {
char dnn_network_identifer[OGS_MAX_DNN_LEN+1];
ogs_assert(home_network_domain > PduSessionCreateData->dnn);
ogs_cpystrn(dnn_network_identifer, PduSessionCreateData->dnn,
ogs_min(OGS_MAX_DNN_LEN,
home_network_domain - PduSessionCreateData->dnn));
if (sess->session.name)
ogs_free(sess->session.name);
sess->session.name = ogs_strdup(dnn_network_identifer);
ogs_assert(sess->session.name);
if (sess->full_dnn)
ogs_free(sess->full_dnn);
sess->full_dnn = ogs_strdup(PduSessionCreateData->dnn);
ogs_assert(sess->full_dnn);
} else {
if (sess->session.name)
ogs_free(sess->session.name);
sess->session.name = ogs_strdup(PduSessionCreateData->dnn);
ogs_assert(sess->session.name);
if (sess->full_dnn)
ogs_free(sess->full_dnn);
sess->full_dnn = NULL;
}
sNssai = PduSessionCreateData->s_nssai;
if (!sNssai) {
ogs_error("[%s:%d] No sNssai", smf_ue->supi, sess->psi);
@ -1374,7 +1487,9 @@ bool smf_nsmf_handle_create_data_in_hsmf(
if (sess->remote_dl_ip.ipv4 && sess->remote_dl_ip.ipv6)
sess->remote_dl_ip.len = OGS_IPV4V6_LEN;
sess->remote_dl_teid = ogs_uint64_from_string_hexadecimal(vcnTunnelInfo->gtp_teid);
if (vcnTunnelInfo->gtp_teid)
sess->remote_dl_teid =
ogs_uint64_from_string_hexadecimal(vcnTunnelInfo->gtp_teid);
ogs_debug("vcnTunnelInfo->ipv4 = 0x%x", sess->remote_dl_ip.addr);
ogs_log_hexdump(OGS_LOG_DEBUG, sess->remote_dl_ip.addr6, OGS_IPV6_LEN);
ogs_debug("vcnTunnelInfo->gtp_teid = 0x%x", sess->remote_dl_teid);
@ -1763,10 +1878,14 @@ bool smf_nsmf_handle_created_data_in_vsmf(
if (sess->remote_ul_ip.ipv4 && sess->remote_ul_ip.ipv6)
sess->remote_ul_ip.len = OGS_IPV4V6_LEN;
sess->remote_ul_teid = ogs_uint64_from_string_hexadecimal(hcnTunnelInfo->gtp_teid);
if (hcnTunnelInfo->gtp_teid) {
sess->remote_ul_teid =
ogs_uint64_from_string_hexadecimal(hcnTunnelInfo->gtp_teid);
ogs_debug("hcnTunnelInfo->ipv4 = 0x%x", sess->remote_ul_ip.addr);
ogs_log_hexdump(OGS_LOG_DEBUG, sess->remote_ul_ip.addr6, OGS_IPV6_LEN);
ogs_log_hexdump(OGS_LOG_DEBUG,
sess->remote_ul_ip.addr6, OGS_IPV6_LEN);
ogs_debug("hcnTunnelInfo->gtp_teid = 0x%x", sess->remote_ul_teid);
}
dl_pdr = qos_flow->dl_pdr;
ogs_assert(dl_pdr);
@ -2015,11 +2134,16 @@ bool smf_nsmf_handle_update_data_in_hsmf(
OpenAPI_hsmf_update_data_t *HsmfUpdateData = NULL;
OpenAPI_plmn_id_nid_t *servingNetwork = NULL;
OpenAPI_tunnel_info_t *vcnTunnelInfo = NULL;
OpenAPI_ref_to_binary_data_t *n1SmInfoFromUe = NULL;
ogs_nas_5gs_message_t nas_message;
ogs_pkbuf_t *n1SmBufFromUe = NULL;
ogs_nas_5gs_pdu_session_modification_request_t
*pdu_session_modification_request = NULL;
ogs_assert(stream);
ogs_assert(message);
ogs_assert(sess);
@ -2051,26 +2175,56 @@ bool smf_nsmf_handle_update_data_in_hsmf(
sess->nsmf_param.request_indication = HsmfUpdateData->request_indication;
n1SmInfoFromUe = HsmfUpdateData->n1_sm_info_from_ue;
if (n1SmInfoFromUe) {
n1SmBufFromUe = ogs_sbi_find_part_by_content_id(
message, n1SmInfoFromUe->content_id);
sess->nsmf_param.up_cnx_state = HsmfUpdateData->up_cnx_state;
if (n1SmBufFromUe) {
rv = gsmue_decode_n1_sm_info(&nas_message, n1SmBufFromUe);
vcnTunnelInfo = HsmfUpdateData->vcn_tunnel_info;
if (vcnTunnelInfo) {
if (vcnTunnelInfo->ipv4_addr) {
rv = ogs_ipv4_from_string(
&sess->nsmf_param.dl_ip.addr, vcnTunnelInfo->ipv4_addr);
if (rv != OGS_OK) {
ogs_error("[%s:%d] cannot decode N1 SM Content [%s]",
smf_ue->supi, sess->psi, n1SmInfoFromUe->content_id);
ogs_log_hexdump(OGS_LOG_ERROR,
n1SmBufFromUe->data, n1SmBufFromUe->len);
ogs_error("ogs_ipv4_from_string() [%s] failed",
vcnTunnelInfo->ipv4_addr);
smf_sbi_send_hsmf_update_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
OGS_5GSM_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE,
"cannot decode N1 SM Content", smf_ue->supi, NULL);
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
"ogs_ipv4_from_string() failed",
vcnTunnelInfo->ipv4_addr, NULL);
return false;
}
sess->nsmf_param.dl_ip.ipv4 = 1;
sess->nsmf_param.dl_ip.len = OGS_IPV4_LEN;
}
if (vcnTunnelInfo->ipv6_addr) {
rv = ogs_ipv6addr_from_string(
sess->nsmf_param.dl_ip.addr6, vcnTunnelInfo->ipv6_addr);
if (rv != OGS_OK) {
ogs_error("ogs_ipv6addr_from_string() [%s] failed",
vcnTunnelInfo->ipv6_addr);
smf_sbi_send_hsmf_update_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
"ogs_ipv6addr_from_string() failed",
vcnTunnelInfo->ipv6_addr, NULL);
return false;
}
sess->nsmf_param.dl_ip.ipv6 = 1;
sess->nsmf_param.dl_ip.len = OGS_IPV6_LEN;
}
if (sess->remote_dl_ip.ipv4 && sess->remote_dl_ip.ipv6)
sess->remote_dl_ip.len = OGS_IPV4V6_LEN;
if (vcnTunnelInfo->gtp_teid)
sess->nsmf_param.dl_teid =
ogs_uint64_from_string_hexadecimal(vcnTunnelInfo->gtp_teid);
}
sess->nsmf_param.an_type = HsmfUpdateData->an_type;
sess->nsmf_param.rat_type = HsmfUpdateData->rat_type;
servingNetwork = HsmfUpdateData->serving_network;
if (servingNetwork && servingNetwork->mcc && servingNetwork->mnc)
sess->nsmf_param.serving_network = true;
if (HsmfUpdateData->ue_location &&
HsmfUpdateData->ue_location->nr_location) {
@ -2108,6 +2262,76 @@ bool smf_nsmf_handle_update_data_in_hsmf(
sess->nsmf_param.gmm_cause = HsmfUpdateData->_5g_mm_cause_value;
sess->nsmf_param.cause = HsmfUpdateData->cause;
n1SmInfoFromUe = HsmfUpdateData->n1_sm_info_from_ue;
if (n1SmInfoFromUe) {
n1SmBufFromUe = ogs_sbi_find_part_by_content_id(
message, n1SmInfoFromUe->content_id);
if (n1SmBufFromUe) {
rv = gsmue_decode_n1_sm_info(&nas_message, n1SmBufFromUe);
if (rv != OGS_OK) {
ogs_error("[%s:%d] cannot decode N1 SM Content [%s]",
smf_ue->supi, sess->psi, n1SmInfoFromUe->content_id);
ogs_log_hexdump(OGS_LOG_ERROR,
n1SmBufFromUe->data, n1SmBufFromUe->len);
smf_sbi_send_hsmf_update_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
OGS_5GSM_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE,
"cannot decode N1 SM Content", smf_ue->supi, NULL);
return false;
}
}
}
switch(nas_message.gsm.h.message_type) {
case OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST:
pdu_session_modification_request =
&nas_message.gsm.pdu_session_modification_request;
if (pdu_session_modification_request->presencemask &
(OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_REQUESTED_QOS_RULES_PRESENT|
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_REQUESTED_QOS_FLOW_DESCRIPTIONS_PRESENT))
ogs_list_init(&sess->qos_flow_to_modify_list);
if (pdu_session_modification_request->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_REQUESTED_QOS_RULES_PRESENT) {
rv = gsm_handle_pdu_session_modification_qos_rules(
sess,
&pdu_session_modification_request->requested_qos_rules,
&sess->nsmf_param.pfcp_flags);
if (rv != OGS_OK) {
ogs_error("[%s:%d] Invalid requested_qos_rules",
smf_ue->supi, sess->psi);
smf_sbi_send_hsmf_update_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
"Invalid requested_qos_rules", smf_ue->supi, NULL);
return false;
}
}
if (pdu_session_modification_request->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_REQUEST_REQUESTED_QOS_FLOW_DESCRIPTIONS_PRESENT) {
rv = gsm_handle_pdu_session_modification_qos_flow_descriptions(
sess,
&pdu_session_modification_request->
requested_qos_flow_descriptions,
&sess->nsmf_param.pfcp_flags);
if (rv != OGS_OK) {
ogs_error("[%s:%d] Invalid requested_qos_flow_descriptions",
smf_ue->supi, sess->psi);
smf_sbi_send_hsmf_update_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
"Invalid qos_flow_descriptions", smf_ue->supi, NULL);
return false;
}
}
break;
default:
break;
}
return true;
}
@ -2120,6 +2344,7 @@ bool smf_nsmf_handle_update_data_in_vsmf(
OpenAPI_vsmf_update_data_t *VsmfUpdateData = NULL;
OpenAPI_list_t *qosFlowsAddModRequestList = NULL;
OpenAPI_list_t *qosFlowsRelRequestList = NULL;
OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL;
OpenAPI_lnode_t *node = NULL;
@ -2196,15 +2421,13 @@ bool smf_nsmf_handle_update_data_in_vsmf(
src = node->data;
if (!src ||
!src->qfi ||
!src->qos_rules ||
!src->qos_flow_description ||
!src->qos_flow_profile) {
ogs_error("[%s:%d] No src [%d:%s:%s]",
!(src->qos_flow_description || src->qos_flow_profile)) {
ogs_error("[%s:%d] No src [%d:%s:%p]",
smf_ue->supi, sess->psi, src->qfi,
src->qos_rules ?
src->qos_rules : "NULL",
src->qos_flow_description ?
src->qos_flow_description : "NULL");
src->qos_flow_description : "NULL",
src->qos_flow_profile ?
src->qos_flow_profile : NULL);
smf_sbi_send_vsmf_update_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
@ -2249,18 +2472,125 @@ bool smf_nsmf_handle_update_data_in_vsmf(
else
OpenAPI_list_free(qosFlowsAddModRequestList);
CLEAR_QOS_FLOWS_REL_REQUEST_LIST(
sess->h_smf_qos_flows_rel_request_list);
qosFlowsRelRequestList = OpenAPI_list_create();
ogs_assert(qosFlowsRelRequestList);
OpenAPI_list_for_each(VsmfUpdateData->qos_flows_rel_request_list, node) {
OpenAPI_qos_flow_release_request_item_t *dst = NULL, *src = NULL;
src = node->data;
if (!src ||
!src->qfi ||
!src->qos_rules ||
!src->qos_flow_description) {
ogs_error("[%s:%d] No src [%d:%s:%s]",
smf_ue->supi, sess->psi, src->qfi,
src->qos_rules ?
src->qos_rules : "NULL",
src->qos_flow_description ?
src->qos_flow_description : "NULL");
smf_sbi_send_vsmf_update_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
"No src", smf_ue->supi, NULL);
return false;
}
dst = OpenAPI_qos_flow_release_request_item_copy(dst, src);
ogs_assert(dst);
OpenAPI_list_add(qosFlowsRelRequestList, dst);
}
if (qosFlowsRelRequestList->count)
sess->h_smf_qos_flows_rel_request_list = qosFlowsRelRequestList;
else
OpenAPI_list_free(qosFlowsRelRequestList);
sess->pti = OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED;
/*
* Network-requested PDU Session Modification
*
* 1. H: OpenAPI_request_indication_NW_REQ_PDU_SES_MOD
* QOS_RULE_CODE_FROM_PFCP_FLAGS
* QOS_RULE_FLOW_DESCRIPTION_CODE_FROM_PFCP_FLAGS
* 2. H: smf_nsmf_pdusession_build_vsmf_update_data
* 3. V: smf_nsmf_handle_update_data_in_vsmf
* 4. V*: gsm_build_pdu_session_modification_command+
* ngap_build_pdu_session_resource_modify_request_transfer
* 5. V: OpenAPI_n2_sm_info_type_PDU_RES_MOD_RSP
* if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING)
* sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
* smf_sbi_send_sm_context_updated_data_up_cnx_state(
* OpenAPI_up_cnx_state_ACTIVATED)
* else
* ogs_sbi_send_http_status_no_content(stream)
* 6. V: ogs_sbi_send_http_status_no_content(stream)
* OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMPLETE:
* ogs_sbi_send_http_status_no_content(n1_n2_modified_stream));
* 7. V: case OGS_EVENT_SBI_CLIENT
* CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
* 8. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|
* OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE
*/
memset(&param, 0, sizeof(param));
param.state = SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION;
param.n1smbuf = gsm_build_pdu_session_modification_command(sess, 0, 0);
ogs_assert(param.n1smbuf);
if (sess->h_smf_qos_flows_rel_request_list) {
param.n2smbuf =
ngap_build_pdu_session_resource_release_request_transfer(
sess, NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release);
ogs_assert(param.n2smbuf);
} else if (sess->h_smf_qos_flows_add_mod_request_list) {
param.n2smbuf =
ngap_build_pdu_session_resource_modify_request_transfer(sess,
qosFlowProfile->gbr_qos_flow_info ? true : false);
ogs_assert(param.n2smbuf);
} else
ogs_error("No LIST");
if (sess->nsmf_param.request_indication ==
OpenAPI_request_indication_NW_REQ_PDU_SES_MOD) {
if (sess->establishment_accept_sent == true) {
smf_namf_comm_send_n1_n2_message_transfer(sess, stream, &param);
} else {
if (sess->pending_modification_xact)
ogs_sbi_xact_remove(sess->pending_modification_xact);
sess->pending_modification_xact =
smf_namf_comm_create_n1_n2_message_xact(
sess, stream, &param);
}
} else if (sess->nsmf_param.request_indication ==
OpenAPI_request_indication_UE_REQ_PDU_SES_MOD) {
ogs_sbi_stream_t *amf_to_vsmf_modify_stream = NULL;
if (sess->amf_to_vsmf_modify_stream_id >= OGS_MIN_POOL_ID &&
sess->amf_to_vsmf_modify_stream_id <= OGS_MAX_POOL_ID)
amf_to_vsmf_modify_stream =
ogs_sbi_stream_find_by_id(
sess->amf_to_vsmf_modify_stream_id);
if (amf_to_vsmf_modify_stream) {
smf_sbi_send_sm_context_updated_data_n1_n2_message(
sess, amf_to_vsmf_modify_stream, param.n1smbuf,
OpenAPI_n2_sm_info_type_PDU_RES_MOD_REQ, param.n2smbuf);
sess->amf_to_vsmf_modify_stream_id = OGS_INVALID_POOL_ID;
if (sess->vsmf_to_hsmf_modify_stream_id >= OGS_MIN_POOL_ID &&
sess->vsmf_to_hsmf_modify_stream_id <= OGS_MAX_POOL_ID)
ogs_error("N1 N2 modified stream ID [%d]"
"has not been used yet",
sess->vsmf_to_hsmf_modify_stream_id);
sess->vsmf_to_hsmf_modify_stream_id =
ogs_sbi_id_from_stream(stream);
}
}
break;
case OpenAPI_request_indication_UE_REQ_PDU_SES_REL:

View file

@ -236,14 +236,13 @@ int smf_sbi_discover_and_send(
return OGS_OK;
}
void smf_namf_comm_send_n1_n2_message_transfer(
ogs_sbi_xact_t *smf_namf_comm_create_n1_n2_message_xact(
smf_sess_t *sess, ogs_sbi_stream_t *stream,
smf_n1_n2_message_transfer_param_t *param)
{
smf_ue_t *smf_ue = NULL;
ogs_sbi_xact_t *xact = NULL;
ogs_sbi_discovery_option_t *discovery_option = NULL;
int r;
ogs_assert(sess);
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
@ -264,8 +263,8 @@ void smf_namf_comm_send_n1_n2_message_transfer(
(ogs_sbi_build_f)smf_namf_comm_build_n1_n2_message_transfer,
sess, param);
if (!xact) {
ogs_error("smf_namf_comm_send_n1_n2_message_transfer() failed");
return;
ogs_error("ogs_sbi_xact_add() failed");
return NULL;
}
xact->state = param->state;
@ -276,6 +275,27 @@ void smf_namf_comm_send_n1_n2_message_transfer(
xact->assoc_stream_id <= OGS_MAX_POOL_ID);
}
return xact;
}
void smf_namf_comm_send_n1_n2_message_transfer(
smf_sess_t *sess, ogs_sbi_stream_t *stream,
smf_n1_n2_message_transfer_param_t *param)
{
ogs_sbi_xact_t *xact = NULL;
int r;
ogs_assert(sess);
ogs_assert(param);
ogs_assert(param->state);
ogs_assert(param->n1smbuf || param->n2smbuf);
xact = smf_namf_comm_create_n1_n2_message_xact(sess, stream, param);
if (!xact) {
ogs_error("smf_namf_comm_create_n1_n2_message_xact() failed");
return;
}
r = ogs_sbi_discover_and_send(xact);
if (r != OGS_OK) {
ogs_error("smf_namf_comm_send_n1_n2_message_transfer() failed");

View file

@ -36,12 +36,95 @@ void smf_sbi_close(void);
bool smf_sbi_send_request(
ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_xact_t *xact);
/*
* PFCP delete triggers are defined in lib/pfcp/xact.h (values 17).
* To avoid overlap with OGS_PFCP_DELETE_TRIGGER_*, SMF states use:
* - UPDATE_STATE_BASE at 0x100x14
* - UECM_STATE_BASE at 0x200x23
* HR flag is bit 7 (0x80).
*/
/* Common HR flag (bit 7) */
#define SMF_STATE_HR (1U << 7) /* 0x80 */
/* Base offset for SMF_CREATE states */
#define SMF_CREATE_STATE_BASE 0x10U /* CREATE at 0x10 */
#define SMF_CREATE_STATE_NONE \
(SMF_CREATE_STATE_BASE + 0x00U) /* 0x00 */
/* Base offset for SMF_UPDATE states */
#define SMF_UPDATE_STATE_BASE 0x20U /* UPDATE at 0x200x24 */
/* SMF_UPDATE base states */
#define SMF_UPDATE_STATE_NONE \
(SMF_UPDATE_STATE_BASE + 0x00U) /* 0x00 */
#define SMF_UPDATE_STATE_ACTIVATING \
(SMF_UPDATE_STATE_BASE + 0x01U) /* 0x01 */
#define SMF_UPDATE_STATE_ACTIVATED_FROM_ACTIVATING \
(SMF_UPDATE_STATE_BASE + 0x02U) /* 0x02 */
#define SMF_UPDATE_STATE_ACTIVATED_FROM_NON_ACTIVATING \
(SMF_UPDATE_STATE_BASE + 0x03U) /* 0x03 */
#define SMF_UPDATE_STATE_DEACTIVATED \
(SMF_UPDATE_STATE_BASE + 0x04U) /* 0x04 */
#define SMF_UPDATE_STATE_UE_REQ_MOD \
(SMF_UPDATE_STATE_BASE + 0x05U) /* 0x05 */
/* Base offset for SMF_REMOVE states */
#define SMF_REMOVE_STATE_BASE 0x30U /* REMOVE at 0x30 */
#define SMF_REMOVE_STATE_NONE \
(SMF_REMOVE_STATE_BASE + 0x00U) /* 0x00 */
/* Base offset for SMF_UECM states */
#define SMF_UECM_STATE_BASE 0x40U /* UECM at 0x400x43 */
/* SMF_UECM base states */
#define SMF_UECM_STATE_NONE \
(SMF_UECM_STATE_BASE + 0x00U) /* 0x20 */
#define SMF_UECM_STATE_REGISTERED \
(SMF_UECM_STATE_BASE + 0x01U) /* 0x21 */
#define SMF_UECM_STATE_DEREG_BY_AMF \
(SMF_UECM_STATE_BASE + 0x02U) /* 0x22 */
#define SMF_UECM_STATE_DEREG_BY_N1N2 \
(SMF_UECM_STATE_BASE + 0x03U) /* 0x23 */
/* HR variants for SMF_UECM */
#define SMF_UECM_STATE_REGISTERED_HR \
(SMF_UECM_STATE_REGISTERED | SMF_STATE_HR) /* 0xC1 */
#define SMF_UECM_STATE_DEREG_BY_AMF_HR \
(SMF_UECM_STATE_DEREG_BY_AMF | SMF_STATE_HR) /* 0xC2 */
#define SMF_UECM_STATE_DEREG_BY_N1N2_HR \
(SMF_UECM_STATE_DEREG_BY_N1N2 | SMF_STATE_HR) /* 0xC3 */
int smf_sbi_discover_and_send(
ogs_sbi_service_type_e service_type,
ogs_sbi_discovery_option_t *discovery_option,
ogs_sbi_request_t *(*build)(smf_sess_t *sess, void *data),
smf_sess_t *sess, ogs_sbi_stream_t *stream, int state, void *data);
/**
* Return true if the PDU session anchor SMF is in the HPLMN
* (Home-Routed Roaming, HR)
*/
static inline bool smf_uecm_anchor_in_hplmn(int state)
{
return !!(state & SMF_STATE_HR);
}
/**
* Return true if the PDU session anchor SMF is in the VPLMN
* (Non-Roaming or Local Break-Out Roaming, LBO)
*/
static inline bool smf_uecm_anchor_in_vplmn(int state)
{
return !(state & SMF_STATE_HR);
}
ogs_sbi_xact_t *smf_namf_comm_create_n1_n2_message_xact(
smf_sess_t *sess, ogs_sbi_stream_t *stream,
smf_n1_n2_message_transfer_param_t *param);
void smf_namf_comm_send_n1_n2_message_transfer(
smf_sess_t *sess, ogs_sbi_stream_t *stream,
smf_n1_n2_message_transfer_param_t *param);

View file

@ -1145,8 +1145,89 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
ogs_assert(true == smf_sbi_send_sm_context_status_notify(sess));
SMF_SESS_CLEAR(sess);
} else if (state == SMF_UECM_STATE_DEREG_BY_AMF_HR) {
/*
* Network-requested PDU Session Release(DUPLICATED)
*
* 1. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_UL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 2. V: OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT,
* 3. V: OpenAPI_request_indication_NW_REQ_PDU_SES_REL
* 4. V: smf_nsmf_pdusession_build_hsmf_update_data
* 5. H: smf_nsmf_handle_update_data_in_hsmf
* 6. H: OpenAPI_request_indication_NW_REQ_PDU_SES_REL
* 6. H: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT
* 7. H: ogs_sbi_send_http_status_no_content
* 8. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 9. H: smf_sbi_cleanup_session(SMF_UECM_STATE_DEREG_BY_AMF_HR
* SMF_SBI_CLEANUP_MODE_POLICY_FIRST);
* 10. H: OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister);
* 11. H*: SMF_SESS_CLEAR(sess)
* 12. V: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT
* 13. V: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 14. V: ogs_sbi_send_http_status_no_content
* 15. V: OGS_FSM_TRAN(s, smf_gsm_state_session_will_release);
*
* Network-requested PDU Session Release
*
* 1. V: smf_nsmf_handle_release_sm_context
* 2. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_UL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 3. V: OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT
* 4. V: smf_nsmf_pdusession_build_release_data
* 5. H: smf_nsmf_handle_release_data_in_hsmf
* 6. H: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT
* 7. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 8. H: ogs_sbi_send_http_status_no_content
* 9. H: smf_sbi_cleanup_session(SMF_UECM_STATE_DEREG_BY_AMF_HR
* SMF_SBI_CLEANUP_MODE_POLICY_FIRST);
* 10. H: OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister);
* 11. H*: SMF_SESS_CLEAR(sess)
* 12. V: smf_nsmf_handle_release_data_in_hsmf
* 13. V: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT
* 14. V: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 15. V: ogs_sbi_send_http_status_no_content
* 16. V: OGS_FSM_TRAN(s, smf_gsm_state_session_will_release);
*/
SMF_SESS_CLEAR(sess);
} else if (state == SMF_UECM_STATE_DEREG_BY_N1N2_HR) {
/*
* UE-requested PDU Session Release
*
* 1. V: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_UL_ONLY|
* OGS_PFCP_MODIFY_DEACTIVATE
* 2. V: OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED
* 3. V: OpenAPI_request_indication_UE_REQ_PDU_SES_REL
* 4. V: smf_nsmf_pdusession_build_hsmf_update_data
* 5. H: smf_nsmf_handle_update_data_in_hsmf
* 6. H: OpenAPI_request_indication_UE_REQ_PDU_SES_REL
* 6. H: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED
* 7. H: ogs_sbi_send_http_status_no_content
* 8. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 9. H: smf_nsmf_pdusession_build_vsmf_update_data
* 10. H: OGS_FSM_TRAN(s, smf_gsm_state_wait_5gc_n1_n2_release);
* 11. V: smf_nsmf_handle_update_data_in_vsmf
* 12. V: OpenAPI_request_indication_UE_REQ_PDU_SES_REL
* 13. V: e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED
* 14. V: OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion)
* 15. V: ngap_build_pdu_session_resource_release_command_transfer+
* gsm_build_pdu_session_release_command
* 16 V: OGS_FSM_TRAN(&sess->sm, smf_gsm_state_wait_5gc_n1_n2_release)
* 17. V: ogs_sbi_send_http_status_no_content(stream)
* 18. V: case OpenAPI_n2_sm_info_type_PDU_RES_REL_RSP:
* case OGS_NAS_5GS_PDU_SESSION_RELEASE_COMPLETE:
* 19. V: ogs_sbi_send_http_status_no_content(n1_n2_released_stream)
* 20. V: OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister);
* 21. H: case OGS_EVENT_SBI_CLIENT:
* 22. H: CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
* 23. H: smf_sbi_cleanup_session(SMF_UECM_STATE_DEREG_BY_N1N2_HR
* SMF_SBI_CLEANUP_MODE_POLICY_FIRST);
* 24. H*: smf_sbi_send_status_notify+SMF_SESS_CLEAR(sess)
* 25. V: case OGS_EVENT_SBI_SERVER:
* 26. V: CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
* 27. V: ogs_sbi_send_http_status_no_content+
* smf_sbi_send_sm_context_status_notify
* 28. V: OGS_FSM_TRAN(s, smf_gsm_state_session_will_release);
*/
ogs_assert(true == smf_sbi_send_status_notify(sess));
SMF_SESS_CLEAR(sess);
}

View file

@ -1886,7 +1886,7 @@ bson_t *test_db_new_session(test_ue_t *test_ue)
"pre_emption_capability", BCON_INT32(1),
"}",
"}",
#if 1
#if 0
"lbo_roaming_allowed", BCON_BOOL(true),
#else
"lbo_roaming_allowed", BCON_BOOL(false),
@ -1953,7 +1953,7 @@ bson_t *test_db_new_session(test_ue_t *test_ue)
"description", BCON_UTF8("permit out udp from 10.200.136.98/32 1-65535 to assigned 50021"), "}",
"]",
"}", "]",
#if 1
#if 0
"lbo_roaming_allowed", BCON_BOOL(true),
#else
"lbo_roaming_allowed", BCON_BOOL(false),
@ -2025,6 +2025,11 @@ bson_t *test_db_new_ims(test_ue_t *test_ue)
"pre_emption_capability", BCON_INT32(1),
"}",
"}",
#if 0
"lbo_roaming_allowed", BCON_BOOL(true),
#else
"lbo_roaming_allowed", BCON_BOOL(false),
#endif
"}",
"{",
"name", BCON_UTF8("ims"),
@ -2109,7 +2114,7 @@ bson_t *test_db_new_ims(test_ue_t *test_ue)
"}",
"}",
"]",
#if 1
#if 0
"lbo_roaming_allowed", BCON_BOOL(true),
#else
"lbo_roaming_allowed", BCON_BOOL(false),

View file

@ -3966,6 +3966,25 @@ static void test7_func(abts_case *tc, void *data)
test_ue_remove(test_ue);
}
/*
* Disable test8_func when running Home Routed Roaming tests,
* to prevent V-SMF from skipping Update Response (step 14)
* and avoid subsequent SBI timeout and PFCP No Context errors.
*/
#define HOME_ROUTED_ROAMING_TEST 0
#if !HOME_ROUTED_ROAMING_TEST
/**
* test8_func:
* - Simulates absence of N2 Resource Release Ack (step 8)
* and PDU Session Release Accept (step 11) from gNB/UE.
* - In Home Routed Roaming, V-SMF will not send the
* Nsmf_PDUSession_Update Response (step 14), causing
* the SBI client to timeout after 10 seconds.
* - Subsequent deregistration triggers a PFCP deactivation
* modification, but UPF has no session, leading to
* a No Context error.
*/
static void test8_func(abts_case *tc, void *data)
{
int rv;
@ -4327,12 +4346,19 @@ static void test8_func(abts_case *tc, void *data)
/* Clear Test UE Context */
test_ue_remove(test_ue);
}
#endif
abts_suite *test_af(abts_suite *suite)
{
suite = ADD_SUITE(suite)
/**
* abts_suite test_af:
* - Always run test1_func through test7_func.
* - Conditionally include test8_func based on
* HOME_ROUTED_ROAMING_TEST flag.
*/
abts_run_test(suite, test1_func, NULL);
abts_run_test(suite, test2_func, NULL);
abts_run_test(suite, test3_func, NULL);
@ -4340,7 +4366,9 @@ abts_suite *test_af(abts_suite *suite)
abts_run_test(suite, test5_func, NULL);
abts_run_test(suite, test6_func, NULL);
abts_run_test(suite, test7_func, NULL);
#if !HOME_ROUTED_ROAMING_TEST
abts_run_test(suite, test8_func, NULL);
#endif
return suite;
}

View file

@ -1367,6 +1367,8 @@ static void test4_func(abts_case *tc, void *data)
bson_t *doc = NULL;
NGAP_ProcedureCode_t ngap_procedure_code;
/* Setup Test UE & Session Context */
memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci));
@ -1551,23 +1553,62 @@ static void test4_func(abts_case *tc, void *data)
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive PDUSessionResourceSetupRequest +
/*
* Receive PDUSessionResourceSetupRequest +
* DL NAS transport +
* PDU session establishment accept */
* PDU session establishment accept
*
* OR
*
* Receive PDUSessionResourceModifyRequest +
* DL NAS transport +
* PDU session modification command
*/
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);
/* Receive PDU session establishment accept */
ngap_procedure_code = test_ue->ngap_procedure_code;
/*
* Receive PDUSessionResourceSetupRequest +
* DL NAS transport +
* PDU session establishment accept
*
* OR
*
* Receive PDUSessionResourceModifyRequest +
* DL NAS transport +
* PDU session modification command
*/
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ngap_procedure_code += test_ue->ngap_procedure_code;
/*
* Receive PDUSessionResourceSetupRequest +
* DL NAS transport +
* PDU session establishment accept
*
* OR
*
* Receive PDUSessionResourceModifyRequest +
* DL NAS transport +
* PDU session modification command
*/
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ngap_procedure_code += test_ue->ngap_procedure_code;
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_PDUSessionResourceSetup,
test_ue->ngap_procedure_code);
NGAP_ProcedureCode_id_PDUSessionResourceSetup +
NGAP_ProcedureCode_id_PDUSessionResourceSetup +
NGAP_ProcedureCode_id_PDUSessionResourceModify,
ngap_procedure_code);
/* Send GTP-U ICMP Packet */
qos_flow1 = test_qos_flow_find_by_qfi(sess5, 1);
@ -1601,16 +1642,6 @@ static void test4_func(abts_case *tc, void *data)
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Receive PDUSessionResourceModifyRequest +
* DL NAS transport +
* PDU session modification command */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_PDUSessionResourceModify,
test_ue->ngap_procedure_code);
/* Send PDU session resource modify response */
qos_flow2 = test_qos_flow_find_by_qfi(sess6, 2);
ogs_assert(qos_flow2);