[ePDG] Add Node-Identifier IE support in GTPv2 S2b Create-Session-Request for SMF Diameter S6b Routing (#3507)

Implement support for Node-Identifier IE in GTPv2 S2b Create-Session-Request
to SMF for Diameter S6b integration

This patch adds support for processing the Node-Identifier IE within GTPv2
Create-Session-Request messages sent via the S2b interface to the SMF.
When the ePDG includes the Node-Identifier IE containing both host and realm
of the AAA-Server, the SMF now uses this information to populate
the Destination-Realm and Destination-Host AVPs in the Diameter S6b AAR message.

This enables seamless integration and allows the SMF to route requests directly
to the appropriate AAA-Server, enhancing interoperability in setups
where the host and realm data are required by the Diameter network.
This commit is contained in:
Sukchan Lee
2024-10-31 22:20:06 +09:00
parent ce36143f5c
commit bc02e48d1a
7 changed files with 186 additions and 5 deletions

View File

@@ -26,13 +26,15 @@
int16_t ogs_gtp2_parse_bearer_qos(
ogs_gtp2_bearer_qos_t *bearer_qos, ogs_tlv_octet_t *octet)
{
ogs_gtp2_bearer_qos_t *source = (ogs_gtp2_bearer_qos_t *)octet->data;
ogs_gtp2_bearer_qos_t *source = NULL;
int16_t size = 0;
ogs_assert(bearer_qos);
ogs_assert(octet);
ogs_assert(octet->len == GTP2_BEARER_QOS_LEN);
source = (ogs_gtp2_bearer_qos_t *)octet->data;
memset(bearer_qos, 0, sizeof(ogs_gtp2_bearer_qos_t));
bearer_qos->pre_emption_capability = source->pre_emption_capability;
@@ -201,13 +203,15 @@ uint64_t ogs_gtp2_qos_to_kbps(uint8_t br, uint8_t extended, uint8_t extended2)
int16_t ogs_gtp2_parse_flow_qos(
ogs_gtp2_flow_qos_t *flow_qos, ogs_tlv_octet_t *octet)
{
ogs_gtp2_flow_qos_t *source = (ogs_gtp2_flow_qos_t *)octet->data;
ogs_gtp2_flow_qos_t *source = NULL;
int16_t size = 0;
ogs_assert(flow_qos);
ogs_assert(octet);
ogs_assert(octet->len == GTP2_FLOW_QOS_LEN);
source = (ogs_gtp2_flow_qos_t *)octet->data;
memset(flow_qos, 0, sizeof(ogs_gtp2_flow_qos_t));
flow_qos->qci = source->qci;
@@ -617,12 +621,14 @@ int16_t ogs_gtp2_build_tft(
/* 8.21 User Location Information (ULI) */
int16_t ogs_gtp2_parse_uli(ogs_gtp2_uli_t *uli, ogs_tlv_octet_t *octet)
{
ogs_gtp2_uli_t *source = (ogs_gtp2_uli_t *)octet->data;
ogs_gtp2_uli_t *source = NULL;
int16_t size = 0;
ogs_assert(uli);
ogs_assert(octet);
source = (ogs_gtp2_uli_t *)octet->data;
memset(uli, 0, sizeof(ogs_gtp2_uli_t));
uli->flags = source->flags;
@@ -796,3 +802,95 @@ int16_t ogs_gtp2_build_uli(
return octet->len;
}
int16_t ogs_gtp2_parse_node_identifier(
ogs_gtp2_node_identifier_t *node_identifier, ogs_tlv_octet_t *octet)
{
int16_t size = 0;
ogs_assert(node_identifier);
ogs_assert(octet);
memset(node_identifier, 0, sizeof(ogs_gtp2_node_identifier_t));
if (size + sizeof(node_identifier->name_len) > octet->len) {
ogs_error("Invalid TLV length [%d != %d]", size, octet->len);
ogs_log_hexdump(OGS_LOG_ERROR, octet->data, octet->len);
return size;
}
memcpy(&node_identifier->name_len,
(unsigned char *)octet->data + size,
sizeof(node_identifier->name_len));
size += sizeof(node_identifier->name_len);
if (size + node_identifier->name_len > octet->len) {
ogs_error("Invalid TLV length [%d != %d]", size, octet->len);
ogs_log_hexdump(OGS_LOG_ERROR, octet->data, octet->len);
return size;
}
node_identifier->name = (char *)octet->data + size;
size += node_identifier->name_len;
if (size + sizeof(node_identifier->realm_len) > octet->len) {
ogs_error("Invalid TLV length [%d != %d]", size, octet->len);
ogs_log_hexdump(OGS_LOG_ERROR, octet->data, octet->len);
return size;
}
memcpy(&node_identifier->realm_len,
(unsigned char *)octet->data + size,
sizeof(node_identifier->realm_len));
size += sizeof(node_identifier->realm_len);
if (size + node_identifier->realm_len > octet->len) {
ogs_error("Invalid TLV length [%d != %d]", size, octet->len);
ogs_log_hexdump(OGS_LOG_ERROR, octet->data, octet->len);
return size;
}
node_identifier->realm = (char *)octet->data + size;
size += node_identifier->realm_len;
if (size != octet->len) {
ogs_error("Invalid TLV length [%d != %d]", size, octet->len);
ogs_log_hexdump(OGS_LOG_ERROR, octet->data, octet->len);
}
return size;
}
int16_t ogs_gtp2_build_node_identifier(ogs_tlv_octet_t *octet,
ogs_gtp2_node_identifier_t *node_identifier, void *data, int data_len)
{
int16_t size = 0;
ogs_assert(node_identifier);
ogs_assert(octet);
ogs_assert(data);
ogs_assert(data_len);
octet->data = data;
ogs_assert(size + sizeof(node_identifier->name_len) <= data_len);
memcpy((unsigned char *)octet->data + size,
&node_identifier->name_len,
sizeof(node_identifier->name_len));
size += sizeof(node_identifier->name_len);
ogs_assert(size + node_identifier->name_len <= data_len);
memcpy((unsigned char *)octet->data + size,
node_identifier->name, node_identifier->name_len);
size += node_identifier->name_len;
ogs_assert(size + sizeof(node_identifier->realm_len) <= data_len);
memcpy((unsigned char *)octet->data + size,
&node_identifier->realm_len,
sizeof(node_identifier->realm_len));
size += sizeof(node_identifier->realm_len);
ogs_assert(size + node_identifier->realm_len <= data_len);
memcpy((unsigned char *)octet->data + size,
node_identifier->realm, node_identifier->realm_len);
size += node_identifier->realm_len;
octet->len = size;
return octet->len;
}

View File

@@ -571,6 +571,20 @@ ED5(uint8_t spare1:1;,
uint8_t pre_emption_capability:1;)
} __attribute__ ((packed)) ogs_gtp2_arp_t;
/* 8.107 Node Identifier */
#define OGS_GTP2_MAX_NODE_IDENTIFIER_LEN (1+OGS_MAX_FQDN_LEN)*2
typedef struct ogs_gtp2_node_identifier_s {
uint8_t name_len;
char *name;
uint8_t realm_len;
char *realm;
} ogs_gtp2_node_identifier_t;
int16_t ogs_gtp2_parse_node_identifier(
ogs_gtp2_node_identifier_t *node_identifier, ogs_tlv_octet_t *octet);
int16_t ogs_gtp2_build_node_identifier(ogs_tlv_octet_t *octet,
ogs_gtp2_node_identifier_t *node_identifier, void *data, int data_len);
#ifdef __cplusplus
}
#endif

View File

@@ -1791,6 +1791,11 @@ void smf_sess_remove(smf_sess_t *sess)
/* Free SBI object memory */
ogs_sbi_object_free(&sess->sbi);
if (sess->aaa_server_identifier.name)
ogs_free(sess->aaa_server_identifier.name);
if (sess->aaa_server_identifier.realm)
ogs_free(sess->aaa_server_identifier.realm);
smf_bearer_remove_all(sess);
ogs_assert(sess->pfcp.bar);

View File

@@ -486,6 +486,12 @@ typedef struct smf_sess_s {
uint32_t id;
} charging;
/* AAA Node Identifier */
struct {
char *name;
char *realm;
} aaa_server_identifier;
/* Data Forwarding between the CP and UP functions */
ogs_pfcp_pdr_t *cp2up_pdr;
ogs_pfcp_pdr_t *up2cp_pdr;

View File

@@ -445,6 +445,34 @@ uint8_t smf_s5c_handle_create_session_request(
smf_ue->imeisv, smf_ue->imeisv_len, smf_ue->imeisv_bcd);
}
/* Set Node Identifier */
if (req->_aaa_server_identifier.presence) {
ogs_gtp2_node_identifier_t node_identifier;
decoded = ogs_gtp2_parse_node_identifier(
&node_identifier, &req->_aaa_server_identifier);
if (req->_aaa_server_identifier.len == decoded) {
if (sess->aaa_server_identifier.name)
ogs_free(sess->aaa_server_identifier.name);
sess->aaa_server_identifier.name = ogs_memdup(
node_identifier.name, node_identifier.name_len+1);
ogs_assert(sess->aaa_server_identifier.name);
sess->aaa_server_identifier.name[node_identifier.name_len] = 0;
if (sess->aaa_server_identifier.realm)
ogs_free(sess->aaa_server_identifier.realm);
sess->aaa_server_identifier.realm = ogs_memdup(
node_identifier.realm, node_identifier.realm_len+1);
ogs_assert(sess->aaa_server_identifier.realm);
sess->aaa_server_identifier.realm[node_identifier.realm_len] = 0;
} else {
ogs_error("Invalid AAA Server Identifier [%d != %d]",
req->_aaa_server_identifier.len, decoded);
ogs_log_hexdump(OGS_LOG_ERROR,
req->_aaa_server_identifier.data,
req->_aaa_server_identifier.len);
}
}
return OGS_GTP2_CAUSE_REQUEST_ACCEPTED;
}

View File

@@ -176,11 +176,28 @@ void smf_s6b_send_aar(smf_sess_t *sess, ogs_gtp_xact_t *xact)
ret = fd_msg_add_origin(req, 0);
ogs_assert(ret == 0);
/* Set the Destination-Host AVP */
if (sess->aaa_server_identifier.name) {
ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)sess->aaa_server_identifier.name;
val.os.len = strlen(sess->aaa_server_identifier.name);
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
}
/* Set the Destination-Realm AVP */
ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp);
ogs_assert(ret == 0);
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
if (sess->aaa_server_identifier.realm) {
val.os.data = (unsigned char *)(sess->aaa_server_identifier.realm);
val.os.len = strlen(sess->aaa_server_identifier.realm);
} else {
val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm);
val.os.len = strlen(fd_g_config->cnf_diamrlm);
}
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp);

View File

@@ -46,6 +46,9 @@ ogs_pkbuf_t *test_s2b_build_create_session_request(
ogs_gtp2_indication_t indication;
char node_identifier_buf[OGS_GTP2_MAX_NODE_IDENTIFIER_LEN];
ogs_gtp2_node_identifier_t node_identifier;
ogs_assert(sess);
test_ue = sess->test_ue;
ogs_assert(test_ue);
@@ -172,6 +175,16 @@ ogs_pkbuf_t *test_s2b_build_create_session_request(
(uint8_t *)"\x80\x00\x0d\x00";
req->additional_protocol_configuration_options.len = 4;
memset(&node_identifier, 0, sizeof(ogs_gtp2_node_identifier_t));
node_identifier.name = "aaa.localdomain";
node_identifier.name_len = strlen(node_identifier.name);
node_identifier.realm = "localdomain";
node_identifier.realm_len = strlen(node_identifier.realm);
req->_aaa_server_identifier.presence = 1;
ogs_gtp2_build_node_identifier(
&req->_aaa_server_identifier, &node_identifier,
node_identifier_buf, OGS_GTP2_MAX_NODE_IDENTIFIER_LEN);
gtp_message.h.type = type;
return ogs_gtp2_build_msg(&gtp_message);
}