mirror of
				https://github.com/open5gs/open5gs.git
				synced 2025-11-04 05:53:18 +00:00 
			
		
		
		
	[HR] Implement Network-Initiated PDU Session Modification (Home-Routed Roaming) (#2194)
This commit adds support for processing network-initiated PDU Session Modification in a home-routed roaming context, following section 4.3.3.3 of the specification.
This commit is contained in:
		@@ -325,6 +325,15 @@ bsf:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +325,15 @@ bsf:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
 
 | 
			
		||||
@@ -320,6 +320,15 @@ bsf:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +325,15 @@ bsf:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
 
 | 
			
		||||
@@ -320,6 +320,15 @@ bsf:
 | 
			
		||||
        scp:
 | 
			
		||||
          - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +325,15 @@ bsf:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +325,15 @@ bsf:
 | 
			
		||||
        scp:
 | 
			
		||||
          - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
    sbi:
 | 
			
		||||
      server:
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +325,15 @@ bsf:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
 
 | 
			
		||||
@@ -320,6 +320,15 @@ bsf:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
af:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
      - address: 127.0.0.16
 | 
			
		||||
        port: 7777
 | 
			
		||||
    client:
 | 
			
		||||
      scp:
 | 
			
		||||
        - uri: http://127.0.0.200:7777
 | 
			
		||||
 | 
			
		||||
udr:
 | 
			
		||||
  sbi:
 | 
			
		||||
    server:
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
#include "s5c-build.h"
 | 
			
		||||
#include "pfcp-path.h"
 | 
			
		||||
#include "gtp-path.h"
 | 
			
		||||
#include "sbi-path.h"
 | 
			
		||||
 | 
			
		||||
#include "ipfw/ipfw2.h"
 | 
			
		||||
 | 
			
		||||
@@ -779,6 +780,9 @@ void smf_qos_flow_binding(smf_sess_t *sess)
 | 
			
		||||
    if (ogs_list_count(&sess->qos_flow_to_modify_list)) {
 | 
			
		||||
        ogs_assert(OGS_OK ==
 | 
			
		||||
                smf_5gc_pfcp_send_qos_flow_list_modification_request(
 | 
			
		||||
                    sess, NULL, pfcp_flags, 0));
 | 
			
		||||
                    sess, NULL,
 | 
			
		||||
                    HOME_ROUTED_ROAMING_IN_HSMF(sess) ?
 | 
			
		||||
                        OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|pfcp_flags :
 | 
			
		||||
                        pfcp_flags, 0));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1865,11 +1865,13 @@ void smf_sess_remove(smf_sess_t *sess)
 | 
			
		||||
    if (sess->n1smbuf)
 | 
			
		||||
        ogs_pkbuf_free(sess->n1smbuf);
 | 
			
		||||
 | 
			
		||||
    OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_rules);
 | 
			
		||||
    OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_flow_descriptions);
 | 
			
		||||
    OGS_NAS_CLEAR_DATA(&sess->h_smf_extended_protocol_configuration_options);
 | 
			
		||||
    sess->h_smf_gsm_cause = 0;
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    /* Free SBI object memory */
 | 
			
		||||
    ogs_sbi_object_free(&sess->sbi);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,25 @@ typedef struct smf_nsmf_pdusession_param_s {
 | 
			
		||||
        uint8_t ue_timezone:1;,
 | 
			
		||||
        uint8_t spare:6;)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
#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_TFT_NEW) ? \
 | 
			
		||||
            OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE : \
 | 
			
		||||
        (pfcp_flags & OGS_PFCP_MODIFY_TFT_ADD) ? \
 | 
			
		||||
            OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_ADD_PACKET_FILTERS : \
 | 
			
		||||
        (pfcp_flags & OGS_PFCP_MODIFY_TFT_REPLACE) ? \
 | 
			
		||||
            OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_REPLACE_ALL_PACKET_FILTERS : \
 | 
			
		||||
        (pfcp_flags & OGS_PFCP_MODIFY_TFT_DELETE) ? \
 | 
			
		||||
            OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_DELETE_PACKET_FILTERS : 0
 | 
			
		||||
    uint8_t qos_rule_code;
 | 
			
		||||
#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_QOS_MODIFY) ? \
 | 
			
		||||
            OGS_NAS_MODIFY_NEW_QOS_FLOW_DESCRIPTION : 0
 | 
			
		||||
    uint8_t qos_flow_description_code;
 | 
			
		||||
} smf_nsmf_pdusession_param_t;
 | 
			
		||||
 | 
			
		||||
/* HR flag bit */
 | 
			
		||||
@@ -469,12 +488,36 @@ typedef struct smf_sess_s {
 | 
			
		||||
    char            *h_smf_id;
 | 
			
		||||
 | 
			
		||||
    /* Saved from H-SMF */
 | 
			
		||||
    ogs_nas_qos_rules_t h_smf_authorized_qos_rules;
 | 
			
		||||
    ogs_nas_qos_flow_descriptions_t h_smf_authorized_qos_flow_descriptions;
 | 
			
		||||
    ogs_nas_extended_protocol_configuration_options_t
 | 
			
		||||
        h_smf_extended_protocol_configuration_options;
 | 
			
		||||
    ogs_nas_5gsm_cause_t h_smf_gsm_cause;
 | 
			
		||||
 | 
			
		||||
    /* Saved from H-SMF */
 | 
			
		||||
#define CLEAR_QOS_FLOWS_SETUP_LIST(__lIST) \
 | 
			
		||||
    do { \
 | 
			
		||||
        OpenAPI_lnode_t *node = NULL; \
 | 
			
		||||
        OpenAPI_list_for_each((__lIST), node) { \
 | 
			
		||||
            OpenAPI_qos_flow_setup_item_t *qosFlowSetupItem = node->data; \
 | 
			
		||||
            if (qosFlowSetupItem) \
 | 
			
		||||
                OpenAPI_qos_flow_setup_item_free(qosFlowSetupItem); \
 | 
			
		||||
        } \
 | 
			
		||||
        OpenAPI_list_free((__lIST)); \
 | 
			
		||||
    } while(0)
 | 
			
		||||
    OpenAPI_list_t *h_smf_qos_flows_setup_list;
 | 
			
		||||
#define CLEAR_QOS_FLOWS_ADD_MOD_REQUEST_LIST(__lIST) \
 | 
			
		||||
    do { \
 | 
			
		||||
        OpenAPI_lnode_t *node = NULL; \
 | 
			
		||||
        OpenAPI_list_for_each((__lIST), node) { \
 | 
			
		||||
            OpenAPI_qos_flow_add_modify_request_item_t \
 | 
			
		||||
                *qosFlowAddModifyRequestItem = node->data; \
 | 
			
		||||
            if (qosFlowAddModifyRequestItem) \
 | 
			
		||||
                OpenAPI_qos_flow_add_modify_request_item_free( \
 | 
			
		||||
                        qosFlowAddModifyRequestItem); \
 | 
			
		||||
        } \
 | 
			
		||||
        OpenAPI_list_free((__lIST)); \
 | 
			
		||||
    } while(0)
 | 
			
		||||
    OpenAPI_list_t *h_smf_qos_flows_add_mod_request_list;
 | 
			
		||||
 | 
			
		||||
#define HOME_ROUTED_ROAMING_IN_HSMF(__sESS) \
 | 
			
		||||
    ((__sESS) && (__sESS)->vsmf_pdu_session_uri)
 | 
			
		||||
    char            *vsmf_pdu_session_uri;
 | 
			
		||||
@@ -637,6 +680,7 @@ typedef struct smf_sess_s {
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    smf_nsmf_pdusession_param_t nsmf_param;
 | 
			
		||||
 
 | 
			
		||||
@@ -51,12 +51,18 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess)
 | 
			
		||||
    uint8_t *epco_buf = NULL;
 | 
			
		||||
    int16_t epco_len;
 | 
			
		||||
 | 
			
		||||
    OpenAPI_list_t *qosFlowsSetupList = NULL;
 | 
			
		||||
    OpenAPI_qos_flow_setup_item_t *qosFlowSetupItem = NULL;
 | 
			
		||||
    OpenAPI_lnode_t *node = NULL;
 | 
			
		||||
    int len;
 | 
			
		||||
 | 
			
		||||
    selected_pdu_session_type = &pdu_session_establishment_accept->
 | 
			
		||||
        selected_pdu_session_type;
 | 
			
		||||
    ogs_assert(selected_pdu_session_type);
 | 
			
		||||
    authorized_qos_rules = &pdu_session_establishment_accept->
 | 
			
		||||
        authorized_qos_rules;
 | 
			
		||||
    ogs_assert(authorized_qos_rules);
 | 
			
		||||
 | 
			
		||||
    session_ambr = &pdu_session_establishment_accept->session_ambr;
 | 
			
		||||
    ogs_assert(session_ambr);
 | 
			
		||||
    pdu_address = &pdu_session_establishment_accept->pdu_address;
 | 
			
		||||
@@ -91,16 +97,29 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess)
 | 
			
		||||
    selected_pdu_session_type->value = sess->session.session_type;
 | 
			
		||||
 | 
			
		||||
    if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
 | 
			
		||||
        ogs_assert(sess->h_smf_authorized_qos_rules.buffer);
 | 
			
		||||
        ogs_assert(sess->h_smf_authorized_qos_rules.length);
 | 
			
		||||
        OGS_NAS_STORE_DATA(
 | 
			
		||||
                authorized_qos_rules, &sess->h_smf_authorized_qos_rules);
 | 
			
		||||
        qosFlowsSetupList = sess->h_smf_qos_flows_setup_list;
 | 
			
		||||
        ogs_assert(qosFlowsSetupList);
 | 
			
		||||
 | 
			
		||||
        node = qosFlowsSetupList->first;
 | 
			
		||||
        ogs_assert(node);
 | 
			
		||||
        qosFlowSetupItem = node->data;
 | 
			
		||||
        ogs_assert(qosFlowSetupItem);
 | 
			
		||||
 | 
			
		||||
        len = ogs_base64_decode_len(qosFlowSetupItem->qos_rules);
 | 
			
		||||
        ogs_assert(len);
 | 
			
		||||
        authorized_qos_rules->buffer = ogs_calloc(1, len);
 | 
			
		||||
        ogs_assert(authorized_qos_rules->buffer);
 | 
			
		||||
        authorized_qos_rules->length =
 | 
			
		||||
            ogs_base64_decode_binary(
 | 
			
		||||
                    authorized_qos_rules->buffer, qosFlowSetupItem->qos_rules);
 | 
			
		||||
        ogs_assert(authorized_qos_rules->length);
 | 
			
		||||
 | 
			
		||||
    } else if (HOME_ROUTED_ROAMING_IN_HSMF(sess)) {
 | 
			
		||||
        ogs_fatal("This should not be invoked from H-SMF during HR-Roaming");
 | 
			
		||||
        ogs_assert_if_reached();
 | 
			
		||||
    } else {
 | 
			
		||||
        memset(qos_rule, 0, sizeof(qos_rule));
 | 
			
		||||
        encode_default_qos_rule(&qos_rule[0], qos_flow);
 | 
			
		||||
        gsm_encode_default_qos_rule(&qos_rule[0], qos_flow);
 | 
			
		||||
 | 
			
		||||
        rv = ogs_nas_build_qos_rules(authorized_qos_rules, qos_rule, 1);
 | 
			
		||||
        if (rv != OGS_OK) {
 | 
			
		||||
@@ -175,20 +194,29 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess)
 | 
			
		||||
 | 
			
		||||
    /* QoS flow descriptions */
 | 
			
		||||
    if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
 | 
			
		||||
        if (sess->h_smf_authorized_qos_flow_descriptions.buffer &&
 | 
			
		||||
            sess->h_smf_authorized_qos_flow_descriptions.length) {
 | 
			
		||||
        ogs_assert(qosFlowSetupItem);
 | 
			
		||||
 | 
			
		||||
        if (qosFlowSetupItem->qos_flow_description) {
 | 
			
		||||
            len = ogs_base64_decode_len(qosFlowSetupItem->qos_flow_description);
 | 
			
		||||
            ogs_assert(len);
 | 
			
		||||
            authorized_qos_flow_descriptions->buffer = ogs_calloc(1, len);
 | 
			
		||||
            ogs_assert(authorized_qos_flow_descriptions->buffer);
 | 
			
		||||
            authorized_qos_flow_descriptions->length =
 | 
			
		||||
                ogs_base64_decode_binary(
 | 
			
		||||
                        authorized_qos_flow_descriptions->buffer,
 | 
			
		||||
                        qosFlowSetupItem->qos_flow_description);
 | 
			
		||||
            ogs_assert(authorized_qos_flow_descriptions->length);
 | 
			
		||||
 | 
			
		||||
            pdu_session_establishment_accept->presencemask |=
 | 
			
		||||
                OGS_NAS_5GS_PDU_SESSION_ESTABLISHMENT_ACCEPT_AUTHORIZED_QOS_FLOW_DESCRIPTIONS_PRESENT;
 | 
			
		||||
            OGS_NAS_STORE_DATA(
 | 
			
		||||
                    authorized_qos_flow_descriptions,
 | 
			
		||||
                    &sess->h_smf_authorized_qos_flow_descriptions);
 | 
			
		||||
        }
 | 
			
		||||
    } else if (HOME_ROUTED_ROAMING_IN_HSMF(sess)) {
 | 
			
		||||
        ogs_fatal("This should not be invoked from H-SMF during HR-Roaming");
 | 
			
		||||
        ogs_assert_if_reached();
 | 
			
		||||
    } else {
 | 
			
		||||
        memset(&qos_flow_description, 0, sizeof(qos_flow_description));
 | 
			
		||||
        encode_default_qos_flow_description(&qos_flow_description[0], qos_flow);
 | 
			
		||||
        gsm_encode_default_qos_flow_description(
 | 
			
		||||
                &qos_flow_description[0], qos_flow);
 | 
			
		||||
 | 
			
		||||
        pdu_session_establishment_accept->presencemask |=
 | 
			
		||||
            OGS_NAS_5GS_PDU_SESSION_ESTABLISHMENT_ACCEPT_AUTHORIZED_QOS_FLOW_DESCRIPTIONS_PRESENT;
 | 
			
		||||
@@ -250,8 +278,6 @@ cleanup:
 | 
			
		||||
    if (extended_protocol_configuration_options->buffer)
 | 
			
		||||
        ogs_free(extended_protocol_configuration_options->buffer);
 | 
			
		||||
 | 
			
		||||
    OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_rules);
 | 
			
		||||
    OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_flow_descriptions);
 | 
			
		||||
    OGS_NAS_CLEAR_DATA(&sess->h_smf_extended_protocol_configuration_options);
 | 
			
		||||
 | 
			
		||||
    return pkbuf;
 | 
			
		||||
