diff --git a/lib/pfcp/conv.c b/lib/pfcp/conv.c index e4c250e7a..46a9089be 100644 --- a/lib/pfcp/conv.c +++ b/lib/pfcp/conv.c @@ -286,23 +286,29 @@ int ogs_pfcp_user_plane_ip_resource_info_to_f_teid( ogs_pfcp_f_teid_t *f_teid, int *len) { const int hdr_len = 5; + int v4, v6; ogs_assert(info); ogs_assert(f_teid); + + v4 = info->v4 & f_teid->ipv4; + v6 = info->v6 & f_teid->ipv6; + ogs_assert(v4 || v6); + memset(f_teid, 0, sizeof *f_teid); - if (info->v4 && info->v6) { + if (v4 && v6) { f_teid->ipv4 = 1; f_teid->both.addr = info->addr; f_teid->ipv6 = 1; memcpy(f_teid->both.addr6, info->addr6, OGS_IPV6_LEN); *len = OGS_IPV4V6_LEN + hdr_len; - } else if (info->v4) { + } else if (v4) { f_teid->ipv4 = 1; f_teid->ipv6 = 0; f_teid->addr = info->addr; *len = OGS_IPV4_LEN + hdr_len; - } else if (info->v6) { + } else if (v6) { f_teid->ipv4 = 0; f_teid->ipv6 = 1; memcpy(f_teid->addr6, info->addr6, OGS_IPV6_LEN); diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index 0d043527d..cd5ebf1da 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -311,6 +311,20 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, return NULL; } + if (message->pdi.local_f_teid.presence) { + ogs_pfcp_f_teid_t f_teid; + + memcpy(&f_teid, message->pdi.local_f_teid.data, + message->pdi.local_f_teid.len); + if (f_teid.ipv4 == 0 && f_teid.ipv6 == 0) { + ogs_error("One of the IPv4 and IPv6 flags should be 1 " + "in the local F-TEID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_F_TEID_TYPE; + return NULL; + } + } + pdr->src_if = message->pdi.source_interface.u8; ogs_pfcp_rule_remove_all(pdr); @@ -437,6 +451,7 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, if (message->pdi.local_f_teid.presence) { pdr->f_teid_len = message->pdi.local_f_teid.len; memcpy(&pdr->f_teid, message->pdi.local_f_teid.data, pdr->f_teid_len); + ogs_assert(pdr->f_teid.ipv4 || pdr->f_teid.ipv6); pdr->f_teid.teid = be32toh(pdr->f_teid.teid); } @@ -522,8 +537,21 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_created_pdr(ogs_pfcp_sess_t *sess, } if (message->local_f_teid.presence) { + ogs_pfcp_f_teid_t f_teid; + + memcpy(&f_teid, message->local_f_teid.data, message->local_f_teid.len); + if (f_teid.ipv4 == 0 && f_teid.ipv6 == 0) { + ogs_error("One of the IPv4 and IPv6 flags should be 1 " + "in the local F-TEID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_F_TEID_TYPE; + + return NULL; + } + pdr->f_teid_len = message->local_f_teid.len; memcpy(&pdr->f_teid, message->local_f_teid.data, pdr->f_teid_len); + ogs_assert(pdr->f_teid.ipv4 || pdr->f_teid.ipv6); pdr->f_teid.teid = be32toh(pdr->f_teid.teid); } @@ -567,6 +595,20 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_update_pdr(ogs_pfcp_sess_t *sess, return NULL; } + if (message->pdi.local_f_teid.presence) { + ogs_pfcp_f_teid_t f_teid; + + memcpy(&f_teid, message->pdi.local_f_teid.data, + message->pdi.local_f_teid.len); + if (f_teid.ipv4 == 0 && f_teid.ipv6 == 0) { + ogs_error("One of the IPv4 and IPv6 flags should be 1 " + "in the local F-TEID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_F_TEID_TYPE; + return NULL; + } + } + pdr->src_if = message->pdi.source_interface.u8; ogs_pfcp_rule_remove_all(pdr); diff --git a/src/sgwc/context.c b/src/sgwc/context.c index c8091d471..d21c8b313 100644 --- a/src/sgwc/context.c +++ b/src/sgwc/context.c @@ -721,6 +721,22 @@ sgwc_tunnel_t *sgwc_tunnel_add( ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { + + /* TS 129 244 V16.5.0 8.2.3 + * + * At least one of the V4 and V6 flags shall be set to "1", + * and both may be set to "1" for both scenarios: + * + * - when the CP function is providing F-TEID, i.e. + * both IPv4 address field and IPv6 address field may be present; + * or + * - when the UP function is requested to allocate the F-TEID, + * i.e. when CHOOSE bit is set to "1", + * and the IPv4 address and IPv6 address fields are not present. + */ + + pdr->f_teid.ipv4 = 1; + pdr->f_teid.ipv6 = 1; pdr->f_teid.ch = 1; pdr->f_teid_len = 1; } else { diff --git a/src/sgwu/sxa-handler.c b/src/sgwu/sxa-handler.c index e756a78c3..b000626d6 100644 --- a/src/sgwu/sxa-handler.c +++ b/src/sgwu/sxa-handler.c @@ -120,6 +120,9 @@ void sgwu_sxa_handle_session_establishment_request( &ogs_gtp_self()->gtpu_resource_list, pdr->apn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { + ogs_assert( + (resource->info.v4 && pdr->f_teid.ipv4) || + (resource->info.v6 && pdr->f_teid.ipv6)); ogs_assert(OGS_OK == ogs_pfcp_user_plane_ip_resource_info_to_f_teid( &resource->info, &pdr->f_teid, &pdr->f_teid_len)); @@ -130,10 +133,15 @@ void sgwu_sxa_handle_session_establishment_request( else pdr->f_teid.teid = pdr->index; } else { + ogs_assert( + (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || + (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); ogs_assert(OGS_OK == ogs_pfcp_sockaddr_to_f_teid( - ogs_gtp_self()->gtpu_addr, - ogs_gtp_self()->gtpu_addr6, + pdr->f_teid.ipv4 ? + ogs_gtp_self()->gtpu_addr : NULL, + pdr->f_teid.ipv6 ? + ogs_gtp_self()->gtpu_addr6 : NULL, &pdr->f_teid, &pdr->f_teid_len)); pdr->f_teid.teid = pdr->index; } @@ -327,6 +335,9 @@ void sgwu_sxa_handle_session_modification_request( &ogs_gtp_self()->gtpu_resource_list, pdr->apn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { + ogs_assert( + (resource->info.v4 && pdr->f_teid.ipv4) || + (resource->info.v6 && pdr->f_teid.ipv6)); ogs_assert(OGS_OK == ogs_pfcp_user_plane_ip_resource_info_to_f_teid( &resource->info, &pdr->f_teid, &pdr->f_teid_len)); @@ -337,10 +348,15 @@ void sgwu_sxa_handle_session_modification_request( else pdr->f_teid.teid = pdr->index; } else { + ogs_assert( + (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || + (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); ogs_assert(OGS_OK == ogs_pfcp_sockaddr_to_f_teid( - ogs_gtp_self()->gtpu_addr, - ogs_gtp_self()->gtpu_addr6, + pdr->f_teid.ipv4 ? + ogs_gtp_self()->gtpu_addr : NULL, + pdr->f_teid.ipv6 ? + ogs_gtp_self()->gtpu_addr6 : NULL, &pdr->f_teid, &pdr->f_teid_len)); pdr->f_teid.teid = pdr->index; } diff --git a/src/smf/binding.c b/src/smf/binding.c index 7c49695a9..ef3922b07 100644 --- a/src/smf/binding.c +++ b/src/smf/binding.c @@ -168,6 +168,22 @@ void smf_bearer_binding(smf_sess_t *sess) ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { + + /* TS 129 244 V16.5.0 8.2.3 + * + * At least one of the V4 and V6 flags shall be set to "1", + * and both may be set to "1" for both scenarios: + * + * - when the CP function is providing F-TEID, i.e. + * both IPv4 address field and IPv6 address field may be present; + * or + * - when the UP function is requested to allocate the F-TEID, + * i.e. when CHOOSE bit is set to "1", + * and the IPv4 address and IPv6 address fields are not present. + */ + + ul_pdr->f_teid.ipv4 = 1; + ul_pdr->f_teid.ipv6 = 1; ul_pdr->f_teid.ch = 1; ul_pdr->f_teid_len = 1; } else { @@ -490,6 +506,22 @@ void smf_qos_flow_binding(smf_sess_t *sess) /* Set UPF-N3 TEID & ADDR to the UL PDR */ ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { + + /* TS 129 244 V16.5.0 8.2.3 + * + * At least one of the V4 and V6 flags shall be set to "1", + * and both may be set to "1" for both scenarios: + * + * - when the CP function is providing F-TEID, i.e. + * both IPv4 address field and IPv6 address field may be present; + * or + * - when the UP function is requested to allocate the F-TEID, + * i.e. when CHOOSE bit is set to "1", + * and the IPv4 address and IPv6 address fields are not present. + */ + + ul_pdr->f_teid.ipv4 = 1; + ul_pdr->f_teid.ipv6 = 1; ul_pdr->f_teid.ch = 1; ul_pdr->f_teid.chid = 1; ul_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID; diff --git a/src/smf/context.c b/src/smf/context.c index 3edd356ac..f11d3e5ec 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -1957,6 +1957,22 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess) ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { + + /* TS 129 244 V16.5.0 8.2.3 + * + * At least one of the V4 and V6 flags shall be set to "1", + * and both may be set to "1" for both scenarios: + * + * - when the CP function is providing F-TEID, i.e. + * both IPv4 address field and IPv6 address field may be present; + * or + * - when the UP function is requested to allocate the F-TEID, + * i.e. when CHOOSE bit is set to "1", + * and the IPv4 address and IPv6 address fields are not present. + */ + + pdr->f_teid.ipv4 = 1; + pdr->f_teid.ipv6 = 1; pdr->f_teid.ch = 1; pdr->f_teid.chid = 1; pdr->f_teid.choose_id = OGS_PFCP_INDIRECT_DATA_FORWARDING_CHOOSE_ID; diff --git a/src/smf/gn-build.c b/src/smf/gn-build.c index bc4f734c3..3eb025e1e 100644 --- a/src/smf/gn-build.c +++ b/src/smf/gn-build.c @@ -168,7 +168,7 @@ ogs_pkbuf_t *smf_gn_build_create_pdp_context_response( /* End User Address */ rv = ogs_gtp2_paa_to_ip(&sess->session.paa, &ip_eua); - rv = ogs_gtp1_ip_to_eua(sess->session.paa.session_type, &ip_eua, &eua, + rv = ogs_gtp1_ip_to_eua(sess->session.session_type, &ip_eua, &eua, &eua_len); rsp->end_user_address.presence = 1; rsp->end_user_address.data = &eua; diff --git a/src/smf/gsm-build.c b/src/smf/gsm-build.c index ace4cb58a..1f6051437 100644 --- a/src/smf/gsm-build.c +++ b/src/smf/gsm-build.c @@ -145,7 +145,7 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess) /* PDU Address */ pdu_session_establishment_accept->presencemask |= OGS_NAS_5GS_PDU_SESSION_ESTABLISHMENT_ACCEPT_PDU_ADDRESS_PRESENT; - pdu_address->pdn_type = sess->session.paa.session_type; + pdu_address->pdn_type = sess->session.session_type; if (pdu_address->pdn_type == OGS_PDU_SESSION_TYPE_IPV4) { pdu_address->addr = sess->session.paa.addr; diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c index 90719a4ce..5d819197d 100644 --- a/src/smf/gx-handler.c +++ b/src/smf/gx-handler.c @@ -170,14 +170,20 @@ uint32_t smf_gx_handle_cca_initial_request( /* Set F-TEID */ ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { + ul_pdr->f_teid.ipv4 = 1; + ul_pdr->f_teid.ipv6 = 1; ul_pdr->f_teid.ch = 1; ul_pdr->f_teid.chid = 1; ul_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID; ul_pdr->f_teid_len = 2; + cp2up_pdr->f_teid.ipv4 = 1; + cp2up_pdr->f_teid.ipv6 = 1; cp2up_pdr->f_teid.ch = 1; cp2up_pdr->f_teid_len = 1; + up2cp_pdr->f_teid.ipv4 = 1; + up2cp_pdr->f_teid.ipv6 = 1; up2cp_pdr->f_teid.ch = 1; up2cp_pdr->f_teid.chid = 1; up2cp_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID; diff --git a/src/smf/n4-build.c b/src/smf/n4-build.c index 82798ed65..c9b0d4555 100644 --- a/src/smf/n4-build.c +++ b/src/smf/n4-build.c @@ -100,7 +100,7 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request( /* PDN Type */ req->pdn_type.presence = 1; - req->pdn_type.u8 = sess->session.paa.session_type; + req->pdn_type.u8 = sess->session.session_type; pfcp_message.h.type = type; pkbuf = ogs_pfcp_build_msg(&pfcp_message); diff --git a/src/smf/npcf-handler.c b/src/smf/npcf-handler.c index 9fb9c2af3..863c7e996 100644 --- a/src/smf/npcf-handler.c +++ b/src/smf/npcf-handler.c @@ -507,44 +507,38 @@ bool smf_npcf_smpolicycontrol_handle_create( /* Set UPF-N3 TEID & ADDR to the Default UL PDR */ ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { + + /* TS 129 244 V16.5.0 8.2.3 + * + * At least one of the V4 and V6 flags shall be set to "1", + * and both may be set to "1" for both scenarios: + * + * - when the CP function is providing F-TEID, i.e. + * both IPv4 address field and IPv6 address field may be present; + * or + * - when the UP function is requested to allocate the F-TEID, + * i.e. when CHOOSE bit is set to "1", + * and the IPv4 address and IPv6 address fields are not present. + */ + + ul_pdr->f_teid.ipv4 = 1; + ul_pdr->f_teid.ipv6 = 1; ul_pdr->f_teid.ch = 1; ul_pdr->f_teid.chid = 1; ul_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID; ul_pdr->f_teid_len = 2; - /* TS 129 244 V16.5.0 8.2.3 - * - * At least one of the V4 and V6 flags shall be set to "1", - * and both may be set to "1" for both scenarios: - * - * - when the CP function is providing F-TEID, i.e. - * both IPv4 address field and IPv6 address field may be present; - * or - * - when the UP function is requested to allocate the F-TEID, - * i.e. when CHOOSE bit is set to "1", - * and the IPv4 address and IPv6 address fields are not present. - */ - - if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) - ul_pdr->f_teid.ipv4 = 1; - else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) - ul_pdr->f_teid.ipv6 = 1; - + cp2up_pdr->f_teid.ipv4 = 1; + cp2up_pdr->f_teid.ipv6 = 1; cp2up_pdr->f_teid.ch = 1; cp2up_pdr->f_teid_len = 1; - if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) - cp2up_pdr->f_teid.ipv4 = 1; - else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) - cp2up_pdr->f_teid.ipv6 = 1; + up2cp_pdr->f_teid.ipv4 = 1; + up2cp_pdr->f_teid.ipv6 = 1; up2cp_pdr->f_teid.ch = 1; up2cp_pdr->f_teid.chid = 1; up2cp_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID; up2cp_pdr->f_teid_len = 2; - if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) - up2cp_pdr->f_teid.ipv4 = 1; - else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) - up2cp_pdr->f_teid.ipv6 = 1; } else { ogs_gtpu_resource_t *resource = NULL; resource = ogs_pfcp_find_gtpu_resource( diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index f8b45f2a9..fba96eac2 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -157,6 +157,9 @@ void upf_n4_handle_session_establishment_request( &ogs_gtp_self()->gtpu_resource_list, pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { + ogs_assert( + (resource->info.v4 && pdr->f_teid.ipv4) || + (resource->info.v6 && pdr->f_teid.ipv6)); ogs_assert(OGS_OK == ogs_pfcp_user_plane_ip_resource_info_to_f_teid( &resource->info, &pdr->f_teid, &pdr->f_teid_len)); @@ -167,10 +170,15 @@ void upf_n4_handle_session_establishment_request( else pdr->f_teid.teid = pdr->index; } else { + ogs_assert( + (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || + (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); ogs_assert(OGS_OK == ogs_pfcp_sockaddr_to_f_teid( - ogs_gtp_self()->gtpu_addr, - ogs_gtp_self()->gtpu_addr6, + pdr->f_teid.ipv4 ? + ogs_gtp_self()->gtpu_addr : NULL, + pdr->f_teid.ipv6 ? + ogs_gtp_self()->gtpu_addr6 : NULL, &pdr->f_teid, &pdr->f_teid_len)); pdr->f_teid.teid = pdr->index; } @@ -392,6 +400,9 @@ void upf_n4_handle_session_modification_request( &ogs_gtp_self()->gtpu_resource_list, pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { + ogs_assert( + (resource->info.v4 && pdr->f_teid.ipv4) || + (resource->info.v6 && pdr->f_teid.ipv6)); ogs_assert(OGS_OK == ogs_pfcp_user_plane_ip_resource_info_to_f_teid( &resource->info, &pdr->f_teid, &pdr->f_teid_len)); @@ -402,10 +413,15 @@ void upf_n4_handle_session_modification_request( else pdr->f_teid.teid = pdr->index; } else { + ogs_assert( + (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || + (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); ogs_assert(OGS_OK == ogs_pfcp_sockaddr_to_f_teid( - ogs_gtp_self()->gtpu_addr, - ogs_gtp_self()->gtpu_addr6, + pdr->f_teid.ipv4 ? + ogs_gtp_self()->gtpu_addr : NULL, + pdr->f_teid.ipv6 ? + ogs_gtp_self()->gtpu_addr6 : NULL, &pdr->f_teid, &pdr->f_teid_len)); pdr->f_teid.teid = pdr->index; }