From 33edd123357b4b08b5c252ec375201becf006210 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Thu, 3 Dec 2020 01:16:57 -0500 Subject: [PATCH] fix: UPF is not working with Landslide (#685) * Flow-Description use 'to assigned' in Gx Interface * Support SDF Filter ID * Support F-TEID's Choose * BAR(Buffering) is added in PFCP session * Default Apply Action uses NOCP|BUFF --- configs/open5gs/smf.yaml.in | 18 +-- configs/open5gs/upf.yaml.in | 16 +-- lib/core/ogs-3gpp-types.h | 3 +- lib/ipfw/ogs-ipfw.c | 26 ++-- lib/pfcp/build.c | 79 ++++++---- lib/pfcp/build.h | 3 + lib/pfcp/context.c | 162 ++++++++++++++------- lib/pfcp/context.h | 37 ++++- lib/pfcp/handler.c | 277 ++++++++++++++++++++++++++---------- lib/pfcp/handler.h | 7 + lib/pfcp/path.c | 6 + lib/pfcp/types.h | 26 ++-- src/pcrf/pcrf-gx-path.c | 4 +- src/sgwc/context.c | 15 +- src/sgwc/s11-handler.c | 8 ++ src/sgwc/s5c-handler.c | 4 + src/sgwc/sxa-build.c | 5 + src/sgwu/context.c | 48 +------ src/sgwu/context.h | 3 +- src/sgwu/sxa-handler.c | 141 ++++++++++++------ src/smf/context.c | 44 ++++-- src/smf/gx-handler.c | 2 + src/smf/n4-build.c | 6 + src/smf/n4-handler.c | 12 ++ src/smf/ngap-handler.c | 2 + src/smf/s5c-handler.c | 2 + src/upf/context.c | 194 +++++++++---------------- src/upf/context.h | 6 +- src/upf/n4-handler.c | 88 +++++++++--- src/upf/rule-match.c | 14 +- tests/volte/bearer-test.c | 8 +- tests/volte/rx-test.c | 8 +- tests/volte/session-test.c | 8 +- 33 files changed, 810 insertions(+), 472 deletions(-) diff --git a/configs/open5gs/smf.yaml.in b/configs/open5gs/smf.yaml.in index f985b6afc..22a8fd67c 100644 --- a/configs/open5gs/smf.yaml.in +++ b/configs/open5gs/smf.yaml.in @@ -98,26 +98,26 @@ logger: # o Specific DNN/APN(e.g 'ims') uses 10.46.0.1/16, cafe:2::1/64 # pdn: # - addr: 10.45.0.1/16 -# apn: internet +# dnn: internet # - addr: cafe:1::1/64 -# apn: internet +# dnn: internet # - addr: 10.46.0.1/16 -# apn: ims +# dnn: ims # - addr: cafe:2::1/64 -# apn: ims +# dnn: ims # # o Multiple Devices (default: ogstun) # pdn: # - addr: 10.45.0.1/16 -# apn: internet +# dnn: internet # - addr: cafe:1::1/64 -# apn: internet +# dnn: internet # dev: ogstun2 # - addr: 10.46.0.1/16 -# apn: ims +# dnn: ims # dev: ogstun3 # - addr: cafe:2::1/64 -# apn: ims +# dnn: ims # dev: ogstun3 # # o Pool Range Sample @@ -261,7 +261,7 @@ nrf: # - addr: 127.0.0.7 # dnn: ims # - addr: 127.0.0.12 -# apn: [internet, web] +# dnn: [internet, web] # # o UPF selection by CellID(e_cell_id: 28bit, nr_cell_id: 36bit) # (either single enb_id or multiple enb_ids, HEX representation) diff --git a/configs/open5gs/upf.yaml.in b/configs/open5gs/upf.yaml.in index 9a12f655e..e07fe9c0f 100644 --- a/configs/open5gs/upf.yaml.in +++ b/configs/open5gs/upf.yaml.in @@ -107,13 +107,13 @@ logger: # # pdn: # - addr: 10.45.0.1/16 -# apn: internet +# dnn: internet # - addr: cafe:1::1/64 -# apn: internet +# dnn: internet # - addr: 10.46.0.1/16 -# apn: ims +# dnn: ims # - addr: cafe:2::1/64 -# apn: ims +# dnn: ims # # o Multiple Devices (default: ogstun) # $ sudo ip addr add 10.45.0.1/16 dev ogstun @@ -123,15 +123,15 @@ logger: # # pdn: # - addr: 10.45.0.1/16 -# apn: internet +# dnn: internet # - addr: cafe:1::1/64 -# apn: internet +# dnn: internet # dev: ogstun2 # - addr: 10.46.0.1/16 -# apn: ims +# dnn: ims # dev: ogstun3 # - addr: cafe:2::1/64 -# apn: ims +# dnn: ims # dev: ogstun3 # # o Pool Range Sample diff --git a/lib/core/ogs-3gpp-types.h b/lib/core/ogs-3gpp-types.h index 7a7ce17bd..88a3501a7 100644 --- a/lib/core/ogs-3gpp-types.h +++ b/lib/core/ogs-3gpp-types.h @@ -57,7 +57,8 @@ extern "C" { #define OGS_MAX_NUM_OF_CELL_ID 16 #define OGS_MAX_NUM_OF_ENB_ID 16 -#define OGS_MAX_NUM_OF_APN 16 +#define OGS_MAX_NUM_OF_DNN 16 +#define OGS_MAX_NUM_OF_APN OGS_MAX_NUM_OF_DNN #define OGS_MAX_NUM_OF_HOSTNAME 16 #define OGS_MAX_DNN_LEN 100 #define OGS_MAX_APN_LEN OGS_MAX_DNN_LEN diff --git a/lib/ipfw/ogs-ipfw.c b/lib/ipfw/ogs-ipfw.c index 23e0a981c..d6d5ce3d5 100644 --- a/lib/ipfw/ogs-ipfw.c +++ b/lib/ipfw/ogs-ipfw.c @@ -36,10 +36,9 @@ void compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, void *tstate); int ogs_ipfw_compile_rule(ogs_ipfw_rule_t *ipfw_rule, char *flow_description) { - ogs_ipfw_rule_t zero_rule; char *token, *dir; char *saveptr; - int i = 2; + int i; char *av[MAX_NUM_OF_TOKEN]; uint32_t rulebuf[MAX_NUM_OF_RULE_BUFFER]; @@ -60,7 +59,6 @@ int ogs_ipfw_compile_rule(ogs_ipfw_rule_t *ipfw_rule, char *flow_description) av[0] = NULL; /* ACTION */ - description = ogs_strdup(flow_description); ogs_assert(description); @@ -81,6 +79,7 @@ int ogs_ipfw_compile_rule(ogs_ipfw_rule_t *ipfw_rule, char *flow_description) } /* ADDR */ + i = 2; token = ogs_strtok_r(NULL, " ", &saveptr); while (token != NULL) { av[i++] = token; @@ -92,6 +91,14 @@ int ogs_ipfw_compile_rule(ogs_ipfw_rule_t *ipfw_rule, char *flow_description) av[i] = NULL; + /* "to assigned" --> "to any" */ + for (i = 2; av[i] != NULL; i++) { + if (strcmp(av[i], "assigned") == 0 && strcmp(av[i-1], "to") == 0) { + av[i] = "any"; + break; + } + } + compile_rule(av, (uint32_t *)rule, &rbufsize, NULL); memset(ipfw_rule, 0, sizeof(ogs_ipfw_rule_t)); @@ -156,13 +163,6 @@ int ogs_ipfw_compile_rule(ogs_ipfw_rule_t *ipfw_rule, char *flow_description) } } - memset(&zero_rule, 0, sizeof(ogs_ipfw_rule_t)); - if (memcmp(ipfw_rule, &zero_rule, sizeof(ogs_ipfw_rule_t)) == 0) { - ogs_error("Cannot find Flow-Description"); - ogs_free(description); - return OGS_ERROR; - } - ogs_free(description); return OGS_OK; } @@ -281,7 +281,7 @@ char *ogs_ipfw_encode_flow_description(ogs_ipfw_rule_t *ipfw_rule) ipfw_rule->ip.dst.mask[3]); return NULL; } else if (prefixlen == 0) { - p = ogs_slprintf(p, last, " any"); + p = ogs_slprintf(p, last, " assigned"); } else if (prefixlen > 0 && prefixlen < IPV4_BITLEN) { p = ogs_slprintf(p, last, " %s/%d", buf, prefixlen); } else if (prefixlen == IPV4_BITLEN) { @@ -308,7 +308,7 @@ char *ogs_ipfw_encode_flow_description(ogs_ipfw_rule_t *ipfw_rule) ipfw_rule->ip.dst.mask[3]); return NULL; } else if (prefixlen == 0) { - p = ogs_slprintf(p, last, " any"); + p = ogs_slprintf(p, last, " assigned"); } else if (prefixlen > 0 && prefixlen < IPV6_BITLEN) { p = ogs_slprintf(p, last, " %s/%d", buf, prefixlen); } else if (prefixlen == IPV6_BITLEN) { @@ -318,7 +318,7 @@ char *ogs_ipfw_encode_flow_description(ogs_ipfw_rule_t *ipfw_rule) ogs_assert_if_reached(); } } else - p = ogs_slprintf(p, last, " any"); + p = ogs_slprintf(p, last, " assigned"); if (ipfw_rule->port.dst.low == ipfw_rule->port.dst.high) { if (ipfw_rule->port.dst.low == 0) { diff --git a/lib/pfcp/build.c b/lib/pfcp/build.c index 687a1ca76..675f090d3 100644 --- a/lib/pfcp/build.c +++ b/lib/pfcp/build.c @@ -281,10 +281,10 @@ void ogs_pfcp_build_create_pdr( message->pdi.source_interface.presence = 1; message->pdi.source_interface.u8 = pdr->src_if; - if (pdr->apn) { + if (pdr->dnn) { message->pdi.network_instance.presence = 1; message->pdi.network_instance.len = ogs_fqdn_build( - pdrbuf[i].dnn, pdr->apn, strlen(pdr->apn)); + pdrbuf[i].dnn, pdr->dnn, strlen(pdr->dnn)); message->pdi.network_instance.data = pdrbuf[i].dnn; } @@ -386,10 +386,10 @@ void ogs_pfcp_build_update_pdr( message->pdi.source_interface.presence = 1; message->pdi.source_interface.u8 = pdr->src_if; - if (pdr->apn) { + if (pdr->dnn) { message->pdi.network_instance.presence = 1; message->pdi.network_instance.len = ogs_fqdn_build( - pdrbuf[i].dnn, pdr->apn, strlen(pdr->apn)); + pdrbuf[i].dnn, pdr->dnn, strlen(pdr->dnn)); message->pdi.network_instance.data = pdrbuf[i].dnn; } @@ -436,8 +436,12 @@ static struct { void ogs_pfcp_build_create_far( ogs_pfcp_tlv_create_far_t *message, int i, ogs_pfcp_far_t *far) { + ogs_pfcp_sess_t *sess = NULL; + ogs_assert(message); ogs_assert(far); + sess = far->sess; + ogs_assert(sess); message->presence = 1; message->far_id.presence = 1; @@ -446,30 +450,40 @@ void ogs_pfcp_build_create_far( message->apply_action.presence = 1; message->apply_action.u8 = far->apply_action; - message->forwarding_parameters.presence = 1; - message->forwarding_parameters.destination_interface.presence = 1; - message->forwarding_parameters.destination_interface.u8 = - far->dst_if; + if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { + message->forwarding_parameters.presence = 1; + message->forwarding_parameters.destination_interface.presence = 1; + message->forwarding_parameters.destination_interface.u8 = + far->dst_if; - if (far->outer_header_creation_len) { - memcpy(&farbuf[i].outer_header_creation, - &far->outer_header_creation, far->outer_header_creation_len); - farbuf[i].outer_header_creation.teid = - htobe32(far->outer_header_creation.teid); + if (far->outer_header_creation_len) { + memcpy(&farbuf[i].outer_header_creation, + &far->outer_header_creation, far->outer_header_creation_len); + farbuf[i].outer_header_creation.teid = + htobe32(far->outer_header_creation.teid); - message->forwarding_parameters.outer_header_creation.presence = 1; - message->forwarding_parameters.outer_header_creation.data = - &farbuf[i].outer_header_creation; - message->forwarding_parameters.outer_header_creation.len = - far->outer_header_creation_len; + message->forwarding_parameters.outer_header_creation.presence = 1; + message->forwarding_parameters.outer_header_creation.data = + &farbuf[i].outer_header_creation; + message->forwarding_parameters.outer_header_creation.len = + far->outer_header_creation_len; + } + } else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) { + ogs_assert(sess->bar); + message->bar_id.presence = 1; + message->bar_id.u8 = sess->bar->id; } } void ogs_pfcp_build_update_far_deactivate( ogs_pfcp_tlv_update_far_t *message, int i, ogs_pfcp_far_t *far) { + ogs_pfcp_sess_t *sess = NULL; + ogs_assert(message); ogs_assert(far); + sess = far->sess; + ogs_assert(sess); message->presence = 1; message->far_id.presence = 1; @@ -479,6 +493,10 @@ void ogs_pfcp_build_update_far_deactivate( OGS_PFCP_APPLY_ACTION_BUFF | OGS_PFCP_APPLY_ACTION_NOCP; message->apply_action.presence = 1; message->apply_action.u8 = far->apply_action; + + ogs_assert(sess->bar); + message->bar_id.presence = 1; + message->bar_id.u8 = sess->bar->id; } void ogs_pfcp_build_update_far_activate( @@ -491,15 +509,17 @@ void ogs_pfcp_build_update_far_activate( message->far_id.presence = 1; message->far_id.u32 = far->id; - if (far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) { - far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_assert(far->apply_action == OGS_PFCP_APPLY_ACTION_FORW); - message->apply_action.presence = 1; - message->apply_action.u8 = far->apply_action; - } + message->apply_action.presence = 1; + message->apply_action.u8 = far->apply_action; + + message->update_forwarding_parameters.presence = 1; + message->update_forwarding_parameters.destination_interface.presence = 1; + message->update_forwarding_parameters. + destination_interface.u8 = far->dst_if; if (far->outer_header_creation_len || far->smreq_flags.value) { - message->update_forwarding_parameters.presence = 1; if (far->outer_header_creation_len) { memcpy(&farbuf[i].outer_header_creation, @@ -596,6 +616,17 @@ void ogs_pfcp_build_create_urr( message->urr_id.u32 = urr->id; } +void ogs_pfcp_build_create_bar( + ogs_pfcp_tlv_create_bar_t *message, ogs_pfcp_bar_t *bar) +{ + ogs_assert(message); + ogs_assert(bar); + + message->presence = 1; + message->bar_id.presence = 1; + message->bar_id.u8 = bar->id; +} + ogs_pkbuf_t *ogs_pfcp_build_session_report_request( uint8_t type, ogs_pfcp_user_plane_report_t *report) { diff --git a/lib/pfcp/build.h b/lib/pfcp/build.h index c41acc3e1..0df71fbc7 100644 --- a/lib/pfcp/build.h +++ b/lib/pfcp/build.h @@ -60,6 +60,9 @@ void ogs_pfcp_build_update_qer( void ogs_pfcp_build_create_urr( ogs_pfcp_tlv_create_urr_t *message, int i, ogs_pfcp_urr_t *urr); +void ogs_pfcp_build_create_bar( + ogs_pfcp_tlv_create_bar_t *message, ogs_pfcp_bar_t *bar); + ogs_pkbuf_t *ogs_pfcp_build_session_report_request( uint8_t type, ogs_pfcp_user_plane_report_t *report); ogs_pkbuf_t *ogs_pfcp_build_session_report_response( diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index f4c2a3890..c19fa2f13 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -245,7 +245,8 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) } } else if (!strcmp(pfcp_key, "dev")) { dev = ogs_yaml_iter_value(&pfcp_iter); - } else if (!strcmp(pfcp_key, "apn")) { + } else if (!strcmp(pfcp_key, "apn") || + !strcmp(pfcp_key, "dnn")) { /* Skip */ } else ogs_warn("unknown key `%s`", pfcp_key); @@ -299,7 +300,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) ogs_pfcp_subnet_t *subnet = NULL; const char *ipstr = NULL; const char *mask_or_numbits = NULL; - const char *apn = NULL; + const char *dnn = NULL; const char *dev = self.tun_ifname; const char *low[MAX_NUM_OF_SUBNET_RANGE]; const char *high[MAX_NUM_OF_SUBNET_RANGE]; @@ -334,7 +335,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) } } else if (!strcmp(pdn_key, "apn") || !strcmp(pdn_key, "dnn")) { - apn = ogs_yaml_iter_value(&pdn_iter); + dnn = ogs_yaml_iter_value(&pdn_iter); } else if (!strcmp(pdn_key, "dev")) { dev = ogs_yaml_iter_value(&pdn_iter); } else if (!strcmp(pdn_key, "range")) { @@ -375,7 +376,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) } subnet = ogs_pfcp_subnet_add( - ipstr, mask_or_numbits, apn, dev); + ipstr, mask_or_numbits, dnn, dev); ogs_assert(subnet); subnet->num_of_range = num; @@ -406,8 +407,8 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) uint16_t port = self.pfcp_port; uint16_t tac[OGS_MAX_NUM_OF_TAI] = {0,}; uint8_t num_of_tac = 0; - const char *apn[OGS_MAX_NUM_OF_APN]; - uint8_t num_of_apn = 0; + const char *dnn[OGS_MAX_NUM_OF_DNN]; + uint8_t num_of_dnn = 0; uint32_t e_cell_id[OGS_MAX_NUM_OF_CELL_ID] = {0,}; uint8_t num_of_e_cell_id = 0; uint64_t nr_cell_id[OGS_MAX_NUM_OF_CELL_ID] = {0,}; @@ -497,29 +498,29 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) YAML_SEQUENCE_NODE); } else if (!strcmp(pfcp_key, "apn") || !strcmp(pfcp_key, "dnn")) { - ogs_yaml_iter_t apn_iter; - ogs_yaml_iter_recurse(&pfcp_iter, &apn_iter); - ogs_assert(ogs_yaml_iter_type(&apn_iter) != + ogs_yaml_iter_t dnn_iter; + ogs_yaml_iter_recurse(&pfcp_iter, &dnn_iter); + ogs_assert(ogs_yaml_iter_type(&dnn_iter) != YAML_MAPPING_NODE); do { const char *v = NULL; - ogs_assert(num_of_apn <= - OGS_MAX_NUM_OF_APN); - if (ogs_yaml_iter_type(&apn_iter) == + ogs_assert(num_of_dnn <= + OGS_MAX_NUM_OF_DNN); + if (ogs_yaml_iter_type(&dnn_iter) == YAML_SEQUENCE_NODE) { - if (!ogs_yaml_iter_next(&apn_iter)) + if (!ogs_yaml_iter_next(&dnn_iter)) break; } - v = ogs_yaml_iter_value(&apn_iter); + v = ogs_yaml_iter_value(&dnn_iter); if (v) { - apn[num_of_apn] = v; - num_of_apn++; + dnn[num_of_dnn] = v; + num_of_dnn++; } } while ( - ogs_yaml_iter_type(&apn_iter) == + ogs_yaml_iter_type(&dnn_iter) == YAML_SEQUENCE_NODE); } else if (!strcmp(pfcp_key, "e_cell_id")) { ogs_yaml_iter_t e_cell_id_iter; @@ -606,9 +607,9 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) if (num_of_tac != 0) memcpy(node->tac, tac, sizeof(node->tac)); - node->num_of_apn = num_of_apn; - if (num_of_apn != 0) - memcpy(node->apn, apn, sizeof(node->apn)); + node->num_of_dnn = num_of_dnn; + if (num_of_dnn != 0) + memcpy(node->dnn, dnn, sizeof(node->dnn)); node->num_of_e_cell_id = num_of_e_cell_id; if (num_of_e_cell_id != 0) @@ -743,7 +744,7 @@ ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_add(ogs_list_t *list, } ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list, - char *apn, ogs_pfcp_interface_t source_interface) + char *dnn, ogs_pfcp_interface_t source_interface) { ogs_pfcp_gtpu_resource_t *resource = NULL; @@ -754,8 +755,8 @@ ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list, if (resource->info.assoni && strlen(resource->info.network_instance) && - apn && strlen(apn) && - ogs_strcasecmp(apn, resource->info.network_instance) != 0) { + dnn && strlen(dnn) && + ogs_strcasecmp(dnn, resource->info.network_instance) != 0) { match = false; } @@ -845,6 +846,8 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess) pdr->id = *(pdr->id_node); ogs_assert(pdr->id > 0 && pdr->id <= OGS_MAX_NUM_OF_PDR); + pdr->src_if = OGS_PFCP_INTERFACE_UNKNOWN; + pdr->sess = sess; ogs_list_add(&sess->pdr_list, pdr); @@ -907,6 +910,20 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi) &hashkey, sizeof(hashkey)); } +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id( + ogs_pfcp_sess_t *sess, uint8_t choose_id) +{ + ogs_pfcp_pdr_t *pdr = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->pdr_list, pdr) + if (pdr->chid == true && pdr->choose_id == choose_id) + return pdr; + + return NULL; +} + void ogs_pfcp_pdr_reorder_by_precedence( ogs_pfcp_pdr_t *pdr, ogs_pfcp_precedence_t precedence) { @@ -926,7 +943,7 @@ void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far) { ogs_assert(pdr); ogs_assert(far); - + pdr->far = far; } void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr) @@ -990,7 +1007,7 @@ ogs_pfcp_far_t *ogs_pfcp_far_add(ogs_pfcp_sess_t *sess) far->id = *(far->id_node); ogs_assert(far->id > 0 && far->id <= OGS_MAX_NUM_OF_FAR); - far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + far->dst_if = OGS_PFCP_INTERFACE_UNKNOWN; far->sess = sess; ogs_list_add(&sess->far_list, far); @@ -1333,6 +1350,9 @@ ogs_pfcp_bar_t *ogs_pfcp_bar_new(ogs_pfcp_sess_t *sess) ogs_pool_alloc(&sess->bar_id_pool, &bar->id_node); ogs_assert(bar->id_node); + bar->id = *(bar->id_node); + ogs_assert(bar->id > 0 && bar->id <= OGS_MAX_NUM_OF_BAR); + bar->sess = sess; sess->bar = bar; @@ -1347,13 +1367,13 @@ void ogs_pfcp_bar_delete(ogs_pfcp_bar_t *bar) sess = bar->sess; ogs_assert(sess); - bar->sess = NULL; - sess->bar = NULL; - if (bar->id_node) ogs_pool_free(&bar->sess->bar_id_pool, bar->id_node); ogs_pool_free(&ogs_pfcp_bar_pool, bar); + + bar->sess = NULL; + sess->bar = NULL; } ogs_pfcp_rule_t *ogs_pfcp_rule_add(ogs_pfcp_pdr_t *pdr) @@ -1372,6 +1392,24 @@ ogs_pfcp_rule_t *ogs_pfcp_rule_add(ogs_pfcp_pdr_t *pdr) return rule; } +ogs_pfcp_rule_t *ogs_pfcp_rule_find_by_sdf_filter_id( + ogs_pfcp_sess_t *sess, uint32_t sdf_filter_id) +{ + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_rule_t *rule = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->pdr_list, pdr) { + ogs_list_for_each(&pdr->rule_list, rule) { + if (rule->bid && rule->sdf_filter_id == sdf_filter_id) + return rule; + } + } + + return NULL; +} + void ogs_pfcp_rule_remove(ogs_pfcp_rule_t *rule) { ogs_pfcp_pdr_t *pdr = NULL; @@ -1490,7 +1528,7 @@ int ogs_pfcp_ue_pool_generate(void) } ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc( - int family, const char *apn, uint8_t *addr) + int family, const char *dnn, uint8_t *addr) { ogs_pfcp_subnet_t *subnet = NULL; ogs_pfcp_ue_ip_t *ue_ip = NULL; @@ -1498,22 +1536,6 @@ ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc( uint8_t zero[16]; size_t maxbytes = 0; - ogs_assert(apn); - subnet = ogs_pfcp_find_subnet(family, apn); - if (subnet == NULL) { - ogs_error("CHECK CONFIGURATION: Cannot find subnet [family:%d, apn:%s]", - family, apn); - ogs_error("smf"); - ogs_error(" pdn:"); - if (family == AF_INET) - ogs_error(" - addr: 10.45.0.1/16"); - else if (family == AF_INET6) - ogs_error(" - addr: cafe::1/64"); - - ogs_assert_if_reached(); - return NULL; - } - memset(zero, 0, sizeof zero); if (family == AF_INET) { maxbytes = 4; @@ -1524,7 +1546,26 @@ ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc( ogs_assert_if_reached(); } - // if assigning a static IP, do so. If not, assign dynamically! + if (dnn) + subnet = ogs_pfcp_find_subnet_by_dnn(family, dnn); + else + subnet = ogs_pfcp_find_subnet(family); + + if (subnet == NULL) { + ogs_error("CHECK CONFIGURATION: Cannot find subnet [family:%d, dnn:%s]", + family, dnn ? dnn : "No DNN"); + ogs_error("smf"); + ogs_error(" pdn:"); + if (family == AF_INET) + ogs_error(" - addr: 10.45.0.1/16"); + else if (family == AF_INET6) + ogs_error(" - addr: cafe::1/64"); + + ogs_assert_if_reached(); + return NULL; + } + + /* if assigning a static IP, do so. If not, assign dynamically! */ if (memcmp(addr, zero, maxbytes) != 0) { ue_ip = ogs_calloc(1, sizeof(ogs_pfcp_ue_ip_t)); @@ -1608,7 +1649,7 @@ ogs_pfcp_dev_t *ogs_pfcp_dev_find_by_ifname(const char *ifname) ogs_pfcp_subnet_t *ogs_pfcp_subnet_add( const char *ipstr, const char *mask_or_numbits, - const char *apn, const char *ifname) + const char *dnn, const char *ifname) { int rv; ogs_pfcp_dev_t *dev = NULL; @@ -1639,8 +1680,8 @@ ogs_pfcp_subnet_t *ogs_pfcp_subnet_add( subnet->prefixlen = atoi(mask_or_numbits); } - if (apn) - strcpy(subnet->apn, apn); + if (dnn) + strcpy(subnet->dnn, dnn); ogs_pool_init(&subnet->pool, ogs_app()->pool.sess); @@ -1668,17 +1709,32 @@ void ogs_pfcp_subnet_remove_all(void) ogs_pfcp_subnet_remove(subnet); } -ogs_pfcp_subnet_t *ogs_pfcp_find_subnet(int family, const char *apn) +ogs_pfcp_subnet_t *ogs_pfcp_find_subnet(int family) { ogs_pfcp_subnet_t *subnet = NULL; - ogs_assert(apn); ogs_assert(family == AF_INET || family == AF_INET6); ogs_list_for_each(&self.subnet_list, subnet) { if ((subnet->family == AF_UNSPEC || subnet->family == family) && - (strlen(subnet->apn) == 0 || - (strlen(subnet->apn) && ogs_strcasecmp(subnet->apn, apn) == 0))) + (strlen(subnet->dnn) == 0)) + break; + } + + return subnet; +} + +ogs_pfcp_subnet_t *ogs_pfcp_find_subnet_by_dnn(int family, const char *dnn) +{ + ogs_pfcp_subnet_t *subnet = NULL; + + ogs_assert(dnn); + ogs_assert(family == AF_INET || family == AF_INET6); + + ogs_list_for_each(&self.subnet_list, subnet) { + if ((subnet->family == AF_UNSPEC || subnet->family == family) && + (strlen(subnet->dnn) == 0 || + (strlen(subnet->dnn) && ogs_strcasecmp(subnet->dnn, dnn) == 0))) break; } diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index bb1621ff5..822a6baac 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -88,8 +88,8 @@ typedef struct ogs_pfcp_node_s { uint16_t tac[OGS_MAX_NUM_OF_TAI]; uint8_t num_of_tac; - const char* apn[OGS_MAX_APN_LEN]; - uint8_t num_of_apn; + const char* dnn[OGS_MAX_DNN_LEN]; + uint8_t num_of_dnn; uint32_t e_cell_id[OGS_MAX_NUM_OF_CELL_ID]; uint8_t num_of_e_cell_id; uint64_t nr_cell_id[OGS_MAX_NUM_OF_CELL_ID]; @@ -138,6 +138,10 @@ typedef struct ogs_pfcp_pdr_s { ogs_pfcp_f_teid_t f_teid; int f_teid_len; + + bool chid; + uint8_t choose_id; + ogs_pfcp_outer_header_removal_t outer_header_removal; int outer_header_removal_len; @@ -255,7 +259,7 @@ typedef struct ogs_pfcp_subnet_s { ogs_ipsubnet_t sub; /* Subnet : cafe::0/64 */ ogs_ipsubnet_t gw; /* Gateway : cafe::1 */ - char apn[OGS_MAX_APN_LEN]; /* APN : "internet", "volte", .. */ + char dnn[OGS_MAX_DNN_LEN]; /* DNN : "internet", "volte", .. */ #define MAX_NUM_OF_SUBNET_RANGE 16 struct { @@ -274,7 +278,20 @@ typedef struct ogs_pfcp_subnet_s { typedef struct ogs_pfcp_rule_s { ogs_lnode_t lnode; + union { + struct { +ED6(uint8_t spare1:3;, + uint8_t bid:1;, + uint8_t fl:1;, + uint8_t spi:1;, + uint8_t ttc:1;, + uint8_t fd:1;) + }; + uint8_t flags; + }; + ogs_ipfw_rule_t ipfw; + uint32_t sdf_filter_id; /* Related Context */ ogs_pfcp_pdr_t *pdr; @@ -298,7 +315,7 @@ void ogs_pfcp_node_remove_all(ogs_list_t *list); ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_add(ogs_list_t *list, ogs_pfcp_user_plane_ip_resource_info_t *info); ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list, - char *apn, ogs_pfcp_interface_t source_interface); + char *dnn, ogs_pfcp_interface_t source_interface); void ogs_pfcp_gtpu_resource_remove(ogs_list_t *list, ogs_pfcp_gtpu_resource_t *resource); void ogs_pfcp_gtpu_resource_remove_all(ogs_list_t *list); @@ -320,6 +337,9 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add( void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr); ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi); +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id( + ogs_pfcp_sess_t *sess, uint8_t choose_id); + void ogs_pfcp_pdr_reorder_by_precedence( ogs_pfcp_pdr_t *pdr, ogs_pfcp_precedence_t precedence); void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far); @@ -360,12 +380,14 @@ ogs_pfcp_bar_t *ogs_pfcp_bar_new(ogs_pfcp_sess_t *sess); void ogs_pfcp_bar_delete(ogs_pfcp_bar_t *bar); ogs_pfcp_rule_t *ogs_pfcp_rule_add(ogs_pfcp_pdr_t *pdr); +ogs_pfcp_rule_t *ogs_pfcp_rule_find_by_sdf_filter_id( + ogs_pfcp_sess_t *sess, uint32_t sdf_filter_id); void ogs_pfcp_rule_remove(ogs_pfcp_rule_t *rule); void ogs_pfcp_rule_remove_all(ogs_pfcp_pdr_t *pdr); int ogs_pfcp_ue_pool_generate(void); ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc( - int family, const char *apn, uint8_t *addr); + int family, const char *dnn, uint8_t *addr); void ogs_pfcp_ue_ip_free(ogs_pfcp_ue_ip_t *ip); ogs_pfcp_dev_t *ogs_pfcp_dev_add(const char *ifname); @@ -375,11 +397,12 @@ ogs_pfcp_dev_t *ogs_pfcp_dev_find_by_ifname(const char *ifname); ogs_pfcp_subnet_t *ogs_pfcp_subnet_add( const char *ipstr, const char *mask_or_numbits, - const char *apn, const char *ifname); + const char *dnn, const char *ifname); ogs_pfcp_subnet_t *ogs_pfcp_subnet_next(ogs_pfcp_subnet_t *subnet); void ogs_pfcp_subnet_remove(ogs_pfcp_subnet_t *subnet); void ogs_pfcp_subnet_remove_all(void); -ogs_pfcp_subnet_t *ogs_pfcp_find_subnet(int family, const char *apn); +ogs_pfcp_subnet_t *ogs_pfcp_find_subnet(int family); +ogs_pfcp_subnet_t *ogs_pfcp_find_subnet_by_dnn(int family, const char *dnn); void ogs_pfcp_pool_init(ogs_pfcp_sess_t *sess); void ogs_pfcp_pool_final(ogs_pfcp_sess_t *sess); diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index 0d2388e9a..0116fdd6f 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -177,7 +177,7 @@ void ogs_pfcp_up_handle_pdr( buffering = true; } else { - ogs_error("Not implemented"); + ogs_error("Not implemented = %d", far->apply_action); ogs_pkbuf_free(sendbuf); } } @@ -280,29 +280,64 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_rule_remove_all(pdr); for (i = 0; i < OGS_MAX_NUM_OF_RULE; i++) { - ogs_pfcp_sdf_filter_t sdf_filter_in_message; + ogs_pfcp_sdf_filter_t sdf_filter; + ogs_pfcp_rule_t *rule = NULL; + ogs_pfcp_rule_t *oppsite_direction_rule = NULL; + if (message->pdi.sdf_filter[i].presence == 0) break; len = ogs_pfcp_parse_sdf_filter( - &sdf_filter_in_message, &message->pdi.sdf_filter[i]); + &sdf_filter, &message->pdi.sdf_filter[i]); ogs_assert(message->pdi.sdf_filter[i].len == len); - if (sdf_filter_in_message.fd) { - ogs_pfcp_rule_t *rule = NULL; + + /* Check Previous SDF Filter ID */ + if (sdf_filter.bid) { + oppsite_direction_rule = ogs_pfcp_rule_find_by_sdf_filter_id( + sess, sdf_filter.sdf_filter_id); + + } + + if (!oppsite_direction_rule && !sdf_filter.fd) { + ogs_error("Not Supported SDF Filter [Flags:0x%x, Len:%d]", + sdf_filter.flags, message->pdi.sdf_filter[i].len); + ogs_log_hexdump(OGS_LOG_ERROR, + message->pdi.sdf_filter[i].data, + message->pdi.sdf_filter[i].len); + continue; + } + + rule = ogs_pfcp_rule_add(pdr); + ogs_assert(rule); + + /* Set All Flags (BID, FL, SPI, TTC, FD) */ + rule->flags = sdf_filter.flags; + + if (oppsite_direction_rule) { + /* Copy oppsite direction rule and Swap */ + memcpy(&rule->ipfw, + &oppsite_direction_rule->ipfw, sizeof(rule->ipfw)); + ogs_ipfw_rule_swap(&rule->ipfw); + } + + /* If BID, Store SDF Filter ID */ + if (rule->bid) + rule->sdf_filter_id = sdf_filter.sdf_filter_id; + + /* If FD, Apply Flow-Description to the RULE */ + if (rule->fd) { char *flow_description = NULL; flow_description = ogs_malloc( - sdf_filter_in_message.flow_description_len+1); + sdf_filter.flow_description_len+1); ogs_cpystrn(flow_description, - sdf_filter_in_message.flow_description, - sdf_filter_in_message.flow_description_len+1); - - rule = ogs_pfcp_rule_add(pdr); - ogs_assert(rule); + sdf_filter.flow_description, + sdf_filter.flow_description_len+1); rv = ogs_ipfw_compile_rule(&rule->ipfw, flow_description); ogs_assert(rv == OGS_OK); + ogs_free(flow_description); /* * * TS29.244 Ch 5.2.1A.2A @@ -337,8 +372,6 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, /* Uplink data flow */ if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) ogs_ipfw_rule_swap(&rule->ipfw); - - ogs_free(flow_description); } } @@ -364,6 +397,12 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, pdr->qfi = message->pdi.qfi.u8; } + if (message->pdi.ue_ip_address.presence) { + pdr->ue_ip_addr_len = message->pdi.ue_ip_address.len; + memcpy(&pdr->ue_ip_addr, + message->pdi.ue_ip_address.data, pdr->ue_ip_addr_len); + } + if (message->outer_header_removal.presence) { pdr->outer_header_removal_len = message->outer_header_removal.len; memcpy(&pdr->outer_header_removal, message->outer_header_removal.data, @@ -382,12 +421,6 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_associate_qer(pdr, qer); } - if (message->far_id.presence) { - far = ogs_pfcp_far_find_or_add(sess, message->far_id.u32); - ogs_assert(far); - ogs_pfcp_pdr_associate_far(pdr, far); - } - if (message->qer_id.presence) { qer = ogs_pfcp_qer_find_or_add(sess, message->qer_id.u32); ogs_assert(qer); @@ -475,67 +508,99 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_update_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_rule_remove_all(pdr); for (i = 0; i < OGS_MAX_NUM_OF_RULE; i++) { - ogs_pfcp_sdf_filter_t sdf_filter_in_message; + ogs_pfcp_sdf_filter_t sdf_filter; + ogs_pfcp_rule_t *rule = NULL; + ogs_pfcp_rule_t *oppsite_direction_rule = NULL; if (message->pdi.sdf_filter[i].presence == 0) break; len = ogs_pfcp_parse_sdf_filter( - &sdf_filter_in_message, &message->pdi.sdf_filter[i]); + &sdf_filter, &message->pdi.sdf_filter[i]); ogs_assert(message->pdi.sdf_filter[i].len == len); - if (sdf_filter_in_message.fd) { - ogs_pfcp_rule_t *rule = NULL; + + /* Check Previous SDF Filter ID */ + if (sdf_filter.bid) { + oppsite_direction_rule = ogs_pfcp_rule_find_by_sdf_filter_id( + sess, sdf_filter.sdf_filter_id); + + } + + if (!oppsite_direction_rule && !sdf_filter.fd) { + ogs_error("Not Supported SDF Filter [Flags:0x%x, Len:%d]", + sdf_filter.flags, message->pdi.sdf_filter[i].len); + ogs_log_hexdump(OGS_LOG_ERROR, + message->pdi.sdf_filter[i].data, + message->pdi.sdf_filter[i].len); + continue; + } + + rule = ogs_pfcp_rule_add(pdr); + ogs_assert(rule); + + /* Set All Flags (BID, FL, SPI, TTC, FD) */ + rule->flags = sdf_filter.flags; + + if (oppsite_direction_rule) { + /* Copy oppsite direction rule and Swap */ + memcpy(&rule->ipfw, + &oppsite_direction_rule->ipfw, sizeof(rule->ipfw)); + ogs_ipfw_rule_swap(&rule->ipfw); + } + + /* If BID, Store SDF Filter ID */ + if (rule->bid) + rule->sdf_filter_id = sdf_filter.sdf_filter_id; + + /* If FD, Apply Flow-Description to the RULE */ + if (rule->fd) { char *flow_description = NULL; flow_description = ogs_malloc( - sdf_filter_in_message.flow_description_len+1); + sdf_filter.flow_description_len+1); ogs_cpystrn(flow_description, - sdf_filter_in_message.flow_description, - sdf_filter_in_message.flow_description_len+1); + sdf_filter.flow_description, + sdf_filter.flow_description_len+1); - rule = ogs_pfcp_rule_add(pdr); - ogs_assert(rule); rv = ogs_ipfw_compile_rule(&rule->ipfw, flow_description); ogs_assert(rv == OGS_OK); -/* - * - * TS29.244 Ch 5.2.1A.2A - * - * The UP function shall apply the SDF filter based on the Source Interface - * of the PDR as follows (see also clause 8.2.5): - * - * - when the Source Interface is CORE, this indicates that the filter is - * for downlink data flow, so the UP function shall apply - * the Flow Description as is; - * - * - when the Source Interface is ACCESS, this indicates that the filter is - * for uplink data flow, so the UP function shall swap the source and - * destination address/port in the Flow Description; - * - * - when the Source Interface is CP-function or SGi-LAN, - * the UP function shall use the Flow Description as is. - * - * - * Refer to lib/ipfw/ogs-ipfw.h - * Issue #338 - * - * - * GX : permit out from to - * RULE : Source Destination - * - * - * GX : permit out from to - * RULE : Source Destination - */ + ogs_free(flow_description); + /* + * + * TS29.244 Ch 5.2.1A.2A + * + * The UP function shall apply the SDF filter based on the Source Interface + * of the PDR as follows (see also clause 8.2.5): + * + * - when the Source Interface is CORE, this indicates that the filter is + * for downlink data flow, so the UP function shall apply + * the Flow Description as is; + * + * - when the Source Interface is ACCESS, this indicates that the filter is + * for uplink data flow, so the UP function shall swap the source and + * destination address/port in the Flow Description; + * + * - when the Source Interface is CP-function or SGi-LAN, + * the UP function shall use the Flow Description as is. + * + * + * Refer to lib/ipfw/ogs-ipfw.h + * Issue #338 + * + * + * GX : permit out from to + * RULE : Source Destination + * + * + * GX : permit out from to + * RULE : Source Destination + */ /* Uplink data flow */ if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) ogs_ipfw_rule_swap(&rule->ipfw); - - ogs_free(flow_description); } - } if (message->pdi.network_instance.presence) { @@ -629,25 +694,28 @@ ogs_pfcp_far_t *ogs_pfcp_handle_create_far(ogs_pfcp_sess_t *sess, *offending_ie_value = OGS_PFCP_APPLY_ACTION_TYPE; return NULL; } - if (message->forwarding_parameters. - destination_interface.presence == 0) { - return far; - } far->apply_action = message->apply_action.u8; - far->dst_if = message->forwarding_parameters.destination_interface.u8; - if (message->forwarding_parameters.outer_header_creation.presence) { - ogs_pfcp_tlv_outer_header_creation_t *outer_header_creation = - &message->forwarding_parameters.outer_header_creation; + if (message->forwarding_parameters.presence) { + if (message->forwarding_parameters.destination_interface.presence) { + far->dst_if = + message->forwarding_parameters.destination_interface.u8; + } - ogs_assert(outer_header_creation->data); - ogs_assert(outer_header_creation->len); + if (message->forwarding_parameters.outer_header_creation.presence) { + ogs_pfcp_tlv_outer_header_creation_t *outer_header_creation = + &message->forwarding_parameters.outer_header_creation; + + ogs_assert(outer_header_creation->data); + ogs_assert(outer_header_creation->len); + + memcpy(&far->outer_header_creation, + outer_header_creation->data, outer_header_creation->len); + far->outer_header_creation.teid = + be32toh(far->outer_header_creation.teid); + } - memcpy(&far->outer_header_creation, - outer_header_creation->data, outer_header_creation->len); - far->outer_header_creation.teid = - be32toh(far->outer_header_creation.teid); } return far; @@ -724,8 +792,8 @@ ogs_pfcp_far_t *ogs_pfcp_handle_update_far(ogs_pfcp_sess_t *sess, if (message->update_forwarding_parameters.presence) { if (message->update_forwarding_parameters. destination_interface.presence) { - far->dst_if = message->update_forwarding_parameters. - destination_interface.u8; + far->dst_if = + message->update_forwarding_parameters.destination_interface.u8; } if (message->update_forwarding_parameters. @@ -889,3 +957,58 @@ bool ogs_pfcp_handle_remove_qer(ogs_pfcp_sess_t *sess, return true; } + +ogs_pfcp_bar_t *ogs_pfcp_handle_create_bar(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_create_bar_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_assert(message); + ogs_assert(sess); + + if (message->presence == 0) + return NULL; + + if (message->bar_id.presence == 0) { + ogs_error("No BAR-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_BAR_ID_TYPE; + return NULL; + } + + if (sess->bar) + ogs_pfcp_bar_delete(sess->bar); + + ogs_pfcp_bar_new(sess); + ogs_assert(sess->bar); + + sess->bar->id = message->bar_id.u8; + + return sess->bar; +} + +bool ogs_pfcp_handle_remove_bar(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_remove_bar_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_assert(sess); + ogs_assert(message); + + if (message->presence == 0) + return false; + + if (message->bar_id.presence == 0) { + ogs_error("No BAR-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_BAR_ID_TYPE; + return false; + } + + if (sess->bar && sess->bar->id == message->bar_id.u8) { + ogs_pfcp_bar_delete(sess->bar); + return true; + } + + ogs_error("[%p] Unknown BAR-ID[%d]", sess->bar, message->bar_id.u8); + *cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + return false; +} diff --git a/lib/pfcp/handler.h b/lib/pfcp/handler.h index 04255c1ed..9ca0e5efb 100644 --- a/lib/pfcp/handler.h +++ b/lib/pfcp/handler.h @@ -87,6 +87,13 @@ bool ogs_pfcp_handle_remove_qer(ogs_pfcp_sess_t *sess, ogs_pfcp_tlv_remove_qer_t *message, uint8_t *cause_value, uint8_t *offending_ie_value); +ogs_pfcp_bar_t *ogs_pfcp_handle_create_bar(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_create_bar_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value); +bool ogs_pfcp_handle_remove_bar(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_remove_bar_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value); + #ifdef __cplusplus } #endif diff --git a/lib/pfcp/path.c b/lib/pfcp/path.c index 592356f61..c905091d7 100644 --- a/lib/pfcp/path.c +++ b/lib/pfcp/path.c @@ -278,6 +278,12 @@ void ogs_pfcp_send_g_pdu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf) return; } + if (far->dst_if == OGS_PFCP_INTERFACE_UNKNOWN) { + ogs_error("No Destination Interface"); + ogs_pkbuf_free(sendbuf); + return; + } + gnode = far->gnode; ogs_assert(gnode); ogs_assert(gnode->sock); diff --git a/lib/pfcp/types.h b/lib/pfcp/types.h index ef2192ffd..5e31eda32 100644 --- a/lib/pfcp/types.h +++ b/lib/pfcp/types.h @@ -480,23 +480,28 @@ ED3(uint8_t spare:6;, * if the CHID bit in octet 5 is set to "1". */ typedef struct ogs_pfcp_f_teid_s { -ED5(uint8_t spare:4;, +ED5(uint8_t spare1:4;, uint8_t chid:1;, uint8_t ch:1;, uint8_t ipv6:1;, uint8_t ipv4:1;) union { - uint32_t teid; - uint8_t choose_id; - }; - union { - union { - uint32_t addr; - uint8_t addr6[OGS_IPV6_LEN]; - struct { + struct { + ED4(uint8_t choose_id;, + uint8_t spare2;, + uint8_t spare3;, + uint8_t spare4;) + }; + struct { + uint32_t teid; + union { uint32_t addr; uint8_t addr6[OGS_IPV6_LEN]; - } both; + struct { + uint32_t addr; + uint8_t addr6[OGS_IPV6_LEN]; + } both; + }; }; }; } __attribute__ ((packed)) ogs_pfcp_f_teid_t; @@ -797,7 +802,6 @@ int16_t ogs_pfcp_parse_user_plane_ip_resource_info( * the UP function shall apply the SDF filter as specified in clause 5.2.1A.2A. */ -#define OGS_PFCP_MAX_SDF_FILTER_LEN 256 typedef struct ogs_pfcp_sdf_filter_s { union { struct { diff --git a/src/pcrf/pcrf-gx-path.c b/src/pcrf/pcrf-gx-path.c index 87aa1e27a..672b9248b 100644 --- a/src/pcrf/pcrf-gx-path.c +++ b/src/pcrf/pcrf-gx-path.c @@ -1348,10 +1348,8 @@ static int flow_rx_to_gx(ogs_flow_t *rx_flow, ogs_flow_t *gx_flow) if (!strncmp(rx_flow->description, "permit out", strlen("permit out"))) { gx_flow->direction = OGS_FLOW_DOWNLINK_ONLY; + gx_flow->description = ogs_strdup(rx_flow->description); - len = strlen(rx_flow->description)+1; - gx_flow->description = ogs_malloc(len); - ogs_cpystrn(gx_flow->description, rx_flow->description, len); } else if (!strncmp(rx_flow->description, "permit in", strlen("permit in"))) { gx_flow->direction = OGS_FLOW_UPLINK_ONLY; diff --git a/src/sgwc/context.c b/src/sgwc/context.c index 886db9ad1..605c6b6c1 100644 --- a/src/sgwc/context.c +++ b/src/sgwc/context.c @@ -409,6 +409,9 @@ sgwc_sess_t *sgwc_sess_add(sgwc_ue_t *sgwc_ue, char *apn) sess->sgw_s5c_teid = sess->index; sess->sgwc_sxa_seid = sess->index; + /* Create BAR in PFCP Session */ + ogs_pfcp_bar_new(&sess->pfcp); + /* Set APN */ ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); @@ -431,8 +434,8 @@ static bool compare_ue_info(ogs_pfcp_node_t *node, sgwc_sess_t *sess) sgwc_ue = sess->sgwc_ue; ogs_assert(sgwc_ue); - for (i = 0; i < node->num_of_apn; i++) - if (ogs_strcasecmp(node->apn[i], sess->pdn.apn) == 0) return true; + for (i = 0; i < node->num_of_dnn; i++) + if (ogs_strcasecmp(node->dnn[i], sess->pdn.apn) == 0) return true; for (i = 0; i < node->num_of_e_cell_id; i++) if (node->e_cell_id[i] == sgwc_ue->e_cgi.cell_id) return true; @@ -532,6 +535,9 @@ int sgwc_sess_remove(sgwc_sess_t *sess) sgwc_bearer_remove_all(sess); + ogs_assert(sess->pfcp.bar); + ogs_pfcp_bar_delete(sess->pfcp.bar); + ogs_pfcp_pool_final(&sess->pfcp); ogs_pool_free(&sgwc_sess_pool, sess); @@ -812,9 +818,14 @@ sgwc_tunnel_t *sgwc_tunnel_add( far = ogs_pfcp_far_add(&sess->pfcp); ogs_assert(far); + far->dst_if = dst_if; ogs_pfcp_pdr_associate_far(pdr, far); + far->apply_action = + OGS_PFCP_APPLY_ACTION_BUFF| OGS_PFCP_APPLY_ACTION_NOCP; + ogs_assert(sess->pfcp.bar); + ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { pdr->f_teid.ch = 1; diff --git a/src/sgwc/s11-handler.c b/src/sgwc/s11-handler.c index 4e4401c8a..52ba6fbb7 100644 --- a/src/sgwc/s11-handler.c +++ b/src/sgwc/s11-handler.c @@ -383,6 +383,8 @@ void sgwc_s11_handle_modify_bearer_request( far = dl_tunnel->far; ogs_assert(far); + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation(&dl_tunnel->remote_ip, &far->outer_header_creation, &far->outer_header_creation_len); far->outer_header_creation.teid = dl_tunnel->remote_teid; @@ -605,6 +607,8 @@ void sgwc_s11_handle_create_bearer_response( far = dl_tunnel->far; ogs_assert(far); + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation(&dl_tunnel->remote_ip, &far->outer_header_creation, &far->outer_header_creation_len); far->outer_header_creation.teid = dl_tunnel->remote_teid; @@ -984,6 +988,8 @@ void sgwc_s11_handle_create_indirect_data_forwarding_tunnel_request( far = tunnel->far; ogs_assert(far); + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation(&tunnel->remote_ip, &far->outer_header_creation, &far->outer_header_creation_len); far->outer_header_creation.teid = tunnel->remote_teid; @@ -1014,6 +1020,8 @@ void sgwc_s11_handle_create_indirect_data_forwarding_tunnel_request( far = tunnel->far; ogs_assert(far); + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation(&tunnel->remote_ip, &far->outer_header_creation, &far->outer_header_creation_len); far->outer_header_creation.teid = tunnel->remote_teid; diff --git a/src/sgwc/s5c-handler.c b/src/sgwc/s5c-handler.c index 4cf3e60dc..135dda9f9 100644 --- a/src/sgwc/s5c-handler.c +++ b/src/sgwc/s5c-handler.c @@ -203,6 +203,8 @@ void sgwc_s5c_handle_create_session_response( far = ul_tunnel->far; ogs_assert(far); + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation(&ul_tunnel->remote_ip, &far->outer_header_creation, &far->outer_header_creation_len); far->outer_header_creation.teid = ul_tunnel->remote_teid; @@ -369,6 +371,8 @@ void sgwc_s5c_handle_create_bearer_request( far = ul_tunnel->far; ogs_assert(far); + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation(&ul_tunnel->remote_ip, &far->outer_header_creation, &far->outer_header_creation_len); far->outer_header_creation.teid = ul_tunnel->remote_teid; diff --git a/src/sgwc/sxa-build.c b/src/sgwc/sxa-build.c index 686022027..5d30b2bdb 100644 --- a/src/sgwc/sxa-build.c +++ b/src/sgwc/sxa-build.c @@ -90,6 +90,11 @@ ogs_pkbuf_t *sgwc_sxa_build_session_establishment_request( i++; } + /* Create BAR */ + if (sess->pfcp.bar) { + ogs_pfcp_build_create_bar(&req->create_bar, sess->pfcp.bar); + } + /* PDN Type */ req->pdn_type.presence = 1; req->pdn_type.u8 = sess->pdn.paa.pdn_type; diff --git a/src/sgwu/context.c b/src/sgwu/context.c index 88b9cea2d..e1c2b8cc4 100644 --- a/src/sgwu/context.c +++ b/src/sgwu/context.c @@ -410,13 +410,11 @@ int sgwu_context_parse_config(void) return OGS_OK; } -sgwu_sess_t *sgwu_sess_add( - ogs_pfcp_f_seid_t *cp_f_seid, const char *apn, uint8_t pdn_type) +sgwu_sess_t *sgwu_sess_add(ogs_pfcp_f_seid_t *cp_f_seid) { sgwu_sess_t *sess = NULL; ogs_assert(cp_f_seid); - ogs_assert(apn); ogs_pool_alloc(&sgwu_sess_pool, &sess); ogs_assert(sess); @@ -432,11 +430,8 @@ sgwu_sess_t *sgwu_sess_add( ogs_hash_set(self.sess_hash, &sess->sgwc_sxa_seid, sizeof(sess->sgwc_sxa_seid), sess); - /* Set APN */ - ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); - - ogs_info("UE F-SEID[CP:0x%lx,UP:0x%lx] APN[%s] PDN-Type[%d]", - (long)sess->sgwu_sxa_seid, (long)sess->sgwc_sxa_seid, apn, pdn_type); + ogs_info("UE F-SEID[CP:0x%lx,UP:0x%lx]", + (long)sess->sgwu_sxa_seid, (long)sess->sgwc_sxa_seid); ogs_list_add(&self.sess_list, sess); @@ -496,11 +491,9 @@ sgwu_sess_t *sgwu_sess_add_by_message(ogs_pfcp_message_t *message) sgwu_sess_t *sess = NULL; ogs_pfcp_f_seid_t *f_seid = NULL; - char apn[OGS_MAX_APN_LEN]; ogs_pfcp_session_establishment_request_t *req = &message->pfcp_session_establishment_request;; - int i; f_seid = req->cp_f_seid.data; if (req->cp_f_seid.presence == 0 || f_seid == NULL) { @@ -509,42 +502,9 @@ sgwu_sess_t *sgwu_sess_add_by_message(ogs_pfcp_message_t *message) } f_seid->seid = be64toh(f_seid->seid); - if (req->pdn_type.presence == 0) { - ogs_error("No PDN Type"); - return NULL; - } - - /* Find APN - * - PDR ID is existed - * - APN(Network Instance) is existed - */ - memset(apn, 0, sizeof(apn)); - for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { - ogs_pfcp_tlv_create_pdr_t *message = &req->create_pdr[i]; - ogs_assert(message); - if (message->presence == 0) - continue; - if (message->pdr_id.presence == 0) - continue; - if (message->pdi.presence == 0) - continue; - if (message->pdi.network_instance.presence == 0) - continue; - - ogs_fqdn_parse(apn, - message->pdi.network_instance.data, - message->pdi.network_instance.len); - break; - } - - if (strlen(apn) == 0) { - ogs_error("No APN in PDR"); - return NULL; - } - sess = sgwu_sess_find_by_cp_seid(f_seid->seid); if (!sess) { - sess = sgwu_sess_add(f_seid, apn, req->pdn_type.u8); + sess = sgwu_sess_add(f_seid); if (!sess) return NULL; } ogs_assert(sess); diff --git a/src/sgwu/context.h b/src/sgwu/context.h index 3914f4562..42ed0185b 100644 --- a/src/sgwu/context.h +++ b/src/sgwu/context.h @@ -72,8 +72,7 @@ int sgwu_context_parse_config(void); sgwu_sess_t *sgwu_sess_add_by_message(ogs_pfcp_message_t *message); -sgwu_sess_t *sgwu_sess_add( - ogs_pfcp_f_seid_t *f_seid, const char *apn, uint8_t pdn_type); +sgwu_sess_t *sgwu_sess_add(ogs_pfcp_f_seid_t *f_seid); int sgwu_sess_remove(sgwu_sess_t *sess); void sgwu_sess_remove_all(void); sgwu_sess_t *sgwu_sess_find(uint32_t index); diff --git a/src/sgwu/sxa-handler.c b/src/sgwu/sxa-handler.c index 8a72b43a4..47a0782d3 100644 --- a/src/sgwu/sxa-handler.c +++ b/src/sgwu/sxa-handler.c @@ -76,7 +76,7 @@ void sgwu_sxa_handle_session_establishment_request( ogs_error("No Context"); ogs_pfcp_send_error_message(xact, 0, OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE, - OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0); + OGS_PFCP_CAUSE_MANDATORY_IE_MISSING, 0); return; } @@ -106,6 +106,11 @@ void sgwu_sxa_handle_session_establishment_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + ogs_pfcp_handle_create_bar(&sess->pfcp, &req->create_bar, + &cause_value, &offending_ie_value); + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + /* Setup GTP Node */ ogs_list_for_each(&sess->pfcp.far_list, far) setup_gtp_node(far); @@ -118,32 +123,50 @@ void sgwu_sxa_handle_session_establishment_request( if (pdr->f_teid_len) { if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) { - ogs_pfcp_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_gtpu_resource_find( - &ogs_pfcp_self()->gtpu_resource_list, - sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_pfcp_user_plane_ip_resource_info_to_f_teid( - &resource->info, &pdr->f_teid, &pdr->f_teid_len); - if (resource->info.teidri) - pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - pdr->index, resource->info.teidri, - resource->info.teid_range); - else - pdr->f_teid.teid = pdr->index; + + ogs_pfcp_pdr_t *choosed_pdr = NULL; + + if (pdr->f_teid.chid) { + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( + &sess->pfcp, pdr->f_teid.choose_id); + if (!choosed_pdr) { + pdr->chid = true; + pdr->choose_id = pdr->f_teid.choose_id; + } + } + + if (choosed_pdr) { + pdr->f_teid_len = choosed_pdr->f_teid_len; + memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); + } else { - ogs_sockaddr_t *addr = NULL, *addr6 = NULL; + ogs_pfcp_gtpu_resource_t *resource = NULL; + resource = ogs_pfcp_gtpu_resource_find( + &ogs_pfcp_self()->gtpu_resource_list, + pdr->apn, OGS_PFCP_INTERFACE_ACCESS); + if (resource) { + ogs_pfcp_user_plane_ip_resource_info_to_f_teid( + &resource->info, &pdr->f_teid, &pdr->f_teid_len); + if (resource->info.teidri) + pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( + pdr->index, resource->info.teidri, + resource->info.teid_range); + else + pdr->f_teid.teid = pdr->index; + } else { + ogs_sockaddr_t *addr = NULL, *addr6 = NULL; - if (sgwu_self()->gtpu_sock) - addr = &sgwu_self()->gtpu_sock->local_addr; - if (sgwu_self()->gtpu_sock6) - addr6 = &sgwu_self()->gtpu_sock6->local_addr; + if (sgwu_self()->gtpu_sock) + addr = &sgwu_self()->gtpu_sock->local_addr; + if (sgwu_self()->gtpu_sock6) + addr6 = &sgwu_self()->gtpu_sock6->local_addr; - ogs_assert(addr || addr6); - ogs_pfcp_sockaddr_to_f_teid( - addr, addr6, &pdr->f_teid, &pdr->f_teid_len); + ogs_assert(addr || addr6); + ogs_pfcp_sockaddr_to_f_teid( + addr, addr6, &pdr->f_teid, &pdr->f_teid_len); - pdr->f_teid.teid = pdr->index; + pdr->f_teid.teid = pdr->index; + } } } @@ -280,6 +303,16 @@ void sgwu_sxa_handle_session_modification_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + ogs_pfcp_handle_create_bar(&sess->pfcp, &req->create_bar, + &cause_value, &offending_ie_value); + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + ogs_pfcp_handle_remove_bar(&sess->pfcp, &req->remove_bar, + &cause_value, &offending_ie_value); + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + /* Setup GTP Node */ ogs_list_for_each(&sess->pfcp.far_list, far) setup_gtp_node(far); @@ -292,32 +325,50 @@ void sgwu_sxa_handle_session_modification_request( if (pdr->f_teid_len) { if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) { - ogs_pfcp_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_gtpu_resource_find( - &ogs_pfcp_self()->gtpu_resource_list, - sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_pfcp_user_plane_ip_resource_info_to_f_teid( - &resource->info, &pdr->f_teid, &pdr->f_teid_len); - if (resource->info.teidri) - pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - pdr->index, resource->info.teidri, - resource->info.teid_range); - else - pdr->f_teid.teid = pdr->index; + + ogs_pfcp_pdr_t *choosed_pdr = NULL; + + if (pdr->f_teid.chid) { + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( + &sess->pfcp, pdr->f_teid.choose_id); + if (!choosed_pdr) { + pdr->chid = true; + pdr->choose_id = pdr->f_teid.choose_id; + } + } + + if (choosed_pdr) { + pdr->f_teid_len = choosed_pdr->f_teid_len; + memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); + } else { - ogs_sockaddr_t *addr = NULL, *addr6 = NULL; + ogs_pfcp_gtpu_resource_t *resource = NULL; + resource = ogs_pfcp_gtpu_resource_find( + &ogs_pfcp_self()->gtpu_resource_list, + pdr->apn, OGS_PFCP_INTERFACE_ACCESS); + if (resource) { + ogs_pfcp_user_plane_ip_resource_info_to_f_teid( + &resource->info, &pdr->f_teid, &pdr->f_teid_len); + if (resource->info.teidri) + pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( + pdr->index, resource->info.teidri, + resource->info.teid_range); + else + pdr->f_teid.teid = pdr->index; + } else { + ogs_sockaddr_t *addr = NULL, *addr6 = NULL; - if (sgwu_self()->gtpu_sock) - addr = &sgwu_self()->gtpu_sock->local_addr; - if (sgwu_self()->gtpu_sock6) - addr6 = &sgwu_self()->gtpu_sock6->local_addr; + if (sgwu_self()->gtpu_sock) + addr = &sgwu_self()->gtpu_sock->local_addr; + if (sgwu_self()->gtpu_sock6) + addr6 = &sgwu_self()->gtpu_sock6->local_addr; - ogs_assert(addr || addr6); - ogs_pfcp_sockaddr_to_f_teid( - addr, addr6, &pdr->f_teid, &pdr->f_teid_len); + ogs_assert(addr || addr6); + ogs_pfcp_sockaddr_to_f_teid( + addr, addr6, &pdr->f_teid, &pdr->f_teid_len); - pdr->f_teid.teid = pdr->index; + pdr->f_teid.teid = pdr->index; + } } } diff --git a/src/smf/context.c b/src/smf/context.c index 5ebbee4dc..95876324c 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -363,7 +363,8 @@ int smf_context_parse_config(void) if (v) port = atoi(v); } else if (!strcmp(gtpc_key, "dev")) { dev = ogs_yaml_iter_value(>pc_iter); - } else if (!strcmp(gtpc_key, "apn")) { + } else if (!strcmp(gtpc_key, "apn") || + !strcmp(gtpc_key, "dnn")) { /* Skip */ } else ogs_warn("unknown key `%s`", gtpc_key); @@ -611,8 +612,8 @@ static bool compare_ue_info(ogs_pfcp_node_t *node, smf_sess_t *sess) ogs_assert(node); ogs_assert(sess); - for (i = 0; i < node->num_of_apn; i++) - if (ogs_strcasecmp(node->apn[i], sess->pdn.apn) == 0) return true; + for (i = 0; i < node->num_of_dnn; i++) + if (ogs_strcasecmp(node->dnn[i], sess->pdn.dnn) == 0) return true; for (i = 0; i < node->num_of_e_cell_id; i++) if (node->e_cell_id[i] == sess->e_cgi.cell_id) return true; @@ -731,6 +732,9 @@ smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn) sess->smf_n4_teid = sess->index; sess->smf_n4_seid = sess->index; + /* Create BAR in PFCP Session */ + ogs_pfcp_bar_new(&sess->pfcp); + /* Set APN */ ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); @@ -837,6 +841,9 @@ smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi) (int)ogs_pool_index(&smf_sess_pool, sess)); ogs_assert(sess->sm_context_ref); + /* Create BAR in PFCP Session */ + ogs_pfcp_bar_new(&sess->pfcp); + /* Set PSI */ sess->psi = psi; @@ -934,8 +941,8 @@ void smf_sess_set_ue_ip(smf_sess_t *sess) ogs_pfcp_subnet_t *subnet = NULL; ogs_pfcp_subnet_t *subnet6 = NULL; - subnet = ogs_pfcp_find_subnet(AF_INET, sess->pdn.apn); - subnet6 = ogs_pfcp_find_subnet(AF_INET6, sess->pdn.apn); + subnet = ogs_pfcp_find_subnet_by_dnn(AF_INET, sess->pdn.dnn); + subnet6 = ogs_pfcp_find_subnet_by_dnn(AF_INET6, sess->pdn.dnn); if (subnet != NULL && subnet6 == NULL) sess->pdn.pdn_type = OGS_PDU_SESSION_TYPE_IPV4; @@ -959,14 +966,14 @@ void smf_sess_set_ue_ip(smf_sess_t *sess) if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4) { sess->ipv4 = ogs_pfcp_ue_ip_alloc( - AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr); + AF_INET, sess->pdn.dnn, (uint8_t *)&sess->pdn.ue_ip.addr); ogs_assert(sess->ipv4); sess->pdn.paa.addr = sess->ipv4->addr[0]; ogs_hash_set(smf_self()->ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); } else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV6) { sess->ipv6 = ogs_pfcp_ue_ip_alloc( - AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6); + AF_INET6, sess->pdn.dnn, sess->pdn.ue_ip.addr6); ogs_assert(sess->ipv6); subnet6 = sess->ipv6->subnet; @@ -978,10 +985,10 @@ void smf_sess_set_ue_ip(smf_sess_t *sess) sess->ipv6->addr, OGS_IPV6_LEN, sess); } else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4V6) { sess->ipv4 = ogs_pfcp_ue_ip_alloc( - AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr); + AF_INET, sess->pdn.dnn, (uint8_t *)&sess->pdn.ue_ip.addr); ogs_assert(sess->ipv4); sess->ipv6 = ogs_pfcp_ue_ip_alloc( - AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6); + AF_INET6, sess->pdn.dnn, sess->pdn.ue_ip.addr6); ogs_assert(sess->ipv6); subnet6 = sess->ipv6->subnet; @@ -1013,9 +1020,9 @@ void smf_sess_remove(smf_sess_t *sess) smf_ue = sess->smf_ue; ogs_assert(smf_ue); - ogs_info("Removed Session: UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]", + ogs_info("Removed Session: UE IMSI:[%s] DNN:[%s] IPv4:[%s] IPv6:[%s]", smf_ue->imsi_bcd, - sess->pdn.apn, + sess->pdn.dnn, sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); @@ -1068,6 +1075,9 @@ void smf_sess_remove(smf_sess_t *sess) smf_bearer_remove_all(sess); + ogs_assert(sess->pfcp.bar); + ogs_pfcp_bar_delete(sess->pfcp.bar); + ogs_pfcp_pool_final(&sess->pfcp); smf_qfi_pool_final(sess); @@ -1221,6 +1231,10 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS; ogs_pfcp_pdr_associate_far(dl_pdr, dl_far); + dl_far->apply_action = + OGS_PFCP_APPLY_ACTION_BUFF| OGS_PFCP_APPLY_ACTION_NOCP; + ogs_assert(sess->pfcp.bar); + ul_far = ogs_pfcp_far_add(&sess->pfcp); ogs_assert(ul_far); qos_flow->ul_far = ul_far; @@ -1228,6 +1242,8 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) ul_far->dst_if = OGS_PFCP_INTERFACE_CORE; ogs_pfcp_pdr_associate_far(ul_pdr, ul_far); + ul_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + qer = ogs_pfcp_qer_add(&sess->pfcp); ogs_assert(qer); qos_flow->qer = qer; @@ -1323,6 +1339,10 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess) dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS; ogs_pfcp_pdr_associate_far(dl_pdr, dl_far); + dl_far->apply_action = + OGS_PFCP_APPLY_ACTION_BUFF| OGS_PFCP_APPLY_ACTION_NOCP; + ogs_assert(sess->pfcp.bar); + ul_far = ogs_pfcp_far_add(&sess->pfcp); ogs_assert(ul_far); bearer->ul_far = ul_far; @@ -1330,6 +1350,8 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess) ul_far->dst_if = OGS_PFCP_INTERFACE_CORE; ogs_pfcp_pdr_associate_far(ul_pdr, ul_far); + ul_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { ul_pdr->f_teid.ch = 1; diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c index a35bed56d..8e1b21865 100644 --- a/src/smf/gx-handler.c +++ b/src/smf/gx-handler.c @@ -135,6 +135,8 @@ void smf_gx_handle_cca_initial_request( dl_far = bearer->dl_far; ogs_assert(dl_far); + dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + /* Set Outer Header Creation to the Default DL FAR */ ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip, &dl_far->outer_header_creation, &dl_far->outer_header_creation_len); diff --git a/src/smf/n4-build.c b/src/smf/n4-build.c index fa0139dae..86cbeadeb 100644 --- a/src/smf/n4-build.c +++ b/src/smf/n4-build.c @@ -91,6 +91,11 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request( i++; } + /* Create BAR */ + if (sess->pfcp.bar) { + ogs_pfcp_build_create_bar(&req->create_bar, sess->pfcp.bar); + } + /* PDN Type */ req->pdn_type.presence = 1; req->pdn_type.u8 = sess->pdn.paa.pdn_type; @@ -171,6 +176,7 @@ ogs_pkbuf_t *smf_n4_build_qos_flow_modification_request( message->qer_id.u32 = qos_flow->qer->id; i++; } + } else { if (modify_flags & OGS_PFCP_MODIFY_CREATE) { ogs_pfcp_pdrbuf_init(); diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index 9568f5909..1ce5f9804 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -154,6 +154,9 @@ void smf_5gc_n4_handle_session_establishment_response( if (!pdr) break; + if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) + continue; + ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup && pdr->f_teid_len) { @@ -244,6 +247,9 @@ void smf_5gc_n4_handle_session_modification_response( if (!pdr) break; + if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) + continue; + ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup && pdr->f_teid_len) { @@ -419,6 +425,9 @@ void smf_epc_n4_handle_session_establishment_response( if (!pdr) break; + if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) + continue; + bearer = smf_bearer_find_by_pdr_id(sess, pdr->id); if (!bearer) { pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; @@ -521,6 +530,9 @@ void smf_epc_n4_handle_session_modification_response( if (!pdr) break; + if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) + continue; + ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup && pdr->f_teid_len) { diff --git a/src/smf/ngap-handler.c b/src/smf/ngap-handler.c index 2d69c38bd..378aeec8e 100644 --- a/src/smf/ngap-handler.c +++ b/src/smf/ngap-handler.c @@ -128,6 +128,8 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( memcpy(&sess->gnb_n3_ip, &upf_n3_ip, sizeof(sess->gnb_n3_ip)); sess->gnb_n3_teid = upf_n3_teid; + dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation(&sess->gnb_n3_ip, &dl_far->outer_header_creation, &dl_far->outer_header_creation_len); dl_far->outer_header_creation.teid = sess->gnb_n3_teid; diff --git a/src/smf/s5c-handler.c b/src/smf/s5c-handler.c index 6bb72e365..36473f359 100644 --- a/src/smf/s5c-handler.c +++ b/src/smf/s5c-handler.c @@ -373,6 +373,8 @@ void smf_s5c_handle_create_bearer_response( dl_far = bearer->dl_far; ogs_assert(dl_far); + dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip, &dl_far->outer_header_creation, &dl_far->outer_header_creation_len); dl_far->outer_header_creation.teid = bearer->sgw_s5u_teid; diff --git a/src/upf/context.c b/src/upf/context.c index c77d7ec03..efe981fba 100644 --- a/src/upf/context.c +++ b/src/upf/context.c @@ -420,16 +420,11 @@ int upf_context_parse_config(void) return OGS_OK; } -upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid, - const char *apn, uint8_t pdn_type, ogs_pfcp_ue_ip_addr_t *ue_ip) +upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid) { - char buf1[OGS_ADDRSTRLEN]; - char buf2[OGS_ADDRSTRLEN]; upf_sess_t *sess = NULL; ogs_assert(cp_f_seid); - ogs_assert(apn); - ogs_assert(ue_ip); ogs_pool_alloc(&upf_sess_pool, &sess); ogs_assert(sess); @@ -445,67 +440,12 @@ upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid, ogs_hash_set(self.sess_hash, &sess->smf_n4_seid, sizeof(sess->smf_n4_seid), sess); - /* Set APN */ - ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); - - /* Set PDN-Type and UE IP Address */ - sess->pdn.pdn_type = pdn_type; - if (pdn_type == OGS_GTP_PDN_TYPE_IPV4) { - if (ue_ip->ipv4 == 0) { - ogs_error("Cannot support PDN-Type[%d] != [IPv4:%d, IPv6:%d]", - pdn_type, ue_ip->ipv4, ue_ip->ipv6); - goto cleanup; - } - sess->ipv4 = ogs_pfcp_ue_ip_alloc( - AF_INET, apn, (uint8_t *)&(ue_ip->addr)); - ogs_assert(sess->ipv4); - ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); - } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV6) { - if (ue_ip->ipv6 == 0) { - ogs_error("Cannot support PDN-Type[%d] != [IPv4:%d, IPv6:%d]", - pdn_type, ue_ip->ipv4, ue_ip->ipv6); - goto cleanup; - } - sess->ipv6 = ogs_pfcp_ue_ip_alloc(AF_INET6, apn, ue_ip->addr6); - ogs_assert(sess->ipv6); - ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); - } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) { - if (ue_ip->ipv4 == 0 || ue_ip->ipv6 == 0) { - ogs_error("Cannot support PDN-Type[%d] != [IPv4:%d, IPv6:%d]", - pdn_type, ue_ip->ipv4, ue_ip->ipv6); - goto cleanup; - } - sess->ipv4 = ogs_pfcp_ue_ip_alloc( - AF_INET, apn, (uint8_t *)&(ue_ip->both.addr)); - ogs_assert(sess->ipv4); - ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); - - sess->ipv6 = ogs_pfcp_ue_ip_alloc(AF_INET6, apn, ue_ip->both.addr6); - ogs_assert(sess->ipv6); - ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); - } else { - ogs_error("Cannot support PDN-Type[%d] != [IPv4:%d, IPv6:%d]", - pdn_type, ue_ip->ipv4, ue_ip->ipv6); - goto cleanup; - } - - ogs_info("UE F-SEID[CP:0x%lx,UP:0x%lx] " - "APN[%s] PDN-Type[%d] IPv4[%s] IPv6[%s]", - (long)sess->upf_n4_seid, (long)sess->smf_n4_seid, - apn, pdn_type, - sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", - sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); - ogs_list_add(&self.sess_list, sess); ogs_info("[Added] Number of UPF-Sessions is now %d", ogs_list_count(&self.sess_list)); return sess; - -cleanup: - ogs_pool_free(&upf_sess_pool, sess); - return NULL; } int upf_sess_remove(upf_sess_t *sess) @@ -578,15 +518,10 @@ upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6) upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message) { upf_sess_t *sess = NULL; - ogs_pfcp_f_seid_t *f_seid = NULL; - char apn[OGS_MAX_APN_LEN]; - ogs_pfcp_ue_ip_addr_t *addr = NULL; - bool default_pdr_found = false; ogs_pfcp_session_establishment_request_t *req = &message->pfcp_session_establishment_request;; - int i; f_seid = req->cp_f_seid.data; if (req->cp_f_seid.presence == 0 || f_seid == NULL) { @@ -595,69 +530,80 @@ upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message) } f_seid->seid = be64toh(f_seid->seid); - if (req->pdn_type.presence == 0) { - ogs_error("No PDN Type"); - return NULL; - } - - /* Find the Default PDR : - * - PDR ID is existed - * - SDF Filter is NOT existed - * - APN(Network Instance) is existed - * - UE IP Address is existed - * - Downlink PDR - */ - memset(apn, 0, sizeof(apn)); - for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { - ogs_pfcp_tlv_create_pdr_t *message = &req->create_pdr[i]; - ogs_assert(message); - if (message->presence == 0) - continue; - if (message->pdr_id.presence == 0) - continue; - if (message->pdi.presence == 0) - continue; - if (message->pdi.sdf_filter[0].presence) /* No SDF Filter */ - continue; - if (message->pdi.network_instance.presence == 0) - continue; - if (message->pdi.ue_ip_address.presence == 0) - continue; - if (message->pdi.source_interface.presence == 0) - continue; - if (message->pdi.source_interface.u8 != OGS_PFCP_INTERFACE_CORE) - continue; - - ogs_fqdn_parse(apn, - message->pdi.network_instance.data, - message->pdi.network_instance.len); - addr = message->pdi.ue_ip_address.data; - - default_pdr_found = true; - break; - } - - if (!default_pdr_found) { - ogs_error("Cannot find Default PDR"); - return NULL; - } - - if (strlen(apn) == 0) { - ogs_error("No APN in PDR"); - return NULL; - } - - if (!addr) { - ogs_error("No UE IP Address in PDR"); - return NULL; - } - sess = upf_sess_find_by_cp_seid(f_seid->seid); if (!sess) { - sess = upf_sess_add(f_seid, apn, req->pdn_type.u8, addr); + sess = upf_sess_add(f_seid); if (!sess) return NULL; } ogs_assert(sess); return sess; } + +void upf_sess_set_ue_ip(upf_sess_t *sess, + uint8_t pdn_type, ogs_pfcp_pdr_t *pdr) +{ + ogs_pfcp_ue_ip_addr_t *ue_ip = NULL; + char buf1[OGS_ADDRSTRLEN]; + char buf2[OGS_ADDRSTRLEN]; + + ogs_assert(sess); + ogs_assert(pdn_type); + ogs_assert(pdr); + ogs_assert(pdr->ue_ip_addr_len); + ue_ip = &pdr->ue_ip_addr; + ogs_assert(ue_ip); + + /* Set PDN-Type and UE IP Address */ + sess->pdn.pdn_type = pdn_type; + if (pdn_type == OGS_GTP_PDN_TYPE_IPV4) { + if (ue_ip->ipv4 || pdr->dnn) { + sess->ipv4 = ogs_pfcp_ue_ip_alloc( + AF_INET, pdr->dnn, (uint8_t *)&(ue_ip->addr)); + ogs_assert(sess->ipv4); + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); + } else { + ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6, pdr->dnn ? pdr->dnn : ""); + } + } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV6) { + if (ue_ip->ipv6 || pdr->dnn) { + sess->ipv6 = ogs_pfcp_ue_ip_alloc(AF_INET6, pdr->dnn, ue_ip->addr6); + ogs_assert(sess->ipv6); + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); + } else { + ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6, pdr->dnn ? pdr->dnn : ""); + } + } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) { + if (ue_ip->ipv4 || pdr->dnn) { + sess->ipv4 = ogs_pfcp_ue_ip_alloc( + AF_INET, pdr->dnn, (uint8_t *)&(ue_ip->both.addr)); + ogs_assert(sess->ipv4); + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); + } else { + ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6, pdr->dnn ? pdr->dnn : ""); + } + + if (ue_ip->ipv6 || pdr->dnn) { + sess->ipv6 = ogs_pfcp_ue_ip_alloc( + AF_INET6, pdr->dnn, ue_ip->both.addr6); + ogs_assert(sess->ipv6); + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); + } else { + ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6, pdr->dnn ? pdr->dnn : ""); + } + } else { + ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6, pdr->dnn ? pdr->dnn : ""); + } + + ogs_info("UE F-SEID[CP:0x%lx,UP:0x%lx] " + "APN[%s] PDN-Type[%d] IPv4[%s] IPv6[%s]", + (long)sess->upf_n4_seid, (long)sess->smf_n4_seid, + pdr->dnn, pdn_type, + sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", + sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); +} diff --git a/src/upf/context.h b/src/upf/context.h index 5e624f952..2194c61e1 100644 --- a/src/upf/context.h +++ b/src/upf/context.h @@ -88,8 +88,7 @@ int upf_context_parse_config(void); upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message); -upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *f_seid, - const char *apn, uint8_t pdn_type, ogs_pfcp_ue_ip_addr_t *ue_ip); +upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *f_seid); int upf_sess_remove(upf_sess_t *sess); void upf_sess_remove_all(void); upf_sess_t *upf_sess_find(uint32_t index); @@ -98,6 +97,9 @@ upf_sess_t *upf_sess_find_by_up_seid(uint64_t seid); upf_sess_t *upf_sess_find_by_ipv4(uint32_t addr); upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6); +void upf_sess_set_ue_ip(upf_sess_t *sess, + uint8_t pdn_type, ogs_pfcp_pdr_t *pdr); + #ifdef __cplusplus } #endif diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index 096af686c..f24b60540 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -74,10 +74,10 @@ void upf_n4_handle_session_establishment_request( cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; if (!sess) { - ogs_error("Invalid Message Format"); + ogs_error("No Context"); ogs_pfcp_send_error_message(xact, 0, OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE, - OGS_GTP_CAUSE_INVALID_MESSAGE_FORMAT, 0); + OGS_PFCP_CAUSE_MANDATORY_IE_MISSING, 0); return; } @@ -107,23 +107,49 @@ void upf_n4_handle_session_establishment_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + ogs_pfcp_handle_create_bar(&sess->pfcp, &req->create_bar, + &cause_value, &offending_ie_value); + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + /* Setup GTP Node */ ogs_list_for_each(&sess->pfcp.far_list, far) setup_gtp_node(far); - /* Setup UPF-N3-TEID & QFI Hash */ for (i = 0; i < num_of_created_pdr; i++) { pdr = created_pdr[i]; ogs_assert(pdr); - if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */ - if (pdr->f_teid_len) { - if (ogs_pfcp_self()->up_function_features.ftup && - pdr->f_teid.ch) { + /* Setup UE IP address */ + if (req->pdn_type.presence && pdr->ue_ip_addr_len) { + upf_sess_set_ue_ip(sess, req->pdn_type.u8, pdr); + } + + /* Setup UPF-N3-TEID & QFI Hash */ + if (pdr->f_teid_len) { + if (ogs_pfcp_self()->up_function_features.ftup && + pdr->f_teid.ch) { + + ogs_pfcp_pdr_t *choosed_pdr = NULL; + + if (pdr->f_teid.chid) { + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( + &sess->pfcp, pdr->f_teid.choose_id); + if (!choosed_pdr) { + pdr->chid = true; + pdr->choose_id = pdr->f_teid.choose_id; + } + } + + if (choosed_pdr) { + pdr->f_teid_len = choosed_pdr->f_teid_len; + memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); + + } else { ogs_pfcp_gtpu_resource_t *resource = NULL; resource = ogs_pfcp_gtpu_resource_find( &ogs_pfcp_self()->gtpu_resource_list, - sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); + pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { ogs_pfcp_user_plane_ip_resource_info_to_f_teid( &resource->info, &pdr->f_teid, &pdr->f_teid_len); @@ -148,9 +174,9 @@ void upf_n4_handle_session_establishment_request( pdr->f_teid.teid = pdr->index; } } - - ogs_pfcp_pdr_hash_set(pdr); } + + ogs_pfcp_pdr_hash_set(pdr); } } @@ -291,6 +317,16 @@ void upf_n4_handle_session_modification_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + ogs_pfcp_handle_create_bar(&sess->pfcp, &req->create_bar, + &cause_value, &offending_ie_value); + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + ogs_pfcp_handle_remove_bar(&sess->pfcp, &req->remove_bar, + &cause_value, &offending_ie_value); + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + /* Setup GTP Node */ ogs_list_for_each(&sess->pfcp.far_list, far) setup_gtp_node(far); @@ -300,17 +336,33 @@ void upf_n4_handle_session_modification_request( pdr = created_pdr[i]; ogs_assert(pdr); - if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */ - if (pdr->f_teid_len) { - if (ogs_pfcp_self()->up_function_features.ftup && - pdr->f_teid.ch) { + if (pdr->f_teid_len) { + if (ogs_pfcp_self()->up_function_features.ftup && + pdr->f_teid.ch) { + + ogs_pfcp_pdr_t *choosed_pdr = NULL; + + if (pdr->f_teid.chid) { + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( + &sess->pfcp, pdr->f_teid.choose_id); + if (!choosed_pdr) { + pdr->chid = true; + pdr->choose_id = pdr->f_teid.choose_id; + } + } + + if (choosed_pdr) { + pdr->f_teid_len = choosed_pdr->f_teid_len; + memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); + + } else { ogs_pfcp_gtpu_resource_t *resource = NULL; resource = ogs_pfcp_gtpu_resource_find( &ogs_pfcp_self()->gtpu_resource_list, - sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); + pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { ogs_pfcp_user_plane_ip_resource_info_to_f_teid( - &resource->info, &pdr->f_teid, &pdr->f_teid_len); + &resource->info, &pdr->f_teid, &pdr->f_teid_len); if (resource->info.teidri) pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( pdr->index, resource->info.teidri, @@ -332,9 +384,9 @@ void upf_n4_handle_session_modification_request( pdr->f_teid.teid = pdr->index; } } - - ogs_pfcp_pdr_hash_set(pdr); } + + ogs_pfcp_pdr_hash_set(pdr); } } diff --git a/src/upf/rule-match.c b/src/upf/rule-match.c index 54db985b0..b8945c209 100644 --- a/src/upf/rule-match.c +++ b/src/upf/rule-match.c @@ -172,13 +172,13 @@ ogs_pfcp_pdr_t *upf_pdr_find_by_packet(ogs_pkbuf_t *pkt) if (pdr->src_if != OGS_PFCP_INTERFACE_CORE) continue; + /* Save the Fallback PDR : Lowest precedence downlink PDR */ + fallback_pdr = pdr; + /* Check if FAR is Downlink */ if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) continue; - /* Save the Fallback PDR : Lowest precedence downlink PDR */ - fallback_pdr = pdr; - /* Check if Outer header creation */ if (far->outer_header_creation.teid == 0) continue; @@ -310,10 +310,12 @@ found: return pdr; } - ogs_assert(fallback_pdr); - ogs_debug("Found Session : Fallback PDR-ID[%d]", fallback_pdr->id); - return fallback_pdr; + if (fallback_pdr) { + ogs_debug("Found Session : Fallback PDR-ID[%d]", fallback_pdr->id); + return fallback_pdr; + } + ogs_error("No PDR in Session"); } else { ogs_debug("No Session"); } diff --git a/tests/volte/bearer-test.c b/tests/volte/bearer-test.c index 8c8ea7019..78b731b85 100644 --- a/tests/volte/bearer-test.c +++ b/tests/volte/bearer-test.c @@ -72,16 +72,16 @@ static void test1_func(abts_case *tc, void *data) "}," "\"flow\" : [" "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to any 1-65535\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to assigned 1-65535\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to any 50020\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50020\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to any 1-65535\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to assigned 1-65535\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to any 50021\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50021\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } }" "]" "}" diff --git a/tests/volte/rx-test.c b/tests/volte/rx-test.c index b221a74b7..f4a81a8dd 100644 --- a/tests/volte/rx-test.c +++ b/tests/volte/rx-test.c @@ -698,16 +698,16 @@ static void test2_func(abts_case *tc, void *data) "}," "\"flow\" : [" "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to any 1-65535\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to assigned 1-65535\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to any 50020\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50020\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to any 1-65535\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to assigned 1-65535\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to any 50021\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50021\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } }" "]" "}" diff --git a/tests/volte/session-test.c b/tests/volte/session-test.c index 2e1a045ed..8de5f19ae 100644 --- a/tests/volte/session-test.c +++ b/tests/volte/session-test.c @@ -85,16 +85,16 @@ static void test1_func(abts_case *tc, void *data) "}," "\"flow\" : [" "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to any 1-65535\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to assigned 1-65535\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to any 50020\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50020\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to any 1-65535\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to assigned 1-65535\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to any 50021\"," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50021\"," "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } }" "]" "}"