@@ -286,8 +312,7 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
 | 
			
		||||
{
 | 
			
		||||
    ogs_pkbuf_t *pkbuf = NULL;
 | 
			
		||||
    smf_bearer_t *qos_flow = NULL;
 | 
			
		||||
    ogs_pfcp_pdr_t *dl_pdr = NULL;
 | 
			
		||||
    int num_of_param, rv, i;
 | 
			
		||||
    int rv, i;
 | 
			
		||||
 | 
			
		||||
    ogs_nas_5gs_message_t message;
 | 
			
		||||
    ogs_nas_5gs_pdu_session_modification_command_t
 | 
			
		||||
@@ -301,6 +326,11 @@ 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_lnode_t *node = NULL;
 | 
			
		||||
    int num, len;
 | 
			
		||||
 | 
			
		||||
    authorized_qos_rules = &pdu_session_modification_command->
 | 
			
		||||
        authorized_qos_rules;
 | 
			
		||||
    ogs_assert(authorized_qos_rules);
 | 
			
		||||
@@ -318,7 +348,47 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
 | 
			
		||||
    message.gsm.h.message_type = OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND;
 | 
			
		||||
 | 
			
		||||
    /* QoS rule */
 | 
			
		||||
    if (qos_rule_code) {
 | 
			
		||||
    if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
 | 
			
		||||
        num = 0;
 | 
			
		||||
        OpenAPI_list_for_each(
 | 
			
		||||
                sess->h_smf_qos_flows_add_mod_request_list, node) {
 | 
			
		||||
            qosFlowAddModifyRequestItem = node->data;
 | 
			
		||||
            if (qosFlowAddModifyRequestItem) {
 | 
			
		||||
                ogs_nas_qos_rules_t qos_rules;
 | 
			
		||||
 | 
			
		||||
                len = ogs_base64_decode_len(
 | 
			
		||||
                        qosFlowAddModifyRequestItem->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);
 | 
			
		||||
                ogs_assert(qos_rules.length);
 | 
			
		||||
 | 
			
		||||
                ogs_assert(1 ==
 | 
			
		||||
                        ogs_nas_parse_qos_rules(
 | 
			
		||||
                            &qos_rule[num], &qos_rules));
 | 
			
		||||
 | 
			
		||||
                ogs_free(qos_rules.buffer);
 | 
			
		||||
 | 
			
		||||
                num++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (num) {
 | 
			
		||||
            ogs_assert(OGS_OK ==
 | 
			
		||||
                    ogs_nas_build_qos_rules(
 | 
			
		||||
                        authorized_qos_rules, qos_rule, num));
 | 
			
		||||
 | 
			
		||||
            pdu_session_modification_command->presencemask |=
 | 
			
		||||
                OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND_AUTHORIZED_QOS_RULES_PRESENT;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (HOME_ROUTED_ROAMING_IN_HSMF(sess)) {
 | 
			
		||||
        ogs_fatal("This should not be invoked from H-SMF during HR-Roaming");
 | 
			
		||||
        ogs_assert_if_reached();
 | 
			
		||||
    } else if (qos_rule_code) {
 | 
			
		||||
 | 
			
		||||
        i = 0;
 | 
			
		||||
        memset(qos_rule, 0, sizeof(qos_rule));
 | 
			
		||||
@@ -326,28 +396,7 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
 | 
			
		||||
        ogs_list_for_each_entry(
 | 
			
		||||
                &sess->qos_flow_to_modify_list, qos_flow, to_modify_node) {
 | 
			
		||||
            ogs_assert(i < OGS_MAX_NUM_OF_BEARER);
 | 
			
		||||
 | 
			
		||||
            dl_pdr = qos_flow->dl_pdr;
 | 
			
		||||
            ogs_assert(dl_pdr);
 | 
			
		||||
 | 
			
		||||
            qos_rule[i].identifier = qos_flow->qfi; /* Use QFI in Open5GS */
 | 
			
		||||
            qos_rule[i].code = qos_rule_code;
 | 
			
		||||
 | 
			
		||||
            if (qos_rule_code != OGS_NAS_QOS_CODE_DELETE_EXISTING_QOS_RULE &&
 | 
			
		||||
                qos_rule_code != OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_WITHOUT_MODIFYING_PACKET_FILTERS)
 | 
			
		||||
                encode_qos_rule_packet_filter(&qos_rule[i], qos_flow);
 | 
			
		||||
 | 
			
		||||
            if (qos_rule_code != OGS_NAS_QOS_CODE_DELETE_EXISTING_QOS_RULE &&
 | 
			
		||||
                qos_rule_code != OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_DELETE_PACKET_FILTERS &&
 | 
			
		||||
                qos_rule_code != OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_WITHOUT_MODIFYING_PACKET_FILTERS) {
 | 
			
		||||
                ogs_assert(dl_pdr->precedence > 0 && dl_pdr->precedence < 255);
 | 
			
		||||
                /* Use PCC Rule Precedence */
 | 
			
		||||
                qos_rule[i].precedence = dl_pdr->precedence;
 | 
			
		||||
 | 
			
		||||
                qos_rule[i].flow.segregation = 0;
 | 
			
		||||
                qos_rule[i].flow.identifier = qos_flow->qfi;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            gsm_encode_qos_rule(&qos_rule[i], qos_flow, qos_rule_code);
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -366,7 +415,48 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* QoS flow descriptions */
 | 
			
		||||
    if (qos_flow_description_code) {
 | 
			
		||||
    if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
 | 
			
		||||
        num = 0;
 | 
			
		||||
        OpenAPI_list_for_each(
 | 
			
		||||
                sess->h_smf_qos_flows_add_mod_request_list, node) {
 | 
			
		||||
            qosFlowAddModifyRequestItem = node->data;
 | 
			
		||||
            if (qosFlowAddModifyRequestItem) {
 | 
			
		||||
                ogs_nas_qos_flow_descriptions_t qos_flow_descriptions;
 | 
			
		||||
 | 
			
		||||
                len = ogs_base64_decode_len(
 | 
			
		||||
                        qosFlowAddModifyRequestItem->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,
 | 
			
		||||
                            qosFlowAddModifyRequestItem->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);
 | 
			
		||||
 | 
			
		||||
                num++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (num) {
 | 
			
		||||
            ogs_assert(OGS_OK ==
 | 
			
		||||
                    ogs_nas_build_qos_flow_descriptions(
 | 
			
		||||
                        authorized_qos_flow_descriptions,
 | 
			
		||||
                        qos_flow_description, num));
 | 
			
		||||
 | 
			
		||||
            pdu_session_modification_command->presencemask |=
 | 
			
		||||
                OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND_AUTHORIZED_QOS_FLOW_DESCRIPTIONS_PRESENT;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (HOME_ROUTED_ROAMING_IN_HSMF(sess)) {
 | 
			
		||||
        ogs_fatal("This should not be invoked from H-SMF during HR-Roaming");
 | 
			
		||||
        ogs_assert_if_reached();
 | 
			
		||||
    } else if (qos_flow_description_code) {
 | 
			
		||||
 | 
			
		||||
        i = 0;
 | 
			
		||||
        memset(&qos_flow_description, 0, sizeof(qos_flow_description));
 | 
			
		||||
@@ -375,67 +465,8 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
 | 
			
		||||
                &sess->qos_flow_to_modify_list, qos_flow, to_modify_node) {
 | 
			
		||||
            ogs_assert(i < OGS_MAX_NUM_OF_BEARER);
 | 
			
		||||
 | 
			
		||||
            qos_flow_description[i].identifier = qos_flow->qfi;
 | 
			
		||||
            qos_flow_description[i].code = qos_flow_description_code;
 | 
			
		||||
 | 
			
		||||
            num_of_param = 0;
 | 
			
		||||
 | 
			
		||||
            if (qos_flow_description_code !=
 | 
			
		||||
                    OGS_NAS_DELETE_NEW_QOS_FLOW_DESCRIPTION) {
 | 
			
		||||
                qos_flow_description[i].E_bit = 1;
 | 
			
		||||
 | 
			
		||||
                qos_flow_description[i].param[num_of_param].identifier =
 | 
			
		||||
                    OGS_NAX_QOS_FLOW_PARAMETER_ID_5QI;
 | 
			
		||||
                qos_flow_description[i].param[num_of_param].len =
 | 
			
		||||
                    sizeof(qos_flow_description[i].param[num_of_param].
 | 
			
		||||
                            qos_index);
 | 
			
		||||
                qos_flow_description[i].param[num_of_param].qos_index =
 | 
			
		||||
                    qos_flow->qos.index;
 | 
			
		||||
                num_of_param++;
 | 
			
		||||
 | 
			
		||||
                if (qos_flow->qos.gbr.uplink) {
 | 
			
		||||
                    qos_flow_description[i].param[num_of_param].identifier =
 | 
			
		||||
                        OGS_NAX_QOS_FLOW_PARAMETER_ID_GFBR_UPLINK;
 | 
			
		||||
                    qos_flow_description[i].param[num_of_param].len =
 | 
			
		||||
                        sizeof(qos_flow_description[i].param[num_of_param].br);
 | 
			
		||||
                    ogs_nas_bitrate_from_uint64(
 | 
			
		||||
                            &qos_flow_description[i].param[num_of_param].br,
 | 
			
		||||
                            qos_flow->qos.gbr.uplink);
 | 
			
		||||
                    num_of_param++;
 | 
			
		||||
                }
 | 
			
		||||
                if (qos_flow->qos.gbr.downlink) {
 | 
			
		||||
                    qos_flow_description[i].param[num_of_param].identifier =
 | 
			
		||||
                        OGS_NAX_QOS_FLOW_PARAMETER_ID_GFBR_DOWNLINK;
 | 
			
		||||
                    qos_flow_description[i].param[num_of_param].len =
 | 
			
		||||
                        sizeof(qos_flow_description[i].param[num_of_param].br);
 | 
			
		||||
                    ogs_nas_bitrate_from_uint64(
 | 
			
		||||
                            &qos_flow_description[i].param[num_of_param].br,
 | 
			
		||||
                            qos_flow->qos.gbr.downlink);
 | 
			
		||||
                    num_of_param++;
 | 
			
		||||
                }
 | 
			
		||||
                if (qos_flow->qos.mbr.uplink) {
 | 
			
		||||
                    qos_flow_description[i].param[num_of_param].identifier =
 | 
			
		||||
                        OGS_NAX_QOS_FLOW_PARAMETER_ID_MFBR_UPLINK;
 | 
			
		||||
                    qos_flow_description[i].param[num_of_param].len =
 | 
			
		||||
                        sizeof(qos_flow_description[i].param[num_of_param].br);
 | 
			
		||||
                    ogs_nas_bitrate_from_uint64(
 | 
			
		||||
                            &qos_flow_description[i].param[num_of_param].br,
 | 
			
		||||
                            qos_flow->qos.mbr.uplink);
 | 
			
		||||
                    num_of_param++;
 | 
			
		||||
                }
 | 
			
		||||
                if (qos_flow->qos.mbr.downlink) {
 | 
			
		||||
                    qos_flow_description[i].param[num_of_param].identifier =
 | 
			
		||||
                        OGS_NAX_QOS_FLOW_PARAMETER_ID_MFBR_DOWNLINK;
 | 
			
		||||
                    qos_flow_description[i].param[num_of_param].len =
 | 
			
		||||
                        sizeof(qos_flow_description[i].param[num_of_param].br);
 | 
			
		||||
                    ogs_nas_bitrate_from_uint64(
 | 
			
		||||
                            &qos_flow_description[i].param[num_of_param].br,
 | 
			
		||||
                            qos_flow->qos.mbr.downlink);
 | 
			
		||||
                    num_of_param++;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            qos_flow_description[i].num_of_parameter = num_of_param;
 | 
			
		||||
            gsm_encode_qos_flow_description(
 | 
			
		||||
                &qos_flow_description[i], qos_flow, qos_flow_description_code);
 | 
			
		||||
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
@@ -458,14 +489,11 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
 | 
			
		||||
    pkbuf = ogs_nas_5gs_plain_encode(&message);
 | 
			
		||||
    ogs_assert(pkbuf);
 | 
			
		||||
 | 
			
		||||
    if (pdu_session_modification_command->presencemask &
 | 
			
		||||
        OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND_AUTHORIZED_QOS_RULES_PRESENT) {
 | 
			
		||||
cleanup:
 | 
			
		||||
    if (authorized_qos_rules->buffer)
 | 
			
		||||
        ogs_free(authorized_qos_rules->buffer);
 | 
			
		||||
    }
 | 
			
		||||
    if (pdu_session_modification_command->presencemask &
 | 
			
		||||
        OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND_AUTHORIZED_QOS_FLOW_DESCRIPTIONS_PRESENT) {
 | 
			
		||||
    if (authorized_qos_flow_descriptions->buffer)
 | 
			
		||||
        ogs_free(authorized_qos_flow_descriptions->buffer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return pkbuf;
 | 
			
		||||
}
 | 
			
		||||
@@ -537,7 +565,7 @@ ogs_pkbuf_t *gsm_build_pdu_session_release_reject(
 | 
			
		||||
    return ogs_nas_5gs_plain_encode(&message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void encode_default_qos_rule(
 | 
			
		||||
void gsm_encode_default_qos_rule(
 | 
			
		||||
        ogs_nas_qos_rule_t *qos_rule, smf_bearer_t *qos_flow)
 | 
			
		||||
{
 | 
			
		||||
    ogs_assert(qos_rule);
 | 
			
		||||
@@ -584,7 +612,7 @@ void encode_default_qos_rule(
 | 
			
		||||
    qos_rule->flow.identifier = qos_flow->qfi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void encode_default_qos_flow_description(
 | 
			
		||||
void gsm_encode_default_qos_flow_description(
 | 
			
		||||
        ogs_nas_qos_flow_description_t *qos_flow_description,
 | 
			
		||||
        smf_bearer_t *qos_flow)
 | 
			
		||||
{
 | 
			
		||||
@@ -609,7 +637,7 @@ void encode_default_qos_flow_description(
 | 
			
		||||
    qos_flow_description->num_of_parameter = num_of_param;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void encode_qos_rule_packet_filter(
 | 
			
		||||
void gsm_encode_qos_rule_packet_filter(
 | 
			
		||||
        ogs_nas_qos_rule_t *qos_rule, smf_bearer_t *qos_flow)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
@@ -643,3 +671,100 @@ void encode_qos_rule_packet_filter(
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gsm_encode_qos_rule(
 | 
			
		||||
        ogs_nas_qos_rule_t *qos_rule,
 | 
			
		||||
        smf_bearer_t *qos_flow, uint8_t qos_rule_code)
 | 
			
		||||
{
 | 
			
		||||
    ogs_pfcp_pdr_t *dl_pdr = NULL;
 | 
			
		||||
 | 
			
		||||
    ogs_assert(qos_rule);
 | 
			
		||||
    ogs_assert(qos_flow);
 | 
			
		||||
    ogs_assert(qos_rule_code);
 | 
			
		||||
 | 
			
		||||
    dl_pdr = qos_flow->dl_pdr;
 | 
			
		||||
    ogs_assert(dl_pdr);
 | 
			
		||||
 | 
			
		||||
    qos_rule->identifier = qos_flow->qfi;
 | 
			
		||||
    qos_rule->code = qos_rule_code;
 | 
			
		||||
 | 
			
		||||
    if (qos_rule_code != OGS_NAS_QOS_CODE_DELETE_EXISTING_QOS_RULE &&
 | 
			
		||||
        qos_rule_code != OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_WITHOUT_MODIFYING_PACKET_FILTERS) {
 | 
			
		||||
        gsm_encode_qos_rule_packet_filter(qos_rule, qos_flow);
 | 
			
		||||
    }
 | 
			
		||||
    if (qos_rule_code != OGS_NAS_QOS_CODE_DELETE_EXISTING_QOS_RULE &&
 | 
			
		||||
        qos_rule_code != OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_DELETE_PACKET_FILTERS &&
 | 
			
		||||
        qos_rule_code != OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_WITHOUT_MODIFYING_PACKET_FILTERS)
 | 
			
		||||
    {
 | 
			
		||||
        ogs_assert(dl_pdr->precedence > 0 && dl_pdr->precedence < 255);
 | 
			
		||||
        qos_rule->precedence = dl_pdr->precedence;
 | 
			
		||||
        qos_rule->flow.segregation = 0;
 | 
			
		||||
        qos_rule->flow.identifier = qos_flow->qfi;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gsm_encode_qos_flow_description(
 | 
			
		||||
        ogs_nas_qos_flow_description_t *qos_flow_description,
 | 
			
		||||
        smf_bearer_t *qos_flow, uint8_t qos_flow_description_code)
 | 
			
		||||
{
 | 
			
		||||
    int num_of_param = 0;
 | 
			
		||||
 | 
			
		||||
    ogs_assert(qos_flow_description);
 | 
			
		||||
    ogs_assert(qos_flow);
 | 
			
		||||
    ogs_assert(qos_flow_description_code);
 | 
			
		||||
 | 
			
		||||
    qos_flow_description->identifier = qos_flow->qfi;
 | 
			
		||||
    qos_flow_description->code = qos_flow_description_code;
 | 
			
		||||
 | 
			
		||||
    if (qos_flow_description_code != OGS_NAS_DELETE_NEW_QOS_FLOW_DESCRIPTION) {
 | 
			
		||||
        qos_flow_description->E_bit = 1;
 | 
			
		||||
        qos_flow_description->param[num_of_param].identifier =
 | 
			
		||||
            OGS_NAX_QOS_FLOW_PARAMETER_ID_5QI;
 | 
			
		||||
        qos_flow_description->param[num_of_param].len =
 | 
			
		||||
            sizeof(qos_flow_description->param[num_of_param].qos_index);
 | 
			
		||||
        qos_flow_description->param[num_of_param++].qos_index =
 | 
			
		||||
            qos_flow->qos.index;
 | 
			
		||||
 | 
			
		||||
        if (qos_flow->qos.gbr.uplink) {
 | 
			
		||||
            qos_flow_description->param[num_of_param].identifier =
 | 
			
		||||
                OGS_NAX_QOS_FLOW_PARAMETER_ID_GFBR_UPLINK;
 | 
			
		||||
            qos_flow_description->param[num_of_param].len =
 | 
			
		||||
                sizeof(qos_flow_description->param[num_of_param].br);
 | 
			
		||||
            ogs_nas_bitrate_from_uint64(
 | 
			
		||||
                &qos_flow_description->param[num_of_param].br,
 | 
			
		||||
                qos_flow->qos.gbr.uplink);
 | 
			
		||||
            num_of_param++;
 | 
			
		||||
        }
 | 
			
		||||
        if (qos_flow->qos.gbr.downlink) {
 | 
			
		||||
            qos_flow_description->param[num_of_param].identifier =
 | 
			
		||||
                OGS_NAX_QOS_FLOW_PARAMETER_ID_GFBR_DOWNLINK;
 | 
			
		||||
            qos_flow_description->param[num_of_param].len =
 | 
			
		||||
                sizeof(qos_flow_description->param[num_of_param].br);
 | 
			
		||||
            ogs_nas_bitrate_from_uint64(
 | 
			
		||||
                &qos_flow_description->param[num_of_param].br,
 | 
			
		||||
                qos_flow->qos.gbr.downlink);
 | 
			
		||||
            num_of_param++;
 | 
			
		||||
        }
 | 
			
		||||
        if (qos_flow->qos.mbr.uplink) {
 | 
			
		||||
            qos_flow_description->param[num_of_param].identifier =
 | 
			
		||||
                OGS_NAX_QOS_FLOW_PARAMETER_ID_MFBR_UPLINK;
 | 
			
		||||
            qos_flow_description->param[num_of_param].len =
 | 
			
		||||
                sizeof(qos_flow_description->param[num_of_param].br);
 | 
			
		||||
            ogs_nas_bitrate_from_uint64(
 | 
			
		||||
                &qos_flow_description->param[num_of_param].br,
 | 
			
		||||
                qos_flow->qos.mbr.uplink);
 | 
			
		||||
            num_of_param++;
 | 
			
		||||
        }
 | 
			
		||||
        if (qos_flow->qos.mbr.downlink) {
 | 
			
		||||
            qos_flow_description->param[num_of_param].identifier =
 | 
			
		||||
                OGS_NAX_QOS_FLOW_PARAMETER_ID_MFBR_DOWNLINK;
 | 
			
		||||
            qos_flow_description->param[num_of_param].len =
 | 
			
		||||
                sizeof(qos_flow_description->param[num_of_param].br);
 | 
			
		||||
            ogs_nas_bitrate_from_uint64(
 | 
			
		||||
                &qos_flow_description->param[num_of_param].br,
 | 
			
		||||
                qos_flow->qos.mbr.downlink);
 | 
			
		||||
            num_of_param++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    qos_flow_description->num_of_parameter = num_of_param;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,14 +43,21 @@ ogs_pkbuf_t *gsm_build_pdu_session_release_reject(
 | 
			
		||||
 | 
			
		||||
ogs_pkbuf_t *gsm_build_status(smf_sess_t *sess, ogs_nas_5gsm_cause_t cause);
 | 
			
		||||
 | 
			
		||||
void encode_default_qos_rule(
 | 
			
		||||
void gsm_encode_default_qos_rule(
 | 
			
		||||
        ogs_nas_qos_rule_t *qos_rule, smf_bearer_t *qos_flow);
 | 
			
		||||
void encode_default_qos_flow_description(
 | 
			
		||||
void gsm_encode_default_qos_flow_description(
 | 
			
		||||
        ogs_nas_qos_flow_description_t *qos_flow_description,
 | 
			
		||||
        smf_bearer_t *qos_flow);
 | 
			
		||||
void encode_qos_rule_packet_filter(
 | 
			
		||||
void gsm_encode_qos_rule_packet_filter(
 | 
			
		||||
        ogs_nas_qos_rule_t *qos_rule, smf_bearer_t *qos_flow);
 | 
			
		||||
 | 
			
		||||
void gsm_encode_qos_rule(
 | 
			
		||||
        ogs_nas_qos_rule_t *qos_rule, smf_bearer_t *qos_flow,
 | 
			
		||||
        uint8_t qos_rule_code);
 | 
			
		||||
void gsm_encode_qos_flow_description(
 | 
			
		||||
        ogs_nas_qos_flow_description_t *qos_flow_description,
 | 
			
		||||
        smf_bearer_t *qos_flow, uint8_t qos_flow_description_code);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -874,6 +874,7 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
    char *strerror = NULL;
 | 
			
		||||
    smf_ue_t *smf_ue = NULL;
 | 
			
		||||
    smf_sess_t *sess = NULL;
 | 
			
		||||
    smf_bearer_t *qos_flow = NULL;
 | 
			
		||||
    ogs_pkbuf_t *pkbuf = NULL;
 | 
			
		||||
 | 
			
		||||
    ogs_pfcp_xact_t *pfcp_xact = NULL;
 | 
			
		||||
@@ -1084,11 +1085,19 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
            CASE(OGS_SBI_RESOURCE_NAME_PDU_SESSIONS)
 | 
			
		||||
                SWITCH(sbi_message->h.resource.component[2])
 | 
			
		||||
                CASE(OGS_SBI_RESOURCE_NAME_MODIFY)
 | 
			
		||||
                    rc = smf_nsmf_handle_hsmf_update_data(
 | 
			
		||||
                    rc = smf_nsmf_handle_update_data_in_hsmf(
 | 
			
		||||
                            sess, stream, sbi_message);
 | 
			
		||||
                    if (rc == true) {
 | 
			
		||||
                        ogs_assert(sess->nsmf_param.request_indication);
 | 
			
		||||
 | 
			
		||||
                        if (sess->nsmf_param.request_indication ==
 | 
			
		||||
                            OpenAPI_request_indication_NW_REQ_PDU_SES_MOD) {
 | 
			
		||||
                            ogs_fatal("TODO");
 | 
			
		||||
 | 
			
		||||
                            ogs_assert(true ==
 | 
			
		||||
                                    ogs_sbi_send_http_status_no_content(
 | 
			
		||||
                                        stream));
 | 
			
		||||
                        } else {
 | 
			
		||||
                            if (sess->nsmf_param.request_indication ==
 | 
			
		||||
                                    OpenAPI_request_indication_UE_REQ_PDU_SES_REL) {
 | 
			
		||||
                                e->h.sbi.state =
 | 
			
		||||
@@ -1097,8 +1106,10 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
                                    OpenAPI_request_indication_NW_REQ_PDU_SES_REL) {
 | 
			
		||||
                                e->h.sbi.state =
 | 
			
		||||
                                OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT;
 | 
			
		||||
 | 
			
		||||
                            } else {
 | 
			
		||||
                            ogs_fatal("Not implemented [requestIndication:%d]",
 | 
			
		||||
                                ogs_fatal("Not implemented "
 | 
			
		||||
                                        "[requestIndication:%d]",
 | 
			
		||||
                                        sess->nsmf_param.request_indication);
 | 
			
		||||
                                ogs_assert_if_reached();
 | 
			
		||||
                            }
 | 
			
		||||
@@ -1120,11 +1131,13 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
     *    (OpenAPI_cause_REL_DUE_TO_DUPLICATE_SESSION_ID);
 | 
			
		||||
     */
 | 
			
		||||
                            ogs_assert(true ==
 | 
			
		||||
                                ogs_sbi_send_http_status_no_content(stream));
 | 
			
		||||
                                    ogs_sbi_send_http_status_no_content(
 | 
			
		||||
                                        stream));
 | 
			
		||||
 | 
			
		||||
                            OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        ogs_error("smf_nsmf_handle_hsmf_update_data() "
 | 
			
		||||
                        ogs_error("smf_nsmf_handle_update_data_in_hsmf() "
 | 
			
		||||
                                "failed");
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -1150,14 +1163,27 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
            CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
 | 
			
		||||
                SWITCH(sbi_message->h.resource.component[2])
 | 
			
		||||
                CASE(OGS_SBI_RESOURCE_NAME_MODIFY)
 | 
			
		||||
                    rc = smf_nsmf_handle_vsmf_update_data(
 | 
			
		||||
                    rc = smf_nsmf_handle_update_data_in_vsmf(
 | 
			
		||||
                            sess, stream, sbi_message);
 | 
			
		||||
 | 
			
		||||
                    if (rc == true) {
 | 
			
		||||
                        e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED;
 | 
			
		||||
                        switch (sess->nsmf_param.request_indication) {
 | 
			
		||||
                        case OpenAPI_request_indication_UE_REQ_PDU_SES_MOD:
 | 
			
		||||
                        case OpenAPI_request_indication_NW_REQ_PDU_SES_MOD:
 | 
			
		||||
                            break;
 | 
			
		||||
                        case OpenAPI_request_indication_UE_REQ_PDU_SES_REL:
 | 
			
		||||
                        case OpenAPI_request_indication_NW_REQ_PDU_SES_REL:
 | 
			
		||||
                            e->h.sbi.state =
 | 
			
		||||
                                OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED;
 | 
			
		||||
                            OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion);
 | 
			
		||||
                            break;
 | 
			
		||||
                        default:
 | 
			
		||||
                            ogs_error("Unknown request_indication:%d",
 | 
			
		||||
                                    sess->nsmf_param.request_indication);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        ogs_error("smf_nsmf_handle_vsmf_update_data() failed");
 | 
			
		||||
                        ogs_error("smf_nsmf_handle_update_data_in_vsmf() "
 | 
			
		||||
                                "failed");
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                DEFAULT
 | 
			
		||||
@@ -1202,6 +1228,10 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
        smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
 | 
			
		||||
        ogs_assert(smf_ue);
 | 
			
		||||
 | 
			
		||||
        stream_id = OGS_POINTER_TO_UINT(e->h.sbi.data);
 | 
			
		||||
        if (stream_id >= OGS_MIN_POOL_ID && stream_id <= OGS_MAX_POOL_ID)
 | 
			
		||||
            stream = ogs_sbi_stream_find_by_id(stream_id);
 | 
			
		||||
 | 
			
		||||
        SWITCH(sbi_message->h.service.name)
 | 
			
		||||
        CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM)
 | 
			
		||||
            SWITCH(sbi_message->h.resource.component[0])
 | 
			
		||||
@@ -1241,7 +1271,7 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
                                    &smf_gsm_state_wait_pfcp_deletion);
 | 
			
		||||
                        break;
 | 
			
		||||
                    DEFAULT
 | 
			
		||||
                        if (smf_nsmf_handle_create_data_in_vsmf(
 | 
			
		||||
                        if (smf_nsmf_handle_created_data_in_vsmf(
 | 
			
		||||
                                    sess, sbi_message) == false) {
 | 
			
		||||
                            ogs_error("[%s:%d] create_pdu_session "
 | 
			
		||||
                                    "failed() [%d]",
 | 
			
		||||
@@ -1259,6 +1289,39 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
                END
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
 | 
			
		||||
                SWITCH(sbi_message->h.resource.component[2])
 | 
			
		||||
                CASE(OGS_SBI_RESOURCE_NAME_MODIFY)
 | 
			
		||||
                    ogs_list_for_each_entry(
 | 
			
		||||
                            &sess->qos_flow_to_modify_list,
 | 
			
		||||
                            qos_flow, to_modify_node) {
 | 
			
		||||
                        ogs_pfcp_far_t *dl_far = qos_flow->dl_far;
 | 
			
		||||
                        ogs_assert(dl_far);
 | 
			
		||||
 | 
			
		||||
                        dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW;
 | 
			
		||||
                        ogs_assert(OGS_OK ==
 | 
			
		||||
                            ogs_pfcp_ip_to_outer_header_creation(
 | 
			
		||||
                                &sess->remote_dl_ip,
 | 
			
		||||
                                &dl_far->outer_header_creation,
 | 
			
		||||
                                &dl_far->outer_header_creation_len));
 | 
			
		||||
                        dl_far->outer_header_creation.teid =
 | 
			
		||||
                            sess->remote_dl_teid;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    ogs_assert(OGS_OK ==
 | 
			
		||||
                            smf_5gc_pfcp_send_qos_flow_list_modification_request(
 | 
			
		||||
                                sess, NULL,
 | 
			
		||||
                                OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|
 | 
			
		||||
                                OGS_PFCP_MODIFY_DL_ONLY|
 | 
			
		||||
                                OGS_PFCP_MODIFY_ACTIVATE, 0));
 | 
			
		||||
                    break;
 | 
			
		||||
                DEFAULT
 | 
			
		||||
                    ogs_error("Invalid resource name [%s]",
 | 
			
		||||
                            sbi_message->h.resource.component[0]);
 | 
			
		||||
                    ogs_assert_if_reached();
 | 
			
		||||
                END
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            DEFAULT
 | 
			
		||||
                ogs_error("Invalid resource name [%s]",
 | 
			
		||||
                        sbi_message->h.resource.component[0]);
 | 
			
		||||
@@ -1302,6 +1365,22 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
 | 
			
		||||
        case OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMPLETE:
 | 
			
		||||
            ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
 | 
			
		||||
            if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
 | 
			
		||||
                ogs_sbi_stream_t *n1_n2_modified_stream = NULL;
 | 
			
		||||
                if (sess->n1_n2_modified_stream_id >= OGS_MIN_POOL_ID &&
 | 
			
		||||
                    sess->n1_n2_modified_stream_id <= OGS_MAX_POOL_ID)
 | 
			
		||||
                    n1_n2_modified_stream =
 | 
			
		||||
                        ogs_sbi_stream_find_by_id(
 | 
			
		||||
                                sess->n1_n2_modified_stream_id);
 | 
			
		||||
 | 
			
		||||
                if (n1_n2_modified_stream) {
 | 
			
		||||
                    ogs_assert(true ==
 | 
			
		||||
                            ogs_sbi_send_http_status_no_content(
 | 
			
		||||
                                n1_n2_modified_stream));
 | 
			
		||||
                } else
 | 
			
		||||
                    ogs_error("No N1-N2 Modifed Stream [%d]",
 | 
			
		||||
                                sess->n1_n2_modified_stream_id);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case OGS_NAS_5GS_PDU_SESSION_RELEASE_REQUEST:
 | 
			
		||||
 
 | 
			
		||||
@@ -1609,6 +1609,23 @@ cleanup:
 | 
			
		||||
    return pkbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ogs_pkbuf_t *gsmue_build_pdu_session_modification_command(smf_sess_t *sess)
 | 
			
		||||
{
 | 
			
		||||
    ogs_pkbuf_t *pkbuf = NULL;
 | 
			
		||||
 | 
			
		||||
    ogs_nas_5gs_message_t message;
 | 
			
		||||
 | 
			
		||||
    ogs_assert(sess);
 | 
			
		||||
 | 
			
		||||
    memset(&message, 0, sizeof(message));
 | 
			
		||||
    message.gsm.h.message_type = OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND;
 | 
			
		||||
 | 
			
		||||
    pkbuf = gsmue_encode_n1_sm_info(&message);
 | 
			
		||||
    ogs_assert(pkbuf);
 | 
			
		||||
 | 
			
		||||
    return pkbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ogs_pkbuf_t *gsmue_build_pdu_session_release_command(smf_sess_t *sess)
 | 
			
		||||
{
 | 
			
		||||
    ogs_pkbuf_t *pkbuf = NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ ogs_pkbuf_t *gsmue_encode_n1_sm_info(ogs_nas_5gs_message_t *message);
 | 
			
		||||
int gsmue_decode_n1_sm_info(ogs_nas_5gs_message_t *message, ogs_pkbuf_t *pkbuf);
 | 
			
		||||
 | 
			
		||||
ogs_pkbuf_t *gsmue_build_pdu_session_establishment_accept(smf_sess_t *sess);
 | 
			
		||||
ogs_pkbuf_t *gsmue_build_pdu_session_modification_command(smf_sess_t *sess);
 | 
			
		||||
ogs_pkbuf_t *gsmue_build_pdu_session_release_command(smf_sess_t *sess);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 
 | 
			
		||||
@@ -257,7 +257,7 @@ void smf_5gc_n4_handle_session_modification_response(
 | 
			
		||||
        smf_sess_t *sess, ogs_pfcp_xact_t *xact,
 | 
			
		||||
        ogs_pfcp_session_modification_response_t *rsp)
 | 
			
		||||
{
 | 
			
		||||
    int status = 0;
 | 
			
		||||
    int r, status = 0;
 | 
			
		||||
    uint64_t flags = 0;
 | 
			
		||||
    int trigger = 0;
 | 
			
		||||
    ogs_sbi_stream_t *stream = NULL;
 | 
			
		||||
@@ -407,33 +407,15 @@ void smf_5gc_n4_handle_session_modification_response(
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (flags & OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING) {
 | 
			
		||||
        if (flags & OGS_PFCP_MODIFY_ACTIVATE) {
 | 
			
		||||
        if (flags & OGS_PFCP_MODIFY_XN_HANDOVER) {
 | 
			
		||||
            ogs_pkbuf_t *n2smbuf =
 | 
			
		||||
                ngap_build_path_switch_request_ack_transfer(sess);
 | 
			
		||||
            ogs_assert(n2smbuf);
 | 
			
		||||
 | 
			
		||||
            smf_sbi_send_sm_context_updated_data_n2smbuf(sess, stream,
 | 
			
		||||
                OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ_ACK, n2smbuf);
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_N2_HANDOVER) {
 | 
			
		||||
 | 
			
		||||
            if (smf_sess_have_indirect_data_forwarding(sess) == true) {
 | 
			
		||||
                ogs_assert(OGS_OK ==
 | 
			
		||||
                    smf_5gc_pfcp_send_all_pdr_modification_request(
 | 
			
		||||
                        sess, stream,
 | 
			
		||||
                        OGS_PFCP_MODIFY_INDIRECT|OGS_PFCP_MODIFY_REMOVE,
 | 
			
		||||
                        0, ogs_local_conf()->time.handover.duration));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            smf_sbi_send_sm_context_updated_data_ho_state(
 | 
			
		||||
                    sess, stream, OpenAPI_ho_state_COMPLETED);
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING) {
 | 
			
		||||
            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 {
 | 
			
		||||
                    if (stream)
 | 
			
		||||
                        ogs_assert(true ==
 | 
			
		||||
                                ogs_sbi_send_http_status_no_content(stream));
 | 
			
		||||
                }
 | 
			
		||||
@@ -455,38 +437,7 @@ void smf_5gc_n4_handle_session_modification_response(
 | 
			
		||||
                ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
 | 
			
		||||
                ogs_assert_if_reached();
 | 
			
		||||
            }
 | 
			
		||||
        } 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(
 | 
			
		||||
                        sess, stream, OpenAPI_up_cnx_state_ACTIVATED);
 | 
			
		||||
            } else {
 | 
			
		||||
                int r = smf_sbi_discover_and_send(
 | 
			
		||||
                        OGS_SBI_SERVICE_TYPE_NUDM_UECM, NULL,
 | 
			
		||||
                        smf_nudm_uecm_build_registration,
 | 
			
		||||
                        sess, stream, SMF_UECM_STATE_REGISTERED, NULL);
 | 
			
		||||
                ogs_expect(r == OGS_OK);
 | 
			
		||||
                ogs_assert(r != OGS_ERROR);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) {
 | 
			
		||||
        if (flags & OGS_PFCP_MODIFY_ERROR_INDICATION) {
 | 
			
		||||
            smf_n1_n2_message_transfer_param_t param;
 | 
			
		||||
 | 
			
		||||
            memset(¶m, 0, sizeof(param));
 | 
			
		||||
            param.state = SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN;
 | 
			
		||||
            param.n2smbuf =
 | 
			
		||||
                ngap_build_pdu_session_resource_release_command_transfer(
 | 
			
		||||
                    sess, SMF_NGAP_STATE_ERROR_INDICATION_RECEIVED_FROM_5G_AN,
 | 
			
		||||
                    NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release);
 | 
			
		||||
            ogs_assert(param.n2smbuf);
 | 
			
		||||
 | 
			
		||||
            param.skip_ind = true;
 | 
			
		||||
 | 
			
		||||
            smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING) {
 | 
			
		||||
            int r;
 | 
			
		||||
            ogs_assert(trigger);
 | 
			
		||||
 | 
			
		||||
            if (trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED) {
 | 
			
		||||
@@ -516,7 +467,84 @@ 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));
 | 
			
		||||
 | 
			
		||||
                /* Network Requested PDU Session Modification */
 | 
			
		||||
                sess->nsmf_param.request_indication =
 | 
			
		||||
                    OpenAPI_request_indication_NW_REQ_PDU_SES_MOD;
 | 
			
		||||
                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);
 | 
			
		||||
 | 
			
		||||
                r = smf_sbi_discover_and_send(
 | 
			
		||||
                        OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
 | 
			
		||||
                        smf_nsmf_pdusession_build_vsmf_update_data,
 | 
			
		||||
                        sess, NULL, 0, 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();
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            ogs_fatal("Invalid flags [%lld]", (long long)flags);
 | 
			
		||||
            ogs_assert_if_reached();
 | 
			
		||||
        }
 | 
			
		||||
    } else if (flags & OGS_PFCP_MODIFY_ACTIVATE) {
 | 
			
		||||
        if (flags & OGS_PFCP_MODIFY_XN_HANDOVER) {
 | 
			
		||||
            ogs_pkbuf_t *n2smbuf =
 | 
			
		||||
                ngap_build_path_switch_request_ack_transfer(sess);
 | 
			
		||||
            ogs_assert(n2smbuf);
 | 
			
		||||
 | 
			
		||||
            smf_sbi_send_sm_context_updated_data_n2smbuf(sess, stream,
 | 
			
		||||
                OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ_ACK, n2smbuf);
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_N2_HANDOVER) {
 | 
			
		||||
 | 
			
		||||
            if (smf_sess_have_indirect_data_forwarding(sess) == true) {
 | 
			
		||||
                ogs_assert(OGS_OK ==
 | 
			
		||||
                    smf_5gc_pfcp_send_all_pdr_modification_request(
 | 
			
		||||
                        sess, stream,
 | 
			
		||||
                        OGS_PFCP_MODIFY_INDIRECT|OGS_PFCP_MODIFY_REMOVE,
 | 
			
		||||
                        0, ogs_local_conf()->time.handover.duration));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            smf_sbi_send_sm_context_updated_data_ho_state(
 | 
			
		||||
                    sess, stream, OpenAPI_ho_state_COMPLETED);
 | 
			
		||||
        } 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(
 | 
			
		||||
                        sess, stream, OpenAPI_up_cnx_state_ACTIVATED);
 | 
			
		||||
            } else {
 | 
			
		||||
                r = smf_sbi_discover_and_send(
 | 
			
		||||
                        OGS_SBI_SERVICE_TYPE_NUDM_UECM, NULL,
 | 
			
		||||
                        smf_nudm_uecm_build_registration,
 | 
			
		||||
                        sess, stream, SMF_UECM_STATE_REGISTERED, NULL);
 | 
			
		||||
                ogs_expect(r == OGS_OK);
 | 
			
		||||
                ogs_assert(r != OGS_ERROR);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) {
 | 
			
		||||
        if (flags & OGS_PFCP_MODIFY_ERROR_INDICATION) {
 | 
			
		||||
            smf_n1_n2_message_transfer_param_t param;
 | 
			
		||||
 | 
			
		||||
            memset(¶m, 0, sizeof(param));
 | 
			
		||||
            param.state = SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN;
 | 
			
		||||
            param.n2smbuf =
 | 
			
		||||
                ngap_build_pdu_session_resource_release_command_transfer(
 | 
			
		||||
                    sess, SMF_NGAP_STATE_ERROR_INDICATION_RECEIVED_FROM_5G_AN,
 | 
			
		||||
                    NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release);
 | 
			
		||||
            ogs_assert(param.n2smbuf);
 | 
			
		||||
 | 
			
		||||
            param.skip_ind = true;
 | 
			
		||||
 | 
			
		||||
            smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
 | 
			
		||||
        } else {
 | 
			
		||||
            smf_sbi_send_sm_context_updated_data_up_cnx_state(
 | 
			
		||||
                    sess, stream, OpenAPI_up_cnx_state_DEACTIVATED);
 | 
			
		||||
@@ -688,23 +716,9 @@ void smf_5gc_n4_handle_session_modification_response(
 | 
			
		||||
        uint8_t qos_rule_code = 0;
 | 
			
		||||
        uint8_t qos_flow_description_code = 0;
 | 
			
		||||
 | 
			
		||||
        if (flags & OGS_PFCP_MODIFY_TFT_NEW) {
 | 
			
		||||
            qos_rule_code = OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE;
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_TFT_ADD) {
 | 
			
		||||
            qos_rule_code = OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_ADD_PACKET_FILTERS;
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_TFT_REPLACE) {
 | 
			
		||||
            qos_rule_code = OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_REPLACE_ALL_PACKET_FILTERS;
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_TFT_DELETE) {
 | 
			
		||||
            qos_rule_code = OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_DELETE_PACKET_FILTERS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (flags & OGS_PFCP_MODIFY_QOS_CREATE) {
 | 
			
		||||
            ogs_assert_if_reached();
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_QOS_MODIFY) {
 | 
			
		||||
            qos_flow_description_code = OGS_NAS_MODIFY_NEW_QOS_FLOW_DESCRIPTION;
 | 
			
		||||
        } else if (flags & OGS_PFCP_MODIFY_QOS_DELETE) {
 | 
			
		||||
            ogs_assert_if_reached();
 | 
			
		||||
        }
 | 
			
		||||
        qos_rule_code = QOS_RULE_CODE_FROM_PFCP_FLAGS(flags);
 | 
			
		||||
        qos_flow_description_code =
 | 
			
		||||
                QOS_RULE_FLOW_DESCRIPTION_CODE_FROM_PFCP_FLAGS(flags);
 | 
			
		||||
 | 
			
		||||
        if (flags & OGS_PFCP_MODIFY_NETWORK_REQUESTED) {
 | 
			
		||||
            ogs_assert(flags & OGS_PFCP_MODIFY_SESSION);
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,15 @@ bool smf_namf_comm_handle_n1_n2_message_transfer(
 | 
			
		||||
    switch (state) {
 | 
			
		||||
    case SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT:
 | 
			
		||||
        if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) {
 | 
			
		||||
/*
 | 
			
		||||
 * Non-roaming/LBO: start network-triggered PDU Session Modification at step 11
 | 
			
		||||
 * after N1N2 transfer (Establishment Accept) and N2/N4 context sync, ensuring
 | 
			
		||||
 * the session is active on UE, RAN, and SMF before applying QoS updates.
 | 
			
		||||
 *
 | 
			
		||||
 * Home-Routed Roaming: trigger PDU Session Modification at step 13
 | 
			
		||||
 * immediately after H-SMF’s CreateSMContext response and H-UPF N4 setup
 | 
			
		||||
 * to apply QoS updates without waiting for V-SMF or RAN setup.
 | 
			
		||||
 */
 | 
			
		||||
            smf_qos_flow_binding(sess);
 | 
			
		||||
        } else {
 | 
			
		||||
            ogs_error("[%s:%d] HTTP response error [%d]",
 | 
			
		||||
@@ -57,7 +66,9 @@ 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) {
 | 
			
		||||
                /* Nothing */
 | 
			
		||||
                if (stream)
 | 
			
		||||
                    sess->n1_n2_modified_stream_id =
 | 
			
		||||
                        ogs_sbi_id_from_stream(stream);
 | 
			
		||||
            } else {
 | 
			
		||||
                ogs_error("Not implemented [cause:%d]",
 | 
			
		||||
                        N1N2MessageTransferRspData->cause);
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,68 @@
 | 
			
		||||
 | 
			
		||||
#include "ngap-build.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fill common QoS flow level parameters: 5QI, ARP, and optional GBR/MBR.
 | 
			
		||||
 */
 | 
			
		||||
static void fill_qos_level_parameters(
 | 
			
		||||
    NGAP_QosFlowLevelQosParameters_t *params,
 | 
			
		||||
    const ogs_qos_t *qos,
 | 
			
		||||
    bool include_gbr)
 | 
			
		||||
{
 | 
			
		||||
    NGAP_AllocationAndRetentionPriority_t
 | 
			
		||||
        *allocationAndRetentionPriority = NULL;
 | 
			
		||||
    NGAP_QosCharacteristics_t *qosCharacteristics = NULL;
 | 
			
		||||
    NGAP_NonDynamic5QIDescriptor_t *nonDynamic5QI = NULL;
 | 
			
		||||
 | 
			
		||||
    /* Allocation and Retention Priority */
 | 
			
		||||
    allocationAndRetentionPriority =
 | 
			
		||||
        ¶ms->allocationAndRetentionPriority;
 | 
			
		||||
 | 
			
		||||
    allocationAndRetentionPriority->priorityLevelARP = qos->arp.priority_level;
 | 
			
		||||
    if (qos->arp.pre_emption_capability == OGS_5GC_PRE_EMPTION_ENABLED)
 | 
			
		||||
        allocationAndRetentionPriority->pre_emptionCapability =
 | 
			
		||||
            NGAP_Pre_emptionCapability_may_trigger_pre_emption;
 | 
			
		||||
    if (qos->arp.pre_emption_vulnerability == OGS_5GC_PRE_EMPTION_ENABLED)
 | 
			
		||||
        allocationAndRetentionPriority->pre_emptionVulnerability =
 | 
			
		||||
            NGAP_Pre_emptionVulnerability_pre_emptable;
 | 
			
		||||
 | 
			
		||||
    /* Non-Dynamic 5QI Descriptor */
 | 
			
		||||
    qosCharacteristics = ¶ms->qosCharacteristics;
 | 
			
		||||
    qosCharacteristics->choice.nonDynamic5QI = nonDynamic5QI =
 | 
			
		||||
        CALLOC(1, sizeof(struct NGAP_NonDynamic5QIDescriptor));
 | 
			
		||||
    ogs_assert(nonDynamic5QI);
 | 
			
		||||
    qosCharacteristics->present = NGAP_QosCharacteristics_PR_nonDynamic5QI;
 | 
			
		||||
 | 
			
		||||
    nonDynamic5QI->fiveQI = qos->index;
 | 
			
		||||
 | 
			
		||||
    /* Optional GBR/MBR Information */
 | 
			
		||||
    if (include_gbr &&
 | 
			
		||||
        qos->mbr.downlink && qos->mbr.uplink &&
 | 
			
		||||
        qos->gbr.downlink && qos->gbr.uplink) {
 | 
			
		||||
        NGAP_GBR_QosInformation_t *gBR_QosInformation =
 | 
			
		||||
            params->gBR_QosInformation = CALLOC(1, sizeof(*gBR_QosInformation));
 | 
			
		||||
        ogs_assert(gBR_QosInformation);
 | 
			
		||||
 | 
			
		||||
        asn_uint642INTEGER(&gBR_QosInformation->maximumFlowBitRateDL,
 | 
			
		||||
                qos->mbr.downlink);
 | 
			
		||||
        asn_uint642INTEGER(&gBR_QosInformation->maximumFlowBitRateUL,
 | 
			
		||||
                qos->mbr.uplink);
 | 
			
		||||
        asn_uint642INTEGER(&gBR_QosInformation->
 | 
			
		||||
                guaranteedFlowBitRateDL, qos->gbr.downlink);
 | 
			
		||||
        asn_uint642INTEGER(&gBR_QosInformation->
 | 
			
		||||
                guaranteedFlowBitRateUL, qos->gbr.uplink);
 | 
			
		||||
    } else if (include_gbr &&
 | 
			
		||||
               (qos->mbr.downlink || qos->mbr.uplink ||
 | 
			
		||||
                qos->gbr.downlink || qos->gbr.uplink)) {
 | 
			
		||||
        ogs_error("Missing one or more MBR/GBR parameters; "
 | 
			
		||||
                "defaulting to Non-GBR flow ");
 | 
			
		||||
        ogs_error("    MBR[DL:%lld,UL:%lld]",
 | 
			
		||||
            (long long)qos->mbr.downlink, (long long)qos->mbr.uplink);
 | 
			
		||||
        ogs_error("    GBR[DL:%lld,UL:%lld]",
 | 
			
		||||
            (long long)qos->gbr.downlink, (long long)qos->gbr.uplink);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
 | 
			
		||||
        smf_sess_t *sess)
 | 
			
		||||
{
 | 
			
		||||
@@ -36,12 +98,6 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
 | 
			
		||||
    NGAP_SecurityIndication_t *SecurityIndication = NULL;
 | 
			
		||||
    NGAP_QosFlowSetupRequestList_t *QosFlowSetupRequestList = NULL;
 | 
			
		||||
    NGAP_QosFlowSetupRequestItem_t *QosFlowSetupRequestItem = NULL;
 | 
			
		||||
    NGAP_QosFlowIdentifier_t *qosFlowIdentifier = NULL;
 | 
			
		||||
    NGAP_QosFlowLevelQosParameters_t *qosFlowLevelQosParameters = NULL;
 | 
			
		||||
    NGAP_QosCharacteristics_t *qosCharacteristics = NULL;
 | 
			
		||||
    NGAP_NonDynamic5QIDescriptor_t *nonDynamic5QI = NULL;
 | 
			
		||||
    NGAP_AllocationAndRetentionPriority_t *allocationAndRetentionPriority;
 | 
			
		||||
    NGAP_GBR_QosInformation_t *gBR_QosInformation = NULL;
 | 
			
		||||
 | 
			
		||||
    ogs_assert(sess);
 | 
			
		||||
 | 
			
		||||
@@ -181,7 +237,8 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
 | 
			
		||||
 | 
			
		||||
            if (smf_self()->security_indication.
 | 
			
		||||
                    maximum_integrity_protected_data_rate_downlink) {
 | 
			
		||||
                NGAP_ProtocolExtensionContainer_11905P297_t *extContainer = NULL;
 | 
			
		||||
                NGAP_ProtocolExtensionContainer_11905P297_t
 | 
			
		||||
                    *extContainer = NULL;
 | 
			
		||||
                NGAP_SecurityIndication_ExtIEs_t *extIe = NULL;
 | 
			
		||||
                NGAP_MaximumIntegrityProtectedDataRate_t
 | 
			
		||||
                    *MaximumIntegrityProtectedDataRate = NULL;
 | 
			
		||||
@@ -224,6 +281,71 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
 | 
			
		||||
 | 
			
		||||
    QosFlowSetupRequestList = &ie->value.choice.QosFlowSetupRequestList;
 | 
			
		||||
 | 
			
		||||
    if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
 | 
			
		||||
        OpenAPI_list_t *qosFlowsSetupList = NULL;
 | 
			
		||||
        OpenAPI_qos_flow_setup_item_t *qosFlowSetupItem = NULL;
 | 
			
		||||
        OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL;
 | 
			
		||||
        OpenAPI_lnode_t *node = NULL;
 | 
			
		||||
 | 
			
		||||
        ogs_qos_t qos;
 | 
			
		||||
 | 
			
		||||
        qosFlowsSetupList = sess->h_smf_qos_flows_setup_list;
 | 
			
		||||
        ogs_assert(qosFlowsSetupList);
 | 
			
		||||
 | 
			
		||||
        node = qosFlowsSetupList->first;
 | 
			
		||||
        ogs_assert(node);
 | 
			
		||||
        qosFlowSetupItem = node->data;
 | 
			
		||||
        ogs_assert(qosFlowSetupItem);
 | 
			
		||||
 | 
			
		||||
        qosFlowProfile = qosFlowSetupItem->qos_flow_profile;
 | 
			
		||||
        ogs_assert(qosFlowProfile);
 | 
			
		||||
 | 
			
		||||
        memset(&qos, 0, sizeof(qos));
 | 
			
		||||
 | 
			
		||||
        qos.index = qosFlowProfile->_5qi;
 | 
			
		||||
        ogs_assert(qosFlowProfile->arp);
 | 
			
		||||
        qos.arp.priority_level = qosFlowProfile->arp->priority_level;
 | 
			
		||||
        if (qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
            OpenAPI_preemption_capability_NOT_PREEMPT)
 | 
			
		||||
            qos.arp.pre_emption_capability =
 | 
			
		||||
                OGS_5GC_PRE_EMPTION_DISABLED;
 | 
			
		||||
        else if (qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
            OpenAPI_preemption_capability_MAY_PREEMPT)
 | 
			
		||||
            qos.arp.pre_emption_capability =
 | 
			
		||||
                OGS_5GC_PRE_EMPTION_ENABLED;
 | 
			
		||||
        else {
 | 
			
		||||
            ogs_error("Invalid preempt_cap [%d]",
 | 
			
		||||
                    qosFlowProfile->arp->preempt_cap);
 | 
			
		||||
            ogs_assert_if_reached();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
            OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE)
 | 
			
		||||
            qos.arp.pre_emption_vulnerability =
 | 
			
		||||
                OGS_5GC_PRE_EMPTION_DISABLED;
 | 
			
		||||
        else if (qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
            OpenAPI_preemption_vulnerability_PREEMPTABLE)
 | 
			
		||||
            qos.arp.pre_emption_vulnerability =
 | 
			
		||||
                OGS_5GC_PRE_EMPTION_ENABLED;
 | 
			
		||||
        else {
 | 
			
		||||
            ogs_error("Invalid preempt_vuln [%d]",
 | 
			
		||||
                    qosFlowProfile->arp->preempt_vuln);
 | 
			
		||||
            ogs_assert_if_reached();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        QosFlowSetupRequestItem =
 | 
			
		||||
            CALLOC(1, sizeof(struct NGAP_QosFlowSetupRequestItem));
 | 
			
		||||
        ogs_assert(QosFlowSetupRequestItem);
 | 
			
		||||
        ASN_SEQUENCE_ADD(&QosFlowSetupRequestList->list,
 | 
			
		||||
            QosFlowSetupRequestItem);
 | 
			
		||||
 | 
			
		||||
        QosFlowSetupRequestItem->qosFlowIdentifier = qosFlowSetupItem->qfi;
 | 
			
		||||
 | 
			
		||||
        fill_qos_level_parameters(
 | 
			
		||||
                &QosFlowSetupRequestItem->qosFlowLevelQosParameters,
 | 
			
		||||
                &qos, true);
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        ogs_list_for_each(&sess->bearer_list, qos_flow) {
 | 
			
		||||
            QosFlowSetupRequestItem =
 | 
			
		||||
                CALLOC(1, sizeof(struct NGAP_QosFlowSetupRequestItem));
 | 
			
		||||
@@ -231,62 +353,11 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
 | 
			
		||||
            ASN_SEQUENCE_ADD(&QosFlowSetupRequestList->list,
 | 
			
		||||
                QosFlowSetupRequestItem);
 | 
			
		||||
 | 
			
		||||
        qosFlowIdentifier = &QosFlowSetupRequestItem->qosFlowIdentifier;
 | 
			
		||||
        qosFlowLevelQosParameters =
 | 
			
		||||
            &QosFlowSetupRequestItem->qosFlowLevelQosParameters;
 | 
			
		||||
            QosFlowSetupRequestItem->qosFlowIdentifier = qos_flow->qfi;
 | 
			
		||||
 | 
			
		||||
        allocationAndRetentionPriority =
 | 
			
		||||
            &qosFlowLevelQosParameters->allocationAndRetentionPriority;
 | 
			
		||||
        qosCharacteristics = &qosFlowLevelQosParameters->qosCharacteristics;
 | 
			
		||||
        nonDynamic5QI = CALLOC(1, sizeof(struct NGAP_NonDynamic5QIDescriptor));
 | 
			
		||||
        ogs_assert(nonDynamic5QI);
 | 
			
		||||
        qosCharacteristics->choice.nonDynamic5QI = nonDynamic5QI;
 | 
			
		||||
        qosCharacteristics->present = NGAP_QosCharacteristics_PR_nonDynamic5QI;
 | 
			
		||||
 | 
			
		||||
        *qosFlowIdentifier = qos_flow->qfi;
 | 
			
		||||
 | 
			
		||||
        nonDynamic5QI->fiveQI = qos_flow->qos.index;
 | 
			
		||||
 | 
			
		||||
        allocationAndRetentionPriority->priorityLevelARP =
 | 
			
		||||
            qos_flow->qos.arp.priority_level;
 | 
			
		||||
        if (qos_flow->qos.arp.pre_emption_capability ==
 | 
			
		||||
                OGS_5GC_PRE_EMPTION_ENABLED)
 | 
			
		||||
            allocationAndRetentionPriority->pre_emptionCapability =
 | 
			
		||||
                NGAP_Pre_emptionCapability_may_trigger_pre_emption;
 | 
			
		||||
        if (qos_flow->qos.arp.pre_emption_vulnerability ==
 | 
			
		||||
                OGS_5GC_PRE_EMPTION_ENABLED)
 | 
			
		||||
            allocationAndRetentionPriority->pre_emptionVulnerability =
 | 
			
		||||
                NGAP_Pre_emptionVulnerability_pre_emptable;
 | 
			
		||||
 | 
			
		||||
        if (qos_flow->qos.mbr.downlink || qos_flow->qos.mbr.uplink ||
 | 
			
		||||
            qos_flow->qos.gbr.downlink || qos_flow->qos.gbr.uplink) {
 | 
			
		||||
 | 
			
		||||
            if (qos_flow->qos.mbr.downlink && qos_flow->qos.mbr.uplink &&
 | 
			
		||||
                qos_flow->qos.gbr.downlink && qos_flow->qos.gbr.uplink) {
 | 
			
		||||
 | 
			
		||||
                qosFlowLevelQosParameters->gBR_QosInformation =
 | 
			
		||||
                    gBR_QosInformation = CALLOC(1, sizeof(*gBR_QosInformation));
 | 
			
		||||
                ogs_assert(gBR_QosInformation);
 | 
			
		||||
 | 
			
		||||
                asn_uint642INTEGER(&gBR_QosInformation->maximumFlowBitRateDL,
 | 
			
		||||
                        qos_flow->qos.mbr.downlink);
 | 
			
		||||
                asn_uint642INTEGER(&gBR_QosInformation->maximumFlowBitRateUL,
 | 
			
		||||
                        qos_flow->qos.mbr.uplink);
 | 
			
		||||
                asn_uint642INTEGER(&gBR_QosInformation->
 | 
			
		||||
                        guaranteedFlowBitRateDL, qos_flow->qos.gbr.downlink);
 | 
			
		||||
                asn_uint642INTEGER(&gBR_QosInformation->
 | 
			
		||||
                        guaranteedFlowBitRateUL, qos_flow->qos.gbr.uplink);
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
                ogs_error("Missing one or more MBR/GBR parameters; "
 | 
			
		||||
                        "defaulting to Non-GBR flow ");
 | 
			
		||||
                ogs_error("    MBR[DL:%lld,UL:%lld]",
 | 
			
		||||
                    (long long)qos_flow->qos.mbr.downlink,
 | 
			
		||||
                    (long long)qos_flow->qos.mbr.uplink);
 | 
			
		||||
                ogs_error("    GBR[DL:%lld,UL:%lld]",
 | 
			
		||||
                    (long long)qos_flow->qos.gbr.downlink,
 | 
			
		||||
                    (long long)qos_flow->qos.gbr.uplink);
 | 
			
		||||
            }
 | 
			
		||||
            fill_qos_level_parameters(
 | 
			
		||||
                    &QosFlowSetupRequestItem->qosFlowLevelQosParameters,
 | 
			
		||||
                    &qos_flow->qos, true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -295,7 +366,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_request_transfer(
 | 
			
		||||
        smf_sess_t *sess, bool qos_presence)
 | 
			
		||||
        smf_sess_t *sess, bool include_gbr)
 | 
			
		||||
{
 | 
			
		||||
    NGAP_PDUSessionResourceModifyRequestTransfer_t message;
 | 
			
		||||
 | 
			
		||||
@@ -303,12 +374,6 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_request_transfer(
 | 
			
		||||
 | 
			
		||||
    NGAP_QosFlowAddOrModifyRequestList_t *QosFlowAddOrModifyRequestList = NULL;
 | 
			
		||||
    NGAP_QosFlowAddOrModifyRequestItem_t *QosFlowAddOrModifyRequestItem = NULL;
 | 
			
		||||
    NGAP_QosFlowIdentifier_t *qosFlowIdentifier = NULL;
 | 
			
		||||
    NGAP_QosFlowLevelQosParameters_t *qosFlowLevelQosParameters = NULL;
 | 
			
		||||
    NGAP_QosCharacteristics_t *qosCharacteristics = NULL;
 | 
			
		||||
    NGAP_NonDynamic5QIDescriptor_t *nonDynamic5QI = NULL;
 | 
			
		||||
    NGAP_AllocationAndRetentionPriority_t *allocationAndRetentionPriority;
 | 
			
		||||
    NGAP_GBR_QosInformation_t *gBR_QosInformation;
 | 
			
		||||
 | 
			
		||||
    smf_bearer_t *qos_flow = NULL;
 | 
			
		||||
 | 
			
		||||
@@ -318,79 +383,125 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_request_transfer(
 | 
			
		||||
    memset(&message, 0, sizeof(NGAP_PDUSessionResourceModifyRequestTransfer_t));
 | 
			
		||||
 | 
			
		||||
    ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceModifyRequestTransferIEs_t));
 | 
			
		||||
    ogs_assert(ie);
 | 
			
		||||
    ASN_SEQUENCE_ADD(&message.protocolIEs, ie);
 | 
			
		||||
 | 
			
		||||
    ie->id = NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList;
 | 
			
		||||
    ie->criticality = NGAP_Criticality_reject;
 | 
			
		||||
    ie->value.present = NGAP_PDUSessionResourceModifyRequestTransferIEs__value_PR_QosFlowAddOrModifyRequestList;
 | 
			
		||||
 | 
			
		||||
    QosFlowAddOrModifyRequestList = &ie->value.choice.QosFlowAddOrModifyRequestList;
 | 
			
		||||
    QosFlowAddOrModifyRequestList =
 | 
			
		||||
        &ie->value.choice.QosFlowAddOrModifyRequestList;
 | 
			
		||||
 | 
			
		||||
    ogs_list_for_each_entry(
 | 
			
		||||
            &sess->qos_flow_to_modify_list, qos_flow, to_modify_node) {
 | 
			
		||||
    /* 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_add_mod_request_list, node) {
 | 
			
		||||
            OpenAPI_qos_flow_add_modify_request_item_t
 | 
			
		||||
                *qosFlowAddModifyRequestItem = node->data;
 | 
			
		||||
            if (qosFlowAddModifyRequestItem) {
 | 
			
		||||
                OpenAPI_qos_flow_profile_t *qosFlowProfile =
 | 
			
		||||
                    qosFlowAddModifyRequestItem->qos_flow_profile;
 | 
			
		||||
                if (qosFlowProfile) {
 | 
			
		||||
                    ogs_qos_t qos;
 | 
			
		||||
 | 
			
		||||
                    memset(&qos, 0, sizeof(qos));
 | 
			
		||||
 | 
			
		||||
                    qos.index = qosFlowProfile->_5qi;
 | 
			
		||||
                    ogs_assert(qosFlowProfile->arp);
 | 
			
		||||
                    qos.arp.priority_level =
 | 
			
		||||
                        qosFlowProfile->arp->priority_level;
 | 
			
		||||
                    if (qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
                        OpenAPI_preemption_capability_NOT_PREEMPT)
 | 
			
		||||
                        qos.arp.pre_emption_capability =
 | 
			
		||||
                            OGS_5GC_PRE_EMPTION_DISABLED;
 | 
			
		||||
                    else if (qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
                        OpenAPI_preemption_capability_MAY_PREEMPT)
 | 
			
		||||
                        qos.arp.pre_emption_capability =
 | 
			
		||||
                            OGS_5GC_PRE_EMPTION_ENABLED;
 | 
			
		||||
                    else {
 | 
			
		||||
                        ogs_error("Invalid preempt_cap [%d]",
 | 
			
		||||
                                qosFlowProfile->arp->preempt_cap);
 | 
			
		||||
                        ogs_assert_if_reached();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
                        OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE)
 | 
			
		||||
                        qos.arp.pre_emption_vulnerability =
 | 
			
		||||
                            OGS_5GC_PRE_EMPTION_DISABLED;
 | 
			
		||||
                    else if (qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
                        OpenAPI_preemption_vulnerability_PREEMPTABLE)
 | 
			
		||||
                        qos.arp.pre_emption_vulnerability =
 | 
			
		||||
                            OGS_5GC_PRE_EMPTION_ENABLED;
 | 
			
		||||
                    else {
 | 
			
		||||
                        ogs_error("Invalid preempt_vuln [%d]",
 | 
			
		||||
                                qosFlowProfile->arp->preempt_vuln);
 | 
			
		||||
                        ogs_assert_if_reached();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (qosFlowProfile->gbr_qos_flow_info) {
 | 
			
		||||
                        OpenAPI_gbr_qos_flow_information_t *gbrQosFlowInfo =
 | 
			
		||||
                                qosFlowProfile->gbr_qos_flow_info;
 | 
			
		||||
                        if (gbrQosFlowInfo->max_fbr_dl)
 | 
			
		||||
                            qos.mbr.downlink =
 | 
			
		||||
                                ogs_sbi_bitrate_from_string(
 | 
			
		||||
                                        gbrQosFlowInfo->max_fbr_dl);
 | 
			
		||||
                        if (gbrQosFlowInfo->max_fbr_ul)
 | 
			
		||||
                            qos.mbr.uplink =
 | 
			
		||||
                                ogs_sbi_bitrate_from_string(
 | 
			
		||||
                                        gbrQosFlowInfo->max_fbr_ul);
 | 
			
		||||
                        if (gbrQosFlowInfo->gua_fbr_dl)
 | 
			
		||||
                            qos.gbr.downlink =
 | 
			
		||||
                                ogs_sbi_bitrate_from_string(
 | 
			
		||||
                                        gbrQosFlowInfo->gua_fbr_dl);
 | 
			
		||||
                        if (gbrQosFlowInfo->gua_fbr_ul)
 | 
			
		||||
                            qos.gbr.uplink =
 | 
			
		||||
                                ogs_sbi_bitrate_from_string(
 | 
			
		||||
                                        gbrQosFlowInfo->gua_fbr_ul);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    QosFlowAddOrModifyRequestItem =
 | 
			
		||||
                        CALLOC(1, sizeof(*QosFlowAddOrModifyRequestItem));
 | 
			
		||||
        ASN_SEQUENCE_ADD(&QosFlowAddOrModifyRequestList->list, QosFlowAddOrModifyRequestItem);
 | 
			
		||||
                    ogs_assert(QosFlowAddOrModifyRequestItem);
 | 
			
		||||
                    ASN_SEQUENCE_ADD(
 | 
			
		||||
                            &QosFlowAddOrModifyRequestList->list,
 | 
			
		||||
                            QosFlowAddOrModifyRequestItem);
 | 
			
		||||
 | 
			
		||||
        qosFlowIdentifier = &QosFlowAddOrModifyRequestItem->qosFlowIdentifier;
 | 
			
		||||
                    QosFlowAddOrModifyRequestItem->qosFlowIdentifier =
 | 
			
		||||
                        qosFlowAddModifyRequestItem->qfi;
 | 
			
		||||
 | 
			
		||||
                    QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters =
 | 
			
		||||
            qosFlowLevelQosParameters =
 | 
			
		||||
                CALLOC(1, sizeof(*qosFlowLevelQosParameters));
 | 
			
		||||
                            CALLOC(1, sizeof(NGAP_QosFlowLevelQosParameters_t));
 | 
			
		||||
                    ogs_assert(
 | 
			
		||||
                            QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters);
 | 
			
		||||
 | 
			
		||||
        allocationAndRetentionPriority =
 | 
			
		||||
            &qosFlowLevelQosParameters->allocationAndRetentionPriority;
 | 
			
		||||
        qosCharacteristics = &qosFlowLevelQosParameters->qosCharacteristics;
 | 
			
		||||
 | 
			
		||||
        qosCharacteristics->present = NGAP_QosCharacteristics_PR_nonDynamic5QI;
 | 
			
		||||
        qosCharacteristics->choice.nonDynamic5QI =
 | 
			
		||||
            nonDynamic5QI = CALLOC(1, sizeof(struct NGAP_NonDynamic5QIDescriptor));
 | 
			
		||||
 | 
			
		||||
        *qosFlowIdentifier = qos_flow->qfi;
 | 
			
		||||
 | 
			
		||||
        nonDynamic5QI->fiveQI = qos_flow->qos.index;
 | 
			
		||||
 | 
			
		||||
        allocationAndRetentionPriority->priorityLevelARP =
 | 
			
		||||
            qos_flow->qos.arp.priority_level;
 | 
			
		||||
        if (qos_flow->qos.arp.pre_emption_capability ==
 | 
			
		||||
                OGS_5GC_PRE_EMPTION_ENABLED)
 | 
			
		||||
            allocationAndRetentionPriority->pre_emptionCapability =
 | 
			
		||||
                NGAP_Pre_emptionCapability_may_trigger_pre_emption;
 | 
			
		||||
        if (qos_flow->qos.arp.pre_emption_vulnerability ==
 | 
			
		||||
                OGS_5GC_PRE_EMPTION_ENABLED)
 | 
			
		||||
            allocationAndRetentionPriority->pre_emptionVulnerability =
 | 
			
		||||
                NGAP_Pre_emptionVulnerability_pre_emptable;
 | 
			
		||||
 | 
			
		||||
        if (qos_presence == true &&
 | 
			
		||||
            (qos_flow->qos.mbr.downlink || qos_flow->qos.mbr.uplink ||
 | 
			
		||||
             qos_flow->qos.gbr.downlink || qos_flow->qos.gbr.uplink)) {
 | 
			
		||||
 | 
			
		||||
            if (qos_flow->qos.mbr.downlink && qos_flow->qos.mbr.uplink &&
 | 
			
		||||
                qos_flow->qos.gbr.downlink && qos_flow->qos.gbr.uplink) {
 | 
			
		||||
 | 
			
		||||
                qosFlowLevelQosParameters->gBR_QosInformation =
 | 
			
		||||
                    gBR_QosInformation = CALLOC(1, sizeof(*gBR_QosInformation));
 | 
			
		||||
 | 
			
		||||
                asn_uint642INTEGER(&gBR_QosInformation->maximumFlowBitRateDL,
 | 
			
		||||
                        qos_flow->qos.mbr.downlink);
 | 
			
		||||
                asn_uint642INTEGER(&gBR_QosInformation->maximumFlowBitRateUL,
 | 
			
		||||
                        qos_flow->qos.mbr.uplink);
 | 
			
		||||
                asn_uint642INTEGER(&gBR_QosInformation->
 | 
			
		||||
                        guaranteedFlowBitRateDL, qos_flow->qos.gbr.downlink);
 | 
			
		||||
                asn_uint642INTEGER(&gBR_QosInformation->
 | 
			
		||||
                        guaranteedFlowBitRateUL, qos_flow->qos.gbr.uplink);
 | 
			
		||||
                    fill_qos_level_parameters(
 | 
			
		||||
                            QosFlowAddOrModifyRequestItem->
 | 
			
		||||
                                qosFlowLevelQosParameters, &qos, true);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
                ogs_error("Missing one or more MBR/GBR parameters; "
 | 
			
		||||
                        "defaulting to Non-GBR flow ");
 | 
			
		||||
                ogs_error("    MBR[DL:%lld,UL:%lld]",
 | 
			
		||||
                    (long long)qos_flow->qos.mbr.downlink,
 | 
			
		||||
                    (long long)qos_flow->qos.mbr.uplink);
 | 
			
		||||
                ogs_error("    GBR[DL:%lld,UL:%lld]",
 | 
			
		||||
                    (long long)qos_flow->qos.gbr.downlink,
 | 
			
		||||
                    (long long)qos_flow->qos.gbr.uplink);
 | 
			
		||||
            }
 | 
			
		||||
        /* Default: iterate modify-list */
 | 
			
		||||
        ogs_list_for_each_entry(&sess->qos_flow_to_modify_list,
 | 
			
		||||
                                 qos_flow, to_modify_node) {
 | 
			
		||||
            QosFlowAddOrModifyRequestItem =
 | 
			
		||||
                CALLOC(1, sizeof(*QosFlowAddOrModifyRequestItem));
 | 
			
		||||
            ogs_assert(QosFlowAddOrModifyRequestItem);
 | 
			
		||||
            ASN_SEQUENCE_ADD(
 | 
			
		||||
                    &QosFlowAddOrModifyRequestList->list,
 | 
			
		||||
                    QosFlowAddOrModifyRequestItem);
 | 
			
		||||
            QosFlowAddOrModifyRequestItem->qosFlowIdentifier = qos_flow->qfi;
 | 
			
		||||
 | 
			
		||||
            QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters =
 | 
			
		||||
                    CALLOC(1, sizeof(NGAP_QosFlowLevelQosParameters_t));
 | 
			
		||||
            ogs_assert(
 | 
			
		||||
                    QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters);
 | 
			
		||||
            fill_qos_level_parameters(
 | 
			
		||||
                    QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters,
 | 
			
		||||
                    &qos_flow->qos, include_gbr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,8 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
 | 
			
		||||
        smf_sess_t *sess);
 | 
			
		||||
 | 
			
		||||
ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_request_transfer(
 | 
			
		||||
        smf_sess_t *sess, bool qos_presence);
 | 
			
		||||
        smf_sess_t *sess, bool include_gbr);
 | 
			
		||||
 | 
			
		||||
ogs_pkbuf_t *ngap_build_pdu_session_resource_release_request_transfer(
 | 
			
		||||
        smf_sess_t *sess, NGAP_Cause_PR group, long cause);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,8 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
 | 
			
		||||
        smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf)
 | 
			
		||||
{
 | 
			
		||||
    smf_ue_t *smf_ue = NULL;
 | 
			
		||||
    smf_bearer_t *qos_flow = NULL;
 | 
			
		||||
 | 
			
		||||
    int rv, i;
 | 
			
		||||
 | 
			
		||||
    uint32_t remote_dl_teid;
 | 
			
		||||
@@ -103,7 +105,8 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
 | 
			
		||||
    ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &remote_dl_teid);
 | 
			
		||||
 | 
			
		||||
    /* Need to Update? */
 | 
			
		||||
    if (memcmp(&sess->remote_dl_ip, &remote_dl_ip, sizeof(sess->remote_dl_ip)) != 0 ||
 | 
			
		||||
    if (memcmp(&sess->remote_dl_ip,
 | 
			
		||||
                &remote_dl_ip, sizeof(sess->remote_dl_ip)) != 0 ||
 | 
			
		||||
        sess->remote_dl_teid != remote_dl_teid)
 | 
			
		||||
        far_update = true;
 | 
			
		||||
 | 
			
		||||
@@ -111,14 +114,32 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
 | 
			
		||||
    memcpy(&sess->remote_dl_ip, &remote_dl_ip, sizeof(sess->remote_dl_ip));
 | 
			
		||||
    sess->remote_dl_teid = remote_dl_teid;
 | 
			
		||||
 | 
			
		||||
    associatedQosFlowList = &dLQosFlowPerTNLInformation->associatedQosFlowList;
 | 
			
		||||
    if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
 | 
			
		||||
        ogs_list_for_each(&sess->bearer_list, qos_flow) {
 | 
			
		||||
            ogs_pfcp_far_t *dl_far = qos_flow->dl_far;
 | 
			
		||||
            ogs_assert(dl_far);
 | 
			
		||||
            if (dl_far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) {
 | 
			
		||||
                far_update = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW;
 | 
			
		||||
            ogs_assert(OGS_OK ==
 | 
			
		||||
                ogs_pfcp_ip_to_outer_header_creation(
 | 
			
		||||
                        &sess->remote_dl_ip,
 | 
			
		||||
                        &dl_far->outer_header_creation,
 | 
			
		||||
                        &dl_far->outer_header_creation_len));
 | 
			
		||||
            dl_far->outer_header_creation.teid = sess->remote_dl_teid;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        associatedQosFlowList =
 | 
			
		||||
            &dLQosFlowPerTNLInformation->associatedQosFlowList;
 | 
			
		||||
        for (i = 0; i < associatedQosFlowList->list.count; i++) {
 | 
			
		||||
            NGAP_AssociatedQosFlowItem_t *associatedQosFlowItem = NULL;
 | 
			
		||||
            associatedQosFlowItem = (NGAP_AssociatedQosFlowItem_t *)
 | 
			
		||||
                    associatedQosFlowList->list.array[i];
 | 
			
		||||
 | 
			
		||||
            if (associatedQosFlowItem) {
 | 
			
		||||
            smf_bearer_t *qos_flow = smf_qos_flow_find_by_qfi(
 | 
			
		||||
                qos_flow = smf_qos_flow_find_by_qfi(
 | 
			
		||||
                        sess, associatedQosFlowItem->qosFlowIdentifier);
 | 
			
		||||
 | 
			
		||||
                if (qos_flow) {
 | 
			
		||||
@@ -135,12 +156,7 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
 | 
			
		||||
                                &dl_far->outer_header_creation,
 | 
			
		||||
                                &dl_far->outer_header_creation_len));
 | 
			
		||||
                    dl_far->outer_header_creation.teid = sess->remote_dl_teid;
 | 
			
		||||
            } else {
 | 
			
		||||
                ogs_error("[%s:%d] No QoS flow", smf_ue->supi, sess->psi);
 | 
			
		||||
                smf_sbi_send_sm_context_update_error_log(
 | 
			
		||||
                        stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
 | 
			
		||||
                        "No QoS flow", smf_ue->supi);
 | 
			
		||||
                goto cleanup;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -309,6 +325,21 @@ int ngap_handle_pdu_session_resource_modify_response_transfer(
 | 
			
		||||
 | 
			
		||||
    rv = OGS_ERROR;
 | 
			
		||||
 | 
			
		||||
    if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
 | 
			
		||||
        /* Home Routed Roaming */
 | 
			
		||||
        rv = OGS_OK;
 | 
			
		||||
 | 
			
		||||
        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 {
 | 
			
		||||
            ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        goto cleanup;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qosFlowAddOrModifyResponseList = message.qosFlowAddOrModifyResponseList;
 | 
			
		||||
    if (!qosFlowAddOrModifyResponseList) {
 | 
			
		||||
        /* QosFlow Release */
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "nsmf-build.h"
 | 
			
		||||
#include "gsm-build.h"
 | 
			
		||||
 | 
			
		||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_create_data(
 | 
			
		||||
        smf_sess_t *sess, void *data)
 | 
			
		||||
@@ -472,6 +473,12 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
 | 
			
		||||
    OpenAPI_ref_to_binary_data_t n1SmInfoToUe;
 | 
			
		||||
    ogs_pkbuf_t *n1SmBufToUe = NULL;
 | 
			
		||||
 | 
			
		||||
    OpenAPI_list_t *qosFlowsAddModRequestList = NULL;
 | 
			
		||||
    OpenAPI_qos_flow_add_modify_request_item_t *qosFlowAddModifyRequestItem =
 | 
			
		||||
        NULL;
 | 
			
		||||
 | 
			
		||||
    smf_bearer_t *qos_flow = NULL;
 | 
			
		||||
 | 
			
		||||
    ogs_assert(sess);
 | 
			
		||||
 | 
			
		||||
    memset(&message, 0, sizeof(message));
 | 
			
		||||
@@ -486,8 +493,172 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
 | 
			
		||||
    VsmfUpdateData.request_indication = sess->nsmf_param.request_indication;
 | 
			
		||||
    ogs_assert(VsmfUpdateData.request_indication);
 | 
			
		||||
 | 
			
		||||
    switch (VsmfUpdateData.request_indication) {
 | 
			
		||||
    case OpenAPI_request_indication_UE_REQ_PDU_SES_MOD:
 | 
			
		||||
    case OpenAPI_request_indication_NW_REQ_PDU_SES_MOD:
 | 
			
		||||
        n1SmBufToUe = gsmue_build_pdu_session_modification_command(sess);
 | 
			
		||||
        ogs_assert(n1SmBufToUe);
 | 
			
		||||
 | 
			
		||||
        qosFlowsAddModRequestList = OpenAPI_list_create();
 | 
			
		||||
        ogs_assert(qosFlowsAddModRequestList);
 | 
			
		||||
 | 
			
		||||
        int i = 0;
 | 
			
		||||
 | 
			
		||||
        ogs_list_for_each_entry(
 | 
			
		||||
                &sess->qos_flow_to_modify_list, qos_flow, to_modify_node) {
 | 
			
		||||
 | 
			
		||||
            int rv, enc_len = 0;
 | 
			
		||||
 | 
			
		||||
            OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL;
 | 
			
		||||
            OpenAPI_arp_t *Arp = NULL;
 | 
			
		||||
            OpenAPI_gbr_qos_flow_information_t *gbrQosFlowInfo = 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;
 | 
			
		||||
 | 
			
		||||
                memset(&qos_rule, 0, sizeof(qos_rule));
 | 
			
		||||
                gsm_encode_qos_rule(
 | 
			
		||||
                        &qos_rule, qos_flow, sess->nsmf_param.qos_rule_code);
 | 
			
		||||
 | 
			
		||||
                rv = ogs_nas_build_qos_rules(
 | 
			
		||||
                        &authorized_qos_rules, &qos_rule, 1);
 | 
			
		||||
                if (rv != OGS_OK) {
 | 
			
		||||
                    ogs_error("ogs_nas_build_qos_rules() failed");
 | 
			
		||||
                    goto end;
 | 
			
		||||
                }
 | 
			
		||||
                if (!authorized_qos_rules.length) {
 | 
			
		||||
                    ogs_error("No length");
 | 
			
		||||
                    goto end;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                enc_len = ogs_base64_encode_len(authorized_qos_rules.length);
 | 
			
		||||
                qosFlowAddModifyRequestItem->qos_rules = ogs_calloc(1, enc_len);
 | 
			
		||||
                ogs_assert(qosFlowAddModifyRequestItem->qos_rules);
 | 
			
		||||
                ogs_base64_encode(
 | 
			
		||||
                        qosFlowAddModifyRequestItem->qos_rules,
 | 
			
		||||
                        authorized_qos_rules.buffer,
 | 
			
		||||
                        authorized_qos_rules.length);
 | 
			
		||||
 | 
			
		||||
                ogs_free(authorized_qos_rules.buffer);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (sess->nsmf_param.qos_flow_description_code) {
 | 
			
		||||
                ogs_nas_qos_flow_descriptions_t
 | 
			
		||||
                    authorized_qos_flow_descriptions;
 | 
			
		||||
                ogs_nas_qos_flow_description_t qos_flow_description;
 | 
			
		||||
 | 
			
		||||
                memset(&qos_flow_description, 0, sizeof(qos_flow_description));
 | 
			
		||||
                gsm_encode_qos_flow_description(
 | 
			
		||||
                        &qos_flow_description, qos_flow,
 | 
			
		||||
                        sess->nsmf_param.qos_flow_description_code);
 | 
			
		||||
                rv = ogs_nas_build_qos_flow_descriptions(
 | 
			
		||||
                        &authorized_qos_flow_descriptions,
 | 
			
		||||
                        &qos_flow_description, 1);
 | 
			
		||||
                if (rv != OGS_OK) {
 | 
			
		||||
                    ogs_error("ogs_nas_build_qos_flow_descriptions() failed");
 | 
			
		||||
                    goto end;
 | 
			
		||||
                }
 | 
			
		||||
                if (!authorized_qos_flow_descriptions.length) {
 | 
			
		||||
                    ogs_error("No length");
 | 
			
		||||
                    goto end;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                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);
 | 
			
		||||
                ogs_base64_encode(
 | 
			
		||||
                        qosFlowAddModifyRequestItem->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);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
            else if (qos_flow->qos.arp.pre_emption_capability ==
 | 
			
		||||
                    OGS_5GC_PRE_EMPTION_DISABLED)
 | 
			
		||||
                Arp->preempt_cap = OpenAPI_preemption_capability_NOT_PREEMPT;
 | 
			
		||||
            else {
 | 
			
		||||
                ogs_error("No Arp->preempt_cap");
 | 
			
		||||
                goto end;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (qos_flow->qos.arp.pre_emption_vulnerability ==
 | 
			
		||||
                    OGS_5GC_PRE_EMPTION_ENABLED)
 | 
			
		||||
                Arp->preempt_vuln =
 | 
			
		||||
                    OpenAPI_preemption_vulnerability_PREEMPTABLE;
 | 
			
		||||
            else if (qos_flow->qos.arp.pre_emption_vulnerability ==
 | 
			
		||||
                    OGS_5GC_PRE_EMPTION_DISABLED)
 | 
			
		||||
                Arp->preempt_vuln =
 | 
			
		||||
                    OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE;
 | 
			
		||||
            else {
 | 
			
		||||
                ogs_error("No Arp->preempt_vuln");
 | 
			
		||||
                goto end;
 | 
			
		||||
            }
 | 
			
		||||
            Arp->priority_level = qos_flow->qos.arp.priority_level;
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
 | 
			
		||||
            OpenAPI_list_add(qosFlowsAddModRequestList,
 | 
			
		||||
                    qosFlowAddModifyRequestItem);
 | 
			
		||||
 | 
			
		||||
            if (qosFlowsAddModRequestList->count)
 | 
			
		||||
                VsmfUpdateData.qos_flows_add_mod_request_list =
 | 
			
		||||
                    qosFlowsAddModRequestList;
 | 
			
		||||
            else
 | 
			
		||||
                OpenAPI_list_free(qosFlowsAddModRequestList);
 | 
			
		||||
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        break;
 | 
			
		||||
    case OpenAPI_request_indication_NW_REQ_PDU_SES_REL:
 | 
			
		||||
    case OpenAPI_request_indication_UE_REQ_PDU_SES_REL:
 | 
			
		||||
        n1SmBufToUe = gsmue_build_pdu_session_release_command(sess);
 | 
			
		||||
        ogs_assert(n1SmBufToUe);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        ogs_fatal("Not implemented [request_indication:%d]",
 | 
			
		||||
                VsmfUpdateData.request_indication);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    n1SmInfoToUe.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
 | 
			
		||||
    VsmfUpdateData.n1_sm_info_to_ue = &n1SmInfoToUe;
 | 
			
		||||
@@ -508,6 +679,9 @@ end:
 | 
			
		||||
    if (message.h.uri)
 | 
			
		||||
        ogs_free(message.h.uri);
 | 
			
		||||
 | 
			
		||||
    CLEAR_QOS_FLOWS_ADD_MOD_REQUEST_LIST(
 | 
			
		||||
            VsmfUpdateData.qos_flows_add_mod_request_list);
 | 
			
		||||
 | 
			
		||||
    return request;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1562,7 +1562,7 @@ bool smf_nsmf_handle_create_data_in_hsmf(
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool smf_nsmf_handle_create_data_in_vsmf(
 | 
			
		||||
bool smf_nsmf_handle_created_data_in_vsmf(
 | 
			
		||||
    smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
 | 
			
		||||
{
 | 
			
		||||
    int rv;
 | 
			
		||||
@@ -1591,12 +1591,9 @@ bool smf_nsmf_handle_create_data_in_vsmf(
 | 
			
		||||
        ogs_ip_t ue_ip;
 | 
			
		||||
        uint8_t prefixlen;
 | 
			
		||||
 | 
			
		||||
        int len;
 | 
			
		||||
 | 
			
		||||
        OpenAPI_tunnel_info_t *hcnTunnelInfo = NULL;
 | 
			
		||||
        OpenAPI_ambr_t *sessionAmbr = NULL;
 | 
			
		||||
        OpenAPI_list_t *qosFlowsSetupList = NULL;
 | 
			
		||||
        OpenAPI_qos_flow_setup_item_t *qosFlowSetupItem = NULL;
 | 
			
		||||
        OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL;
 | 
			
		||||
        OpenAPI_lnode_t *node = NULL;
 | 
			
		||||
 | 
			
		||||
@@ -1818,59 +1815,42 @@ bool smf_nsmf_handle_create_data_in_vsmf(
 | 
			
		||||
                &ul_far->outer_header_creation_len));
 | 
			
		||||
        ul_far->outer_header_creation.teid = sess->remote_ul_teid;
 | 
			
		||||
 | 
			
		||||
        qosFlowsSetupList = PduSessionCreatedData->qos_flows_setup_list;
 | 
			
		||||
        if (qosFlowsSetupList) {
 | 
			
		||||
            node = qosFlowsSetupList->first;
 | 
			
		||||
            if (node) {
 | 
			
		||||
                qosFlowSetupItem = node->data;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        CLEAR_QOS_FLOWS_SETUP_LIST(sess->h_smf_qos_flows_setup_list);
 | 
			
		||||
 | 
			
		||||
        if (!qosFlowSetupItem ||
 | 
			
		||||
            !qosFlowSetupItem->qfi ||
 | 
			
		||||
            !qosFlowSetupItem->qos_rules ||
 | 
			
		||||
            !qosFlowSetupItem->qos_flow_description ||
 | 
			
		||||
            !qosFlowSetupItem->qos_flow_profile) {
 | 
			
		||||
            ogs_error("[%s:%d] No qosFlowSetupItem [%d:%s:%s]",
 | 
			
		||||
                    smf_ue->supi, sess->psi, qosFlowSetupItem->qfi,
 | 
			
		||||
                    qosFlowSetupItem->qos_rules ?
 | 
			
		||||
                        qosFlowSetupItem->qos_rules : "NULL",
 | 
			
		||||
                    qosFlowSetupItem->qos_flow_description ?
 | 
			
		||||
                        qosFlowSetupItem->qos_flow_description : "NULL");
 | 
			
		||||
        qosFlowsSetupList = OpenAPI_list_create();
 | 
			
		||||
        ogs_assert(qosFlowsSetupList);
 | 
			
		||||
        OpenAPI_list_for_each(
 | 
			
		||||
                PduSessionCreatedData->qos_flows_setup_list, node) {
 | 
			
		||||
            OpenAPI_qos_flow_setup_item_t *dst = NULL, *src = NULL;
 | 
			
		||||
 | 
			
		||||
            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]",
 | 
			
		||||
                        smf_ue->supi, sess->psi, src->qfi,
 | 
			
		||||
                        src->qos_rules ?
 | 
			
		||||
                            src->qos_rules : "NULL",
 | 
			
		||||
                        src->qos_flow_description ?
 | 
			
		||||
                            src->qos_flow_description : "NULL");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        qos_flow->qfi = qosFlowSetupItem->qfi;
 | 
			
		||||
 | 
			
		||||
        OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_rules);
 | 
			
		||||
        len = ogs_base64_decode_len(qosFlowSetupItem->qos_rules);
 | 
			
		||||
        ogs_assert(len);
 | 
			
		||||
        sess->h_smf_authorized_qos_rules.buffer = ogs_calloc(1, len);
 | 
			
		||||
        ogs_assert(sess->h_smf_authorized_qos_rules.buffer);
 | 
			
		||||
        sess->h_smf_authorized_qos_rules.length =
 | 
			
		||||
            ogs_base64_decode_binary(
 | 
			
		||||
                    sess->h_smf_authorized_qos_rules.buffer,
 | 
			
		||||
                    qosFlowSetupItem->qos_rules);
 | 
			
		||||
        ogs_assert(sess->h_smf_authorized_qos_rules.length);
 | 
			
		||||
 | 
			
		||||
        OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_flow_descriptions);
 | 
			
		||||
        len = ogs_base64_decode_len(qosFlowSetupItem->qos_flow_description);
 | 
			
		||||
        ogs_assert(len);
 | 
			
		||||
        sess->h_smf_authorized_qos_flow_descriptions.buffer =
 | 
			
		||||
            ogs_calloc(1, len);
 | 
			
		||||
        ogs_assert(sess->h_smf_authorized_qos_flow_descriptions.buffer);
 | 
			
		||||
        sess->h_smf_authorized_qos_flow_descriptions.length =
 | 
			
		||||
            ogs_base64_decode_binary(
 | 
			
		||||
                    sess->h_smf_authorized_qos_flow_descriptions.buffer,
 | 
			
		||||
                    qosFlowSetupItem->qos_flow_description);
 | 
			
		||||
        ogs_assert(sess->h_smf_authorized_qos_flow_descriptions.length);
 | 
			
		||||
 | 
			
		||||
        qosFlowProfile = qosFlowSetupItem->qos_flow_profile;
 | 
			
		||||
        ogs_assert(qosFlowProfile);
 | 
			
		||||
 | 
			
		||||
        if (!qosFlowProfile->_5qi ||
 | 
			
		||||
            qosFlowProfile = src->qos_flow_profile;
 | 
			
		||||
            if (!qosFlowProfile ||
 | 
			
		||||
                !qosFlowProfile->_5qi ||
 | 
			
		||||
                !qosFlowProfile->arp ||
 | 
			
		||||
            !qosFlowProfile->arp->priority_level) {
 | 
			
		||||
                !qosFlowProfile->arp->priority_level ||
 | 
			
		||||
                !(qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
                    OpenAPI_preemption_capability_NOT_PREEMPT ||
 | 
			
		||||
                 qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
                    OpenAPI_preemption_capability_MAY_PREEMPT) ||
 | 
			
		||||
                !(qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
                     OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE ||
 | 
			
		||||
                 qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
                     OpenAPI_preemption_vulnerability_PREEMPTABLE)) {
 | 
			
		||||
                ogs_error("[%s:%d] Invalid qosFlowProfile [%d:%p:%d]",
 | 
			
		||||
                        smf_ue->supi, sess->psi,
 | 
			
		||||
                        qosFlowProfile->_5qi,
 | 
			
		||||
@@ -1880,43 +1860,15 @@ bool smf_nsmf_handle_create_data_in_vsmf(
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        sess->session.qos.index = qosFlowProfile->_5qi;
 | 
			
		||||
        if (qosFlowProfile->arp) {
 | 
			
		||||
            sess->session.qos.arp.priority_level =
 | 
			
		||||
                    qosFlowProfile->arp->priority_level;
 | 
			
		||||
            if (qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
                OpenAPI_preemption_capability_NOT_PREEMPT)
 | 
			
		||||
                sess->session.qos.arp.pre_emption_capability =
 | 
			
		||||
                    OGS_5GC_PRE_EMPTION_DISABLED;
 | 
			
		||||
            else if (qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
                OpenAPI_preemption_capability_MAY_PREEMPT)
 | 
			
		||||
                sess->session.qos.arp.pre_emption_capability =
 | 
			
		||||
                    OGS_5GC_PRE_EMPTION_ENABLED;
 | 
			
		||||
            else {
 | 
			
		||||
                ogs_error("[%s:%d] Invalid preempt_cap [%d]",
 | 
			
		||||
                        smf_ue->supi, sess->psi,
 | 
			
		||||
                        qosFlowProfile->arp->preempt_cap);
 | 
			
		||||
                return false;
 | 
			
		||||
            dst = OpenAPI_qos_flow_setup_item_copy(dst, src);
 | 
			
		||||
            ogs_assert(dst);
 | 
			
		||||
            OpenAPI_list_add(qosFlowsSetupList, dst);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            if (qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
                OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE)
 | 
			
		||||
                sess->session.qos.arp.pre_emption_vulnerability =
 | 
			
		||||
                    OGS_5GC_PRE_EMPTION_DISABLED;
 | 
			
		||||
            else if (qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
                OpenAPI_preemption_vulnerability_PREEMPTABLE)
 | 
			
		||||
                sess->session.qos.arp.pre_emption_vulnerability =
 | 
			
		||||
                    OGS_5GC_PRE_EMPTION_ENABLED;
 | 
			
		||||
            else {
 | 
			
		||||
                ogs_error("[%s:%d] Invalid preempt_vuln [%d]",
 | 
			
		||||
                        smf_ue->supi, sess->psi,
 | 
			
		||||
                        qosFlowProfile->arp->preempt_vuln);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Copy Session QoS information to Default QoS Flow */
 | 
			
		||||
        memcpy(&qos_flow->qos, &sess->session.qos, sizeof(ogs_qos_t));
 | 
			
		||||
        if (qosFlowsSetupList->count)
 | 
			
		||||
            sess->h_smf_qos_flows_setup_list = qosFlowsSetupList;
 | 
			
		||||
        else
 | 
			
		||||
            OpenAPI_list_free(qosFlowsSetupList);
 | 
			
		||||
 | 
			
		||||
        sessionAmbr = PduSessionCreatedData->session_ambr;
 | 
			
		||||
        if (sessionAmbr) {
 | 
			
		||||
@@ -1977,7 +1929,7 @@ bool smf_nsmf_handle_create_data_in_vsmf(
 | 
			
		||||
                ogs_freeaddrinfo(addr);
 | 
			
		||||
                ogs_freeaddrinfo(addr6);
 | 
			
		||||
 | 
			
		||||
                return OGS_ERROR;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        OGS_SBI_SETUP_CLIENT(&sess->pdu_session, client);
 | 
			
		||||
@@ -2055,7 +2007,7 @@ bool smf_nsmf_handle_create_data_in_vsmf(
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool smf_nsmf_handle_hsmf_update_data(
 | 
			
		||||
bool smf_nsmf_handle_update_data_in_hsmf(
 | 
			
		||||
    smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
 | 
			
		||||
{
 | 
			
		||||
    int rv;
 | 
			
		||||
@@ -2159,7 +2111,7 @@ bool smf_nsmf_handle_hsmf_update_data(
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool smf_nsmf_handle_vsmf_update_data(
 | 
			
		||||
bool smf_nsmf_handle_update_data_in_vsmf(
 | 
			
		||||
    smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
 | 
			
		||||
{
 | 
			
		||||
    int rv;
 | 
			
		||||
@@ -2167,10 +2119,16 @@ bool smf_nsmf_handle_vsmf_update_data(
 | 
			
		||||
 | 
			
		||||
    OpenAPI_vsmf_update_data_t *VsmfUpdateData = NULL;
 | 
			
		||||
 | 
			
		||||
    OpenAPI_list_t *qosFlowsAddModRequestList = NULL;
 | 
			
		||||
    OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL;
 | 
			
		||||
    OpenAPI_lnode_t *node = NULL;
 | 
			
		||||
 | 
			
		||||
    ogs_nas_5gs_message_t nas_message;
 | 
			
		||||
    ogs_pkbuf_t *n1SmBufToUe = NULL;
 | 
			
		||||
    OpenAPI_ref_to_binary_data_t *n1SmInfoToUe = NULL;
 | 
			
		||||
 | 
			
		||||
    smf_n1_n2_message_transfer_param_t param;
 | 
			
		||||
 | 
			
		||||
    ogs_assert(stream);
 | 
			
		||||
    ogs_assert(message);
 | 
			
		||||
    ogs_assert(sess);
 | 
			
		||||
@@ -2223,6 +2181,101 @@ bool smf_nsmf_handle_vsmf_update_data(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (sess->nsmf_param.request_indication) {
 | 
			
		||||
    case OpenAPI_request_indication_UE_REQ_PDU_SES_MOD:
 | 
			
		||||
    case OpenAPI_request_indication_NW_REQ_PDU_SES_MOD:
 | 
			
		||||
        CLEAR_QOS_FLOWS_ADD_MOD_REQUEST_LIST(
 | 
			
		||||
                sess->h_smf_qos_flows_add_mod_request_list);
 | 
			
		||||
 | 
			
		||||
        qosFlowsAddModRequestList = OpenAPI_list_create();
 | 
			
		||||
        ogs_assert(qosFlowsAddModRequestList);
 | 
			
		||||
        OpenAPI_list_for_each(
 | 
			
		||||
                VsmfUpdateData->qos_flows_add_mod_request_list, node) {
 | 
			
		||||
            OpenAPI_qos_flow_add_modify_request_item_t *dst = NULL, *src = NULL;
 | 
			
		||||
 | 
			
		||||
            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]",
 | 
			
		||||
                        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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            qosFlowProfile = src->qos_flow_profile;
 | 
			
		||||
            if (!qosFlowProfile ||
 | 
			
		||||
                !qosFlowProfile->_5qi ||
 | 
			
		||||
                !qosFlowProfile->arp ||
 | 
			
		||||
                !qosFlowProfile->arp->priority_level ||
 | 
			
		||||
                !(qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
                    OpenAPI_preemption_capability_NOT_PREEMPT ||
 | 
			
		||||
                 qosFlowProfile->arp->preempt_cap ==
 | 
			
		||||
                    OpenAPI_preemption_capability_MAY_PREEMPT) ||
 | 
			
		||||
                !(qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
                     OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE ||
 | 
			
		||||
                 qosFlowProfile->arp->preempt_vuln ==
 | 
			
		||||
                     OpenAPI_preemption_vulnerability_PREEMPTABLE)) {
 | 
			
		||||
                ogs_error("[%s:%d] Invalid qosFlowProfile [%d:%p:%d]",
 | 
			
		||||
                        smf_ue->supi, sess->psi,
 | 
			
		||||
                        qosFlowProfile->_5qi,
 | 
			
		||||
                        qosFlowProfile->arp,
 | 
			
		||||
                        qosFlowProfile->arp ?
 | 
			
		||||
                            qosFlowProfile->arp->priority_level : 0);
 | 
			
		||||
                smf_sbi_send_vsmf_update_error(stream,
 | 
			
		||||
                        OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
 | 
			
		||||
                        OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
 | 
			
		||||
                        "Invalid qosFlowProfile", smf_ue->supi, NULL);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            dst = OpenAPI_qos_flow_add_modify_request_item_copy(dst, src);
 | 
			
		||||
            ogs_assert(dst);
 | 
			
		||||
            OpenAPI_list_add(qosFlowsAddModRequestList, dst);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (qosFlowsAddModRequestList->count)
 | 
			
		||||
            sess->h_smf_qos_flows_add_mod_request_list =
 | 
			
		||||
                qosFlowsAddModRequestList;
 | 
			
		||||
        else
 | 
			
		||||
            OpenAPI_list_free(qosFlowsAddModRequestList);
 | 
			
		||||
 | 
			
		||||
        sess->pti = OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED;
 | 
			
		||||
 | 
			
		||||
        memset(¶m, 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);
 | 
			
		||||
        param.n2smbuf =
 | 
			
		||||
            ngap_build_pdu_session_resource_modify_request_transfer(sess,
 | 
			
		||||
                    qosFlowProfile->gbr_qos_flow_info ? true : false);
 | 
			
		||||
        ogs_assert(param.n2smbuf);
 | 
			
		||||
 | 
			
		||||
        smf_namf_comm_send_n1_n2_message_transfer(sess, stream, ¶m);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case OpenAPI_request_indication_UE_REQ_PDU_SES_REL:
 | 
			
		||||
    case OpenAPI_request_indication_NW_REQ_PDU_SES_REL:
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        ogs_error("[%s:%d] Unknown requestIndication [%d]",
 | 
			
		||||
                smf_ue->supi, sess->psi, sess->nsmf_param.request_indication);
 | 
			
		||||
        smf_sbi_send_vsmf_update_error(stream,
 | 
			
		||||
                OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
 | 
			
		||||
                OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
 | 
			
		||||
                "Unknown requestIndication", smf_ue->supi, NULL);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,12 +35,12 @@ bool smf_nsmf_handle_release_sm_context(
 | 
			
		||||
 | 
			
		||||
bool smf_nsmf_handle_create_data_in_hsmf(
 | 
			
		||||
    smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
 | 
			
		||||
bool smf_nsmf_handle_create_data_in_vsmf(
 | 
			
		||||
bool smf_nsmf_handle_created_data_in_vsmf(
 | 
			
		||||
    smf_sess_t *sess, ogs_sbi_message_t *recvmsg);
 | 
			
		||||
 | 
			
		||||
bool smf_nsmf_handle_hsmf_update_data(
 | 
			
		||||
bool smf_nsmf_handle_update_data_in_hsmf(
 | 
			
		||||
    smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message);
 | 
			
		||||
bool smf_nsmf_handle_vsmf_update_data(
 | 
			
		||||
bool smf_nsmf_handle_update_data_in_vsmf(
 | 
			
		||||
    smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message);
 | 
			
		||||
 | 
			
		||||
bool smf_nsmf_handle_release_data_in_hsmf(
 | 
			
		||||
 
 | 
			
		||||
@@ -398,9 +398,8 @@ void smf_sbi_send_pdu_session_created_data(
 | 
			
		||||
    OpenAPI_ambr_t sessionAmbr;
 | 
			
		||||
    OpenAPI_list_t *qosFlowsSetupList = NULL;
 | 
			
		||||
    OpenAPI_qos_flow_setup_item_t *qosFlowSetupItem = NULL;
 | 
			
		||||
    OpenAPI_qos_flow_profile_t qosFlowProfile;
 | 
			
		||||
    OpenAPI_arp_t Arp;
 | 
			
		||||
    OpenAPI_lnode_t *node = NULL;
 | 
			
		||||
    OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL;
 | 
			
		||||
    OpenAPI_arp_t *Arp = NULL;
 | 
			
		||||
 | 
			
		||||
    ogs_nas_qos_rule_t qos_rule[OGS_NAS_MAX_NUM_OF_QOS_RULE];
 | 
			
		||||
    ogs_nas_qos_rules_t authorized_qos_rules;
 | 
			
		||||
@@ -472,7 +471,7 @@ void smf_sbi_send_pdu_session_created_data(
 | 
			
		||||
    ogs_assert(ogs_list_next(qos_flow) == NULL);
 | 
			
		||||
 | 
			
		||||
    memset(qos_rule, 0, sizeof(qos_rule));
 | 
			
		||||
    encode_default_qos_rule(&qos_rule[0], qos_flow);
 | 
			
		||||
    gsm_encode_default_qos_rule(&qos_rule[0], qos_flow);
 | 
			
		||||
 | 
			
		||||
    memset(&authorized_qos_rules, 0, sizeof(authorized_qos_rules));
 | 
			
		||||
    rv = ogs_nas_build_qos_rules(&authorized_qos_rules, qos_rule, 1);
 | 
			
		||||
@@ -481,8 +480,7 @@ void smf_sbi_send_pdu_session_created_data(
 | 
			
		||||
 | 
			
		||||
    /* QoS flow descriptions */
 | 
			
		||||
    memset(&qos_flow_description, 0, sizeof(qos_flow_description));
 | 
			
		||||
    encode_default_qos_flow_description(&qos_flow_description[0],
 | 
			
		||||
            qos_flow);
 | 
			
		||||
    gsm_encode_default_qos_flow_description(&qos_flow_description[0], qos_flow);
 | 
			
		||||
 | 
			
		||||
    memset(&authorized_qos_flow_descriptions, 0,
 | 
			
		||||
            sizeof(authorized_qos_flow_descriptions));
 | 
			
		||||
@@ -521,35 +519,37 @@ void smf_sbi_send_pdu_session_created_data(
 | 
			
		||||
 | 
			
		||||
    ogs_free(authorized_qos_flow_descriptions.buffer);
 | 
			
		||||
 | 
			
		||||
    memset(&Arp, 0, sizeof(Arp));
 | 
			
		||||
    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_fatal("No Arp.preempt_cap");
 | 
			
		||||
        ogs_assert_if_reached();
 | 
			
		||||
        ogs_error("No Arp->preempt_cap");
 | 
			
		||||
        goto end;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (qos_flow->qos.arp.pre_emption_vulnerability ==
 | 
			
		||||
            OGS_5GC_PRE_EMPTION_ENABLED)
 | 
			
		||||
        Arp.preempt_vuln = OpenAPI_preemption_vulnerability_PREEMPTABLE;
 | 
			
		||||
        Arp->preempt_vuln = OpenAPI_preemption_vulnerability_PREEMPTABLE;
 | 
			
		||||
    else if (qos_flow->qos.arp.pre_emption_vulnerability ==
 | 
			
		||||
            OGS_5GC_PRE_EMPTION_DISABLED)
 | 
			
		||||
        Arp.preempt_vuln = OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE;
 | 
			
		||||
        Arp->preempt_vuln = OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE;
 | 
			
		||||
    else {
 | 
			
		||||
        ogs_fatal("No Arp.preempt_vuln");
 | 
			
		||||
        ogs_assert_if_reached();
 | 
			
		||||
        ogs_error("No Arp->preempt_vuln");
 | 
			
		||||
        goto end;
 | 
			
		||||
    }
 | 
			
		||||
    Arp.priority_level = qos_flow->qos.arp.priority_level;
 | 
			
		||||
    Arp->priority_level = qos_flow->qos.arp.priority_level;
 | 
			
		||||
 | 
			
		||||
    memset(&qosFlowProfile, 0, sizeof(qosFlowProfile));
 | 
			
		||||
    qosFlowProfile.arp = &Arp;
 | 
			
		||||
    qosFlowProfile._5qi = qos_flow->qos.index;
 | 
			
		||||
    qosFlowProfile = ogs_calloc(1, sizeof(*qosFlowProfile));
 | 
			
		||||
    ogs_assert(qosFlowProfile);
 | 
			
		||||
    qosFlowProfile->arp = Arp;
 | 
			
		||||
    qosFlowProfile->_5qi = qos_flow->qos.index;
 | 
			
		||||
 | 
			
		||||
    qosFlowSetupItem->qos_flow_profile = &qosFlowProfile;
 | 
			
		||||
    qosFlowSetupItem->qos_flow_profile = qosFlowProfile;
 | 
			
		||||
 | 
			
		||||
    OpenAPI_list_add(qosFlowsSetupList, qosFlowSetupItem);
 | 
			
		||||
 | 
			
		||||
@@ -585,9 +585,9 @@ void smf_sbi_send_pdu_session_created_data(
 | 
			
		||||
                ue_ipv6_interface_id, sizeof(ue_ipv6_interface_id));
 | 
			
		||||
        PduSessionCreatedData.ue_ipv6_interface_id = ue_ipv6_interface_id;
 | 
			
		||||
    } else {
 | 
			
		||||
        ogs_fatal("Invalid sess->session.session_type[%d]",
 | 
			
		||||
        ogs_error("Invalid sess->session.session_type[%d]",
 | 
			
		||||
                sess->paa.session_type);
 | 
			
		||||
        ogs_assert_if_reached();
 | 
			
		||||
        goto end;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memset(&sendmsg, 0, sizeof(sendmsg));
 | 
			
		||||
@@ -627,6 +627,7 @@ void smf_sbi_send_pdu_session_created_data(
 | 
			
		||||
 | 
			
		||||
    ogs_free(sendmsg.http.location);
 | 
			
		||||
 | 
			
		||||
end:
 | 
			
		||||
    if (hcnTunnelInfo.ipv4_addr)
 | 
			
		||||
        ogs_free(hcnTunnelInfo.ipv4_addr);
 | 
			
		||||
    if (hcnTunnelInfo.ipv6_addr)
 | 
			
		||||
@@ -639,18 +640,7 @@ void smf_sbi_send_pdu_session_created_data(
 | 
			
		||||
    if (sessionAmbr.downlink)
 | 
			
		||||
        ogs_free(sessionAmbr.downlink);
 | 
			
		||||
 | 
			
		||||
    OpenAPI_list_for_each(
 | 
			
		||||
            PduSessionCreatedData.qos_flows_setup_list, node) {
 | 
			
		||||
        qosFlowSetupItem = node->data;
 | 
			
		||||
        if (qosFlowSetupItem) {
 | 
			
		||||
            if (qosFlowSetupItem->qos_rules)
 | 
			
		||||
                ogs_free(qosFlowSetupItem->qos_rules);
 | 
			
		||||
            if (qosFlowSetupItem->qos_flow_description)
 | 
			
		||||
                ogs_free(qosFlowSetupItem->qos_flow_description);
 | 
			
		||||
            ogs_free(qosFlowSetupItem);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    OpenAPI_list_free(PduSessionCreatedData.qos_flows_setup_list);
 | 
			
		||||
    CLEAR_QOS_FLOWS_SETUP_LIST(PduSessionCreatedData.qos_flows_setup_list);
 | 
			
		||||
 | 
			
		||||
    if (PduSessionCreatedData.ue_ipv4_address)
 | 
			
		||||
        ogs_free(PduSessionCreatedData.ue_ipv4_address);
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@
 | 
			
		||||
#include "nsmf-handler.h"
 | 
			
		||||
#include "npcf-handler.h"
 | 
			
		||||
#include "nsmf-handler.h"
 | 
			
		||||
#include "binding.h"
 | 
			
		||||
 | 
			
		||||
void smf_state_initial(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
{
 | 
			
		||||
@@ -1048,14 +1049,29 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (state == SMF_UECM_STATE_REGISTERED) {
 | 
			
		||||
                /* SMF Registration */
 | 
			
		||||
                ogs_assert(stream);
 | 
			
		||||
                ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
 | 
			
		||||
                smf_metrics_inst_by_slice_add(
 | 
			
		||||
                        &sess->serving_plmn_id, &sess->s_nssai,
 | 
			
		||||
                        SMF_METR_CTR_SM_PDUSESSIONCREATIONSUCC, 1);
 | 
			
		||||
            } else if (state == SMF_UECM_STATE_REGISTERED_HR) {
 | 
			
		||||
                ogs_assert(stream);
 | 
			
		||||
                smf_sbi_send_pdu_session_created_data(sess, stream);
 | 
			
		||||
                smf_metrics_inst_by_slice_add(
 | 
			
		||||
                        &sess->serving_plmn_id, &sess->s_nssai,
 | 
			
		||||
                        SMF_METR_CTR_SM_PDUSESSIONCREATIONSUCC, 1);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Non-roaming/LBO: start network-triggered PDU Session Modification at step 11
 | 
			
		||||
 * after N1N2 transfer (Establishment Accept) and N2/N4 context sync, ensuring
 | 
			
		||||
 * the session is active on UE, RAN, and SMF before applying QoS updates.
 | 
			
		||||
 *
 | 
			
		||||
 * Home-Routed Roaming: trigger PDU Session Modification at step 13
 | 
			
		||||
 * immediately after H-SMF’s CreateSMContext response and H-UPF N4 setup
 | 
			
		||||
 * to apply QoS updates without waiting for V-SMF or RAN setup.
 | 
			
		||||
 */
 | 
			
		||||
                smf_qos_flow_binding(sess);
 | 
			
		||||
 | 
			
		||||
            } else if (state == SMF_UECM_STATE_DEREG_BY_AMF) {
 | 
			
		||||
/*
 | 
			
		||||
 * Handle deregistration states SMF_UECM_STATE_DEREG_BY_AMF and
 | 
			
		||||
 
 | 
			
		||||
@@ -1709,6 +1709,11 @@ bson_t *test_db_new_qos_flow(test_ue_t *test_ue)
 | 
			
		||||
                                 "description", BCON_UTF8("permit out udp from 10.200.136.98/32 1-65535 to assigned 50021"), "}",
 | 
			
		||||
                        "]",
 | 
			
		||||
                    "}", "]",
 | 
			
		||||
#if 0
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                "}", "]",
 | 
			
		||||
            "}", "]",
 | 
			
		||||
            "security", "{",
 | 
			
		||||
@@ -1810,6 +1815,11 @@ bson_t *test_db_new_qos_flow_bi_directional(test_ue_t *test_ue)
 | 
			
		||||
                                 "description", BCON_UTF8("permit out udp from 10.200.136.98/32 23455 to assigned 1-65535"), "}",
 | 
			
		||||
                        "]",
 | 
			
		||||
                    "}", "]",
 | 
			
		||||
#if 0
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                "}", "]",
 | 
			
		||||
            "}", "]",
 | 
			
		||||
            "security", "{",
 | 
			
		||||
@@ -1876,6 +1886,11 @@ bson_t *test_db_new_session(test_ue_t *test_ue)
 | 
			
		||||
                            "pre_emption_capability", BCON_INT32(1),
 | 
			
		||||
                        "}",
 | 
			
		||||
                    "}",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                  "{",
 | 
			
		||||
                    "name", BCON_UTF8("ims"),
 | 
			
		||||
@@ -1938,6 +1953,11 @@ 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
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                "]",
 | 
			
		||||
            "}", "]",
 | 
			
		||||
@@ -2162,6 +2182,11 @@ bson_t *test_db_new_slice_with_same_dnn(test_ue_t *test_ue)
 | 
			
		||||
                            "pre_emption_capability", BCON_INT32(1),
 | 
			
		||||
                        "}",
 | 
			
		||||
                    "}",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                  "{",
 | 
			
		||||
                    "name", BCON_UTF8("ims"),
 | 
			
		||||
@@ -2246,6 +2271,11 @@ bson_t *test_db_new_slice_with_same_dnn(test_ue_t *test_ue)
 | 
			
		||||
                        "}",
 | 
			
		||||
                      "}",
 | 
			
		||||
                    "]",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                "]",
 | 
			
		||||
              "}",
 | 
			
		||||
@@ -2274,6 +2304,11 @@ bson_t *test_db_new_slice_with_same_dnn(test_ue_t *test_ue)
 | 
			
		||||
                            "pre_emption_capability", BCON_INT32(1),
 | 
			
		||||
                        "}",
 | 
			
		||||
                    "}",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                  "{",
 | 
			
		||||
                    "name", BCON_UTF8("ims"),
 | 
			
		||||
@@ -2358,6 +2393,11 @@ bson_t *test_db_new_slice_with_same_dnn(test_ue_t *test_ue)
 | 
			
		||||
                        "}",
 | 
			
		||||
                      "}",
 | 
			
		||||
                    "]",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                "]",
 | 
			
		||||
              "}",
 | 
			
		||||
@@ -2387,6 +2427,11 @@ bson_t *test_db_new_slice_with_same_dnn(test_ue_t *test_ue)
 | 
			
		||||
                            "pre_emption_capability", BCON_INT32(1),
 | 
			
		||||
                        "}",
 | 
			
		||||
                    "}",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                  "{",
 | 
			
		||||
                    "name", BCON_UTF8("ims"),
 | 
			
		||||
@@ -2471,6 +2516,11 @@ bson_t *test_db_new_slice_with_same_dnn(test_ue_t *test_ue)
 | 
			
		||||
                        "}",
 | 
			
		||||
                      "}",
 | 
			
		||||
                    "]",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                "]",
 | 
			
		||||
              "}",
 | 
			
		||||
@@ -2540,6 +2590,11 @@ bson_t *test_db_new_slice_with_different_dnn(test_ue_t *test_ue)
 | 
			
		||||
                            "pre_emption_capability", BCON_INT32(1),
 | 
			
		||||
                        "}",
 | 
			
		||||
                    "}",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                  "{",
 | 
			
		||||
                    "name", BCON_UTF8("ims"),
 | 
			
		||||
@@ -2624,6 +2679,11 @@ bson_t *test_db_new_slice_with_different_dnn(test_ue_t *test_ue)
 | 
			
		||||
                        "}",
 | 
			
		||||
                      "}",
 | 
			
		||||
                    "]",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                "]",
 | 
			
		||||
              "}",
 | 
			
		||||
@@ -2652,6 +2712,11 @@ bson_t *test_db_new_slice_with_different_dnn(test_ue_t *test_ue)
 | 
			
		||||
                            "pre_emption_capability", BCON_INT32(1),
 | 
			
		||||
                        "}",
 | 
			
		||||
                    "}",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                  "{",
 | 
			
		||||
                    "name", BCON_UTF8("ims2"),
 | 
			
		||||
@@ -2736,6 +2801,11 @@ bson_t *test_db_new_slice_with_different_dnn(test_ue_t *test_ue)
 | 
			
		||||
                        "}",
 | 
			
		||||
                      "}",
 | 
			
		||||
                    "]",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                "]",
 | 
			
		||||
              "}",
 | 
			
		||||
@@ -2765,6 +2835,11 @@ bson_t *test_db_new_slice_with_different_dnn(test_ue_t *test_ue)
 | 
			
		||||
                            "pre_emption_capability", BCON_INT32(1),
 | 
			
		||||
                        "}",
 | 
			
		||||
                    "}",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                  "{",
 | 
			
		||||
                    "name", BCON_UTF8("ims3"),
 | 
			
		||||
@@ -2849,6 +2924,11 @@ bson_t *test_db_new_slice_with_different_dnn(test_ue_t *test_ue)
 | 
			
		||||
                        "}",
 | 
			
		||||
                      "}",
 | 
			
		||||
                    "]",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                "]",
 | 
			
		||||
              "}",
 | 
			
		||||
@@ -2921,6 +3001,11 @@ bson_t *test_db_new_non3gpp(test_ue_t *test_ue)
 | 
			
		||||
                        "addr", BCON_UTF8("127.0.0.4"),
 | 
			
		||||
                        "addr6", BCON_UTF8("::1"),
 | 
			
		||||
                    "}",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                  "{",
 | 
			
		||||
                    "name", BCON_UTF8("wlan"),
 | 
			
		||||
@@ -3005,6 +3090,11 @@ bson_t *test_db_new_non3gpp(test_ue_t *test_ue)
 | 
			
		||||
                        "}",
 | 
			
		||||
                      "}",
 | 
			
		||||
                    "]",
 | 
			
		||||
#if 1
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(true),
 | 
			
		||||
#else
 | 
			
		||||
                    "lbo_roaming_allowed", BCON_BOOL(false),
 | 
			
		||||
#endif
 | 
			
		||||
                  "}",
 | 
			
		||||
                "]",
 | 
			
		||||
            "}", "]",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user