From 46621538af656b63ae6b9a1e210d073a4668bb8f Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Tue, 17 May 2022 03:29:11 +0200 Subject: [PATCH] [SMF] Improve 3GPP-User-Location-Info in Gn,Gx,Gy (#1539) * [GTP] Fix trailing whitespace * [SMF] Improve 3GPP-User-Location-Info in Gn,Gx,Gy --- lib/diameter/gy/message.h | 13 ++++-- lib/gtp/v2/types.c | 30 +++++++++++--- lib/gtp/v2/types.h | 32 +++++++++++---- src/smf/fd-path.c | 86 +++++++++++++++++++++++++++++++++++++++ src/smf/fd-path.h | 2 + src/smf/gn-handler.c | 15 +++---- src/smf/gx-path.c | 39 +----------------- src/smf/gy-path.c | 39 +----------------- 8 files changed, 156 insertions(+), 100 deletions(-) diff --git a/lib/diameter/gy/message.h b/lib/diameter/gy/message.h index 75a289e44..36dae478b 100644 --- a/lib/diameter/gy/message.h +++ b/lib/diameter/gy/message.h @@ -125,9 +125,16 @@ extern struct dict_object *ogs_diam_gy_pre_emption_vulnerability; extern struct dict_object *ogs_diam_gy_apn_aggregate_max_bitrate_ul; extern struct dict_object *ogs_diam_gy_apn_aggregate_max_bitrate_dl; extern struct dict_object *ogs_diam_gy_3gpp_rat_type; -#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI 128 -#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_ECGI 129 -#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI 130 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_CGI 0 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_SAI 1 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_RAI 2 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI 128 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_ECGI 129 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI 130 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_ENODEB_ID 131 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ENODEB_ID 132 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_EXT_ENODEB_ID 133 +#define OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_EXT_ENODEB_ID 134 extern struct dict_object *ogs_diam_gy_3gpp_user_location_info; extern struct dict_object *ogs_diam_gy_called_station_id; extern struct dict_object *ogs_diam_gy_3gpp_ms_timezone; diff --git a/lib/gtp/v2/types.c b/lib/gtp/v2/types.c index 1e2d864a4..018b497ae 100644 --- a/lib/gtp/v2/types.c +++ b/lib/gtp/v2/types.c @@ -19,7 +19,7 @@ #include "ogs-gtp.h" -/* 8.13 Protocol Configuration Options (PCO) +/* 8.13 Protocol Configuration Options (PCO) * 10.5.6.3 Protocol configuration options in 3GPP TS 24.008 */ /* 8.15 Bearer Quality of Service (Bearer QoS) */ @@ -63,7 +63,7 @@ int16_t ogs_gtp2_parse_bearer_qos( size += 5; ogs_assert(size == octet->len); - + return size; } int16_t ogs_gtp2_build_bearer_qos(ogs_tlv_octet_t *octet, @@ -233,7 +233,7 @@ int16_t ogs_gtp2_parse_flow_qos( size += 5; ogs_assert(size == octet->len); - + return size; } int16_t ogs_gtp2_build_flow_qos(ogs_tlv_octet_t *octet, @@ -277,7 +277,7 @@ int16_t ogs_gtp2_build_flow_qos(ogs_tlv_octet_t *octet, return octet->len; } -/* 8.19 EPS Bearer Level Traffic Flow Template (Bearer TFT) +/* 8.19 EPS Bearer Level Traffic Flow Template (Bearer TFT) * See subclause 10.5.6.12 in 3GPP TS 24.008 [13]. */ int16_t ogs_gtp2_parse_tft(ogs_gtp2_tft_t *tft, ogs_tlv_octet_t *octet) { @@ -673,6 +673,16 @@ int16_t ogs_gtp2_parse_uli(ogs_gtp2_uli_t *uli, ogs_tlv_octet_t *octet) uli->lai.lac = be16toh(uli->lai.lac); size += sizeof(uli->lai); } + if (uli->flags.enodeb_id) { + ogs_assert(size + sizeof(uli->enodeb_id) <= octet->len); + memcpy(&uli->enodeb_id, + (unsigned char *)octet->data + size, sizeof(uli->enodeb_id)); + uli->enodeb_id.enodeb_id = be16toh(uli->enodeb_id.enodeb_id); + size += sizeof(uli->enodeb_id); + } + if (uli->flags.ext_enodeb_id) { /* TODO */ + ogs_error("Extended Macro eNodeB ID in ULI not implemented! see 3GPP TS 29.274 8.21.8"); + } ogs_assert(size == octet->len); @@ -714,7 +724,7 @@ int16_t ogs_gtp2_build_uli( size += sizeof(target.sai); } if (target.flags.rai) { - ogs_assert(size + sizeof(target.rai) <= data_len); + ogs_assert(size + sizeof(target.rai) <= data_len); target.rai.lac = htobe16(target.rai.lac); target.rai.rac = htobe16(target.rai.rac); memcpy((unsigned char *)octet->data + size, @@ -742,6 +752,16 @@ int16_t ogs_gtp2_build_uli( &target.lai, sizeof(target.lai)); size += sizeof(target.lai); } + if (target.flags.enodeb_id) { + ogs_assert(size + sizeof(target.enodeb_id) <= data_len); + target.enodeb_id.enodeb_id = htobe16(target.enodeb_id.enodeb_id); + memcpy((unsigned char *)octet->data + size, + &target.enodeb_id, sizeof(target.enodeb_id)); + size += sizeof(target.enodeb_id); + } + if (uli->flags.ext_enodeb_id) { /* TODO */ + ogs_error("Extended Macro eNodeB ID in ULI not implemented! see 3GPP TS 29.274 8.21.8"); + } octet->len = size; diff --git a/lib/gtp/v2/types.h b/lib/gtp/v2/types.h index e8554e6d7..592aef78d 100644 --- a/lib/gtp/v2/types.h +++ b/lib/gtp/v2/types.h @@ -389,15 +389,29 @@ typedef struct ogs_gtp2_uli_e_cgi_s { uint32_t cell_id; } __attribute__ ((packed)) ogs_gtp2_uli_e_cgi_t; +typedef struct ogs_gtp2_uli_enodeb_id_s { + ogs_nas_plmn_id_t nas_plmn_id; + uint16_t enodeb_id; +} __attribute__ ((packed)) ogs_gtp2_uli_enodeb_id_t; + +typedef struct ogs_gtp2_uli_ext_enodeb_id_s { + ogs_nas_plmn_id_t nas_plmn_id; + uint32_t enodeb_id; +} __attribute__ ((packed)) ogs_gtp2_uli_ext_enodeb_id_t; + typedef struct ogs_gtp2_uli_s { - struct { - ED7(uint8_t spare:2;, - uint8_t lai:1;, - uint8_t e_cgi:1;, - uint8_t tai:1;, - uint8_t rai:1;, - uint8_t sai:1;, - uint8_t cgi:1;) + union { + struct { + ED8(uint8_t ext_enodeb_id:1;, + uint8_t enodeb_id:1;, + uint8_t lai:1;, + uint8_t e_cgi:1;, + uint8_t tai:1;, + uint8_t rai:1;, + uint8_t sai:1;, + uint8_t cgi:1;) + }; + uint8_t octet; } flags; ogs_gtp2_uli_cgi_t cgi; ogs_gtp2_uli_sai_t sai; @@ -405,6 +419,8 @@ typedef struct ogs_gtp2_uli_s { ogs_gtp2_uli_tai_t tai; ogs_gtp2_uli_e_cgi_t e_cgi; ogs_gtp2_uli_lai_t lai; + ogs_gtp2_uli_enodeb_id_t enodeb_id; + ogs_gtp2_uli_ext_enodeb_id_t ext_enodeb_id; } ogs_gtp2_uli_t; int16_t ogs_gtp2_parse_uli(ogs_gtp2_uli_t *uli, ogs_tlv_octet_t *octet); diff --git a/src/smf/fd-path.c b/src/smf/fd-path.c index 622181278..cca7fd5dc 100644 --- a/src/smf/fd-path.c +++ b/src/smf/fd-path.c @@ -59,3 +59,89 @@ void smf_fd_final(void) ogs_diam_final(); } + +/* Append 3GPP-User-Location-Info, 3GPP TS 29.061 16.4.7.2 22 */ +void smf_fd_msg_avp_add_3gpp_uli(smf_sess_t *sess, struct avp *avp) +{ + struct avp *avpch1; + union avp_value val; + ogs_gtp2_uli_t uli; + int16_t uli_len; + uint8_t uli_buf[OGS_GTP2_MAX_ULI_LEN], reencoded_uli_buf[OGS_GTP2_MAX_ULI_LEN]; + uint8_t uli_type; + int ret; + ogs_gtp2_tlv_uli_t reencoded_uli; + + if (sess->gtp.user_location_information.presence == 0) + return; + + if (sess->gtp.version == 1) { + /* For GTPv1C, it's a 1-1 coding match with TS 29.060 7.7.51: */ + ret = fd_msg_avp_new( + ogs_diam_gy_3gpp_user_location_info, 0, &avpch1); + ogs_assert(ret == 0); + val.os.data = sess->gtp.user_location_information.data; + val.os.len = sess->gtp.user_location_information.len; + ret = fd_msg_avp_setvalue(avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + return; + } + + /* GTPv2C and Diameter 3GPP-User-Location-Information encoding don't match */ + 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.cgi) { + uli_type = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_CGI; + uli.flags.octet = 0; uli.flags.cgi = 1; + } else if (uli.flags.sai) { + uli_type = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_SAI; + uli.flags.octet = 0; uli.flags.sai = 1; + } else if (uli.flags.rai) { + uli_type = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_RAI; + uli.flags.octet = 0; uli.flags.rai = 1; + } else if (uli.flags.tai && uli.flags.e_cgi) { + uli_type = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI; + uli.flags.octet = 0; uli.flags.tai = 1; uli.flags.e_cgi = 1; + } else if (uli.flags.tai && uli.flags.enodeb_id) { + uli_type = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ENODEB_ID; + uli.flags.octet = 0; uli.flags.tai = 1; uli.flags.enodeb_id = 1; + } else if (uli.flags.tai && uli.flags.ext_enodeb_id) { + uli_type = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_EXT_ENODEB_ID; + uli.flags.octet = 0; uli.flags.tai = 1; uli.flags.ext_enodeb_id = 1; + } else if (uli.flags.tai) { + uli_type = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_TAI; + uli.flags.octet = 0; uli.flags.tai = 1; + } else if (uli.flags.e_cgi) { + uli_type = OGS_DIAM_GY_3GPP_USER_LOCATION_INFO_TYPE_ECGI; + uli.flags.octet = 0; uli.flags.e_cgi = 1; + } else { + ogs_error("Unexpected ULI content, unable to convert to Diameter!"); + return; + } + + /* Reencode ULI dropping unrelated values: */ + uli_len = ogs_gtp2_build_uli(&reencoded_uli, &uli, + reencoded_uli_buf, sizeof(reencoded_uli_buf)); + reencoded_uli_buf[0] = uli_type; + + ret = fd_msg_avp_new( + ogs_diam_gy_3gpp_user_location_info, 0, &avpch1); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)&reencoded_uli_buf; + val.os.len = uli_len; + ret = fd_msg_avp_setvalue(avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + +} diff --git a/src/smf/fd-path.h b/src/smf/fd-path.h index 571057ce8..9346da693 100644 --- a/src/smf/fd-path.h +++ b/src/smf/fd-path.h @@ -46,6 +46,8 @@ void smf_gy_send_ccr(smf_sess_t *sess, void *xact, void smf_s6b_send_aar(smf_sess_t *sess, ogs_gtp_xact_t *xact); void smf_s6b_send_str(smf_sess_t *sess, ogs_gtp_xact_t *xact, uint32_t cause); +void smf_fd_msg_avp_add_3gpp_uli(smf_sess_t *sess, struct avp *avp); + #ifdef __cplusplus } #endif diff --git a/src/smf/gn-handler.c b/src/smf/gn-handler.c index d554e6ff0..fea5bef85 100644 --- a/src/smf/gn-handler.c +++ b/src/smf/gn-handler.c @@ -141,10 +141,13 @@ uint8_t smf_gn_handle_create_pdp_context_request( ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); + /* User Location Information, TS 29.060 sec 7.7.51 */ + /* Note: the IE is content is different in GTPv1C and GTPv2C */ + OGS_TLV_STORE_DATA(&sess->gtp.user_location_information, + &req->user_location_information); if (ogs_gtp1_parse_uli(&uli, &req->user_location_information) == 0) return OGS_GTP1_CAUSE_MANDATORY_IE_INCORRECT; - /* TODO: Copy uli->cgi/sai/rai into sess-> */ switch (uli.geo_loc_type) { case OGS_GTP1_GEO_LOC_TYPE_CGI: ogs_nas_to_plmn_id(&sess->plmn_id, &uli.cgi.nas_plmn_id); @@ -155,6 +158,7 @@ uint8_t smf_gn_handle_create_pdp_context_request( case OGS_GTP1_GEO_LOC_TYPE_RAI: ogs_nas_to_plmn_id(&sess->plmn_id, &uli.rai.nas_plmn_id); break; + /* default: should not happen */ } /* Set MSISDN: */ @@ -203,15 +207,6 @@ uint8_t smf_gn_handle_create_pdp_context_request( &req->protocol_configuration_options); } -#if 0 - /* Set User Location Information */ - /* TODO: the IE is probably different between GTPv1C and GTPv2, see what needs to be adapted */ - if (req->user_location_information.presence) { - OGS_TLV_STORE_DATA(&sess->gtp.user_location_information, - &req->user_location_information); - } -#endif - /* Set UE Timezone */ if (req->ms_time_zone.presence) { /* value part is compatible between UE Time Zone and MS Time Zone */ diff --git a/src/smf/gx-path.c b/src/smf/gx-path.c index fb3b51927..1f4e22097 100644 --- a/src/smf/gx-path.c +++ b/src/smf/gx-path.c @@ -486,43 +486,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); ogs_assert(ret == 0); - /* Set 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 Gx ULI Type */ - if (uli.flags.tai && uli.flags.e_cgi) - uli_buf[0] = - OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI; - else if (uli.flags.tai) - uli_buf[0] = OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_TAI; - else if (uli.flags.e_cgi) - uli_buf[0] = OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_ECGI; - - if (uli_buf[0]) { - ret = fd_msg_avp_new( - ogs_diam_gx_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-User-Location-Info, 3GPP TS 29.061 16.4.7.2 22 */ + smf_fd_msg_avp_add_3gpp_uli(sess, avpch1); /* Set 3GPP-MS-Timezone */ if (sess->gtp.ue_timezone.presence && diff --git a/src/smf/gy-path.c b/src/smf/gy-path.c index 1faa9f824..c45497d29 100644 --- a/src/smf/gy-path.c +++ b/src/smf/gy-path.c @@ -466,43 +466,8 @@ static void fill_service_information_ccr(smf_sess_t *sess, 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); - } - } + /* 3GPP-User-Location-Info, 3GPP TS 29.061 16.4.7.2 22 */ + smf_fd_msg_avp_add_3gpp_uli(sess, avpch1); if (sess->smf_ue->imeisv_len > 0) { /* User-Equipment-Info, 3GPP TS 32.299 7.1.17 */