From e8d6b0be20bd018dcdee02dd014b88c2b3ad62fb Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Wed, 11 May 2022 08:53:24 +0200 Subject: [PATCH] [SMF] Append PDP-Address AVP to Gy CCR msg (#1527) * [SMF] Append PDP-Address AVP to Gy CCR msg * [SMF] Gy CCR: Move some AVPs under Service-Information/PS-Information They belong there. Nokia infocenter documentation seems to be document the possibility to configure its software to have it in top level, but that's not what 3GPP TS 32.299 states, so let's stick to it. * [SMF] Gy CCR: append 3GPP-PDP-Type AVP * [SMF] Gy CCR: append 3GPP-Charging-Id AVP * [SMF] Gy CCR: append SGSN-Address AVP * [SMF] Gy CCR: append GGSN-Address AVP --- lib/diameter/gy/message.c | 16 +++ lib/diameter/gy/message.h | 14 ++ src/smf/gy-path.c | 273 ++++++++++++++++++++++++++++---------- 3 files changed, 231 insertions(+), 72 deletions(-) diff --git a/lib/diameter/gy/message.c b/lib/diameter/gy/message.c index 00585583b7..920c365692 100644 --- a/lib/diameter/gy/message.c +++ b/lib/diameter/gy/message.c @@ -46,6 +46,14 @@ struct dict_object *ogs_diam_gy_cc_service_specific_units = NULL; struct dict_object *ogs_diam_gy_reporting_reason = NULL; struct dict_object *ogs_diam_gy_service_id = NULL; +struct dict_object *ogs_diam_gy_service_information = NULL; +struct dict_object *ogs_diam_gy_ps_information = NULL; +struct dict_object *ogs_diam_gy_3gpp_charging_id = NULL; +struct dict_object *ogs_diam_gy_3gpp_pdp_type = NULL; +struct dict_object *ogs_diam_gy_pdp_address = NULL; +struct dict_object *ogs_diam_gy_sgsn_address = NULL; +struct dict_object *ogs_diam_gy_ggsn_address = NULL; + struct dict_object *ogs_diam_gy_feature_list_id = NULL; struct dict_object *ogs_diam_gy_feature_list = NULL; struct dict_object *ogs_diam_gy_qos_information = NULL; @@ -98,6 +106,14 @@ int ogs_diam_gy_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Reporting-Reason", &ogs_diam_gy_reporting_reason); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Service-Identifier", &ogs_diam_gy_service_id); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Service-Information", &ogs_diam_gy_service_information); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "PS-Information", &ogs_diam_gy_ps_information); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "3GPP-Charging-Id", &ogs_diam_gy_3gpp_charging_id); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "3GPP-PDP-Type", &ogs_diam_gy_3gpp_pdp_type); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "PDP-Address", &ogs_diam_gy_pdp_address); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "SGSN-Address", &ogs_diam_gy_sgsn_address); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "GGSN-Address", &ogs_diam_gy_ggsn_address); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Feature-List-ID", &ogs_diam_gy_feature_list_id); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Feature-List", &ogs_diam_gy_feature_list); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "QoS-Information", &ogs_diam_gy_qos_information); diff --git a/lib/diameter/gy/message.h b/lib/diameter/gy/message.h index dd9ce5deda..e08e1a73c8 100644 --- a/lib/diameter/gy/message.h +++ b/lib/diameter/gy/message.h @@ -90,6 +90,20 @@ extern struct dict_object *ogs_diam_gy_reporting_reason; #define OGS_DIAM_GY_REPORTING_REASON_POOL_EXHAUSTED 8 #define OGS_DIAM_GY_REPORTING_REASON_UNUSED_QUOTA_TIMER 9 extern struct dict_object *ogs_diam_gy_service_id; +extern struct dict_object *ogs_diam_gy_service_information; +extern struct dict_object *ogs_diam_gy_ps_information; +extern struct dict_object *ogs_diam_gy_3gpp_charging_id; +extern struct dict_object *ogs_diam_gy_3gpp_pdp_type; +#define OGS_DIAM_GY_3GPP_PDP_TYPE_IPv4 0 +#define OGS_DIAM_GY_3GPP_PDP_TYPE_PPP 1 +#define OGS_DIAM_GY_3GPP_PDP_TYPE_IPv6 2 +#define OGS_DIAM_GY_3GPP_PDP_TYPE_IPv4v6 3 +#define OGS_DIAM_GY_3GPP_PDP_TYPE_NON_IP 4 +#define OGS_DIAM_GY_3GPP_PDP_TYPE_UNSTRUCTURED 5 +#define OGS_DIAM_GY_3GPP_PDP_TYPE_ETHERNET 6 +extern struct dict_object *ogs_diam_gy_pdp_address; +extern struct dict_object *ogs_diam_gy_sgsn_address; +extern struct dict_object *ogs_diam_gy_ggsn_address; extern struct dict_object *ogs_diam_gy_feature_list_id; extern struct dict_object *ogs_diam_gy_feature_list; extern struct dict_object *ogs_diam_gy_qos_information; diff --git a/src/smf/gy-path.c b/src/smf/gy-path.c index d3cad2864c..c2cd79002c 100644 --- a/src/smf/gy-path.c +++ b/src/smf/gy-path.c @@ -244,6 +244,205 @@ static void fill_multiple_services_credit_control_ccr(smf_sess_t *sess, ogs_assert(ret == 0); } +/* TS 32.299 7.2.192 Service-Information AVP for CCR */ +static void fill_service_information_ccr(smf_sess_t *sess, + uint32_t cc_request_type, struct msg *req) +{ + int ret; + union avp_value val; + struct avp *avp; + struct avp *avpch1, *avpch2; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + char buf[OGS_PLMNIDSTRLEN]; + + /* Service-Information, TS 32.299 sec 7.2.192 */ + ret = fd_msg_avp_new(ogs_diam_gy_service_information, 0, &avp); + + /* PS-Information, TS 32.299 sec 7.2.158 */ + ret = fd_msg_avp_new(ogs_diam_gy_ps_information, 0, &avpch1); + + /* 3GPP-Charging-Id, 3GPP TS 29.061 16.4.7.2 2 */ + ret = fd_msg_avp_new(ogs_diam_gy_3gpp_charging_id, 0, &avpch2); + ogs_assert(ret == 0); + val.u32 = sess->charging.id; + ret = fd_msg_avp_setvalue(avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + + /* 3GPP-PDP-Type, 3GPP TS 29.061 16.4.7.2 3 */ + if (cc_request_type == OGS_DIAM_GY_CC_REQUEST_TYPE_INITIAL_REQUEST) { + ret = fd_msg_avp_new(ogs_diam_gy_3gpp_pdp_type, 0, &avpch2); + ogs_assert(ret == 0); + switch (sess->session.session_type) { + case OGS_PDU_SESSION_TYPE_IPV4: + val.i32 = OGS_DIAM_GY_3GPP_PDP_TYPE_IPv4; + break; + case OGS_PDU_SESSION_TYPE_IPV6: + val.i32 = OGS_DIAM_GY_3GPP_PDP_TYPE_IPv6; + break; + case OGS_PDU_SESSION_TYPE_IPV4V6: + val.i32 = OGS_DIAM_GY_3GPP_PDP_TYPE_IPv4v6; + break; + case OGS_PDU_SESSION_TYPE_UNSTRUCTURED: + val.i32 = OGS_DIAM_GY_3GPP_PDP_TYPE_UNSTRUCTURED; + break; + case OGS_PDU_SESSION_TYPE_ETHERNET: + val.i32 = OGS_DIAM_GY_3GPP_PDP_TYPE_ETHERNET; + break; + default: + val.i32 = OGS_DIAM_GY_3GPP_PDP_TYPE_NON_IP; + } + ret = fd_msg_avp_setvalue(avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + } + + /* PDP-Address, TS 32.299 7.2.137 */ + if (sess->ipv4) { + ret = fd_msg_avp_new(ogs_diam_gy_pdp_address, 0, &avpch2); + sin.sin_family = AF_INET; + memcpy(&sin.sin_addr.s_addr, (uint8_t*)&sess->ipv4->addr[0], OGS_IPV4_LEN); + ret = fd_msg_avp_value_encode(&sin, avpch2); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + } + if (sess->ipv6) { + ret = fd_msg_avp_new(ogs_diam_gy_pdp_address, 0, &avpch2); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr.s6_addr, (uint8_t*)&sess->ipv6->addr[0], OGS_IPV6_LEN); + ret = fd_msg_avp_value_encode(&sin6, avpch2); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + /* PDP-Address-Prefix-Length, TS 32.299 7.2.137 */ + /* TODO: not yet needed since used OGS_IPV6_DEFAULT_PREFIX_LEN is 64. + if (OGS_IPV6_DEFAULT_PREFIX_LEN != 64) { + .u32 = sess->ipv6->subnet->prefixlen; + } + */ + } + + /* SGSN-Address */ + if (sess->sgw_s5c_ip.ipv4) { + ret = fd_msg_avp_new(ogs_diam_gy_sgsn_address, 0, &avpch2); + sin.sin_family = AF_INET; + memcpy(&sin.sin_addr.s_addr, (uint8_t*)&sess->sgw_s5c_ip.addr, OGS_IPV4_LEN); + ret = fd_msg_avp_value_encode(&sin, avpch2); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + } + if (sess->sgw_s5c_ip.ipv6) { + ret = fd_msg_avp_new(ogs_diam_gy_sgsn_address, 0, &avpch2); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr.s6_addr, (uint8_t*)&sess->sgw_s5c_ip.addr6[0], OGS_IPV6_LEN); + ret = fd_msg_avp_value_encode(&sin6, avpch2); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + } + + /* GGSN-Address */ + if (ogs_gtp_self()->gtpc_addr) { + ret = fd_msg_avp_new(ogs_diam_gy_ggsn_address, 0, &avpch2); + ogs_assert(ret == 0); + ret = fd_msg_avp_value_encode(&ogs_gtp_self()->gtpc_addr->sin, avpch2); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + } + if (ogs_gtp_self()->gtpc_addr6) { + ret = fd_msg_avp_new(ogs_diam_gy_ggsn_address, 0, &avpch2); + ogs_assert(ret == 0); + ret = fd_msg_avp_value_encode(&ogs_gtp_self()->gtpc_addr->sin6, avpch2); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + } + + /* Called-Station-Id */ + ret = fd_msg_avp_new(ogs_diam_gy_called_station_id, 0, &avpch2); + ogs_assert(ret == 0); + ogs_assert(sess->session.name); + val.os.data = (uint8_t*)sess->session.name; + val.os.len = strlen(sess->session.name); + ret = fd_msg_avp_setvalue(avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + + /* 3GPP-SGSN-MCC-MNC */ + ret = fd_msg_avp_new(ogs_diam_gy_3gpp_sgsn_mcc_mnc, 0, &avpch2); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)ogs_plmn_id_to_string(&sess->plmn_id, buf); + val.os.len = strlen(buf); + ret = fd_msg_avp_setvalue(avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + + /* 3GPP-MS-Timezone */ + if (sess->gtp.ue_timezone.presence && + sess->gtp.ue_timezone.len && sess->gtp.ue_timezone.data) { + ret = fd_msg_avp_new(ogs_diam_gy_3gpp_ms_timezone, 0, &avpch2); + ogs_assert(ret == 0); + val.os.data = sess->gtp.ue_timezone.data; + val.os.len = sess->gtp.ue_timezone.len; + ret = fd_msg_avp_setvalue(avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + } + + /* 3GPP-User-Location-Info */ + if (sess->gtp.user_location_information.presence) { + ogs_gtp2_uli_t uli; + int16_t uli_len; + + uint8_t uli_buf[OGS_GTP2_MAX_ULI_LEN]; + + uli_len = ogs_gtp2_parse_uli( + &uli, &sess->gtp.user_location_information); + ogs_assert(sess->gtp.user_location_information.len == uli_len); + + ogs_assert(sess->gtp.user_location_information.data); + ogs_assert(sess->gtp.user_location_information.len); + memcpy(&uli_buf, sess->gtp.user_location_information.data, + sess->gtp.user_location_information.len); + + /* Update Gy ULI Type */ + if (uli.flags.tai && uli.flags.e_cgi) + uli_buf[0] = + OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI; + else if (uli.flags.tai) + uli_buf[0] = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI; + else if (uli.flags.e_cgi) + uli_buf[0] = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_ECGI; + + if (uli_buf[0]) { + ret = fd_msg_avp_new( + ogs_diam_gy_3gpp_user_location_info, 0, &avpch2); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)&uli_buf; + val.os.len = sess->gtp.user_location_information.len; + ret = fd_msg_avp_setvalue(avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + } + } + + /* PS-Information AVP add to req: */ + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + + /* Service-Information AVP add to req: */ + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); +} + /* 3GPP TS 32.299 6.4.2 Credit-Control-Request message */ void smf_gy_send_ccr(smf_sess_t *sess, void *xact, uint32_t cc_request_type) @@ -258,7 +457,6 @@ void smf_gy_send_ccr(smf_sess_t *sess, void *xact, struct sess_state *sess_data = NULL, *svg; struct session *session = NULL; int new; - char buf[OGS_PLMNIDSTRLEN]; const char *service_context_id = "open5gs-smfd@open5gs.org"; uint32_t timestamp; @@ -550,77 +748,8 @@ void smf_gy_send_ccr(smf_sess_t *sess, void *xact, /* OC-Supported-Features */ - /* 3GPP-User-Location-Info */ - if (sess->gtp.user_location_information.presence) { - ogs_gtp2_uli_t uli; - int16_t uli_len; - - uint8_t uli_buf[OGS_GTP2_MAX_ULI_LEN]; - - uli_len = ogs_gtp2_parse_uli( - &uli, &sess->gtp.user_location_information); - ogs_assert(sess->gtp.user_location_information.len == uli_len); - - ogs_assert(sess->gtp.user_location_information.data); - ogs_assert(sess->gtp.user_location_information.len); - memcpy(&uli_buf, sess->gtp.user_location_information.data, - sess->gtp.user_location_information.len); - - /* Update Gy ULI Type */ - if (uli.flags.tai && uli.flags.e_cgi) - uli_buf[0] = - OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI; - else if (uli.flags.tai) - uli_buf[0] = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI; - else if (uli.flags.e_cgi) - uli_buf[0] = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_ECGI; - - if (uli_buf[0]) { - ret = fd_msg_avp_new( - ogs_diam_gy_3gpp_user_location_info, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)&uli_buf; - val.os.len = sess->gtp.user_location_information.len; - 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); - } - } - - /* 3GPP-MS-Timezone */ - if (sess->gtp.ue_timezone.presence && - sess->gtp.ue_timezone.len && sess->gtp.ue_timezone.data) { - ret = fd_msg_avp_new(ogs_diam_gy_3gpp_ms_timezone, 0, &avp); - ogs_assert(ret == 0); - val.os.data = sess->gtp.ue_timezone.data; - val.os.len = sess->gtp.ue_timezone.len; - 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); - } - - /* 3GPP-SGSN-MCC-MNC */ - ret = fd_msg_avp_new(ogs_diam_gy_3gpp_sgsn_mcc_mnc, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)ogs_plmn_id_to_string(&sess->plmn_id, buf); - val.os.len = strlen(buf); - 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); - - /* Called-Station-Id */ - ret = fd_msg_avp_new(ogs_diam_gy_called_station_id, 0, &avp); - ogs_assert(ret == 0); - ogs_assert(sess->session.name); - val.os.data = (uint8_t*)sess->session.name; - val.os.len = strlen(sess->session.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); + /* Service-Information */ + fill_service_information_ccr(sess, cc_request_type, req); ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts);