mirror of
https://github.com/open5gs/open5gs.git
synced 2025-11-03 13:33:26 +00:00
[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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(>p_message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user