From a470131489231bff384d54561f66b937328d2e2d Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sun, 25 Oct 2020 22:43:53 -0400 Subject: [PATCH] Now, F-TEID is allocated in the UP function. --- lib/pfcp/build.c | 23 +++++ lib/pfcp/build.h | 2 + lib/pfcp/context.c | 20 ++-- lib/pfcp/context.h | 7 +- lib/pfcp/conv.c | 39 +++++++ lib/pfcp/conv.h | 3 + lib/pfcp/handler.c | 52 ++++++++-- lib/pfcp/handler.h | 3 + lib/pfcp/types.h | 50 ++++++++- src/mme/mme-s11-handler.c | 2 +- src/sgwc/context.c | 101 +++++++++++------- src/sgwc/context.h | 6 +- src/sgwc/s11-handler.c | 13 ++- src/sgwc/sxa-handler.c | 105 +++++++++++++++++++ src/sgwu/sxa-build.c | 32 +++--- src/sgwu/sxa-handler.c | 68 ++++++++++++- src/smf/bearer-binding.c | 83 +++++++++++---- src/smf/bearer-binding.h | 1 + src/smf/context.c | 115 ++++++++++++--------- src/smf/context.h | 5 +- src/smf/gx-handler.c | 1 - src/smf/n4-handler.c | 208 +++++++++++++++++++++++++++++++++++++- src/smf/ngap-build.c | 1 + src/smf/nudm-handler.c | 82 +++++++-------- src/smf/s5c-build.c | 2 + src/smf/s5c-handler.c | 35 ++----- src/upf/n4-build.c | 32 +++--- src/upf/n4-handler.c | 68 ++++++++++++- 28 files changed, 922 insertions(+), 237 deletions(-) diff --git a/lib/pfcp/build.c b/lib/pfcp/build.c index 5fa056954..32b0611fa 100644 --- a/lib/pfcp/build.c +++ b/lib/pfcp/build.c @@ -341,6 +341,29 @@ void ogs_pfcp_build_create_pdr( } } +void ogs_pfcp_build_created_pdr( + ogs_pfcp_tlv_created_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr) +{ + ogs_assert(message); + + ogs_assert(pdr); + + message->presence = 1; + message->pdr_id.presence = 1; + message->pdr_id.u16 = pdr->id; + + if (ogs_pfcp_self()->up_function_features.ftup) { + if (pdr->f_teid_len) { + memcpy(&pdrbuf[i].f_teid, &pdr->f_teid, pdr->f_teid_len); + pdrbuf[i].f_teid.teid = htobe32(pdr->f_teid.teid); + + message->local_f_teid.presence = 1; + message->local_f_teid.data = &pdrbuf[i].f_teid; + message->local_f_teid.len = pdr->f_teid_len; + } + } +} + void ogs_pfcp_build_update_pdr( ogs_pfcp_tlv_update_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr) { diff --git a/lib/pfcp/build.h b/lib/pfcp/build.h index 84980fe43..c41acc3e1 100644 --- a/lib/pfcp/build.h +++ b/lib/pfcp/build.h @@ -40,6 +40,8 @@ void ogs_pfcp_pdrbuf_clear(void); void ogs_pfcp_build_create_pdr( ogs_pfcp_tlv_create_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr); +void ogs_pfcp_build_created_pdr( + ogs_pfcp_tlv_created_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr); void ogs_pfcp_build_update_pdr( ogs_pfcp_tlv_update_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr); diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index 00890d657..2c306b273 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -835,11 +835,15 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess) ogs_assert(pdr); memset(pdr, 0, sizeof *pdr); + pdr->index = ogs_pool_index(&ogs_pfcp_pdr_pool, pdr); + ogs_assert(pdr->index > 0 && + pdr->index <= ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR); + ogs_pool_alloc(&sess->pdr_id_pool, &pdr->id_node); ogs_assert(pdr->id_node); - pdr->index = *(pdr->id_node); - ogs_assert(pdr->index > 0 && pdr->index <= OGS_MAX_NUM_OF_PDR); + pdr->id = *(pdr->id_node); + ogs_assert(pdr->id > 0 && pdr->id <= OGS_MAX_NUM_OF_PDR); pdr->sess = sess; ogs_list_add(&sess->pdr_list, pdr); @@ -983,8 +987,8 @@ ogs_pfcp_far_t *ogs_pfcp_far_add(ogs_pfcp_sess_t *sess) ogs_pool_alloc(&sess->far_id_pool, &far->id_node); ogs_assert(far->id_node); - far->index = *(far->id_node); - ogs_assert(far->index > 0 && far->index <= OGS_MAX_NUM_OF_FAR); + 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; @@ -1172,8 +1176,8 @@ ogs_pfcp_urr_t *ogs_pfcp_urr_add(ogs_pfcp_sess_t *sess) ogs_pool_alloc(&sess->urr_id_pool, &urr->id_node); ogs_assert(urr->id_node); - urr->index = *(urr->id_node); - ogs_assert(urr->index > 0 && urr->index <= OGS_MAX_NUM_OF_URR); + urr->id = *(urr->id_node); + ogs_assert(urr->id > 0 && urr->id <= OGS_MAX_NUM_OF_URR); urr->sess = sess; ogs_list_add(&sess->urr_list, urr); @@ -1250,8 +1254,8 @@ ogs_pfcp_qer_t *ogs_pfcp_qer_add(ogs_pfcp_sess_t *sess) ogs_pool_alloc(&sess->qer_id_pool, &qer->id_node); ogs_assert(qer->id_node); - qer->index = *(qer->id_node); - ogs_assert(qer->index > 0 && qer->index <= OGS_MAX_NUM_OF_QER); + qer->id = *(qer->id_node); + ogs_assert(qer->id > 0 && qer->id <= OGS_MAX_NUM_OF_QER); qer->sess = sess; ogs_list_add(&sess->qer_list, qer); diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index 2d991cea5..bb1621ff5 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -99,6 +99,9 @@ typedef struct ogs_pfcp_node_s { uint8_t rr_enable; ogs_list_t gtpu_resource_list; /* User Plane IP Resource Information */ + + ogs_pfcp_up_function_features_t up_function_features; + int up_function_features_len; } ogs_pfcp_node_t; typedef struct ogs_pfcp_gtpu_resource_s { @@ -160,7 +163,6 @@ typedef struct ogs_pfcp_far_hashkey_s { typedef struct ogs_pfcp_far_s { ogs_lnode_t lnode; - uint32_t index; int hashkey_len; ogs_pfcp_far_hashkey_t hashkey; @@ -184,7 +186,6 @@ typedef struct ogs_pfcp_far_s { typedef struct ogs_pfcp_urr_s { ogs_lnode_t lnode; - uint32_t index; uint8_t *id_node; /* Pool-Node for ID */ ogs_pfcp_urr_id_t id; @@ -194,7 +195,6 @@ typedef struct ogs_pfcp_urr_s { typedef struct ogs_pfcp_qer_s { ogs_lnode_t lnode; - uint32_t index; uint8_t *id_node; /* Pool-Node for ID */ ogs_pfcp_qer_id_t id; @@ -210,7 +210,6 @@ typedef struct ogs_pfcp_qer_s { typedef struct ogs_pfcp_bar_s { ogs_lnode_t lnode; - uint32_t index; uint8_t *id_node; /* Pool-Node for ID */ ogs_pfcp_bar_id_t id; diff --git a/lib/pfcp/conv.c b/lib/pfcp/conv.c index f0b2b269d..7da5d7269 100644 --- a/lib/pfcp/conv.c +++ b/lib/pfcp/conv.c @@ -206,6 +206,43 @@ int ogs_pfcp_sockaddr_to_f_teid( return OGS_OK; } +int ogs_pfcp_f_teid_to_sockaddr( + ogs_pfcp_f_teid_t *f_teid, int f_teid_len, + ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6) +{ + ogs_assert(addr && addr6); + ogs_assert(f_teid); + ogs_assert(f_teid_len); + + *addr = NULL; + *addr6 = NULL; + + if (f_teid->ipv4 && f_teid->ipv6) { + *addr = ogs_calloc(1, sizeof(**addr)); + ogs_assert(*addr); + (*addr)->sin.sin_addr.s_addr = f_teid->both.addr; + (*addr)->ogs_sa_family = AF_INET; + + *addr6 = ogs_calloc(1, sizeof(**addr6)); + ogs_assert(*addr6); + memcpy((*addr6)->sin6.sin6_addr.s6_addr, + f_teid->both.addr6, OGS_IPV6_LEN); + (*addr6)->ogs_sa_family = AF_INET6; + } else if (f_teid->ipv4) { + *addr = ogs_calloc(1, sizeof(**addr)); + ogs_assert(*addr); + (*addr)->sin.sin_addr.s_addr = f_teid->addr; + (*addr)->ogs_sa_family = AF_INET; + } else if (f_teid->ipv6) { + *addr6 = ogs_calloc(1, sizeof(**addr6)); + ogs_assert(*addr6); + memcpy((*addr6)->sin6.sin6_addr.s6_addr, f_teid->addr6, OGS_IPV6_LEN); + (*addr6)->ogs_sa_family = AF_INET6; + } + + return OGS_OK; +} + int ogs_pfcp_sockaddr_to_user_plane_ip_resource_info( ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, ogs_pfcp_user_plane_ip_resource_info_t *info) @@ -237,12 +274,14 @@ int ogs_pfcp_user_plane_ip_resource_info_to_sockaddr( if (info->v4) { *addr = ogs_calloc(1, sizeof(**addr)); + ogs_assert(*addr); (*addr)->sin.sin_addr.s_addr = info->addr; (*addr)->ogs_sa_family = AF_INET; } if (info->v6) { *addr6 = ogs_calloc(1, sizeof(**addr6)); + ogs_assert(*addr6); memcpy((*addr6)->sin6.sin6_addr.s6_addr, info->addr6, OGS_IPV6_LEN); (*addr6)->ogs_sa_family = AF_INET6; } diff --git a/lib/pfcp/conv.h b/lib/pfcp/conv.h index 9c8851281..8f46fa70a 100644 --- a/lib/pfcp/conv.h +++ b/lib/pfcp/conv.h @@ -41,6 +41,9 @@ int ogs_pfcp_f_seid_to_ip(ogs_pfcp_f_seid_t *f_seid, ogs_ip_t *ip); int ogs_pfcp_sockaddr_to_f_teid( ogs_sockaddr_t *a, ogs_sockaddr_t *b, ogs_pfcp_f_teid_t *f_teid, int *len); +int ogs_pfcp_f_teid_to_sockaddr( + ogs_pfcp_f_teid_t *f_teid, int f_teid_len, + ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6); int ogs_pfcp_sockaddr_to_user_plane_ip_resource_info( ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index 186763255..0d2388e9a 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -67,11 +67,9 @@ void ogs_pfcp_cp_handle_association_setup_request( if (req->up_function_features.presence) { if (req->up_function_features.data && req->up_function_features.len) { - ogs_pfcp_self()->up_function_features_len = - req->up_function_features.len; - memcpy(&ogs_pfcp_self()->up_function_features, - req->up_function_features.data, - ogs_pfcp_self()->up_function_features_len); + node->up_function_features_len = req->up_function_features.len; + memcpy(&node->up_function_features, req->up_function_features.data, + node->up_function_features_len); } } } @@ -104,11 +102,9 @@ void ogs_pfcp_cp_handle_association_setup_response( if (rsp->up_function_features.presence) { if (rsp->up_function_features.data && rsp->up_function_features.len) { - ogs_pfcp_self()->up_function_features_len = - rsp->up_function_features.len; - memcpy(&ogs_pfcp_self()->up_function_features, - rsp->up_function_features.data, - ogs_pfcp_self()->up_function_features_len); + node->up_function_features_len = rsp->up_function_features.len; + memcpy(&node->up_function_features, rsp->up_function_features.data, + node->up_function_features_len); } } } @@ -401,6 +397,42 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, return pdr; } +ogs_pfcp_pdr_t *ogs_pfcp_handle_created_pdr(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_created_pdr_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_pfcp_pdr_t *pdr = NULL; + + ogs_assert(sess); + ogs_assert(message); + + if (message->presence == 0) + return NULL; + + if (message->pdr_id.presence == 0) { + ogs_error("No PDR-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_PDR_ID_TYPE; + return NULL; + } + + pdr = ogs_pfcp_pdr_find(sess, message->pdr_id.u16); + if (!pdr) { + ogs_error("Cannot find PDR-ID[%d] in PDR", message->pdr_id.u16); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_PDR_ID_TYPE; + return NULL; + } + + if (message->local_f_teid.presence) { + pdr->f_teid_len = message->local_f_teid.len; + memcpy(&pdr->f_teid, message->local_f_teid.data, pdr->f_teid_len); + pdr->f_teid.teid = be32toh(pdr->f_teid.teid); + } + + return pdr; +} + ogs_pfcp_pdr_t *ogs_pfcp_handle_update_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_tlv_update_pdr_t *message, uint8_t *cause_value, uint8_t *offending_ie_value) diff --git a/lib/pfcp/handler.h b/lib/pfcp/handler.h index 6fb8cbf14..04255c1ed 100644 --- a/lib/pfcp/handler.h +++ b/lib/pfcp/handler.h @@ -54,6 +54,9 @@ void ogs_pfcp_up_handle_error_indication( ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_tlv_create_pdr_t *message, uint8_t *cause_value, uint8_t *offending_ie_value); +ogs_pfcp_pdr_t *ogs_pfcp_handle_created_pdr(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_created_pdr_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value); ogs_pfcp_pdr_t *ogs_pfcp_handle_update_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_tlv_update_pdr_t *message, uint8_t *cause_value, uint8_t *offending_ie_value); diff --git a/lib/pfcp/types.h b/lib/pfcp/types.h index ebb4193c1..ef2192ffd 100644 --- a/lib/pfcp/types.h +++ b/lib/pfcp/types.h @@ -435,13 +435,60 @@ ED3(uint8_t spare:6;, }; } __attribute__ ((packed)) ogs_pfcp_f_seid_t; +/* + * 8.2.3 F-TEID + * + * The following flags are coded within Octet 5: + * + * - Bit 1 – V4: If this bit is set to "1" and the CH bit is not set, + * then the IPv4 address field shall be present, + * otherwise the IPv4 address field shall not be present. + * - Bit 2 – V6: If this bit is set to "1" and the CH bit is not set, + * then the IPv6 address field shall be present, + * otherwise the IPv6 address field shall not be present. + * - Bit 3 – CH (CHOOSE): If this bit is set to "1", then the TEID, + * IPv4 address and IPv6 address fields shall not be present and + * the UP function shall assign an F-TEID with an IP4 or an IPv6 address + * if the V4 or V6 bit is set respectively. This bit shall only be set + * by the CP function. + * - Bit 4 – CHID (CHOOSE ID): If this bit is set to "1", + * then the UP function shall assign the same F-TEID to the PDRs requested + * to be created in a PFCP Session Establishment Request or + * PFCP Session Modification Request with the same CHOOSE ID value. + * This bit may only be set to "1" if the CH bit it set to "1". + * This bit shall only be set by the CP function. + * - Bit 5 to 8: Spare, for future use and set to 0. + * + * 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 allocating 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. + * + * Octet 6 to 9 (TEID) shall be present and shall contain a GTP-U TEID, + * if the CH bit in octet 5 is not set. When the TEID is present, + * if both IPv4 and IPv6 addresses are present in the F-TEID IE, + * then the TEID value shall be shared by both addresses. + * + * Octets "m to (m+3)" and/or "p to (p+15)"(IPv4 address / IPv6 address fields), + * if present, it shall contain the respective IP address values. + * + * Octet q shall be present and shall contain a binary integer value + * if the CHID bit in octet 5 is set to "1". + */ typedef struct ogs_pfcp_f_teid_s { ED5(uint8_t spare:4;, uint8_t chid:1;, uint8_t ch:1;, uint8_t ipv6:1;, uint8_t ipv4:1;) - uint32_t teid; + union { + uint32_t teid; + uint8_t choose_id; + }; union { union { uint32_t addr; @@ -451,7 +498,6 @@ ED5(uint8_t spare:4;, uint8_t addr6[OGS_IPV6_LEN]; } both; }; - uint8_t choose_id; }; } __attribute__ ((packed)) ogs_pfcp_f_teid_t; diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index 2be54e54b..c8270de31 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -126,7 +126,7 @@ void mme_s11_handle_create_session_response( } if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { - if (SESSION_CONTEXT_IN_ATTACH(sess)) { + if (sess && SESSION_CONTEXT_IN_ATTACH(sess)) { ogs_error("[%s] Attach reject", mme_ue->imsi_bcd); nas_eps_send_attach_reject(mme_ue, EMM_CAUSE_NETWORK_FAILURE, ESM_CAUSE_NETWORK_FAILURE); diff --git a/src/sgwc/context.c b/src/sgwc/context.c index 158b9ea44..ab58b8652 100644 --- a/src/sgwc/context.c +++ b/src/sgwc/context.c @@ -646,11 +646,6 @@ void sgwc_bearer_remove_all(sgwc_sess_t *sess) sgwc_bearer_remove(bearer); } -sgwc_bearer_t *sgwc_bearer_find_by_sgwc_s5u_teid(uint32_t sgwc_s5u_teid) -{ - return ogs_pool_find(&sgwc_bearer_pool, sgwc_s5u_teid); -} - sgwc_bearer_t *sgwc_bearer_find_by_sess_ebi(sgwc_sess_t *sess, uint8_t ebi) { sgwc_bearer_t *bearer = NULL; @@ -797,7 +792,6 @@ sgwc_tunnel_t *sgwc_tunnel_add( pdr = ogs_pfcp_pdr_add(&sess->pfcp); ogs_assert(pdr); - pdr->id = pdr->index; pdr->src_if = src_if; if (strlen(sess->pdn.apn)) @@ -818,40 +812,43 @@ sgwc_tunnel_t *sgwc_tunnel_add( far = ogs_pfcp_far_add(&sess->pfcp); ogs_assert(far); - far->id = far->index; far->dst_if = dst_if; ogs_pfcp_pdr_associate_far(pdr, far); ogs_assert(sess->pfcp_node); - resource = ogs_pfcp_gtpu_resource_find( - &sess->pfcp_node->gtpu_resource_list, - sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, - &tunnel->local_addr, &tunnel->local_addr6); - ogs_assert(tunnel->local_addr || tunnel->local_addr6); - if (resource->info.teidri) - tunnel->local_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - tunnel->index, resource->info.teidri, - resource->info.teid_range); - else - tunnel->local_teid = tunnel->index; + if (sess->pfcp_node->up_function_features.ftup) { + pdr->f_teid.ch = 1; + pdr->f_teid_len = 1; } else { - if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) - ogs_copyaddrinfo(&tunnel->local_addr, &sess->pfcp_node->addr); - else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) - ogs_copyaddrinfo(&tunnel->local_addr6, &sess->pfcp_node->addr); - else - ogs_assert_if_reached(); + resource = ogs_pfcp_gtpu_resource_find( + &sess->pfcp_node->gtpu_resource_list, + sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); + if (resource) { + ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, + &tunnel->local_addr, &tunnel->local_addr6); + if (resource->info.teidri) + tunnel->local_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( + tunnel->index, resource->info.teidri, + resource->info.teid_range); + else + tunnel->local_teid = tunnel->index; + } else { + if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) + ogs_copyaddrinfo(&tunnel->local_addr, &sess->pfcp_node->addr); + else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) + ogs_copyaddrinfo(&tunnel->local_addr6, &sess->pfcp_node->addr); + else + ogs_assert_if_reached(); + + tunnel->local_teid = tunnel->index; + } + ogs_assert(tunnel->local_addr || tunnel->local_addr6); - - tunnel->local_teid = tunnel->index; + ogs_pfcp_sockaddr_to_f_teid(tunnel->local_addr, tunnel->local_addr6, + &pdr->f_teid, &pdr->f_teid_len); + pdr->f_teid.teid = tunnel->local_teid; } - ogs_pfcp_sockaddr_to_f_teid(tunnel->local_addr, tunnel->local_addr6, - &pdr->f_teid, &pdr->f_teid_len); - pdr->f_teid.teid = tunnel->local_teid; - tunnel->pdr = pdr; tunnel->far = far; @@ -891,9 +888,23 @@ void sgwc_tunnel_remove_all(sgwc_bearer_t *bearer) sgwc_tunnel_remove(tunnel); } -sgwc_tunnel_t *sgwc_tunnel_find_by_teid(uint32_t teid) +sgwc_tunnel_t *sgwc_tunnel_find_by_teid(sgwc_ue_t *sgwc_ue, uint32_t teid) { - return ogs_pool_find(&sgwc_tunnel_pool, teid); + sgwc_sess_t *sess = NULL; + sgwc_bearer_t *bearer = NULL; + sgwc_tunnel_t *tunnel = NULL; + + ogs_assert(sgwc_ue); + + ogs_list_for_each(&sgwc_ue->sess_list, sess) { + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_list_for_each(&bearer->tunnel_list, tunnel) { + if (tunnel->local_teid == teid) return tunnel; + } + } + } + + return NULL; } sgwc_tunnel_t *sgwc_tunnel_find_by_interface_type( @@ -909,6 +920,28 @@ sgwc_tunnel_t *sgwc_tunnel_find_by_interface_type( return NULL; } +sgwc_tunnel_t *sgwc_tunnel_find_by_pdr_id( + sgwc_sess_t *sess, ogs_pfcp_pdr_id_t pdr_id) +{ + sgwc_bearer_t *bearer = NULL; + sgwc_tunnel_t *tunnel = NULL; + + ogs_pfcp_pdr_t *pdr = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_list_for_each(&bearer->tunnel_list, tunnel) { + pdr = tunnel->pdr; + ogs_assert(pdr); + + if (pdr->id == pdr_id) return tunnel; + } + } + + return NULL; +} + sgwc_tunnel_t *sgwc_dl_tunnel_in_bearer(sgwc_bearer_t *bearer) { ogs_assert(bearer); diff --git a/src/sgwc/context.h b/src/sgwc/context.h index 68d13b42f..a29b04fc8 100644 --- a/src/sgwc/context.h +++ b/src/sgwc/context.h @@ -179,8 +179,6 @@ sgwc_sess_t *sgwc_sess_find_by_ebi(sgwc_ue_t *sgwc_ue, uint8_t ebi); sgwc_bearer_t *sgwc_bearer_add(sgwc_sess_t *sess); int sgwc_bearer_remove(sgwc_bearer_t *bearer); void sgwc_bearer_remove_all(sgwc_sess_t *sess); -sgwc_bearer_t *sgwc_bearer_find_by_sgwc_s5u_teid( - uint32_t sgwc_s5u_teid); sgwc_bearer_t *sgwc_bearer_find_by_sess_ebi( sgwc_sess_t *sess, uint8_t ebi); sgwc_bearer_t *sgwc_bearer_find_by_ue_ebi( @@ -194,9 +192,11 @@ sgwc_tunnel_t *sgwc_tunnel_add( sgwc_bearer_t *bearer, uint8_t interface_type); int sgwc_tunnel_remove(sgwc_tunnel_t *tunnel); void sgwc_tunnel_remove_all(sgwc_bearer_t *bearer); -sgwc_tunnel_t *sgwc_tunnel_find_by_teid(uint32_t teid); +sgwc_tunnel_t *sgwc_tunnel_find_by_teid(sgwc_ue_t *sgwc_ue, uint32_t teid); sgwc_tunnel_t *sgwc_tunnel_find_by_interface_type( sgwc_bearer_t *bearer, uint8_t interface_type); +sgwc_tunnel_t *sgwc_tunnel_find_by_pdr_id( + sgwc_sess_t *sess, ogs_pfcp_pdr_id_t pdr_id); sgwc_tunnel_t *sgwc_dl_tunnel_in_bearer(sgwc_bearer_t *bearer); sgwc_tunnel_t *sgwc_ul_tunnel_in_bearer(sgwc_bearer_t *bearer); diff --git a/src/sgwc/s11-handler.c b/src/sgwc/s11-handler.c index 1b8c928ec..9fa2c216b 100644 --- a/src/sgwc/s11-handler.c +++ b/src/sgwc/s11-handler.c @@ -235,6 +235,7 @@ void sgwc_s11_handle_modify_bearer_request( uint16_t decoded; uint64_t flags = 0; + sgwc_sess_t *sess = NULL; sgwc_bearer_t *bearer = NULL; sgwc_tunnel_t *dl_tunnel = NULL; ogs_pfcp_far_t *far = NULL; @@ -291,6 +292,10 @@ void sgwc_s11_handle_modify_bearer_request( return; } + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + dl_tunnel = sgwc_dl_tunnel_in_bearer(bearer); ogs_assert(dl_tunnel); @@ -332,8 +337,10 @@ void sgwc_s11_handle_modify_bearer_request( if (memcmp(&dl_tunnel->remote_ip, &zero_ip, sizeof(ogs_ip_t)) != 0 && memcmp(&dl_tunnel->remote_ip, &remote_ip, sizeof(ogs_ip_t)) != 0) { + ogs_assert(sess->pfcp_node); + /* eNB IP is changed during handover */ - if (ogs_pfcp_self()->up_function_features.empu) { + if (sess->pfcp_node->up_function_features.empu) { flags |= OGS_PFCP_MODIFY_END_MARKER; } else { ogs_error("SGW-U does not support End Marker"); @@ -519,12 +526,14 @@ void sgwc_s11_handle_create_bearer_response( return; } + ogs_assert(sgwc_ue); + /* Correlate with SGW-S1U-TEID */ sgw_s1u_teid = rsp->bearer_contexts.s4_u_sgsn_f_teid.data; ogs_assert(sgw_s1u_teid); /* Find the Tunnel by SGW-S1U-TEID */ - ul_tunnel = sgwc_tunnel_find_by_teid(be32toh(sgw_s1u_teid->teid)); + ul_tunnel = sgwc_tunnel_find_by_teid(sgwc_ue, be32toh(sgw_s1u_teid->teid)); ogs_assert(ul_tunnel); bearer = ul_tunnel->bearer; ogs_assert(bearer); diff --git a/src/sgwc/sxa-handler.c b/src/sgwc/sxa-handler.c index da13c859f..a02dd79e7 100644 --- a/src/sgwc/sxa-handler.c +++ b/src/sgwc/sxa-handler.c @@ -84,6 +84,7 @@ void sgwc_sxa_handle_session_establishment_response( { int rv, len = 0; uint8_t cause_value = 0; + ogs_pfcp_f_seid_t *up_f_seid = NULL; ogs_gtp_f_teid_t sgw_s5c_teid, sgw_s5u_teid; @@ -123,6 +124,11 @@ void sgwc_sxa_handle_session_establishment_response( cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + if (pfcp_rsp->created_pdr[0].presence == 0) { + ogs_error("No Created PDR"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (pfcp_rsp->cause.presence) { if (pfcp_rsp->cause.u8 != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { ogs_warn("PFCP Cause [%d] : Not Accepted", pfcp_rsp->cause.u8); @@ -133,6 +139,48 @@ void sgwc_sxa_handle_session_establishment_response( cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + int i; + + uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + uint8_t offending_ie_value = 0; + + ogs_assert(sess); + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + sgwc_tunnel_t *tunnel = NULL; + ogs_pfcp_pdr_t *pdr = NULL; + + pdr = ogs_pfcp_handle_created_pdr( + &sess->pfcp, &pfcp_rsp->created_pdr[i], + &pfcp_cause_value, &offending_ie_value); + + if (!pdr) + break; + + tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id); + if (!tunnel) { + pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + break; + } + + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (tunnel->local_addr) + ogs_freeaddrinfo(tunnel->local_addr); + if (tunnel->local_addr6) + ogs_freeaddrinfo(tunnel->local_addr6); + + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &tunnel->local_addr, &tunnel->local_addr6); + tunnel->local_teid = pdr->f_teid.teid; + } + } + + cause_value = gtp_cause_from_pfcp(pfcp_cause_value); + } + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { if (sess) sgwc_ue = sess->sgwc_ue; ogs_gtp_send_error_message( @@ -148,6 +196,15 @@ void sgwc_sxa_handle_session_establishment_response( dl_tunnel = sgwc_dl_tunnel_in_bearer(bearer); ogs_assert(dl_tunnel); + if (dl_tunnel->local_addr == NULL && dl_tunnel->local_addr6 == NULL) { + ogs_error("No UP F-TEID"); + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, + OGS_GTP_CAUSE_GRE_KEY_NOT_FOUND); + return; + } + /* UP F-SEID */ up_f_seid = pfcp_rsp->up_f_seid.data; ogs_assert(up_f_seid); @@ -195,6 +252,7 @@ void sgwc_sxa_handle_session_establishment_response( memset(&sgw_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t)); sgw_s5u_teid.teid = htobe32(dl_tunnel->local_teid); sgw_s5u_teid.interface_type = dl_tunnel->interface_type; + ogs_assert(dl_tunnel->local_addr || dl_tunnel->local_addr6); rv = ogs_gtp_sockaddr_to_f_teid( dl_tunnel->local_addr, dl_tunnel->local_addr6, &sgw_s5u_teid, &len); ogs_assert(rv == OGS_OK); @@ -265,6 +323,46 @@ void sgwc_sxa_handle_session_modification_response( cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + uint8_t offending_ie_value = 0; + + ogs_assert(sess); + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + sgwc_tunnel_t *tunnel = NULL; + ogs_pfcp_pdr_t *pdr = NULL; + + pdr = ogs_pfcp_handle_created_pdr( + &sess->pfcp, &pfcp_rsp->created_pdr[i], + &pfcp_cause_value, &offending_ie_value); + + if (!pdr) + break; + + tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id); + if (!tunnel) { + pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + break; + } + + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (tunnel->local_addr) + ogs_freeaddrinfo(tunnel->local_addr); + if (tunnel->local_addr6) + ogs_freeaddrinfo(tunnel->local_addr6); + + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &tunnel->local_addr, &tunnel->local_addr6); + tunnel->local_teid = pdr->f_teid.teid; + } + } + + cause_value = gtp_cause_from_pfcp(pfcp_cause_value); + } + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { if (sess) sgwc_ue = sess->sgwc_ue; if (flags & OGS_PFCP_MODIFY_CREATE) { @@ -353,6 +451,7 @@ void sgwc_sxa_handle_session_modification_response( memset(&sgw_s1u_teid, 0, sizeof(ogs_gtp_f_teid_t)); sgw_s1u_teid.interface_type = ul_tunnel->interface_type; sgw_s1u_teid.teid = htobe32(ul_tunnel->local_teid); + ogs_assert(ul_tunnel->local_addr || ul_tunnel->local_addr6); rv = ogs_gtp_sockaddr_to_f_teid( ul_tunnel->local_addr, ul_tunnel->local_addr6, &sgw_s1u_teid, &len); @@ -398,6 +497,7 @@ void sgwc_sxa_handle_session_modification_response( memset(&sgw_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t)); sgw_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_SGW_GTP_U; sgw_s5u_teid.teid = htobe32(dl_tunnel->local_teid); + ogs_assert(dl_tunnel->local_addr || dl_tunnel->local_addr6); rv = ogs_gtp_sockaddr_to_f_teid( dl_tunnel->local_addr, dl_tunnel->local_addr6, &sgw_s5u_teid, &len); @@ -485,6 +585,8 @@ void sgwc_sxa_handle_session_modification_response( rsp_dl_teid[i].interface_type = tunnel->interface_type; rsp_dl_teid[i].teid = htobe32(tunnel->local_teid); + ogs_assert( + tunnel->local_addr || tunnel->local_addr6); rv = ogs_gtp_sockaddr_to_f_teid( tunnel->local_addr, tunnel->local_addr6, &rsp_dl_teid[i], &len); @@ -504,6 +606,8 @@ void sgwc_sxa_handle_session_modification_response( rsp_ul_teid[i].teid = htobe32(tunnel->local_teid); rsp_ul_teid[i].interface_type = tunnel->interface_type; + ogs_assert( + tunnel->local_addr || tunnel->local_addr6); rv = ogs_gtp_sockaddr_to_f_teid( tunnel->local_addr, tunnel->local_addr6, &rsp_ul_teid[i], &len); @@ -663,6 +767,7 @@ void sgwc_sxa_handle_session_modification_response( memset(&sgw_s1u_teid, 0, sizeof(ogs_gtp_f_teid_t)); sgw_s1u_teid.interface_type = ul_tunnel->interface_type; sgw_s1u_teid.teid = htobe32(ul_tunnel->local_teid); + ogs_assert(ul_tunnel->local_addr || ul_tunnel->local_addr6); rv = ogs_gtp_sockaddr_to_f_teid( ul_tunnel->local_addr, ul_tunnel->local_addr6, &sgw_s1u_teid, &len); diff --git a/src/sgwu/sxa-build.c b/src/sgwu/sxa-build.c index b53fac283..16df93677 100644 --- a/src/sgwu/sxa-build.c +++ b/src/sgwu/sxa-build.c @@ -24,6 +24,7 @@ ogs_pkbuf_t *sgwu_sxa_build_session_establishment_response(uint8_t type, { ogs_pfcp_message_t pfcp_message; ogs_pfcp_session_establishment_response_t *rsp = NULL; + ogs_pkbuf_t *pkbuf = NULL; int i = 0; @@ -58,18 +59,19 @@ ogs_pkbuf_t *sgwu_sxa_build_session_establishment_response(uint8_t type, rsp->up_f_seid.data = &f_seid; rsp->up_f_seid.len = len; + ogs_pfcp_pdrbuf_init(); + /* Created PDR */ for (i = 0; i < num_of_created_pdr; i++) { - ogs_pfcp_tlv_created_pdr_t *message = &rsp->created_pdr[i]; - ogs_assert(message); - - message->presence = 1; - message->pdr_id.presence = 1; - message->pdr_id.u16 = created_pdr[i]->id; + ogs_pfcp_build_created_pdr(&rsp->created_pdr[i], i, created_pdr[i]); } pfcp_message.h.type = type; - return ogs_pfcp_build_msg(&pfcp_message); + pkbuf = ogs_pfcp_build_msg(&pfcp_message); + + ogs_pfcp_pdrbuf_clear(); + + return pkbuf; } ogs_pkbuf_t *sgwu_sxa_build_session_modification_response(uint8_t type, @@ -77,6 +79,7 @@ ogs_pkbuf_t *sgwu_sxa_build_session_modification_response(uint8_t type, { ogs_pfcp_message_t pfcp_message; ogs_pfcp_session_modification_response_t *rsp = NULL; + ogs_pkbuf_t *pkbuf = NULL; int i = 0; @@ -89,18 +92,19 @@ ogs_pkbuf_t *sgwu_sxa_build_session_modification_response(uint8_t type, rsp->cause.presence = 1; rsp->cause.u8 = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + ogs_pfcp_pdrbuf_init(); + /* Created PDR */ for (i = 0; i < num_of_created_pdr; i++) { - ogs_pfcp_tlv_created_pdr_t *message = &rsp->created_pdr[i]; - ogs_assert(message); - - message->presence = 1; - message->pdr_id.presence = 1; - message->pdr_id.u16 = created_pdr[i]->id; + ogs_pfcp_build_created_pdr(&rsp->created_pdr[i], i, created_pdr[i]); } pfcp_message.h.type = type; - return ogs_pfcp_build_msg(&pfcp_message); + pkbuf = ogs_pfcp_build_msg(&pfcp_message); + + ogs_pfcp_pdrbuf_clear(); + + return pkbuf; } ogs_pkbuf_t *sgwu_sxa_build_session_deletion_response(uint8_t type, diff --git a/src/sgwu/sxa-handler.c b/src/sgwu/sxa-handler.c index b8784c7ca..8a72b43a4 100644 --- a/src/sgwu/sxa-handler.c +++ b/src/sgwu/sxa-handler.c @@ -115,8 +115,40 @@ void sgwu_sxa_handle_session_establishment_request( pdr = created_pdr[i]; ogs_assert(pdr); - if (pdr->f_teid_len) + 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; + } 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; + + 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; + } + } + ogs_pfcp_pdr_hash_set(pdr); + } } /* Send Buffered Packet to gNB */ @@ -257,8 +289,40 @@ void sgwu_sxa_handle_session_modification_request( pdr = created_pdr[i]; ogs_assert(pdr); - if (pdr->f_teid_len) + 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; + } 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; + + 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; + } + } + ogs_pfcp_pdr_hash_set(pdr); + } } /* Send Buffered Packet to gNB */ diff --git a/src/smf/bearer-binding.c b/src/smf/bearer-binding.c index 403e8d043..5c2062d3a 100644 --- a/src/smf/bearer-binding.c +++ b/src/smf/bearer-binding.c @@ -19,6 +19,7 @@ #include "bearer-binding.h" #include "s5c-build.h" +#include "pfcp-path.h" #include "ipfw/ipfw2.h" @@ -203,7 +204,6 @@ void smf_bearer_binding(smf_sess_t *sess) ogs_pcc_rule_t *pcc_rule = &sess->pcc_rule[i]; int bearer_created = 0; int qos_presence = 0; - ogs_gtp_tft_t tft; ogs_assert(pcc_rule); if (pcc_rule->name == NULL) { @@ -334,28 +334,40 @@ void smf_bearer_binding(smf_sess_t *sess) } } - memset(&tft, 0, sizeof tft); - if (pcc_rule->num_of_flow) - encode_traffic_flow_template(&tft, bearer); - - memset(&h, 0, sizeof(ogs_gtp_header_t)); if (bearer_created == 1) { - h.type = OGS_GTP_CREATE_BEARER_REQUEST_TYPE; - h.teid = sess->sgw_s5c_teid; + /* Setup QER */ + if (bearer->qos.mbr.downlink || bearer->qos.mbr.uplink || + bearer->qos.gbr.downlink || bearer->qos.gbr.uplink) { + ogs_pfcp_qer_t *qer = NULL; - /* TFT is mandatory in - * activate dedicated EPS bearer context request */ - ogs_assert(pcc_rule->num_of_flow); + /* Only 1 QER is used per bearer */ + qer = bearer->qer; + if (!qer) { + qer = ogs_pfcp_qer_add(&sess->pfcp); + ogs_assert(qer); + bearer->qer = qer; + } - pkbuf = smf_s5c_build_create_bearer_request( - h.type, bearer, pcc_rule->num_of_flow ? &tft : NULL); - ogs_expect_or_return(pkbuf); + ogs_pfcp_pdr_associate_qer(bearer->dl_pdr, qer); + ogs_pfcp_pdr_associate_qer(bearer->ul_pdr, qer); - xact = ogs_gtp_xact_local_create( - sess->gnode, &h, pkbuf, timeout, sess); - ogs_expect_or_return(xact); + qer->mbr.uplink = bearer->qos.mbr.uplink; + qer->mbr.downlink = bearer->qos.mbr.downlink; + qer->gbr.uplink = bearer->qos.gbr.uplink; + qer->gbr.downlink = bearer->qos.gbr.downlink; + } + + smf_epc_pfcp_send_bearer_modification_request( + bearer, OGS_PFCP_MODIFY_CREATE); } else { + ogs_gtp_tft_t tft; + + memset(&tft, 0, sizeof tft); + if (pcc_rule->num_of_flow) + encode_traffic_flow_template(&tft, bearer); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); h.type = OGS_GTP_UPDATE_BEARER_REQUEST_TYPE; h.teid = sess->sgw_s5c_teid; @@ -373,10 +385,10 @@ void smf_bearer_binding(smf_sess_t *sess) xact->update_flags |= OGS_GTP_MODIFY_TFT_UPDATE; if (qos_presence) xact->update_flags |= OGS_GTP_MODIFY_QOS_UPDATE; - } - rv = ogs_gtp_xact_commit(xact); - ogs_expect(rv == OGS_OK); + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + } } else if (pcc_rule->type == OGS_PCC_RULE_TYPE_REMOVE) { bearer = smf_bearer_find_by_name(sess, pcc_rule->name); @@ -407,3 +419,34 @@ void smf_bearer_binding(smf_sess_t *sess) } } } + +void smf_gtp_send_create_bearer_request(smf_bearer_t *bearer) +{ + int rv; + + smf_sess_t *sess = NULL; + ogs_gtp_xact_t *xact = NULL; + + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + ogs_gtp_tft_t tft; + + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + h.type = OGS_GTP_CREATE_BEARER_REQUEST_TYPE; + h.teid = sess->sgw_s5c_teid; + + memset(&tft, 0, sizeof tft); + encode_traffic_flow_template(&tft, bearer); + + pkbuf = smf_s5c_build_create_bearer_request(h.type, bearer, &tft); + ogs_expect_or_return(pkbuf); + + xact = ogs_gtp_xact_local_create(sess->gnode, &h, pkbuf, timeout, sess); + ogs_expect_or_return(xact); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} diff --git a/src/smf/bearer-binding.h b/src/smf/bearer-binding.h index 09fa77e6b..4843754f7 100644 --- a/src/smf/bearer-binding.h +++ b/src/smf/bearer-binding.h @@ -27,6 +27,7 @@ extern "C" { #endif void smf_bearer_binding(smf_sess_t *sess); +void smf_gtp_send_create_bearer_request(smf_bearer_t *bearer); #ifdef __cplusplus } diff --git a/src/smf/context.c b/src/smf/context.c index 45a44f4cb..a057086e6 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -1176,7 +1176,6 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) dl_pdr = ogs_pfcp_pdr_add(&sess->pfcp); ogs_assert(dl_pdr); - dl_pdr->id = dl_pdr->index; qos_flow->dl_pdr = dl_pdr; dl_pdr->src_if = OGS_PFCP_INTERFACE_CORE; @@ -1186,7 +1185,6 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) ul_pdr = ogs_pfcp_pdr_add(&sess->pfcp); ogs_assert(ul_pdr); - ul_pdr->id = ul_pdr->index; qos_flow->ul_pdr = ul_pdr; ul_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS; @@ -1209,7 +1207,6 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) dl_far = ogs_pfcp_far_add(&sess->pfcp); ogs_assert(dl_far); - dl_far->id = dl_far->index; qos_flow->dl_far = dl_far; dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS; @@ -1217,7 +1214,6 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) ul_far = ogs_pfcp_far_add(&sess->pfcp); ogs_assert(ul_far); - ul_far->id = ul_far->index; qos_flow->ul_far = ul_far; ul_far->dst_if = OGS_PFCP_INTERFACE_CORE; @@ -1225,7 +1221,6 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) qer = ogs_pfcp_qer_add(&sess->pfcp); ogs_assert(qer); - qer->id = qer->index; qos_flow->qer = qer; ogs_pfcp_pdr_associate_qer(dl_pdr, qer); @@ -1283,7 +1278,6 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess) dl_pdr = ogs_pfcp_pdr_add(&sess->pfcp); ogs_assert(dl_pdr); - dl_pdr->id = dl_pdr->index; bearer->dl_pdr = dl_pdr; dl_pdr->src_if = OGS_PFCP_INTERFACE_CORE; @@ -1293,7 +1287,6 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess) ul_pdr = ogs_pfcp_pdr_add(&sess->pfcp); ogs_assert(ul_pdr); - ul_pdr->id = ul_pdr->index; bearer->ul_pdr = ul_pdr; ul_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS; @@ -1316,7 +1309,6 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess) dl_far = ogs_pfcp_far_add(&sess->pfcp); ogs_assert(dl_far); - dl_far->id = dl_far->index; bearer->dl_far = dl_far; dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS; @@ -1324,42 +1316,46 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess) ul_far = ogs_pfcp_far_add(&sess->pfcp); ogs_assert(ul_far); - ul_far->id = ul_far->index; bearer->ul_far = ul_far; ul_far->dst_if = OGS_PFCP_INTERFACE_CORE; ogs_pfcp_pdr_associate_far(ul_pdr, ul_far); ogs_assert(sess->pfcp_node); - resource = ogs_pfcp_gtpu_resource_find( - &sess->pfcp_node->gtpu_resource_list, - sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, - &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); - ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6); - if (resource->info.teidri) - bearer->pgw_s5u_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - bearer->index, resource->info.teidri, - resource->info.teid_range); - else - bearer->pgw_s5u_teid = bearer->index; + if (sess->pfcp_node->up_function_features.ftup) { + ul_pdr->f_teid.ch = 1; + ul_pdr->f_teid_len = 1; } else { - if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) - ogs_copyaddrinfo(&bearer->pgw_s5u_addr, &sess->pfcp_node->addr); - else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) - ogs_copyaddrinfo(&bearer->pgw_s5u_addr6, &sess->pfcp_node->addr); - else - ogs_assert_if_reached(); + resource = ogs_pfcp_gtpu_resource_find( + &sess->pfcp_node->gtpu_resource_list, + sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); + if (resource) { + ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, + &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); + if (resource->info.teidri) + bearer->pgw_s5u_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( + bearer->index, resource->info.teidri, + resource->info.teid_range); + else + bearer->pgw_s5u_teid = bearer->index; + } else { + if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) + ogs_copyaddrinfo(&bearer->pgw_s5u_addr, &sess->pfcp_node->addr); + else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) + ogs_copyaddrinfo( + &bearer->pgw_s5u_addr6, &sess->pfcp_node->addr); + else + ogs_assert_if_reached(); + + bearer->pgw_s5u_teid = bearer->index; + } + ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6); - - bearer->pgw_s5u_teid = bearer->index; + ogs_pfcp_sockaddr_to_f_teid(bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6, + &ul_pdr->f_teid, &ul_pdr->f_teid_len); + ul_pdr->f_teid.teid = bearer->pgw_s5u_teid; } - ogs_pfcp_sockaddr_to_f_teid(bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6, - &ul_pdr->f_teid, &ul_pdr->f_teid_len); - ul_pdr->f_teid.teid = bearer->pgw_s5u_teid; - bearer->sess = sess; ogs_list_add(&sess->bearer_list, bearer); @@ -1415,9 +1411,19 @@ smf_bearer_t *smf_bearer_find(uint32_t index) return ogs_pool_find(&smf_bearer_pool, index); } -smf_bearer_t *smf_bearer_find_by_pgw_s5u_teid(uint32_t pgw_s5u_teid) +smf_bearer_t *smf_bearer_find_by_pgw_s5u_teid( + smf_sess_t *sess, uint32_t pgw_s5u_teid) { - return smf_bearer_find(pgw_s5u_teid); + smf_bearer_t *bearer = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->bearer_list, bearer) { + if (bearer->pgw_s5u_teid == pgw_s5u_teid) + return bearer; + } + + return NULL; } smf_bearer_t *smf_bearer_find_by_ebi(smf_sess_t *sess, uint8_t ebi) @@ -1426,15 +1432,12 @@ smf_bearer_t *smf_bearer_find_by_ebi(smf_sess_t *sess, uint8_t ebi) ogs_assert(sess); - bearer = smf_bearer_first(sess); - while (bearer) { + ogs_list_for_each(&sess->bearer_list, bearer) { if (bearer->ebi == ebi) - break; - - bearer = smf_bearer_next(bearer); + return bearer; } - return bearer; + return NULL; } smf_bearer_t *smf_bearer_find_by_name(smf_sess_t *sess, char *name) @@ -1444,12 +1447,9 @@ smf_bearer_t *smf_bearer_find_by_name(smf_sess_t *sess, char *name) ogs_assert(sess); ogs_assert(name); - bearer = smf_bearer_first(sess); - while (bearer) { + ogs_list_for_each(&sess->bearer_list, bearer) { if (bearer->name && strcmp(bearer->name, name) == 0) return bearer; - - bearer = smf_bearer_next(bearer); } return NULL; @@ -1493,6 +1493,29 @@ smf_bearer_t *smf_bearer_find_by_qci_arp(smf_sess_t *sess, return NULL; } +smf_bearer_t *smf_bearer_find_by_pdr_id( + smf_sess_t *sess, ogs_pfcp_pdr_id_t pdr_id) +{ + smf_bearer_t *bearer = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_pfcp_pdr_t *dl_pdr = NULL; + ogs_pfcp_pdr_t *ul_pdr = NULL; + + dl_pdr = bearer->dl_pdr; + ogs_assert(dl_pdr); + ul_pdr = bearer->ul_pdr; + ogs_assert(ul_pdr); + + if (dl_pdr->id == pdr_id || ul_pdr->id == pdr_id) + return bearer; + } + + return NULL; +} + smf_bearer_t *smf_default_bearer_in_sess(smf_sess_t *sess) { return smf_bearer_first(sess); diff --git a/src/smf/context.h b/src/smf/context.h index b4832e01b..a2192fbb7 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -327,7 +327,8 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess); int smf_bearer_remove(smf_bearer_t *bearer); void smf_bearer_remove_all(smf_sess_t *sess); smf_bearer_t *smf_bearer_find(uint32_t index); -smf_bearer_t *smf_bearer_find_by_pgw_s5u_teid(uint32_t pgw_s5u_teid); +smf_bearer_t *smf_bearer_find_by_pgw_s5u_teid( + smf_sess_t *sess, uint32_t pgw_s5u_teid); smf_bearer_t *smf_bearer_find_by_ebi(smf_sess_t *sess, uint8_t ebi); smf_bearer_t *smf_bearer_find_by_name(smf_sess_t *sess, char *name); smf_bearer_t *smf_bearer_find_by_qci_arp(smf_sess_t *sess, @@ -335,6 +336,8 @@ smf_bearer_t *smf_bearer_find_by_qci_arp(smf_sess_t *sess, uint8_t priority_level, uint8_t pre_emption_capability, uint8_t pre_emption_vulnerability); +smf_bearer_t *smf_bearer_find_by_pdr_id( + smf_sess_t *sess, ogs_pfcp_pdr_id_t pdr_id); smf_bearer_t *smf_default_bearer_in_sess(smf_sess_t *sess); bool smf_bearer_is_default(smf_bearer_t *bearer); smf_bearer_t *smf_bearer_first(smf_sess_t *sess); diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c index 6033a1bf6..a35bed56d 100644 --- a/src/smf/gx-handler.c +++ b/src/smf/gx-handler.c @@ -124,7 +124,6 @@ void smf_gx_handle_cca_initial_request( if (!qer) { qer = ogs_pfcp_qer_add(&sess->pfcp); ogs_assert(qer); - qer->id = qer->index; bearer->qer = qer; } diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index 94cdb38cb..b5d088b0d 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -99,8 +99,13 @@ void smf_5gc_n4_handle_session_establishment_response( smf_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_establishment_response_t *rsp) { + int i; + ogs_sbi_session_t *session = NULL; + uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + uint8_t offending_ie_value = 0; + ogs_pfcp_f_seid_t *up_f_seid = NULL; ogs_assert(xact); @@ -121,6 +126,11 @@ void smf_5gc_n4_handle_session_establishment_response( return; } + if (rsp->created_pdr[0].presence == 0) { + ogs_error("No Created PDR"); + return; + } + if (rsp->cause.presence) { if (rsp->cause.u8 != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { ogs_error("PFCP Cause [%d] : Not Accepted", rsp->cause.u8); @@ -133,6 +143,42 @@ void smf_5gc_n4_handle_session_establishment_response( ogs_assert(sess); + pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + ogs_pfcp_pdr_t *pdr = NULL; + + pdr = ogs_pfcp_handle_created_pdr( + &sess->pfcp, &rsp->created_pdr[i], + &pfcp_cause_value, &offending_ie_value); + + if (!pdr) + break; + + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (sess->upf_n3_addr) + ogs_freeaddrinfo(sess->upf_n3_addr); + if (sess->upf_n3_addr6) + ogs_freeaddrinfo(sess->upf_n3_addr6); + + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &sess->upf_n3_addr, &sess->upf_n3_addr6); + sess->upf_n3_teid = pdr->f_teid.teid; + } + } + + if (pfcp_cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { + ogs_error("PFCP Cause [%d] : Not Accepted", pfcp_cause_value); + return; + } + + if (sess->upf_n3_addr == NULL && sess->upf_n3_addr6 == NULL) { + ogs_error("No UP F-TEID"); + return; + } + /* UP F-SEID */ up_f_seid = rsp->up_f_seid.data; ogs_assert(up_f_seid); @@ -181,6 +227,41 @@ void smf_5gc_n4_handle_session_modification_response( status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; } + if (status == OGS_SBI_HTTP_STATUS_OK) { + int i; + + uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + uint8_t offending_ie_value = 0; + + ogs_assert(sess); + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + ogs_pfcp_pdr_t *pdr = NULL; + + pdr = ogs_pfcp_handle_created_pdr( + &sess->pfcp, &rsp->created_pdr[i], + &pfcp_cause_value, &offending_ie_value); + + if (!pdr) + break; + + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (sess->upf_n3_addr) + ogs_freeaddrinfo(sess->upf_n3_addr); + if (sess->upf_n3_addr6) + ogs_freeaddrinfo(sess->upf_n3_addr6); + + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &sess->upf_n3_addr, &sess->upf_n3_addr6); + sess->upf_n3_teid = pdr->f_teid.teid; + } + } + + status = sbi_status_from_pfcp(pfcp_cause_value); + } + if (status != OGS_SBI_HTTP_STATUS_OK) { char *strerror = ogs_msprintf( "PFCP Cause [%d] : Not Accepted", rsp->cause.u8); @@ -192,6 +273,12 @@ void smf_5gc_n4_handle_session_modification_response( ogs_assert(sess); + if (sess->upf_n3_addr == NULL && sess->upf_n3_addr6 == NULL) { + smf_sbi_send_sm_context_update_error(session, status, "No UP F_TEID", + NULL, NULL, NULL); + return; + } + if (flags & OGS_PFCP_MODIFY_ACTIVATE) { /* ACTIVATED Is NOT Inlcuded in RESPONSE */ smf_sbi_send_sm_context_updated_data(sess, session, 0); @@ -274,7 +361,10 @@ void smf_epc_n4_handle_session_establishment_response( ogs_pfcp_session_establishment_response_t *rsp) { uint8_t cause_value = 0; + + smf_bearer_t *bearer = NULL; ogs_gtp_xact_t *gtp_xact = NULL; + ogs_pfcp_f_seid_t *up_f_seid = NULL; ogs_assert(xact); @@ -297,6 +387,11 @@ void smf_epc_n4_handle_session_establishment_response( cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + if (rsp->created_pdr[0].presence == 0) { + ogs_error("No Created PDR"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (rsp->cause.presence) { if (rsp->cause.u8 != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { ogs_warn("PFCP Cause [%d] : Not Accepted", rsp->cause.u8); @@ -307,6 +402,47 @@ void smf_epc_n4_handle_session_establishment_response( cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + int i; + + uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + uint8_t offending_ie_value = 0; + + ogs_assert(sess); + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + ogs_pfcp_pdr_t *pdr = NULL; + + pdr = ogs_pfcp_handle_created_pdr( + &sess->pfcp, &rsp->created_pdr[i], + &pfcp_cause_value, &offending_ie_value); + + if (!pdr) + break; + + bearer = smf_bearer_find_by_pdr_id(sess, pdr->id); + if (!bearer) { + pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + break; + } + + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (bearer->pgw_s5u_addr) + ogs_freeaddrinfo(bearer->pgw_s5u_addr); + if (bearer->pgw_s5u_addr) + ogs_freeaddrinfo(bearer->pgw_s5u_addr6); + + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); + bearer->pgw_s5u_teid = pdr->f_teid.teid; + } + } + + cause_value = gtp_cause_from_pfcp(pfcp_cause_value); + } + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { ogs_gtp_send_error_message(gtp_xact, sess ? sess->sgw_s5c_teid : 0, OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value); @@ -314,6 +450,16 @@ void smf_epc_n4_handle_session_establishment_response( } ogs_assert(sess); + bearer = smf_default_bearer_in_sess(sess); + ogs_assert(bearer); + + if (bearer->pgw_s5u_addr == NULL && bearer->pgw_s5u_addr6 == NULL) { + ogs_error("No UP F-TEID"); + ogs_gtp_send_error_message(gtp_xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, + OGS_GTP_CAUSE_GRE_KEY_NOT_FOUND); + return; + } /* UP F-SEID */ up_f_seid = rsp->up_f_seid.data; @@ -329,9 +475,14 @@ void smf_epc_n4_handle_session_modification_response( smf_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_modification_response_t *rsp) { + int i; + smf_bearer_t *bearer = NULL; uint64_t flags = 0; + uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + uint8_t offending_ie_value = 0; + ogs_assert(xact); ogs_assert(rsp); @@ -342,8 +493,63 @@ void smf_epc_n4_handle_session_modification_response( ogs_pfcp_xact_commit(xact); - if (flags & OGS_PFCP_MODIFY_REMOVE) + if (!sess) { + ogs_error("No Context"); + return; + } + + if (rsp->cause.presence) { + if (rsp->cause.u8 != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { + ogs_error("PFCP Cause [%d] : Not Accepted", rsp->cause.u8); + return; + } + } else { + ogs_error("No Cause"); + return; + } + + ogs_assert(sess); + + pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + ogs_pfcp_pdr_t *pdr = NULL; + + pdr = ogs_pfcp_handle_created_pdr( + &sess->pfcp, &rsp->created_pdr[i], + &pfcp_cause_value, &offending_ie_value); + + if (!pdr) + break; + + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (bearer->pgw_s5u_addr) + ogs_freeaddrinfo(bearer->pgw_s5u_addr); + if (bearer->pgw_s5u_addr) + ogs_freeaddrinfo(bearer->pgw_s5u_addr6); + + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); + bearer->pgw_s5u_teid = pdr->f_teid.teid; + } + } + + if (pfcp_cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { + ogs_error("PFCP Cause [%d] : Not Accepted", pfcp_cause_value); + return; + } + + if (flags & OGS_PFCP_MODIFY_CREATE) { + smf_gtp_send_create_bearer_request(bearer); + + } else if (flags & OGS_PFCP_MODIFY_REMOVE) { smf_bearer_remove(bearer); + + } else if (flags & OGS_PFCP_MODIFY_ACTIVATE) { + /* Nothing */ + } } void smf_epc_n4_handle_session_deletion_response( diff --git a/src/smf/ngap-build.c b/src/smf/ngap-build.c index 47e5529c9..7ec0c6660 100644 --- a/src/smf/ngap-build.c +++ b/src/smf/ngap-build.c @@ -79,6 +79,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( NGAP_UPTransportLayerInformation_PR_gTPTunnel; UPTransportLayerInformation->choice.gTPTunnel = gTPTunnel; + ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6); ogs_sockaddr_to_ip(sess->upf_n3_addr, sess->upf_n3_addr6, &upf_n3_ip); ogs_asn_ip_to_BIT_STRING(&upf_n3_ip, &gTPTunnel->transportLayerAddress); ogs_asn_uint32_to_OCTET_STRING(sess->upf_n3_teid, &gTPTunnel->gTP_TEID); diff --git a/src/smf/nudm-handler.c b/src/smf/nudm-handler.c index 4981b4463..d582fd6e6 100644 --- a/src/smf/nudm-handler.c +++ b/src/smf/nudm-handler.c @@ -235,45 +235,6 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_session_t *session, return false; } - /* Setup GTP-U Tunnel */ - resource = ogs_pfcp_gtpu_resource_find( - &sess->pfcp_node->gtpu_resource_list, - sess->pdn.dnn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, - &sess->upf_n3_addr, &sess->upf_n3_addr6); - ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6); - if (resource->info.teidri) - sess->upf_n3_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - sess->index, resource->info.teidri, - resource->info.teid_range); - else - sess->upf_n3_teid = sess->index; - } else { - if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) - ogs_copyaddrinfo(&sess->upf_n3_addr, &sess->pfcp_node->addr); - else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) - ogs_copyaddrinfo(&sess->upf_n3_addr6, &sess->pfcp_node->addr); - else - ogs_assert_if_reached(); - ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6); - - sess->upf_n3_teid = sess->index; - } - - ogs_debug("UPF TEID:[0x%x], IPv4:[%s] IPv6:[%s]", - sess->upf_n3_teid, - sess->upf_n3_addr ? OGS_ADDR(sess->upf_n3_addr, buf1) : "", - sess->upf_n3_addr6 ? OGS_ADDR(sess->upf_n3_addr6, buf2) : ""); - - /* UE IP Address */ - smf_sess_set_ue_ip(sess); - - ogs_info("UE SUPI:[%s] DNN:[%s] IPv4:[%s] IPv6:[%s]", - smf_ue->supi, sess->pdn.dnn, - sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", - sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); - /********************************************************************* * Send HTTP_STATUS_CREATED(/nsmf-pdusession/v1/sm-context) to the AMF *********************************************************************/ @@ -299,7 +260,6 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_session_t *session, ogs_free(sendmsg.http.location); - /********************************************************************* * Send PFCP Session Establiashment Request to the UPF *********************************************************************/ @@ -324,14 +284,50 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_session_t *session, ogs_assert(ul_pdr); /* Set UE IP Address to the Default DL PDR */ + smf_sess_set_ue_ip(sess); + ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa, &dl_pdr->ue_ip_addr, &dl_pdr->ue_ip_addr_len); dl_pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST; + ogs_info("UE SUPI:[%s] DNN:[%s] IPv4:[%s] IPv6:[%s]", + smf_ue->supi, sess->pdn.dnn, + sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", + sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); + /* Set UPF-N3 TEID & ADDR to the Default UL PDR */ - ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6, - &ul_pdr->f_teid, &ul_pdr->f_teid_len); - ul_pdr->f_teid.teid = sess->upf_n3_teid; + if (sess->pfcp_node->up_function_features.ftup) { + ul_pdr->f_teid.ch = 1; + ul_pdr->f_teid_len = 1; + } else { + resource = ogs_pfcp_gtpu_resource_find( + &sess->pfcp_node->gtpu_resource_list, + sess->pdn.dnn, OGS_PFCP_INTERFACE_ACCESS); + if (resource) { + ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, + &sess->upf_n3_addr, &sess->upf_n3_addr6); + if (resource->info.teidri) + sess->upf_n3_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( + sess->index, resource->info.teidri, + resource->info.teid_range); + else + sess->upf_n3_teid = sess->index; + } else { + if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) + ogs_copyaddrinfo(&sess->upf_n3_addr, &sess->pfcp_node->addr); + else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) + ogs_copyaddrinfo(&sess->upf_n3_addr6, &sess->pfcp_node->addr); + else + ogs_assert_if_reached(); + + sess->upf_n3_teid = sess->index; + } + + ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6); + ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6, + &ul_pdr->f_teid, &ul_pdr->f_teid_len); + ul_pdr->f_teid.teid = sess->upf_n3_teid; + } /* Default PDRs is set to lowest precedence(highest precedence value) */ dl_pdr->precedence = 0xffffffff; diff --git a/src/smf/s5c-build.c b/src/smf/s5c-build.c index 1afaf5128..2a7f76a12 100644 --- a/src/smf/s5c-build.c +++ b/src/smf/s5c-build.c @@ -143,6 +143,7 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( memset(&pgw_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t)); pgw_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; pgw_s5u_teid.teid = htobe32(bearer->pgw_s5u_teid); + ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6); rv = ogs_gtp_sockaddr_to_f_teid( bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6, &pgw_s5u_teid, &len); ogs_assert(rv == OGS_OK); @@ -238,6 +239,7 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request( memset(&pgw_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t)); pgw_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; pgw_s5u_teid.teid = htobe32(bearer->pgw_s5u_teid); + ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6); rv = ogs_gtp_sockaddr_to_f_teid( bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6, &pgw_s5u_teid, &len); ogs_assert(rv == OGS_OK); diff --git a/src/smf/s5c-handler.c b/src/smf/s5c-handler.c index 15556c877..0dda7b0e2 100644 --- a/src/smf/s5c-handler.c +++ b/src/smf/s5c-handler.c @@ -323,11 +323,11 @@ void smf_s5c_handle_create_bearer_response( /* Correlate with PGW-S5U-TEID */ pgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_pgw_f_teid.data; - ogs_assert(pgw_s5u_teid); + ogs_expect_or_return(pgw_s5u_teid); /* Find the Bearer by PGW-S5U-TEID */ - bearer = smf_bearer_find_by_pgw_s5u_teid(be32toh(pgw_s5u_teid->teid)); - ogs_assert(bearer); + bearer = smf_bearer_find_by_pgw_s5u_teid(sess, be32toh(pgw_s5u_teid->teid)); + ogs_expect_or_return(bearer); /* Set EBI */ bearer->ebi = rsp->bearer_contexts.eps_bearer_id.u8; @@ -350,31 +350,8 @@ void smf_s5c_handle_create_bearer_response( &dl_far->outer_header_creation, &dl_far->outer_header_creation_len); dl_far->outer_header_creation.teid = bearer->sgw_s5u_teid; - /* Setup QER */ - if (bearer->qos.mbr.downlink || bearer->qos.mbr.uplink || - bearer->qos.gbr.downlink || bearer->qos.gbr.uplink) { - ogs_pfcp_qer_t *qer = NULL; - - /* Only 1 QER is used per bearer */ - qer = bearer->qer; - if (!qer) { - qer = ogs_pfcp_qer_add(&sess->pfcp); - ogs_assert(qer); - qer->id = qer->index; - bearer->qer = qer; - } - - ogs_pfcp_pdr_associate_qer(bearer->dl_pdr, qer); - ogs_pfcp_pdr_associate_qer(bearer->ul_pdr, qer); - - qer->mbr.uplink = bearer->qos.mbr.uplink; - qer->mbr.downlink = bearer->qos.mbr.downlink; - qer->gbr.uplink = bearer->qos.gbr.uplink; - qer->gbr.downlink = bearer->qos.gbr.downlink; - } - smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_CREATE); + bearer, OGS_PFCP_MODIFY_ACTIVATE); } void smf_s5c_handle_update_bearer_response( @@ -425,7 +402,7 @@ void smf_s5c_handle_update_bearer_response( bearer = smf_bearer_find_by_ebi( sess, rsp->bearer_contexts.eps_bearer_id.u8); - ogs_assert(bearer); + ogs_expect_or_return(bearer); ogs_debug("[SMF] Update Bearer Response : SGW[0x%x] --> SMF[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); @@ -523,7 +500,7 @@ void smf_s5c_handle_delete_bearer_response( bearer = smf_bearer_find_by_ebi( sess, rsp->bearer_contexts.eps_bearer_id.u8); - ogs_assert(bearer); + ogs_expect_or_return(bearer); ogs_debug("[SMF] Delete Bearer Response : SGW[0x%x] --> SMF[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); diff --git a/src/upf/n4-build.c b/src/upf/n4-build.c index f7d766072..f0b9b51b5 100644 --- a/src/upf/n4-build.c +++ b/src/upf/n4-build.c @@ -25,6 +25,7 @@ ogs_pkbuf_t *upf_n4_build_session_establishment_response(uint8_t type, { ogs_pfcp_message_t pfcp_message; ogs_pfcp_session_establishment_response_t *rsp = NULL; + ogs_pkbuf_t *pkbuf = NULL; int i = 0; @@ -59,18 +60,19 @@ ogs_pkbuf_t *upf_n4_build_session_establishment_response(uint8_t type, rsp->up_f_seid.data = &f_seid; rsp->up_f_seid.len = len; + ogs_pfcp_pdrbuf_init(); + /* Created PDR */ for (i = 0; i < num_of_created_pdr; i++) { - ogs_pfcp_tlv_created_pdr_t *message = &rsp->created_pdr[i]; - ogs_assert(message); - - message->presence = 1; - message->pdr_id.presence = 1; - message->pdr_id.u16 = created_pdr[i]->id; + ogs_pfcp_build_created_pdr(&rsp->created_pdr[i], i, created_pdr[i]); } pfcp_message.h.type = type; - return ogs_pfcp_build_msg(&pfcp_message); + pkbuf = ogs_pfcp_build_msg(&pfcp_message); + + ogs_pfcp_pdrbuf_clear(); + + return pkbuf; } ogs_pkbuf_t *upf_n4_build_session_modification_response(uint8_t type, @@ -78,6 +80,7 @@ ogs_pkbuf_t *upf_n4_build_session_modification_response(uint8_t type, { ogs_pfcp_message_t pfcp_message; ogs_pfcp_session_modification_response_t *rsp = NULL; + ogs_pkbuf_t *pkbuf = NULL; int i = 0; @@ -90,18 +93,19 @@ ogs_pkbuf_t *upf_n4_build_session_modification_response(uint8_t type, rsp->cause.presence = 1; rsp->cause.u8 = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + ogs_pfcp_pdrbuf_init(); + /* Created PDR */ for (i = 0; i < num_of_created_pdr; i++) { - ogs_pfcp_tlv_created_pdr_t *message = &rsp->created_pdr[i]; - ogs_assert(message); - - message->presence = 1; - message->pdr_id.presence = 1; - message->pdr_id.u16 = created_pdr[i]->id; + ogs_pfcp_build_created_pdr(&rsp->created_pdr[i], i, created_pdr[i]); } pfcp_message.h.type = type; - return ogs_pfcp_build_msg(&pfcp_message); + pkbuf = ogs_pfcp_build_msg(&pfcp_message); + + ogs_pfcp_pdrbuf_clear(); + + return pkbuf; } ogs_pkbuf_t *upf_n4_build_session_deletion_response(uint8_t type, diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index e8a82a9e6..5202365d6 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -117,8 +117,40 @@ void upf_n4_handle_session_establishment_request( ogs_assert(pdr); if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */ - if (pdr->f_teid_len) + 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; + } else { + ogs_sockaddr_t *addr = NULL, *addr6 = NULL; + + if (upf_self()->gtpu_sock) + addr = &upf_self()->gtpu_sock->local_addr; + if (upf_self()->gtpu_sock6) + addr6 = &upf_self()->gtpu_sock6->local_addr; + + 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; + } + } + ogs_pfcp_pdr_hash_set(pdr); + } } } @@ -269,8 +301,40 @@ void upf_n4_handle_session_modification_request( ogs_assert(pdr); if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */ - if (pdr->f_teid_len) + 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; + } else { + ogs_sockaddr_t *addr = NULL, *addr6 = NULL; + + if (upf_self()->gtpu_sock) + addr = &upf_self()->gtpu_sock->local_addr; + if (upf_self()->gtpu_sock6) + addr6 = &upf_self()->gtpu_sock6->local_addr; + + 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; + } + } + ogs_pfcp_pdr_hash_set(pdr); + } } }