diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index 6784653a5..92d425557 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -929,6 +929,20 @@ ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid) self.object_teid_hash, &teid, sizeof(teid)); } +int ogs_pfcp_object_count_by_teid(ogs_pfcp_sess_t *sess, uint32_t teid) +{ + ogs_pfcp_pdr_t *pdr = NULL; + int count = 0; + + ogs_assert(sess); + + ogs_list_for_each(&sess->pdr_list, pdr) { + if (pdr->f_teid.teid == teid) count++; + } + + return count; +} + ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id( ogs_pfcp_sess_t *sess, uint8_t choose_id) { @@ -997,9 +1011,21 @@ void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr) ogs_pfcp_rule_remove_all(pdr); - if (pdr->hash.teid.len) - ogs_hash_set(self.object_teid_hash, - &pdr->hash.teid.key, pdr->hash.teid.len, NULL); + if (pdr->hash.teid.len) { + /* + * Issues #2003 + * + * In 5G Core, two PDRs can use different QFIDs for the same TEID. + * So, before deleting a TEID, we should check if there is a PDR + * using the same TEID. + * + * Since this PDR has already been deleted with ogs_list_remove() above, + * if the current list has a TEID count of 0, there are no other PDRs. + */ + if (ogs_pfcp_object_count_by_teid(pdr->sess, pdr->f_teid.teid) == 0) + ogs_hash_set(self.object_teid_hash, + &pdr->hash.teid.key, pdr->hash.teid.len, NULL); + } if (pdr->dnn) ogs_free(pdr->dnn); diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index 0ecb95279..d0a9643a1 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -397,6 +397,7 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add( void ogs_pfcp_object_teid_hash_set( ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr); ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid); +int ogs_pfcp_object_count_by_teid(ogs_pfcp_sess_t *sess, uint32_t teid); ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id( ogs_pfcp_sess_t *sess, uint8_t choose_id); diff --git a/tests/vonr/simple-test.c b/tests/vonr/simple-test.c index 2329c5e28..e8267e87d 100644 --- a/tests/vonr/simple-test.c +++ b/tests/vonr/simple-test.c @@ -418,6 +418,20 @@ static void test1_func(abts_case *tc, void *data) /* Test Bearer Remove */ test_bearer_remove(qos_flow); + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Wait for PDU session resource modify complete */ + ogs_msleep(100); + /* Send UEContextReleaseRequest */ sendbuf = testngap_build_ue_context_release_request(test_ue, NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity,