[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:
Sukchan Lee
2025-05-31 15:44:44 +09:00
parent 3e6b7e961d
commit ae4d8433eb
28 changed files with 1352 additions and 501 deletions

View File

@@ -325,6 +325,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -325,6 +325,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -320,6 +320,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -325,6 +325,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -320,6 +320,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -325,6 +325,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -325,6 +325,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -325,6 +325,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -320,6 +320,15 @@ bsf:
scp: scp:
- uri: http://127.0.0.200:7777 - 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: udr:
sbi: sbi:
server: server:

View File

@@ -21,6 +21,7 @@
#include "s5c-build.h" #include "s5c-build.h"
#include "pfcp-path.h" #include "pfcp-path.h"
#include "gtp-path.h" #include "gtp-path.h"
#include "sbi-path.h"
#include "ipfw/ipfw2.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)) { if (ogs_list_count(&sess->qos_flow_to_modify_list)) {
ogs_assert(OGS_OK == ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_qos_flow_list_modification_request( 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));
} }
} }

View File

@@ -1865,11 +1865,13 @@ void smf_sess_remove(smf_sess_t *sess)
if (sess->n1smbuf) if (sess->n1smbuf)
ogs_pkbuf_free(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); OGS_NAS_CLEAR_DATA(&sess->h_smf_extended_protocol_configuration_options);
sess->h_smf_gsm_cause = 0; 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 */ /* Free SBI object memory */
ogs_sbi_object_free(&sess->sbi); ogs_sbi_object_free(&sess->sbi);

View File

@@ -82,6 +82,25 @@ typedef struct smf_nsmf_pdusession_param_s {
uint8_t ue_timezone:1;, uint8_t ue_timezone:1;,
uint8_t spare:6;) 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; } smf_nsmf_pdusession_param_t;
/* HR flag bit */ /* HR flag bit */
@@ -469,12 +488,36 @@ typedef struct smf_sess_s {
char *h_smf_id; char *h_smf_id;
/* Saved from H-SMF */ /* 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 ogs_nas_extended_protocol_configuration_options_t
h_smf_extended_protocol_configuration_options; h_smf_extended_protocol_configuration_options;
ogs_nas_5gsm_cause_t h_smf_gsm_cause; 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) \ #define HOME_ROUTED_ROAMING_IN_HSMF(__sESS) \
((__sESS) && (__sESS)->vsmf_pdu_session_uri) ((__sESS) && (__sESS)->vsmf_pdu_session_uri)
char *vsmf_pdu_session_uri; char *vsmf_pdu_session_uri;
@@ -637,6 +680,7 @@ typedef struct smf_sess_s {
bool n1_released; bool n1_released;
bool n2_released; bool n2_released;
ogs_pool_id_t amf_update_request_stream_id; 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; ogs_pool_id_t n1_n2_released_stream_id;
smf_nsmf_pdusession_param_t nsmf_param; smf_nsmf_pdusession_param_t nsmf_param;

View File

@@ -51,12 +51,18 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess)
uint8_t *epco_buf = NULL; uint8_t *epco_buf = NULL;
int16_t epco_len; 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 = &pdu_session_establishment_accept->
selected_pdu_session_type; selected_pdu_session_type;
ogs_assert(selected_pdu_session_type); ogs_assert(selected_pdu_session_type);
authorized_qos_rules = &pdu_session_establishment_accept-> authorized_qos_rules = &pdu_session_establishment_accept->
authorized_qos_rules; authorized_qos_rules;
ogs_assert(authorized_qos_rules); ogs_assert(authorized_qos_rules);
session_ambr = &pdu_session_establishment_accept->session_ambr; session_ambr = &pdu_session_establishment_accept->session_ambr;
ogs_assert(session_ambr); ogs_assert(session_ambr);
pdu_address = &pdu_session_establishment_accept->pdu_address; 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; selected_pdu_session_type->value = sess->session.session_type;
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
ogs_assert(sess->h_smf_authorized_qos_rules.buffer); qosFlowsSetupList = sess->h_smf_qos_flows_setup_list;
ogs_assert(sess->h_smf_authorized_qos_rules.length); ogs_assert(qosFlowsSetupList);
OGS_NAS_STORE_DATA(
authorized_qos_rules, &sess->h_smf_authorized_qos_rules); 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)) { } else if (HOME_ROUTED_ROAMING_IN_HSMF(sess)) {
ogs_fatal("This should not be invoked from H-SMF during HR-Roaming"); ogs_fatal("This should not be invoked from H-SMF during HR-Roaming");
ogs_assert_if_reached(); ogs_assert_if_reached();
} else { } else {
memset(qos_rule, 0, sizeof(qos_rule)); 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); rv = ogs_nas_build_qos_rules(authorized_qos_rules, qos_rule, 1);
if (rv != OGS_OK) { if (rv != OGS_OK) {
@@ -175,20 +194,29 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess)
/* QoS flow descriptions */ /* QoS flow descriptions */
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
if (sess->h_smf_authorized_qos_flow_descriptions.buffer && ogs_assert(qosFlowSetupItem);
sess->h_smf_authorized_qos_flow_descriptions.length) {
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 |= pdu_session_establishment_accept->presencemask |=
OGS_NAS_5GS_PDU_SESSION_ESTABLISHMENT_ACCEPT_AUTHORIZED_QOS_FLOW_DESCRIPTIONS_PRESENT; 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)) { } else if (HOME_ROUTED_ROAMING_IN_HSMF(sess)) {
ogs_fatal("This should not be invoked from H-SMF during HR-Roaming"); ogs_fatal("This should not be invoked from H-SMF during HR-Roaming");
ogs_assert_if_reached(); ogs_assert_if_reached();
} else { } else {
memset(&qos_flow_description, 0, sizeof(qos_flow_description)); 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 |= pdu_session_establishment_accept->presencemask |=
OGS_NAS_5GS_PDU_SESSION_ESTABLISHMENT_ACCEPT_AUTHORIZED_QOS_FLOW_DESCRIPTIONS_PRESENT; OGS_NAS_5GS_PDU_SESSION_ESTABLISHMENT_ACCEPT_AUTHORIZED_QOS_FLOW_DESCRIPTIONS_PRESENT;
@@ -250,8 +278,6 @@ cleanup:
if (extended_protocol_configuration_options->buffer) if (extended_protocol_configuration_options->buffer)
ogs_free(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); OGS_NAS_CLEAR_DATA(&sess->h_smf_extended_protocol_configuration_options);
return pkbuf; return pkbuf;
@@ -286,8 +312,7 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
{ {
ogs_pkbuf_t *pkbuf = NULL; ogs_pkbuf_t *pkbuf = NULL;
smf_bearer_t *qos_flow = NULL; smf_bearer_t *qos_flow = NULL;
ogs_pfcp_pdr_t *dl_pdr = NULL; int rv, i;
int num_of_param, rv, i;
ogs_nas_5gs_message_t message; ogs_nas_5gs_message_t message;
ogs_nas_5gs_pdu_session_modification_command_t 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 ogs_nas_qos_flow_description_t
qos_flow_description[OGS_NAS_MAX_NUM_OF_QOS_FLOW_DESCRIPTION]; 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 = &pdu_session_modification_command->
authorized_qos_rules; authorized_qos_rules;
ogs_assert(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; message.gsm.h.message_type = OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND;
/* QoS rule */ /* 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; i = 0;
memset(qos_rule, 0, sizeof(qos_rule)); 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( ogs_list_for_each_entry(
&sess->qos_flow_to_modify_list, qos_flow, to_modify_node) { &sess->qos_flow_to_modify_list, qos_flow, to_modify_node) {
ogs_assert(i < OGS_MAX_NUM_OF_BEARER); ogs_assert(i < OGS_MAX_NUM_OF_BEARER);
gsm_encode_qos_rule(&qos_rule[i], qos_flow, qos_rule_code);
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;
}
i++; i++;
} }
@@ -366,7 +415,48 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
} }
/* QoS flow descriptions */ /* 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; i = 0;
memset(&qos_flow_description, 0, sizeof(qos_flow_description)); 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) { &sess->qos_flow_to_modify_list, qos_flow, to_modify_node) {
ogs_assert(i < OGS_MAX_NUM_OF_BEARER); ogs_assert(i < OGS_MAX_NUM_OF_BEARER);
qos_flow_description[i].identifier = qos_flow->qfi; gsm_encode_qos_flow_description(
qos_flow_description[i].code = qos_flow_description_code; &qos_flow_description[i], qos_flow, 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;
i++; i++;
} }
@@ -458,14 +489,11 @@ ogs_pkbuf_t *gsm_build_pdu_session_modification_command(
pkbuf = ogs_nas_5gs_plain_encode(&message); pkbuf = ogs_nas_5gs_plain_encode(&message);
ogs_assert(pkbuf); ogs_assert(pkbuf);
if (pdu_session_modification_command->presencemask & cleanup:
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND_AUTHORIZED_QOS_RULES_PRESENT) { if (authorized_qos_rules->buffer)
ogs_free(authorized_qos_rules->buffer); ogs_free(authorized_qos_rules->buffer);
} if (authorized_qos_flow_descriptions->buffer)
if (pdu_session_modification_command->presencemask &
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND_AUTHORIZED_QOS_FLOW_DESCRIPTIONS_PRESENT) {
ogs_free(authorized_qos_flow_descriptions->buffer); ogs_free(authorized_qos_flow_descriptions->buffer);
}
return pkbuf; return pkbuf;
} }
@@ -537,7 +565,7 @@ ogs_pkbuf_t *gsm_build_pdu_session_release_reject(
return ogs_nas_5gs_plain_encode(&message); 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_nas_qos_rule_t *qos_rule, smf_bearer_t *qos_flow)
{ {
ogs_assert(qos_rule); ogs_assert(qos_rule);
@@ -584,7 +612,7 @@ void encode_default_qos_rule(
qos_rule->flow.identifier = qos_flow->qfi; 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, ogs_nas_qos_flow_description_t *qos_flow_description,
smf_bearer_t *qos_flow) smf_bearer_t *qos_flow)
{ {
@@ -609,7 +637,7 @@ void encode_default_qos_flow_description(
qos_flow_description->num_of_parameter = num_of_param; 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) ogs_nas_qos_rule_t *qos_rule, smf_bearer_t *qos_flow)
{ {
int i; 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;
}

View File

@@ -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); 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); 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, ogs_nas_qos_flow_description_t *qos_flow_description,
smf_bearer_t *qos_flow); 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); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -874,6 +874,7 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
char *strerror = NULL; char *strerror = NULL;
smf_ue_t *smf_ue = NULL; smf_ue_t *smf_ue = NULL;
smf_sess_t *sess = NULL; smf_sess_t *sess = NULL;
smf_bearer_t *qos_flow = NULL;
ogs_pkbuf_t *pkbuf = NULL; ogs_pkbuf_t *pkbuf = NULL;
ogs_pfcp_xact_t *pfcp_xact = NULL; ogs_pfcp_xact_t *pfcp_xact = NULL;
@@ -1084,24 +1085,34 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
CASE(OGS_SBI_RESOURCE_NAME_PDU_SESSIONS) CASE(OGS_SBI_RESOURCE_NAME_PDU_SESSIONS)
SWITCH(sbi_message->h.resource.component[2]) SWITCH(sbi_message->h.resource.component[2])
CASE(OGS_SBI_RESOURCE_NAME_MODIFY) 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); sess, stream, sbi_message);
if (rc == true) { if (rc == true) {
ogs_assert(sess->nsmf_param.request_indication); ogs_assert(sess->nsmf_param.request_indication);
if (sess->nsmf_param.request_indication == if (sess->nsmf_param.request_indication ==
OpenAPI_request_indication_UE_REQ_PDU_SES_REL) { OpenAPI_request_indication_NW_REQ_PDU_SES_MOD) {
e->h.sbi.state = ogs_fatal("TODO");
OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED;
} else if (sess->nsmf_param.request_indication == ogs_assert(true ==
OpenAPI_request_indication_NW_REQ_PDU_SES_REL) { ogs_sbi_send_http_status_no_content(
e->h.sbi.state = stream));
OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT;
} else { } else {
ogs_fatal("Not implemented [requestIndication:%d]", if (sess->nsmf_param.request_indication ==
sess->nsmf_param.request_indication); OpenAPI_request_indication_UE_REQ_PDU_SES_REL) {
ogs_assert_if_reached(); e->h.sbi.state =
} OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED;
} else if (sess->nsmf_param.request_indication ==
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]",
sess->nsmf_param.request_indication);
ogs_assert_if_reached();
}
/* /*
* TS23.502 clause 4.3.4.3 UE or network requested PDU Session Release * TS23.502 clause 4.3.4.3 UE or network requested PDU Session Release
* for Home-routed Roaming. * for Home-routed Roaming.
@@ -1119,12 +1130,14 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
* - the V-SMF invokes the Nsmf_PDUSession_Update Request towards H-SMF. * - the V-SMF invokes the Nsmf_PDUSession_Update Request towards H-SMF.
* (OpenAPI_cause_REL_DUE_TO_DUPLICATE_SESSION_ID); * (OpenAPI_cause_REL_DUE_TO_DUPLICATE_SESSION_ID);
*/ */
ogs_assert(true == 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); OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion);
}
} else { } else {
ogs_error("smf_nsmf_handle_hsmf_update_data() " ogs_error("smf_nsmf_handle_update_data_in_hsmf() "
"failed"); "failed");
} }
break; 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) CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
SWITCH(sbi_message->h.resource.component[2]) SWITCH(sbi_message->h.resource.component[2])
CASE(OGS_SBI_RESOURCE_NAME_MODIFY) 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); sess, stream, sbi_message);
if (rc == true) { if (rc == true) {
e->h.sbi.state = OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED; switch (sess->nsmf_param.request_indication) {
OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion); 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 { } else {
ogs_error("smf_nsmf_handle_vsmf_update_data() failed"); ogs_error("smf_nsmf_handle_update_data_in_vsmf() "
"failed");
} }
break; break;
DEFAULT 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); smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
ogs_assert(smf_ue); 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) SWITCH(sbi_message->h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM) CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM)
SWITCH(sbi_message->h.resource.component[0]) 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); &smf_gsm_state_wait_pfcp_deletion);
break; break;
DEFAULT DEFAULT
if (smf_nsmf_handle_create_data_in_vsmf( if (smf_nsmf_handle_created_data_in_vsmf(
sess, sbi_message) == false) { sess, sbi_message) == false) {
ogs_error("[%s:%d] create_pdu_session " ogs_error("[%s:%d] create_pdu_session "
"failed() [%d]", "failed() [%d]",
@@ -1259,6 +1289,39 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
END END
break; 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 DEFAULT
ogs_error("Invalid resource name [%s]", ogs_error("Invalid resource name [%s]",
sbi_message->h.resource.component[0]); 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: case OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMPLETE:
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream)); 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; break;
case OGS_NAS_5GS_PDU_SESSION_RELEASE_REQUEST: case OGS_NAS_5GS_PDU_SESSION_RELEASE_REQUEST:

View File

@@ -1609,6 +1609,23 @@ cleanup:
return pkbuf; 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 *gsmue_build_pdu_session_release_command(smf_sess_t *sess)
{ {
ogs_pkbuf_t *pkbuf = NULL; ogs_pkbuf_t *pkbuf = NULL;

View File

@@ -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); 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_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); ogs_pkbuf_t *gsmue_build_pdu_session_release_command(smf_sess_t *sess);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -257,7 +257,7 @@ void smf_5gc_n4_handle_session_modification_response(
smf_sess_t *sess, ogs_pfcp_xact_t *xact, smf_sess_t *sess, ogs_pfcp_xact_t *xact,
ogs_pfcp_session_modification_response_t *rsp) ogs_pfcp_session_modification_response_t *rsp)
{ {
int status = 0; int r, status = 0;
uint64_t flags = 0; uint64_t flags = 0;
int trigger = 0; int trigger = 0;
ogs_sbi_stream_t *stream = NULL; ogs_sbi_stream_t *stream = NULL;
@@ -407,35 +407,17 @@ void smf_5gc_n4_handle_session_modification_response(
return; return;
} }
if (flags & OGS_PFCP_MODIFY_ACTIVATE) { if (flags & OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING) {
if (flags & OGS_PFCP_MODIFY_XN_HANDOVER) { if (flags & OGS_PFCP_MODIFY_ACTIVATE) {
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 (flags & OGS_PFCP_MODIFY_DL_ONLY) {
if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING) { if (sess->up_cnx_state == OpenAPI_up_cnx_state_ACTIVATING) {
sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED; sess->up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED;
smf_sbi_send_sm_context_updated_data_up_cnx_state( smf_sbi_send_sm_context_updated_data_up_cnx_state(
sess, stream, OpenAPI_up_cnx_state_ACTIVATED); sess, stream, OpenAPI_up_cnx_state_ACTIVATED);
} else { } else {
ogs_assert(true == if (stream)
ogs_sbi_send_http_status_no_content(stream)); ogs_assert(true ==
ogs_sbi_send_http_status_no_content(stream));
} }
} else if (flags & OGS_PFCP_MODIFY_UL_ONLY) { } else if (flags & OGS_PFCP_MODIFY_UL_ONLY) {
smf_n1_n2_message_transfer_param_t param; smf_n1_n2_message_transfer_param_t param;
@@ -455,38 +437,7 @@ void smf_5gc_n4_handle_session_modification_response(
ogs_fatal("Invalid flags [0x%llx]", (long long)flags); ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
ogs_assert_if_reached(); ogs_assert_if_reached();
} }
} else { } else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) {
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(&param, 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, &param);
} else if (flags & OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING) {
int r;
ogs_assert(trigger); ogs_assert(trigger);
if (trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED) { 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_fatal("Invalid delete trigger[%d]", trigger);
ogs_assert_if_reached(); 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(&param, 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, &param);
} else { } else {
smf_sbi_send_sm_context_updated_data_up_cnx_state( smf_sbi_send_sm_context_updated_data_up_cnx_state(
sess, stream, OpenAPI_up_cnx_state_DEACTIVATED); 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_rule_code = 0;
uint8_t qos_flow_description_code = 0; uint8_t qos_flow_description_code = 0;
if (flags & OGS_PFCP_MODIFY_TFT_NEW) { qos_rule_code = QOS_RULE_CODE_FROM_PFCP_FLAGS(flags);
qos_rule_code = OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE; qos_flow_description_code =
} else if (flags & OGS_PFCP_MODIFY_TFT_ADD) { QOS_RULE_FLOW_DESCRIPTION_CODE_FROM_PFCP_FLAGS(flags);
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();
}
if (flags & OGS_PFCP_MODIFY_NETWORK_REQUESTED) { if (flags & OGS_PFCP_MODIFY_NETWORK_REQUESTED) {
ogs_assert(flags & OGS_PFCP_MODIFY_SESSION); ogs_assert(flags & OGS_PFCP_MODIFY_SESSION);

View File

@@ -38,6 +38,15 @@ bool smf_namf_comm_handle_n1_n2_message_transfer(
switch (state) { switch (state) {
case SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT: case SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT:
if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) { 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-SMFs CreateSMContext response and H-UPF N4 setup
* to apply QoS updates without waiting for V-SMF or RAN setup.
*/
smf_qos_flow_binding(sess); smf_qos_flow_binding(sess);
} else { } else {
ogs_error("[%s:%d] HTTP response error [%d]", 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 (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) {
if (N1N2MessageTransferRspData->cause == if (N1N2MessageTransferRspData->cause ==
OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED) { 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 { } else {
ogs_error("Not implemented [cause:%d]", ogs_error("Not implemented [cause:%d]",
N1N2MessageTransferRspData->cause); N1N2MessageTransferRspData->cause);

View File

@@ -19,6 +19,68 @@
#include "ngap-build.h" #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 =
&params->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 = &params->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( ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
smf_sess_t *sess) 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_SecurityIndication_t *SecurityIndication = NULL;
NGAP_QosFlowSetupRequestList_t *QosFlowSetupRequestList = NULL; NGAP_QosFlowSetupRequestList_t *QosFlowSetupRequestList = NULL;
NGAP_QosFlowSetupRequestItem_t *QosFlowSetupRequestItem = 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); ogs_assert(sess);
@@ -181,7 +237,8 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
if (smf_self()->security_indication. if (smf_self()->security_indication.
maximum_integrity_protected_data_rate_downlink) { 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_SecurityIndication_ExtIEs_t *extIe = NULL;
NGAP_MaximumIntegrityProtectedDataRate_t NGAP_MaximumIntegrityProtectedDataRate_t
*MaximumIntegrityProtectedDataRate = NULL; *MaximumIntegrityProtectedDataRate = NULL;
@@ -224,69 +281,83 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
QosFlowSetupRequestList = &ie->value.choice.QosFlowSetupRequestList; QosFlowSetupRequestList = &ie->value.choice.QosFlowSetupRequestList;
ogs_list_for_each(&sess->bearer_list, qos_flow) { 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 = QosFlowSetupRequestItem =
CALLOC(1, sizeof(struct NGAP_QosFlowSetupRequestItem)); CALLOC(1, sizeof(struct NGAP_QosFlowSetupRequestItem));
ogs_assert(QosFlowSetupRequestItem); ogs_assert(QosFlowSetupRequestItem);
ASN_SEQUENCE_ADD(&QosFlowSetupRequestList->list, ASN_SEQUENCE_ADD(&QosFlowSetupRequestList->list,
QosFlowSetupRequestItem); QosFlowSetupRequestItem);
qosFlowIdentifier = &QosFlowSetupRequestItem->qosFlowIdentifier; QosFlowSetupRequestItem->qosFlowIdentifier = qosFlowSetupItem->qfi;
qosFlowLevelQosParameters =
&QosFlowSetupRequestItem->qosFlowLevelQosParameters;
allocationAndRetentionPriority = fill_qos_level_parameters(
&qosFlowLevelQosParameters->allocationAndRetentionPriority; &QosFlowSetupRequestItem->qosFlowLevelQosParameters,
qosCharacteristics = &qosFlowLevelQosParameters->qosCharacteristics; &qos, true);
nonDynamic5QI = CALLOC(1, sizeof(struct NGAP_NonDynamic5QIDescriptor));
ogs_assert(nonDynamic5QI);
qosCharacteristics->choice.nonDynamic5QI = nonDynamic5QI;
qosCharacteristics->present = NGAP_QosCharacteristics_PR_nonDynamic5QI;
*qosFlowIdentifier = qos_flow->qfi; } else {
ogs_list_for_each(&sess->bearer_list, qos_flow) {
QosFlowSetupRequestItem =
CALLOC(1, sizeof(struct NGAP_QosFlowSetupRequestItem));
ogs_assert(QosFlowSetupRequestItem);
ASN_SEQUENCE_ADD(&QosFlowSetupRequestList->list,
QosFlowSetupRequestItem);
nonDynamic5QI->fiveQI = qos_flow->qos.index; QosFlowSetupRequestItem->qosFlowIdentifier = qos_flow->qfi;
allocationAndRetentionPriority->priorityLevelARP = fill_qos_level_parameters(
qos_flow->qos.arp.priority_level; &QosFlowSetupRequestItem->qosFlowLevelQosParameters,
if (qos_flow->qos.arp.pre_emption_capability == &qos_flow->qos, true);
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);
}
} }
} }
@@ -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( 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; 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_QosFlowAddOrModifyRequestList_t *QosFlowAddOrModifyRequestList = NULL;
NGAP_QosFlowAddOrModifyRequestItem_t *QosFlowAddOrModifyRequestItem = 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; smf_bearer_t *qos_flow = NULL;
@@ -318,80 +383,126 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_request_transfer(
memset(&message, 0, sizeof(NGAP_PDUSessionResourceModifyRequestTransfer_t)); memset(&message, 0, sizeof(NGAP_PDUSessionResourceModifyRequestTransfer_t));
ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceModifyRequestTransferIEs_t)); ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceModifyRequestTransferIEs_t));
ogs_assert(ie);
ASN_SEQUENCE_ADD(&message.protocolIEs, ie); ASN_SEQUENCE_ADD(&message.protocolIEs, ie);
ie->id = NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList; ie->id = NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList;
ie->criticality = NGAP_Criticality_reject; ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_PDUSessionResourceModifyRequestTransferIEs__value_PR_QosFlowAddOrModifyRequestList; ie->value.present = NGAP_PDUSessionResourceModifyRequestTransferIEs__value_PR_QosFlowAddOrModifyRequestList;
QosFlowAddOrModifyRequestList = &ie->value.choice.QosFlowAddOrModifyRequestList; QosFlowAddOrModifyRequestList =
&ie->value.choice.QosFlowAddOrModifyRequestList;
ogs_list_for_each_entry( /* Home-Routed V-SMF: QoS flow */
&sess->qos_flow_to_modify_list, qos_flow, to_modify_node) { 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;
QosFlowAddOrModifyRequestItem = memset(&qos, 0, sizeof(qos));
CALLOC(1, sizeof(*QosFlowAddOrModifyRequestItem));
ASN_SEQUENCE_ADD(&QosFlowAddOrModifyRequestList->list, QosFlowAddOrModifyRequestItem);
qosFlowIdentifier = &QosFlowAddOrModifyRequestItem->qosFlowIdentifier; 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();
}
QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters = if (qosFlowProfile->arp->preempt_vuln ==
qosFlowLevelQosParameters = OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE)
CALLOC(1, sizeof(*qosFlowLevelQosParameters)); 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();
}
allocationAndRetentionPriority = if (qosFlowProfile->gbr_qos_flow_info) {
&qosFlowLevelQosParameters->allocationAndRetentionPriority; OpenAPI_gbr_qos_flow_information_t *gbrQosFlowInfo =
qosCharacteristics = &qosFlowLevelQosParameters->qosCharacteristics; 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);
}
qosCharacteristics->present = NGAP_QosCharacteristics_PR_nonDynamic5QI; QosFlowAddOrModifyRequestItem =
qosCharacteristics->choice.nonDynamic5QI = CALLOC(1, sizeof(*QosFlowAddOrModifyRequestItem));
nonDynamic5QI = CALLOC(1, sizeof(struct NGAP_NonDynamic5QIDescriptor)); ogs_assert(QosFlowAddOrModifyRequestItem);
ASN_SEQUENCE_ADD(
&QosFlowAddOrModifyRequestList->list,
QosFlowAddOrModifyRequestItem);
*qosFlowIdentifier = qos_flow->qfi; QosFlowAddOrModifyRequestItem->qosFlowIdentifier =
qosFlowAddModifyRequestItem->qfi;
nonDynamic5QI->fiveQI = qos_flow->qos.index; QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters =
CALLOC(1, sizeof(NGAP_QosFlowLevelQosParameters_t));
ogs_assert(
QosFlowAddOrModifyRequestItem->qosFlowLevelQosParameters);
allocationAndRetentionPriority->priorityLevelARP = fill_qos_level_parameters(
qos_flow->qos.arp.priority_level; QosFlowAddOrModifyRequestItem->
if (qos_flow->qos.arp.pre_emption_capability == qosFlowLevelQosParameters, &qos, true);
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);
} 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);
} }
} }
} else {
/* 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);
}
} }
return ogs_asn_encode( return ogs_asn_encode(

View File

@@ -30,7 +30,8 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
smf_sess_t *sess); smf_sess_t *sess);
ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_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);
ogs_pkbuf_t *ngap_build_pdu_session_resource_release_request_transfer( ogs_pkbuf_t *ngap_build_pdu_session_resource_release_request_transfer(
smf_sess_t *sess, NGAP_Cause_PR group, long cause); smf_sess_t *sess, NGAP_Cause_PR group, long cause);

View File

@@ -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_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf)
{ {
smf_ue_t *smf_ue = NULL; smf_ue_t *smf_ue = NULL;
smf_bearer_t *qos_flow = NULL;
int rv, i; int rv, i;
uint32_t remote_dl_teid; 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); ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &remote_dl_teid);
/* Need to Update? */ /* 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) sess->remote_dl_teid != remote_dl_teid)
far_update = true; far_update = true;
@@ -111,36 +114,49 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
memcpy(&sess->remote_dl_ip, &remote_dl_ip, sizeof(sess->remote_dl_ip)); memcpy(&sess->remote_dl_ip, &remote_dl_ip, sizeof(sess->remote_dl_ip));
sess->remote_dl_teid = remote_dl_teid; sess->remote_dl_teid = remote_dl_teid;
associatedQosFlowList = &dLQosFlowPerTNLInformation->associatedQosFlowList; if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
for (i = 0; i < associatedQosFlowList->list.count; i++) { ogs_list_for_each(&sess->bearer_list, qos_flow) {
NGAP_AssociatedQosFlowItem_t *associatedQosFlowItem = NULL; ogs_pfcp_far_t *dl_far = qos_flow->dl_far;
associatedQosFlowItem = (NGAP_AssociatedQosFlowItem_t *) ogs_assert(dl_far);
associatedQosFlowList->list.array[i]; if (dl_far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) {
far_update = true;
}
if (associatedQosFlowItem) { dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW;
smf_bearer_t *qos_flow = smf_qos_flow_find_by_qfi( ogs_assert(OGS_OK ==
sess, associatedQosFlowItem->qosFlowIdentifier); 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 (qos_flow) { if (associatedQosFlowItem) {
ogs_pfcp_far_t *dl_far = qos_flow->dl_far; qos_flow = smf_qos_flow_find_by_qfi(
ogs_assert(dl_far); sess, associatedQosFlowItem->qosFlowIdentifier);
if (dl_far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) {
far_update = true; if (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;
} }
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 {
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; 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; qosFlowAddOrModifyResponseList = message.qosFlowAddOrModifyResponseList;
if (!qosFlowAddOrModifyResponseList) { if (!qosFlowAddOrModifyResponseList) {
/* QosFlow Release */ /* QosFlow Release */

View File

@@ -18,6 +18,7 @@
*/ */
#include "nsmf-build.h" #include "nsmf-build.h"
#include "gsm-build.h"
ogs_sbi_request_t *smf_nsmf_pdusession_build_create_data( ogs_sbi_request_t *smf_nsmf_pdusession_build_create_data(
smf_sess_t *sess, void *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; OpenAPI_ref_to_binary_data_t n1SmInfoToUe;
ogs_pkbuf_t *n1SmBufToUe = NULL; 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); ogs_assert(sess);
memset(&message, 0, sizeof(message)); 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; VsmfUpdateData.request_indication = sess->nsmf_param.request_indication;
ogs_assert(VsmfUpdateData.request_indication); ogs_assert(VsmfUpdateData.request_indication);
n1SmBufToUe = gsmue_build_pdu_session_release_command(sess); switch (VsmfUpdateData.request_indication) {
ogs_assert(n1SmBufToUe); 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; n1SmInfoToUe.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
VsmfUpdateData.n1_sm_info_to_ue = &n1SmInfoToUe; VsmfUpdateData.n1_sm_info_to_ue = &n1SmInfoToUe;
@@ -508,6 +679,9 @@ end:
if (message.h.uri) if (message.h.uri)
ogs_free(message.h.uri); ogs_free(message.h.uri);
CLEAR_QOS_FLOWS_ADD_MOD_REQUEST_LIST(
VsmfUpdateData.qos_flows_add_mod_request_list);
return request; return request;
} }

View File

@@ -1562,7 +1562,7 @@ bool smf_nsmf_handle_create_data_in_hsmf(
return true; 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) smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
{ {
int rv; int rv;
@@ -1591,12 +1591,9 @@ bool smf_nsmf_handle_create_data_in_vsmf(
ogs_ip_t ue_ip; ogs_ip_t ue_ip;
uint8_t prefixlen; uint8_t prefixlen;
int len;
OpenAPI_tunnel_info_t *hcnTunnelInfo = NULL; OpenAPI_tunnel_info_t *hcnTunnelInfo = NULL;
OpenAPI_ambr_t *sessionAmbr = NULL; OpenAPI_ambr_t *sessionAmbr = NULL;
OpenAPI_list_t *qosFlowsSetupList = NULL; OpenAPI_list_t *qosFlowsSetupList = NULL;
OpenAPI_qos_flow_setup_item_t *qosFlowSetupItem = NULL;
OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL; OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL;
OpenAPI_lnode_t *node = NULL; OpenAPI_lnode_t *node = NULL;
@@ -1818,105 +1815,60 @@ bool smf_nsmf_handle_create_data_in_vsmf(
&ul_far->outer_header_creation_len)); &ul_far->outer_header_creation_len));
ul_far->outer_header_creation.teid = sess->remote_ul_teid; ul_far->outer_header_creation.teid = sess->remote_ul_teid;
qosFlowsSetupList = PduSessionCreatedData->qos_flows_setup_list; CLEAR_QOS_FLOWS_SETUP_LIST(sess->h_smf_qos_flows_setup_list);
if (qosFlowsSetupList) {
node = qosFlowsSetupList->first;
if (node) {
qosFlowSetupItem = node->data;
}
}
if (!qosFlowSetupItem || qosFlowsSetupList = OpenAPI_list_create();
!qosFlowSetupItem->qfi || ogs_assert(qosFlowsSetupList);
!qosFlowSetupItem->qos_rules || OpenAPI_list_for_each(
!qosFlowSetupItem->qos_flow_description || PduSessionCreatedData->qos_flows_setup_list, node) {
!qosFlowSetupItem->qos_flow_profile) { OpenAPI_qos_flow_setup_item_t *dst = NULL, *src = NULL;
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");
return false;
}
qos_flow->qfi = qosFlowSetupItem->qfi; src = node->data;
if (!src ||
OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_rules); !src->qfi ||
len = ogs_base64_decode_len(qosFlowSetupItem->qos_rules); !src->qos_rules ||
ogs_assert(len); !src->qos_flow_description ||
sess->h_smf_authorized_qos_rules.buffer = ogs_calloc(1, len); !src->qos_flow_profile) {
ogs_assert(sess->h_smf_authorized_qos_rules.buffer); ogs_error("[%s:%d] No src [%d:%s:%s]",
sess->h_smf_authorized_qos_rules.length = smf_ue->supi, sess->psi, src->qfi,
ogs_base64_decode_binary( src->qos_rules ?
sess->h_smf_authorized_qos_rules.buffer, src->qos_rules : "NULL",
qosFlowSetupItem->qos_rules); src->qos_flow_description ?
ogs_assert(sess->h_smf_authorized_qos_rules.length); src->qos_flow_description : "NULL");
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->arp ||
!qosFlowProfile->arp->priority_level) {
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);
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; return false;
} }
if (qosFlowProfile->arp->preempt_vuln == qosFlowProfile = src->qos_flow_profile;
OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE) if (!qosFlowProfile ||
sess->session.qos.arp.pre_emption_vulnerability = !qosFlowProfile->_5qi ||
OGS_5GC_PRE_EMPTION_DISABLED; !qosFlowProfile->arp ||
else if (qosFlowProfile->arp->preempt_vuln == !qosFlowProfile->arp->priority_level ||
OpenAPI_preemption_vulnerability_PREEMPTABLE) !(qosFlowProfile->arp->preempt_cap ==
sess->session.qos.arp.pre_emption_vulnerability = OpenAPI_preemption_capability_NOT_PREEMPT ||
OGS_5GC_PRE_EMPTION_ENABLED; qosFlowProfile->arp->preempt_cap ==
else { OpenAPI_preemption_capability_MAY_PREEMPT) ||
ogs_error("[%s:%d] Invalid preempt_vuln [%d]", !(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, smf_ue->supi, sess->psi,
qosFlowProfile->arp->preempt_vuln); qosFlowProfile->_5qi,
qosFlowProfile->arp,
qosFlowProfile->arp ?
qosFlowProfile->arp->priority_level : 0);
return false; return false;
} }
dst = OpenAPI_qos_flow_setup_item_copy(dst, src);
ogs_assert(dst);
OpenAPI_list_add(qosFlowsSetupList, dst);
} }
/* Copy Session QoS information to Default QoS Flow */ if (qosFlowsSetupList->count)
memcpy(&qos_flow->qos, &sess->session.qos, sizeof(ogs_qos_t)); sess->h_smf_qos_flows_setup_list = qosFlowsSetupList;
else
OpenAPI_list_free(qosFlowsSetupList);
sessionAmbr = PduSessionCreatedData->session_ambr; sessionAmbr = PduSessionCreatedData->session_ambr;
if (sessionAmbr) { if (sessionAmbr) {
@@ -1977,7 +1929,7 @@ bool smf_nsmf_handle_create_data_in_vsmf(
ogs_freeaddrinfo(addr); ogs_freeaddrinfo(addr);
ogs_freeaddrinfo(addr6); ogs_freeaddrinfo(addr6);
return OGS_ERROR; return false;
} }
} }
OGS_SBI_SETUP_CLIENT(&sess->pdu_session, client); OGS_SBI_SETUP_CLIENT(&sess->pdu_session, client);
@@ -2055,7 +2007,7 @@ bool smf_nsmf_handle_create_data_in_vsmf(
return true; 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) smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
{ {
int rv; int rv;
@@ -2159,7 +2111,7 @@ bool smf_nsmf_handle_hsmf_update_data(
return true; 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) smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
{ {
int rv; int rv;
@@ -2167,10 +2119,16 @@ bool smf_nsmf_handle_vsmf_update_data(
OpenAPI_vsmf_update_data_t *VsmfUpdateData = NULL; 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_nas_5gs_message_t nas_message;
ogs_pkbuf_t *n1SmBufToUe = NULL; ogs_pkbuf_t *n1SmBufToUe = NULL;
OpenAPI_ref_to_binary_data_t *n1SmInfoToUe = NULL; OpenAPI_ref_to_binary_data_t *n1SmInfoToUe = NULL;
smf_n1_n2_message_transfer_param_t param;
ogs_assert(stream); ogs_assert(stream);
ogs_assert(message); ogs_assert(message);
ogs_assert(sess); 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(&param, 0, sizeof(param));
param.state = SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION;
param.n1smbuf = gsm_build_pdu_session_modification_command(sess, 0, 0);
ogs_assert(param.n1smbuf);
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, &param);
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; return true;
} }

View File

@@ -35,12 +35,12 @@ bool smf_nsmf_handle_release_sm_context(
bool smf_nsmf_handle_create_data_in_hsmf( bool smf_nsmf_handle_create_data_in_hsmf(
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); 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); 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); 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); smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message);
bool smf_nsmf_handle_release_data_in_hsmf( bool smf_nsmf_handle_release_data_in_hsmf(

View File

@@ -398,9 +398,8 @@ void smf_sbi_send_pdu_session_created_data(
OpenAPI_ambr_t sessionAmbr; OpenAPI_ambr_t sessionAmbr;
OpenAPI_list_t *qosFlowsSetupList = NULL; OpenAPI_list_t *qosFlowsSetupList = NULL;
OpenAPI_qos_flow_setup_item_t *qosFlowSetupItem = NULL; OpenAPI_qos_flow_setup_item_t *qosFlowSetupItem = NULL;
OpenAPI_qos_flow_profile_t qosFlowProfile; OpenAPI_qos_flow_profile_t *qosFlowProfile = NULL;
OpenAPI_arp_t Arp; OpenAPI_arp_t *Arp = NULL;
OpenAPI_lnode_t *node = NULL;
ogs_nas_qos_rule_t qos_rule[OGS_NAS_MAX_NUM_OF_QOS_RULE]; ogs_nas_qos_rule_t qos_rule[OGS_NAS_MAX_NUM_OF_QOS_RULE];
ogs_nas_qos_rules_t authorized_qos_rules; 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); ogs_assert(ogs_list_next(qos_flow) == NULL);
memset(qos_rule, 0, sizeof(qos_rule)); 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)); memset(&authorized_qos_rules, 0, sizeof(authorized_qos_rules));
rv = ogs_nas_build_qos_rules(&authorized_qos_rules, qos_rule, 1); 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 */ /* QoS flow descriptions */
memset(&qos_flow_description, 0, sizeof(qos_flow_description)); memset(&qos_flow_description, 0, sizeof(qos_flow_description));
encode_default_qos_flow_description(&qos_flow_description[0], gsm_encode_default_qos_flow_description(&qos_flow_description[0], qos_flow);
qos_flow);
memset(&authorized_qos_flow_descriptions, 0, memset(&authorized_qos_flow_descriptions, 0,
sizeof(authorized_qos_flow_descriptions)); sizeof(authorized_qos_flow_descriptions));
@@ -521,35 +519,37 @@ void smf_sbi_send_pdu_session_created_data(
ogs_free(authorized_qos_flow_descriptions.buffer); 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 == if (qos_flow->qos.arp.pre_emption_capability ==
OGS_5GC_PRE_EMPTION_ENABLED) 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 == else if (qos_flow->qos.arp.pre_emption_capability ==
OGS_5GC_PRE_EMPTION_DISABLED) OGS_5GC_PRE_EMPTION_DISABLED)
Arp.preempt_cap = OpenAPI_preemption_capability_NOT_PREEMPT; Arp->preempt_cap = OpenAPI_preemption_capability_NOT_PREEMPT;
else { else {
ogs_fatal("No Arp.preempt_cap"); ogs_error("No Arp->preempt_cap");
ogs_assert_if_reached(); goto end;
} }
if (qos_flow->qos.arp.pre_emption_vulnerability == if (qos_flow->qos.arp.pre_emption_vulnerability ==
OGS_5GC_PRE_EMPTION_ENABLED) 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 == else if (qos_flow->qos.arp.pre_emption_vulnerability ==
OGS_5GC_PRE_EMPTION_DISABLED) OGS_5GC_PRE_EMPTION_DISABLED)
Arp.preempt_vuln = OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE; Arp->preempt_vuln = OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE;
else { else {
ogs_fatal("No Arp.preempt_vuln"); ogs_error("No Arp->preempt_vuln");
ogs_assert_if_reached(); 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 = ogs_calloc(1, sizeof(*qosFlowProfile));
qosFlowProfile.arp = &Arp; ogs_assert(qosFlowProfile);
qosFlowProfile._5qi = qos_flow->qos.index; qosFlowProfile->arp = Arp;
qosFlowProfile->_5qi = qos_flow->qos.index;
qosFlowSetupItem->qos_flow_profile = &qosFlowProfile; qosFlowSetupItem->qos_flow_profile = qosFlowProfile;
OpenAPI_list_add(qosFlowsSetupList, qosFlowSetupItem); 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)); ue_ipv6_interface_id, sizeof(ue_ipv6_interface_id));
PduSessionCreatedData.ue_ipv6_interface_id = ue_ipv6_interface_id; PduSessionCreatedData.ue_ipv6_interface_id = ue_ipv6_interface_id;
} else { } else {
ogs_fatal("Invalid sess->session.session_type[%d]", ogs_error("Invalid sess->session.session_type[%d]",
sess->paa.session_type); sess->paa.session_type);
ogs_assert_if_reached(); goto end;
} }
memset(&sendmsg, 0, sizeof(sendmsg)); memset(&sendmsg, 0, sizeof(sendmsg));
@@ -627,6 +627,7 @@ void smf_sbi_send_pdu_session_created_data(
ogs_free(sendmsg.http.location); ogs_free(sendmsg.http.location);
end:
if (hcnTunnelInfo.ipv4_addr) if (hcnTunnelInfo.ipv4_addr)
ogs_free(hcnTunnelInfo.ipv4_addr); ogs_free(hcnTunnelInfo.ipv4_addr);
if (hcnTunnelInfo.ipv6_addr) if (hcnTunnelInfo.ipv6_addr)
@@ -639,18 +640,7 @@ void smf_sbi_send_pdu_session_created_data(
if (sessionAmbr.downlink) if (sessionAmbr.downlink)
ogs_free(sessionAmbr.downlink); ogs_free(sessionAmbr.downlink);
OpenAPI_list_for_each( CLEAR_QOS_FLOWS_SETUP_LIST(PduSessionCreatedData.qos_flows_setup_list);
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);
if (PduSessionCreatedData.ue_ipv4_address) if (PduSessionCreatedData.ue_ipv4_address)
ogs_free(PduSessionCreatedData.ue_ipv4_address); ogs_free(PduSessionCreatedData.ue_ipv4_address);

View File

@@ -31,6 +31,7 @@
#include "nsmf-handler.h" #include "nsmf-handler.h"
#include "npcf-handler.h" #include "npcf-handler.h"
#include "nsmf-handler.h" #include "nsmf-handler.h"
#include "binding.h"
void smf_state_initial(ogs_fsm_t *s, smf_event_t *e) 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) { if (state == SMF_UECM_STATE_REGISTERED) {
/* SMF Registration */
ogs_assert(stream); ogs_assert(stream);
ogs_assert(true == ogs_sbi_send_http_status_no_content(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) { } else if (state == SMF_UECM_STATE_REGISTERED_HR) {
ogs_assert(stream);
smf_sbi_send_pdu_session_created_data(sess, stream); smf_sbi_send_pdu_session_created_data(sess, stream);
smf_metrics_inst_by_slice_add( smf_metrics_inst_by_slice_add(
&sess->serving_plmn_id, &sess->s_nssai, &sess->serving_plmn_id, &sess->s_nssai,
SMF_METR_CTR_SM_PDUSESSIONCREATIONSUCC, 1); 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-SMFs 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) { } else if (state == SMF_UECM_STATE_DEREG_BY_AMF) {
/* /*
* Handle deregistration states SMF_UECM_STATE_DEREG_BY_AMF and * Handle deregistration states SMF_UECM_STATE_DEREG_BY_AMF and

View File

@@ -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"), "}", "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", "{", "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"), "}", "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", "{", "security", "{",
@@ -1876,6 +1886,11 @@ bson_t *test_db_new_session(test_ue_t *test_ue)
"pre_emption_capability", BCON_INT32(1), "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"), "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"), "}", "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), "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"), "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), "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"), "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), "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"), "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), "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"), "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), "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"), "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), "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"), "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"), "addr", BCON_UTF8("127.0.0.4"),
"addr6", BCON_UTF8("::1"), "addr6", BCON_UTF8("::1"),
"}", "}",
#if 1
"lbo_roaming_allowed", BCON_BOOL(true),
#else
"lbo_roaming_allowed", BCON_BOOL(false),
#endif
"}", "}",
"{", "{",
"name", BCON_UTF8("wlan"), "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
"}", "}",
"]", "]",
"}", "]", "}", "]",