diff --git a/src/smf/context.h b/src/smf/context.h index c2b765d50..bc3e937aa 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -330,6 +330,7 @@ typedef struct smf_sess_s { uint8_t selection_mode; /* OGS_GTP{1,2}_SELECTION_MODE_*, same in GTPv1C and 2C. */ struct { uint8_t nsapi; + bool peer_supports_apn_ambr; } v1; /* GTPv1C specific fields */ } gtp; /* Saved from S5-C/Gn */ diff --git a/src/smf/gn-build.c b/src/smf/gn-build.c index 8593f4038..bc4f734c3 100644 --- a/src/smf/gn-build.c +++ b/src/smf/gn-build.c @@ -269,12 +269,14 @@ ogs_pkbuf_t *smf_gn_build_create_pdp_context_response( /* TODO: Extended Common Flag */ /* TODO: CSG Information Reporting Action */ - /* APN-AMBR + /* APN-AMBR, TS 29.060 7.7.98 * if PCRF changes APN-AMBR, this should be included. */ - if (sess->gtp.create_session_response_apn_ambr == true) { + if (sess->gtp.v1.peer_supports_apn_ambr == true && + sess->gtp.create_session_response_apn_ambr == true) { memset(&ambr, 0, sizeof(ogs_gtp1_apn_ambr_t)); - ambr.uplink = htobe32(sess->session.ambr.uplink / 1000); - ambr.downlink = htobe32(sess->session.ambr.downlink / 1000); + /* "the values [...] shall be rounded upwards" */ + ambr.uplink = htobe32((sess->session.ambr.uplink + 999)/ 1000); + ambr.downlink = htobe32((sess->session.ambr.downlink + 999) / 1000); rsp->apn_ambr.presence = 1; rsp->apn_ambr.data = &ambr; rsp->apn_ambr.len = sizeof(ambr); @@ -456,12 +458,14 @@ ogs_pkbuf_t *smf_gn_build_update_pdp_context_response( /* TODO: Evolved Allocation/Retention Priority I */ /* TODO: CSG Information Reporting Action */ - /* APN-AMBR + /* APN-AMBR, TS 29.060 7.7.98 * if PCRF changes APN-AMBR, this should be included. */ - if (sess->gtp.create_session_response_apn_ambr == true) { + if (sess->gtp.v1.peer_supports_apn_ambr == true && + sess->gtp.create_session_response_apn_ambr == true) { memset(&ambr, 0, sizeof(ogs_gtp1_apn_ambr_t)); - ambr.uplink = htobe32(sess->session.ambr.uplink / 1000); - ambr.downlink = htobe32(sess->session.ambr.downlink / 1000); + /* "the values [...] shall be rounded upwards" */ + ambr.uplink = htobe32((sess->session.ambr.uplink + 999)/ 1000); + ambr.downlink = htobe32((sess->session.ambr.downlink + 999) / 1000); rsp->apn_ambr.presence = 1; rsp->apn_ambr.data = &ambr; rsp->apn_ambr.len = sizeof(ambr); diff --git a/src/smf/gn-handler.c b/src/smf/gn-handler.c index 3498f4296..76e2459b4 100644 --- a/src/smf/gn-handler.c +++ b/src/smf/gn-handler.c @@ -178,6 +178,10 @@ uint8_t smf_gn_handle_create_pdp_context_request( smf_ue->msisdn, smf_ue->msisdn_len, smf_ue->msisdn_bcd); } + /* Set some sane default if infomation not present in Qos Profile or APN-AMBR: */ + sess->session.ambr.downlink = 102400000; + sess->session.ambr.uplink = 102400000; + /* Set Bearer QoS */ rv = ogs_gtp1_parse_qos_profile(&qos_pdec, &req->quality_of_service_profile); @@ -195,10 +199,19 @@ uint8_t smf_gn_handle_create_pdp_context_request( if (qos_pdec.data_octet6_to_13_present) { sess->session.ambr.downlink = qos_pdec.dec_mbr_kbps_dl * 1000; sess->session.ambr.uplink = qos_pdec.dec_mbr_kbps_ul * 1000; - } else { - /* Set some sane default if infomation not present in Qos Profile IE: */ - sess->session.ambr.downlink = 102400000; - sess->session.ambr.uplink = 102400000; + } + + /* APN-AMBR, 7.7.98 */ + if (req->apn_ambr.presence) { + /* "The APN-AMBR IE shall be included as the authorized APN-AMBR if the + * GGSN supports this IE and if the APN-AMBR IE has been included in the + * corresponding request message." */ + sess->gtp.v1.peer_supports_apn_ambr = true; + if (req->apn_ambr.len >= sizeof(ogs_gtp1_apn_ambr_t)) { + ogs_gtp1_apn_ambr_t *ambr = req->apn_ambr.data; + sess->session.ambr.uplink = be32toh(ambr->uplink) * 1000; + sess->session.ambr.downlink = be32toh(ambr->downlink) * 1000; + } } /* PCO */