diff --git a/lib/core/ogs-3gpp-types.h b/lib/core/ogs-3gpp-types.h index c643bf125..0e372412b 100644 --- a/lib/core/ogs-3gpp-types.h +++ b/lib/core/ogs-3gpp-types.h @@ -56,6 +56,8 @@ extern "C" { #define OGS_PLMN_ID_LEN 3 #define OGS_MAX_PLMN_ID_BCD_LEN 6 +#define OGS_CHRGCHARS_LEN 2 + #define OGS_BCD_TO_BUFFER_LEN(x) (((x)+1)/2) #define OGS_MAX_IMSI_BCD_LEN 15 #define OGS_MAX_IMSI_LEN \ @@ -453,6 +455,9 @@ typedef struct ogs_session_s { uint32_t context_identifier; /* EPC */ bool default_dnn_indicator; /* 5GC */ + uint8_t charging_characteristics[OGS_CHRGCHARS_LEN]; + bool charging_characteristics_presence; + #define OGS_PDU_SESSION_TYPE_IPV4 1 #define OGS_PDU_SESSION_TYPE_IPV6 2 #define OGS_PDU_SESSION_TYPE_IPV4V6 3 diff --git a/lib/diameter/s6a/message.c b/lib/diameter/s6a/message.c index 3b60e8070..38f370348 100644 --- a/lib/diameter/s6a/message.c +++ b/lib/diameter/s6a/message.c @@ -57,6 +57,7 @@ struct dict_object *ogs_diam_s6a_apn_configuration = NULL; struct dict_object *ogs_diam_s6a_max_bandwidth_ul = NULL; struct dict_object *ogs_diam_s6a_max_bandwidth_dl = NULL; struct dict_object *ogs_diam_s6a_pdn_type = NULL; +struct dict_object *ogs_diam_s6a_3gpp_charging_characteristics = NULL; struct dict_object *ogs_diam_s6a_served_party_ip_address = NULL; struct dict_object *ogs_diam_s6a_eps_subscribed_qos_profile = NULL; struct dict_object *ogs_diam_s6a_qos_class_identifier = NULL; @@ -125,6 +126,7 @@ int ogs_diam_s6a_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "All-APN-Configurations-Included-Indicator", &ogs_diam_s6a_all_apn_configuration_included_indicator); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "APN-Configuration", &ogs_diam_s6a_apn_configuration); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "PDN-Type", &ogs_diam_s6a_pdn_type); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "3GPP-Charging-Characteristics", &ogs_diam_s6a_3gpp_charging_characteristics); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Served-Party-IP-Address", &ogs_diam_s6a_served_party_ip_address); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Subscription-Data", &ogs_diam_s6a_subscription_data); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Subscriber-Status", &ogs_diam_s6a_subscriber_status); diff --git a/lib/diameter/s6a/message.h b/lib/diameter/s6a/message.h index 7ddff6229..583447e0d 100644 --- a/lib/diameter/s6a/message.h +++ b/lib/diameter/s6a/message.h @@ -103,6 +103,7 @@ extern struct dict_object *ogs_diam_s6a_apn_configuration; extern struct dict_object *ogs_diam_s6a_max_bandwidth_ul; extern struct dict_object *ogs_diam_s6a_max_bandwidth_dl; extern struct dict_object *ogs_diam_s6a_pdn_type; +extern struct dict_object *ogs_diam_s6a_3gpp_charging_characteristics; extern struct dict_object *ogs_diam_s6a_served_party_ip_address; extern struct dict_object *ogs_diam_s6a_eps_subscribed_qos_profile; extern struct dict_object *ogs_diam_s6a_qos_class_identifier; diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index aecfee3c0..d8414ff88 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -422,6 +422,8 @@ struct mme_ue_s { /* HSS Info */ ogs_bitrate_t ambr; /* UE-AMBR */ uint32_t network_access_mode; /* Permitted EPS Attach Type */ + uint8_t charging_characteristics[OGS_CHRGCHARS_LEN]; /* Subscription Level Charging Characteristics */ + bool charging_characteristics_presence; uint32_t context_identifier; /* default APN */ diff --git a/src/mme/mme-fd-path.c b/src/mme/mme-fd-path.c index 8bb19c305..6336e3b84 100644 --- a/src/mme/mme-fd-path.c +++ b/src/mme/mme-fd-path.c @@ -593,6 +593,8 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) { int ret; + char buf[OGS_CHRGCHARS_LEN]; + struct sess_state *sess_data = NULL; struct timespec ts; struct session *session; @@ -795,6 +797,26 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) ogs_warn("no subscribed Network-Access-Mode, defaulting to PACKET_AND_CIRCUIT (0)"); } + /* AVP: '3GPP-Charging-Characteristics'(13) + * For GGSN, it contains the charging characteristics for + * this PDP Context received in the Create PDP Context + * Request Message (only available in R99 and later releases). + * For PGW, it contains the charging characteristics for the + * IP-CAN bearer. + * Reference: 3GPP TS 29.061 16.4.7.2 13 + */ + ret = fd_avp_search_avp(avp, ogs_diam_s6a_3gpp_charging_characteristics, &avpch1); + ogs_assert(ret == 0); + if (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + memcpy(mme_ue->charging_characteristics, + OGS_HEX(hdr->avp_value->os.data, (int)hdr->avp_value->os.len, buf), OGS_CHRGCHARS_LEN); + mme_ue->charging_characteristics_presence = true; + } else { + memcpy(mme_ue->charging_characteristics, (uint8_t *)"\x00\x00", OGS_CHRGCHARS_LEN); + mme_ue->charging_characteristics_presence = false; + } + /* AVP: 'AMBR'(1435) * The Amber AVP contains the Max-Requested-Bandwidth-UL and * Max-Requested-Bandwidth-DL AVPs. @@ -984,6 +1006,27 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) error++; } + /* AVP: '3GPP-Charging-Characteristics'(13) + * For GGSN, it contains the charging characteristics for + * this PDP Context received in the Create PDP Context + * Request Message (only available in R99 and later releases). + * For PGW, it contains the charging characteristics for the + * IP-CAN bearer. + * Reference: 3GPP TS 29.061 16.4.7.2 13 + */ + ret = fd_avp_search_avp(avpch2, ogs_diam_s6a_3gpp_charging_characteristics, + &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_msg_avp_hdr(avpch3, &hdr); + memcpy(session->charging_characteristics, + OGS_HEX(hdr->avp_value->os.data, (int)hdr->avp_value->os.len, buf), OGS_CHRGCHARS_LEN); + session->charging_characteristics_presence = true; + } else { + memcpy(session->charging_characteristics, mme_ue->charging_characteristics, OGS_CHRGCHARS_LEN); + session->charging_characteristics_presence = mme_ue->charging_characteristics_presence; + } + /* AVP: 'Served-Party-IP-Address'(848) * The Served-Party-IP-Address AVP holds the IP address of * either the calling or called party, depending on whether diff --git a/src/mme/mme-s11-build.c b/src/mme/mme-s11-build.c index da21d3a3c..7e142176c 100644 --- a/src/mme/mme-s11-build.c +++ b/src/mme/mme-s11-build.c @@ -330,9 +330,11 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( req->ue_time_zone.data = &ue_timezone; req->ue_time_zone.len = sizeof(ue_timezone); - req->charging_characteristics.presence = 1; - req->charging_characteristics.data = (uint8_t *)"\x54\x00"; - req->charging_characteristics.len = 2; + if (session->charging_characteristics_presence == true) { + req->charging_characteristics.presence = 1; + req->charging_characteristics.data = session->charging_characteristics; + req->charging_characteristics.len = 2; + } gtp_message.h.type = type; return ogs_gtp2_build_msg(>p_message); diff --git a/src/mme/mme-s6a-handler.c b/src/mme/mme-s6a-handler.c index 1864b7790..572295d3f 100644 --- a/src/mme/mme-s6a-handler.c +++ b/src/mme/mme-s6a-handler.c @@ -91,6 +91,11 @@ void mme_s6a_handle_ula(mme_ue_t *mme_ue, memcpy(&mme_ue->session[i].smf_ip, &slice_data->session[i].smf_ip, sizeof(mme_ue->session[i].smf_ip)); + + memcpy(&mme_ue->session[i].charging_characteristics, &slice_data->session[i].charging_characteristics, + sizeof(mme_ue->session[i].charging_characteristics)); + mme_ue->session[i].charging_characteristics_presence = + slice_data->session[i].charging_characteristics_presence; } mme_ue->num_of_session = i;