diff --git a/configs/epc-fdconf.yaml.in b/configs/epc-fdconf.yaml.in index f86fad320..103627a0f 100644 --- a/configs/epc-fdconf.yaml.in +++ b/configs/epc-fdconf.yaml.in @@ -9,19 +9,21 @@ parameter: mme: freeDiameter: @sysconfdir@/freeDiameter/mme.conf s1ap: + addr: 127.0.0.1 gtpc: + addr: 127.0.0.1 sgsap: gummei: plmn_id: - mcc: 001 - mnc: 01 + mcc: 901 + mnc: 70 mme_gid: 2 mme_code: 1 tai: plmn_id: - mcc: 001 - mnc: 01 - tac: 12345 + mcc: 901 + mnc: 70 + tac: 1 security: integrity_order : [ EIA1, EIA2, EIA0 ] @@ -36,6 +38,7 @@ sgw: gtpc: addr: 127.0.0.2 gtpu: + addr: 127.0.0.2 pgw: freeDiameter: @sysconfdir@/freeDiameter/pgw.conf diff --git a/configs/open5gs/mme.yaml.in b/configs/open5gs/mme.yaml.in index ce436aeeb..b185251bc 100644 --- a/configs/open5gs/mme.yaml.in +++ b/configs/open5gs/mme.yaml.in @@ -204,18 +204,20 @@ logger: mme: freeDiameter: @sysconfdir@/freeDiameter/mme.conf s1ap: + addr: 127.0.0.1 gtpc: + addr: 127.0.0.1 gummei: plmn_id: - mcc: 001 - mnc: 01 + mcc: 901 + mnc: 70 mme_gid: 2 mme_code: 1 tai: plmn_id: - mcc: 001 - mnc: 01 - tac: 12345 + mcc: 901 + mnc: 70 + tac: 1 security: integrity_order : [ EIA1, EIA2, EIA0 ] ciphering_order : [ EEA0, EEA1, EEA2 ] diff --git a/configs/open5gs/sgw.yaml.in b/configs/open5gs/sgw.yaml.in index 4d2329563..6c0c44317 100644 --- a/configs/open5gs/sgw.yaml.in +++ b/configs/open5gs/sgw.yaml.in @@ -60,6 +60,7 @@ sgw: gtpc: addr: 127.0.0.2 gtpu: + addr: 127.0.0.2 # # parameter: diff --git a/lib/gtp/conv.c b/lib/gtp/conv.c index 9612271df..6d4eb8e99 100644 --- a/lib/gtp/conv.c +++ b/lib/gtp/conv.c @@ -139,3 +139,29 @@ int ogs_gtp_ip_to_f_teid(ogs_ip_t *ip, ogs_gtp_f_teid_t *f_teid, int *len) return OGS_OK; } + +int ogs_gtp_paa_to_ip(ogs_paa_t *paa, ogs_ip_t *ip) +{ + ogs_assert(paa); + ogs_assert(ip); + + memset(ip, 0, sizeof *ip); + + if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) { + ip->ipv4 = 1; + ip->addr = paa->both.addr; + ip->ipv6 = 1; + memcpy(ip->addr6, paa->both.addr6, OGS_IPV6_LEN); + } else if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV4) { + ip->ipv4 = 1; + ip->ipv6 = 0; + ip->addr = paa->addr; + } else if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV6) { + ip->ipv4 = 0; + ip->ipv6 = 1; + memcpy(ip->addr6, paa->addr6, OGS_IPV6_LEN); + } else + ogs_assert_if_reached(); + + return OGS_OK; +} diff --git a/lib/gtp/conv.h b/lib/gtp/conv.h index 84dd9f201..2d6ac45ff 100644 --- a/lib/gtp/conv.h +++ b/lib/gtp/conv.h @@ -35,6 +35,8 @@ int ogs_gtp_sockaddr_to_f_teid(ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, int ogs_gtp_f_teid_to_ip(ogs_gtp_f_teid_t *f_teid, ogs_ip_t *ip); int ogs_gtp_ip_to_f_teid(ogs_ip_t *ip, ogs_gtp_f_teid_t *f_teid, int *len); +int ogs_gtp_paa_to_ip(ogs_paa_t *paa, ogs_ip_t *ip); + #ifdef __cplusplus } #endif diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index ae96f7d31..8cbf0340e 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -868,9 +868,36 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find( return NULL; } -ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid(uint32_t teid) +static uint64_t pdr_hash_keygen(uint32_t teid, uint8_t qfi) { - return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash, &teid, sizeof(teid)); + uint64_t hashkey = (teid << 8) + qfi; + return hashkey; +} + +void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr) +{ + ogs_pfcp_qer_t *qer = NULL; + uint8_t qfi = 0; + + ogs_assert(pdr); + + qer = pdr->qer; + if (qer && qer->qfi) qfi = qer->qfi; + + if (pdr->hashkey) + ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey, + sizeof(pdr->hashkey), NULL); + + pdr->hashkey = pdr_hash_keygen(pdr->f_teid.teid, qfi); + ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey, + sizeof(pdr->hashkey), pdr); +} + +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi) +{ + uint64_t hashkey = pdr_hash_keygen(teid, qfi); + return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash, + &hashkey, sizeof(hashkey)); } ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add( @@ -911,7 +938,6 @@ void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far) ogs_assert(far); pdr->far = far; - far->pdr = pdr; } void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr) { @@ -919,7 +945,6 @@ void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr) ogs_assert(urr); pdr->urr = urr; - urr->pdr = pdr; } void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer) { @@ -927,7 +952,6 @@ void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer) ogs_assert(qer); pdr->qer = qer; - qer->pdr = pdr; } void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr) @@ -937,9 +961,9 @@ void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr) ogs_list_remove(&pdr->sess->pdr_list, pdr); - if (pdr->f_teid.teid) - ogs_hash_set(self.pdr_hash, &pdr->f_teid.teid, - sizeof(pdr->f_teid.teid), NULL); + if (pdr->hashkey) + ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey, + sizeof(pdr->hashkey), NULL); ogs_pool_free(&ogs_pfcp_pdr_pool, pdr); } diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index 902dbddff..4edd923f9 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -115,11 +115,17 @@ typedef struct ogs_pfcp_sess_s { typedef struct ogs_pfcp_pdr_s { ogs_lnode_t lnode; + uint64_t hashkey; + ogs_pfcp_pdr_id_t id; ogs_pfcp_precedence_t precedence; ogs_pfcp_interface_t src_if; + ogs_pfcp_ue_ip_addr_t ue_ip_addr; + int ue_ip_addr_len; + ogs_pfcp_f_teid_t f_teid; + int f_teid_len; ogs_pfcp_outer_header_removal_t outer_header_removal; ogs_pfcp_far_t *far; @@ -149,7 +155,6 @@ typedef struct ogs_pfcp_far_s { /* Related Context */ ogs_pfcp_sess_t *sess; void *gnode; - ogs_pfcp_pdr_t *pdr; } ogs_pfcp_far_t; typedef struct ogs_pfcp_urr_s { @@ -157,7 +162,6 @@ typedef struct ogs_pfcp_urr_s { ogs_pfcp_urr_id_t id; - ogs_pfcp_pdr_t *pdr; ogs_pfcp_sess_t *sess; } ogs_pfcp_urr_t; @@ -172,7 +176,6 @@ typedef struct ogs_pfcp_qer_s { uint8_t qfi; - ogs_pfcp_pdr_t *pdr; ogs_pfcp_sess_t *sess; } ogs_pfcp_qer_t; @@ -256,9 +259,11 @@ ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr(ogs_pfcp_sess_t *sess); void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess); ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess); +void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr); + ogs_pfcp_pdr_t *ogs_pfcp_pdr_find( ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id); -ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid(uint32_t teid); +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_or_add( ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id); void ogs_pfcp_pdr_reorder_by_precedence( diff --git a/src/smf/context.c b/src/smf/context.c index 371ce3390..e3d0dca93 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -644,25 +644,38 @@ static ogs_pfcp_node_t *selected_upf_node( return next ? next : ogs_list_first(&ogs_pfcp_self()->n4_list); } - -smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn, - uint8_t pdn_type, uint8_t ebi, ogs_paa_t *paa, ogs_gtp_uli_t *uli) +void smf_sess_select_upf(smf_sess_t *sess) +{ + char buf[OGS_ADDRSTRLEN]; + + ogs_assert(sess); + + /* + * When used for the first time, if last node is set, + * the search is performed from the first SGW in a round-robin manner. + */ + if (ogs_pfcp_self()->node == NULL) + ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->n4_list); + + /* setup GTP session with selected UPF */ + ogs_pfcp_self()->node = selected_upf_node(ogs_pfcp_self()->node, sess); + ogs_assert(ogs_pfcp_self()->node); + OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node); + ogs_debug("UE using UPF on IP[%s]", + OGS_ADDR(&ogs_pfcp_self()->node->addr, buf)); + + /* iterate to next UPF in list for next UE attach */ + ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node); +} + +smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn) { - ogs_debug("smf_sess_add_by_apn"); smf_event_t e; - char buf[OGS_ADDRSTRLEN]; - char buf1[OGS_ADDRSTRLEN]; - char buf2[OGS_ADDRSTRLEN]; smf_sess_t *sess = NULL; - smf_bearer_t *bearer = NULL; - ogs_pfcp_pdr_t *pdr = NULL; - ogs_pfcp_subnet_t *subnet6 = NULL; ogs_assert(smf_ue); ogs_assert(apn); - ogs_assert(paa); - ogs_assert(uli); ogs_pool_alloc(&smf_sess_pool, &sess); if (!sess) { @@ -682,83 +695,6 @@ smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn, /* Set APN */ ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); - /* UE IP Address */ - sess->pdn.paa.pdn_type = pdn_type; - ogs_expect(pdn_type == paa->pdn_type); - - if (pdn_type == OGS_GTP_PDN_TYPE_IPV4) { - sess->ipv4 = ogs_pfcp_ue_ip_alloc( - AF_INET, apn, (uint8_t *)&(paa->addr)); - ogs_assert(sess->ipv4); - sess->pdn.paa.addr = sess->ipv4->addr[0]; - ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); - } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV6) { - sess->ipv6 = ogs_pfcp_ue_ip_alloc( - AF_INET6, apn, (paa->addr6)); - ogs_assert(sess->ipv6); - - subnet6 = sess->ipv6->subnet; - ogs_assert(subnet6); - - sess->pdn.paa.len = subnet6->prefixlen; - memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN); - ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); - } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) { - sess->ipv4 = ogs_pfcp_ue_ip_alloc( - AF_INET, apn, (uint8_t *)&(paa->both.addr)); - ogs_assert(sess->ipv4); - sess->ipv6 = ogs_pfcp_ue_ip_alloc( - AF_INET6, apn, (paa->both.addr6)); - ogs_assert(sess->ipv6); - - subnet6 = sess->ipv6->subnet; - ogs_assert(subnet6); - - sess->pdn.paa.both.addr = sess->ipv4->addr[0]; - sess->pdn.paa.both.len = subnet6->prefixlen; - memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN); - ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); - ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); - } else - ogs_assert_if_reached(); - - memcpy(&sess->e_tai, &uli->tai, sizeof(sess->e_tai)); - memcpy(&sess->e_cgi, &uli->e_cgi, sizeof(sess->e_cgi)); - - ogs_info("UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]", - sess->imsi_bcd, apn, - sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", - sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); - - /* - * When used for the first time, if last node is set, - * the search is performed from the first SGW in a round-robin manner. - */ - if (ogs_pfcp_self()->node == NULL) - ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->n4_list); - - /* setup GTP session with selected UPF */ - ogs_pfcp_self()->node = selected_upf_node(ogs_pfcp_self()->node, sess); - ogs_assert(ogs_pfcp_self()->node); - OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node); - ogs_debug("UE using UPF on IP[%s]", - OGS_ADDR(&ogs_pfcp_self()->node->addr, buf)); - - /* iterate to next UPF in list for next UE attach */ - ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node); - - /* Set Default Bearer */ - ogs_list_init(&sess->bearer_list); - - bearer = smf_bearer_add(sess); - ogs_assert(bearer); - - bearer->ebi = ebi; /* EPC only */ - - /* Default PDRs is set to lowest precedence(highest precedence value). */ - ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) - pdr->precedence = 0xffffffff; - /* Setup SBI */ sess->sbi.client_wait.timer = ogs_timer_add( self.timer_mgr, smf_timer_sbi_client_wait_expire, sess); @@ -779,9 +715,7 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message) { smf_ue_t *smf_ue = NULL; smf_sess_t *sess = NULL; - ogs_paa_t *paa = NULL; char apn[OGS_MAX_APN_LEN]; - ogs_gtp_uli_t uli; ogs_gtp_create_session_request_t *req = &message->create_session_request; @@ -793,39 +727,11 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message) ogs_error("No APN"); return NULL; } - if (req->bearer_contexts_to_be_created.presence == 0) { - ogs_error("No Bearer"); - return NULL; - } - if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) { - ogs_error("No EPS Bearer ID"); - return NULL; - } - if (req->pdn_type.presence == 0) { - ogs_error("No PDN Type"); - return NULL; - } - - if (req->pdn_address_allocation.presence == 0) { - ogs_error("No PAA"); - return NULL; - } - - if (req->user_location_information.presence == 0) { - ogs_error("No UE Location Information"); - return NULL; - } ogs_fqdn_parse(apn, req->access_point_name.data, req->access_point_name.len); - ogs_trace("smf_sess_add_by_message() [APN:%s, PDN:%d, EDI:%d]", - apn, req->pdn_type.u8, - req->bearer_contexts_to_be_created.eps_bearer_id.u8); - - paa = (ogs_paa_t *)req->pdn_address_allocation.data; - - ogs_gtp_parse_uli(&uli, &req->user_location_information); + ogs_trace("smf_sess_add_by_message() [APN:%s]", apn); /* * 7.2.1 in 3GPP TS 29.274 Release 15 @@ -859,20 +765,15 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message) smf_sess_remove(sess); } - sess = smf_sess_add_by_apn(smf_ue, apn, req->pdn_type.u8, - req->bearer_contexts_to_be_created.eps_bearer_id.u8, paa, &uli); + sess = smf_sess_add_by_apn(smf_ue, apn); return sess; } smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi) { - ogs_debug("smf_sess_add_by_psi"); - smf_event_t e; smf_sess_t *sess = NULL; - smf_bearer_t *bearer = NULL; - ogs_pfcp_pdr_t *pdr = NULL; ogs_assert(smf_ue); ogs_assert(psi != OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED); @@ -905,33 +806,6 @@ smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi) sess->smf_n4_teid = sess->index; sess->smf_n4_seid = sess->index; - /* Select UPF with round-robin manner */ - if (ogs_pfcp_self()->node == NULL) - ogs_pfcp_self()->node = ogs_list_first(&ogs_pfcp_self()->n4_list); - - for (; ogs_pfcp_self()->node; - ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node)) { - if (OGS_FSM_CHECK( - &ogs_pfcp_self()->node->sm, smf_pfcp_state_associated)) { - OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node); - break; - } - } - - /* Set Default Bearer */ - ogs_list_init(&sess->bearer_list); - - bearer = smf_bearer_add(sess); - ogs_assert(bearer); - - /* QFI is only used in 5GC */ - bearer->qfi = OGS_NEXT_ID( - sess->qos_flow_identifier, 1, OGS_MAX_QOS_FLOW_ID+1); - - /* Default PDRs is set to lowest precedence(highest precedence value). */ - ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) - pdr->precedence = 0xffffffff; - /* Setup SBI */ sess->sbi.client_wait.timer = ogs_timer_add( self.timer_mgr, smf_timer_sbi_client_wait_expire, sess); @@ -988,6 +862,70 @@ smf_sess_t *smf_sess_add_by_sbi_message(ogs_sbi_message_t *message) return sess; } +void smf_sess_set_ue_ip(smf_sess_t *sess) +{ + ogs_pfcp_subnet_t *subnet6 = NULL; + smf_ue_t *smf_ue = NULL; + + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + sess->pdn.paa.pdn_type = sess->pdn.pdn_type; + ogs_assert(sess->pdn.pdn_type); + + if (sess->ipv4) { + ogs_hash_set(smf_self()->ipv4_hash, + sess->ipv4->addr, OGS_IPV4_LEN, NULL); + ogs_pfcp_ue_ip_free(sess->ipv4); + } + if (sess->ipv6) { + ogs_hash_set(smf_self()->ipv6_hash, + sess->ipv6->addr, OGS_IPV6_LEN, NULL); + ogs_pfcp_ue_ip_free(sess->ipv6); + } + + 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); + 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); + ogs_assert(sess->ipv6); + + subnet6 = sess->ipv6->subnet; + ogs_assert(subnet6); + + sess->pdn.paa.len = subnet6->prefixlen; + memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN); + ogs_hash_set(smf_self()->ipv6_hash, + 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); + ogs_assert(sess->ipv4); + sess->ipv6 = ogs_pfcp_ue_ip_alloc( + AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6); + ogs_assert(sess->ipv6); + + subnet6 = sess->ipv6->subnet; + ogs_assert(subnet6); + + sess->pdn.paa.both.addr = sess->ipv4->addr[0]; + sess->pdn.paa.both.len = subnet6->prefixlen; + memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN); + ogs_hash_set(smf_self()->ipv4_hash, + sess->ipv4->addr, OGS_IPV4_LEN, sess); + ogs_hash_set(smf_self()->ipv6_hash, + sess->ipv6->addr, OGS_IPV6_LEN, sess); + } else + ogs_assert_if_reached(); +} + void smf_sess_remove(smf_sess_t *sess) { int i; @@ -1035,6 +973,11 @@ void smf_sess_remove(smf_sess_t *sess) if (sess->dnn) ogs_free(sess->dnn); + if (sess->upf_n3_addr) + ogs_freeaddrinfo(sess->upf_n3_addr); + if (sess->upf_n3_addr6) + ogs_freeaddrinfo(sess->upf_n3_addr6); + /* Free SBI object memory */ ogs_sbi_object_free(&sess->sbi); ogs_timer_delete(sess->sbi.client_wait.timer); @@ -1119,6 +1062,80 @@ smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6) return (smf_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN); } +smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) +{ + smf_bearer_t *qos_flow = NULL; + + ogs_pfcp_pdr_t *dl_pdr = NULL; + ogs_pfcp_pdr_t *ul_pdr = NULL; + ogs_pfcp_far_t *dl_far = NULL; + ogs_pfcp_far_t *ul_far = NULL; + ogs_pfcp_qer_t *qer = NULL; + + ogs_assert(sess); + + ogs_pool_alloc(&smf_bearer_pool, &qos_flow); + ogs_assert(qos_flow); + memset(qos_flow, 0, sizeof *qos_flow); + + qos_flow->index = ogs_pool_index(&smf_bearer_pool, qos_flow); + ogs_assert(qos_flow->index > 0 && qos_flow->index <= + ogs_config()->pool.bearer); + + ogs_list_init(&qos_flow->pf_list); + + dl_pdr = ogs_pfcp_pdr_add(&qos_flow->pfcp); + ogs_assert(dl_pdr); + dl_pdr->id = OGS_NEXT_ID(sess->pdr_id, 1, OGS_MAX_NUM_OF_PDR+1); + dl_pdr->src_if = OGS_PFCP_INTERFACE_CORE; + + ul_pdr = ogs_pfcp_pdr_add(&qos_flow->pfcp); + ogs_assert(ul_pdr); + ul_pdr->id = OGS_NEXT_ID(sess->pdr_id, 1, OGS_MAX_NUM_OF_PDR+1); + ul_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS; + + dl_far = ogs_pfcp_far_add(&qos_flow->pfcp); + ogs_assert(dl_far); + dl_far->id = OGS_NEXT_ID(sess->far_id, 1, OGS_MAX_NUM_OF_FAR+1); + dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS; + ogs_pfcp_pdr_associate_far(dl_pdr, dl_far); + + ul_far = ogs_pfcp_far_add(&qos_flow->pfcp); + ogs_assert(ul_far); + ul_far->id = OGS_NEXT_ID(sess->far_id, 1, OGS_MAX_NUM_OF_FAR+1); + ul_far->dst_if = OGS_PFCP_INTERFACE_CORE; + ogs_pfcp_pdr_associate_far(ul_pdr, ul_far); + + qer = ogs_pfcp_qer_add(&qos_flow->pfcp); + ogs_assert(qer); + qer->id = OGS_NEXT_ID(sess->qer_id, 1, OGS_MAX_NUM_OF_QER+1); + ogs_pfcp_pdr_associate_qer(dl_pdr, qer); + ogs_pfcp_pdr_associate_qer(ul_pdr, qer); + + /* Allocate QFI */ + qer->qfi = OGS_NEXT_ID(sess->qos_flow_identifier, 1, OGS_MAX_QOS_FLOW_ID+1); + qos_flow->qfi = qer->qfi; + + qos_flow->sess = sess; + + ogs_list_add(&sess->bearer_list, qos_flow); + + return qos_flow; +} + +smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi) +{ + smf_bearer_t *qos_flow = NULL; + + ogs_assert(sess); + ogs_list_for_each(&sess->bearer_list, qos_flow) { + if (qos_flow->qfi == qfi) + return qos_flow; + } + + return qos_flow; +} + smf_bearer_t *smf_bearer_add(smf_sess_t *sess) { smf_bearer_t *bearer = NULL; @@ -1169,26 +1186,30 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess) sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, - &bearer->upf_addr, &bearer->upf_addr6); - ogs_assert(bearer->upf_addr || bearer->upf_addr6); + &bearer->upf_s5u_addr, &bearer->upf_s5u_addr6); + ogs_assert(bearer->upf_s5u_addr || bearer->upf_s5u_addr6); if (resource->info.teidri) - bearer->upf_n3_teid = UPF_S5U_INDEX_TO_TEID( + bearer->upf_s5u_teid = UPF_GTPU_INDEX_TO_TEID( bearer->index, resource->info.teidri, resource->info.teid_range); else - bearer->upf_n3_teid = bearer->index; + bearer->upf_s5u_teid = bearer->index; } else { if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) - ogs_copyaddrinfo(&bearer->upf_addr, &sess->pfcp_node->addr); + ogs_copyaddrinfo(&bearer->upf_s5u_addr, &sess->pfcp_node->addr); else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) - ogs_copyaddrinfo(&bearer->upf_addr6, &sess->pfcp_node->addr); + ogs_copyaddrinfo(&bearer->upf_s5u_addr6, &sess->pfcp_node->addr); else ogs_assert_if_reached(); - ogs_assert(bearer->upf_addr || bearer->upf_addr6); + ogs_assert(bearer->upf_s5u_addr || bearer->upf_s5u_addr6); - bearer->upf_n3_teid = bearer->index; + bearer->upf_s5u_teid = bearer->index; } + ogs_pfcp_sockaddr_to_f_teid(bearer->upf_s5u_addr, bearer->upf_s5u_addr6, + &ul_pdr->f_teid, &ul_pdr->f_teid_len); + ul_pdr->f_teid.teid = bearer->upf_s5u_teid; + bearer->sess = sess; ogs_list_add(&sess->bearer_list, bearer); @@ -1206,10 +1227,10 @@ int smf_bearer_remove(smf_bearer_t *bearer) if (bearer->name) ogs_free(bearer->name); - if (bearer->upf_addr) - ogs_freeaddrinfo(bearer->upf_addr); - if (bearer->upf_addr6) - ogs_freeaddrinfo(bearer->upf_addr6); + if (bearer->upf_s5u_addr) + ogs_freeaddrinfo(bearer->upf_s5u_addr); + if (bearer->upf_s5u_addr6) + ogs_freeaddrinfo(bearer->upf_s5u_addr6); smf_pf_remove_all(bearer); @@ -1327,7 +1348,7 @@ bool smf_bearer_is_default(smf_bearer_t *bearer) default_bearer = smf_default_bearer_in_sess(sess); ogs_assert(default_bearer); - return bearer->ebi == default_bearer->ebi; + return bearer == default_bearer; } smf_bearer_t *smf_bearer_first(smf_sess_t *sess) @@ -1566,4 +1587,3 @@ int smf_pco_build(uint8_t *pco_buf, uint8_t *buffer, int length) size = ogs_pco_build(pco_buf, OGS_MAX_PCO_LEN, &smf); return size; } - diff --git a/src/smf/context.h b/src/smf/context.h index ac4d933f8..e023f420a 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -143,7 +143,6 @@ typedef struct smf_sess_s { ogs_fsm_t sm; /* A state machine */ uint32_t smf_n4_teid; /* SMF-N4-TEID is derived from INDEX */ -#define SMF_5GC_SESS(__sESS) ((__sESS)->sgw_s5c_teid == 0) uint32_t sgw_s5c_teid; /* SGW-S5C-TEID is received from SGW */ #define SMF_SEID_TO_INDEX(__iNDEX) (__iNDEX & ~0x8000000000000000) @@ -152,6 +151,21 @@ typedef struct smf_sess_s { uint64_t smf_n4_seid; /* SMF SEID is dervied from INDEX */ uint64_t upf_n4_seid; /* UPF SEID is received from Peer */ + /* + * UPF-GTPU-TEID = INDEX | TEID_RANGE + * INDEX = UPF-GTPU-TEID & ~TEID_RANGE + */ +#define UPF_GTPU_TEID_TO_INDEX(__tEID, __iND, __rANGE) \ + (__tEID & ~(__rANGE << (32 - __iND))) +#define UPF_GTPU_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \ + (__iNDEX | (__rANGE << (32 - __iND))) + uint32_t upf_n3_teid; /* UPF-N3 TEID */ + ogs_sockaddr_t *upf_n3_addr; /* UPF-N3 IPv4 */ + ogs_sockaddr_t *upf_n3_addr6; /* UPF-N3 IPv6 */ + + uint32_t gnb_n3_teid; /* gNB-N3 TEID */ + ogs_ip_t gnb_n3_ip; /* gNB-N3 IPv4/IPv6 */ + char *gx_sid; /* Gx Session ID */ ogs_pfcp_pdr_id_t pdr_id; /* ID Generator(1~OGS_MAX_NUM_OF_PDR) */ @@ -162,11 +176,6 @@ typedef struct smf_sess_s { uint8_t qos_flow_identifier; /* ID Generator(1~OGS_MAX_QOS_FLOW_ID) */ - /* IMSI */ - uint8_t imsi[OGS_MAX_IMSI_LEN]; - int imsi_len; - char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; - char *sm_context_ref; /* smContextRef */ uint8_t psi; /* PDU session identity */ uint8_t pti; /* Procedure transaction identity */ @@ -227,6 +236,11 @@ typedef struct smf_sess_s { bool remove; } pfcp_5gc_modify; + struct { + bool create_session_response_apn_ambr; + bool create_session_response_bearer_qos; + } gtp_5gc;; + /* UE session context is activated or not */ OpenAPI_up_cnx_state_e ueUpCnxState; /* SMF session context is activated or not */ @@ -250,20 +264,12 @@ typedef struct smf_bearer_s { uint8_t qfi; /* 5GC */ uint8_t ebi; /* EPC */ - /* - * UPF-S5U-TEID = INDEX | TEID_RANGE - * INDEX = UPF-S5U-TEID & ~TEID_RANGE - */ -#define UPF_S5U_TEID_TO_INDEX(__tEID, __iND, __rANGE) \ - (__tEID & ~(__rANGE << (32 - __iND))) -#define UPF_S5U_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \ - (__iNDEX | (__rANGE << (32 - __iND))) - uint32_t upf_n3_teid; /* UPF_N3 TEID */ - ogs_sockaddr_t *upf_addr; /* UPF_N3 IPv4 */ - ogs_sockaddr_t *upf_addr6; /* UPF_N3 IPv6 */ + uint32_t upf_s5u_teid; /* UPF-S5U TEID */ + ogs_sockaddr_t *upf_s5u_addr; /* UPF-S5U IPv4 */ + ogs_sockaddr_t *upf_s5u_addr6; /* UPF-S5U IPv6 */ - uint32_t gnb_n3_teid; /* gNB_N3 TEID */ - ogs_ip_t gnb_n3_ip; /* gNB_N3 IP */ + uint32_t sgw_s5u_teid; /* SGW-S5U TEID */ + ogs_ip_t sgw_s5u_ip; /* SGW-S5U IPv4/IPv6 */ char *name; /* PCC Rule Name */ ogs_qos_t qos; /* QoS Infomration */ @@ -308,12 +314,14 @@ smf_ue_t *smf_ue_find_by_supi(char *supi); smf_ue_t *smf_ue_find_by_imsi(uint8_t *imsi, int imsi_len); smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message); -smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn, - uint8_t pdn_type, uint8_t ebi, ogs_paa_t *paa, ogs_gtp_uli_t *uli); +smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn); smf_sess_t *smf_sess_add_by_sbi_message(ogs_sbi_message_t *message); smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi); +void smf_sess_select_upf(smf_sess_t *sess); +void smf_sess_set_ue_ip(smf_sess_t *sess); + void smf_sess_remove(smf_sess_t *sess); void smf_sess_remove_all(smf_ue_t *smf_ue); @@ -326,6 +334,9 @@ smf_sess_t *smf_sess_find_by_sm_context_ref(char *sm_context_ref); smf_sess_t *smf_sess_find_by_ipv4(uint32_t addr); smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6); +smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess); +smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi); + 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); diff --git a/src/smf/fd-path.c b/src/smf/fd-path.c index 95f6cfcee..9a4900174 100644 --- a/src/smf/fd-path.c +++ b/src/smf/fd-path.c @@ -73,6 +73,7 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, uint32_t cc_request_type) { int ret; + smf_ue_t *smf_ue = NULL; struct msg *req = NULL; struct avp *avp; @@ -85,6 +86,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, ogs_assert(sess); ogs_assert(sess->ipv4 || sess->ipv6); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); ogs_debug("[Credit-Control-Request]"); @@ -221,8 +224,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, ret = fd_msg_avp_new(ogs_diam_gx_subscription_id_data, 0, &avpch1); ogs_assert(ret == 0); - val.os.data = (uint8_t *)sess->imsi_bcd; - val.os.len = strlen(sess->imsi_bcd); + val.os.data = (uint8_t *)smf_ue->imsi_bcd; + val.os.len = strlen(smf_ue->imsi_bcd); ret = fd_msg_avp_setvalue (avpch1, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); @@ -352,7 +355,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); ogs_assert(ret == 0); - ret = fd_msg_avp_new(ogs_diam_gx_allocation_retention_priority, 0, &avpch1); + ret = fd_msg_avp_new( + ogs_diam_gx_allocation_retention_priority, 0, &avpch1); ogs_assert(ret == 0); ret = fd_msg_avp_new(ogs_diam_gx_priority_level, 0, &avpch2); @@ -615,14 +619,16 @@ static void smf_gx_cca_cb(void *data, struct msg **msg) ret = fd_msg_search_avp(*msg, ogs_diam_gx_qos_information, &avp); ogs_assert(ret == 0); if (avp) { - ret = fd_avp_search_avp(avp, ogs_diam_gx_apn_aggregate_max_bitrate_ul, &avpch1); + ret = fd_avp_search_avp( + avp, ogs_diam_gx_apn_aggregate_max_bitrate_ul, &avpch1); ogs_assert(ret == 0); if (avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); ogs_assert(ret == 0); gx_message->pdn.ambr.uplink = hdr->avp_value->u32; } - ret = fd_avp_search_avp(avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1); + ret = fd_avp_search_avp( + avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1); ogs_assert(ret == 0); if (avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); @@ -642,10 +648,12 @@ static void smf_gx_cca_cb(void *data, struct msg **msg) gx_message->pdn.qos.qci = hdr->avp_value->u32; } - ret = fd_avp_search_avp(avp, ogs_diam_gx_allocation_retention_priority, &avpch1); + ret = fd_avp_search_avp( + avp, ogs_diam_gx_allocation_retention_priority, &avpch1); ogs_assert(ret == 0); if (avpch1) { - ret = fd_avp_search_avp(avpch1, ogs_diam_gx_priority_level, &avpch2); + ret = fd_avp_search_avp( + avpch1, ogs_diam_gx_priority_level, &avpch2); ogs_assert(ret == 0); if (avpch2) { ret = fd_msg_avp_hdr(avpch2, &hdr); @@ -653,7 +661,8 @@ static void smf_gx_cca_cb(void *data, struct msg **msg) gx_message->pdn.qos.arp.priority_level = hdr->avp_value->u32; } - ret = fd_avp_search_avp(avpch1, ogs_diam_gx_pre_emption_capability, &avpch2); + ret = fd_avp_search_avp( + avpch1, ogs_diam_gx_pre_emption_capability, &avpch2); ogs_assert(ret == 0); if (avpch2) { ret = fd_msg_avp_hdr(avpch2, &hdr); @@ -791,7 +800,8 @@ out: ogs_debug(" CC-Request-Type[%d] Number[%d] in Session Data", sess_data->cc_request_type, sess_data->cc_request_number); ogs_debug(" Current CC-Request-Number[%d]", cc_request_number); - if (sess_data->cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST && + if (sess_data->cc_request_type == + OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST && sess_data->cc_request_number <= cc_request_number) { ogs_debug(" [LAST] state_cleanup(): [%s]", sess_data->gx_sid); state_cleanup(sess_data, NULL, NULL); diff --git a/src/smf/gsm-build.c b/src/smf/gsm-build.c index 1b1abca3c..1934103c1 100644 --- a/src/smf/gsm-build.c +++ b/src/smf/gsm-build.c @@ -87,18 +87,44 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess) selected_pdu_session_type->type = sess->pdn.ssc_mode; selected_pdu_session_type->value = sess->pdn.pdn_type; - /* Default QoS Rule */ + /* + * TS23.501 + * 5.7.1.3 QoS Rules + * + * A default QoS rule is required to be sent to the UE for every PDU + * Session establishment and it is associated with a QoS Flow. For IP type + * PDU Session or Ethernet type PDU Session, the default QoS rule is + * the only QoS rule of a PDU Session which may contain a Packet Filter + * Set that allows all UL packets, and in this case, the highest + * precedence value shall be used for the QoS rule. + * + * As long as the default QoS rule does not contain a Packet Filter Set or + * contains a Packet Filter Set that allows all UL packets, Reflective QoS + * should not be applied for the QoS Flow which the default QoS rule is + * associated with and the RQA should not be sent for this QoS Flow. + */ memset(qos_rule, 0, sizeof(qos_rule)); qos_rule[0].identifier = 1; qos_rule[0].length = 6; qos_rule[0].code = OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE; qos_rule[0].DQR_bit = 1; qos_rule[0].num_of_packet_filter = 1; + qos_rule[0].pf[0].direction = OGS_NAS_QOS_DIRECTION_UPLINK; qos_rule[0].pf[0].pf_identifier = 1; qos_rule[0].pf[0].length = 1; qos_rule[0].pf[0].num_of_component = 1; qos_rule[0].pf[0].component[0].type = OGS_PACKET_FILTER_MATCH_ALL; + + /* + * TS23.501 + * 5.7.1.9 Precedence Value + * + * The QoS rule precedence value and the PDR precedence value determine + * the order in which a QoS rule or a PDR, respectively, shall be evaluated. + * The evaluation of the QoS rules or PDRs is performed in increasing order + * of their precedence value. + */ qos_rule[0].precedence = 255; /* lowest precedence */ qos_rule[0].flow.segregation = 0; qos_rule[0].flow.identifier = bearer->qfi; diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index 30bc2205d..edd440fa5 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -261,8 +261,7 @@ void smf_gsm_state_released(ogs_fsm_t *s, smf_event_t *e) break; default: - ogs_error("[%s] Unknown event %s", - sess->imsi_bcd, smf_event_get_name(e)); + ogs_error("Unknown event %s", smf_event_get_name(e)); break; } } @@ -286,8 +285,7 @@ void smf_gsm_state_exception(ogs_fsm_t *s, smf_event_t *e) break; default: - ogs_error("[%s] Unknown event %s", - sess->imsi_bcd, smf_event_get_name(e)); + ogs_error("Unknown event %s", smf_event_get_name(e)); break; } } diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c index 40a24dd42..4cfea2f2a 100644 --- a/src/smf/gx-handler.c +++ b/src/smf/gx-handler.c @@ -46,6 +46,12 @@ void smf_gx_handle_cca_initial_request( ogs_gtp_xact_t *gtp_xact) { int i; + + smf_bearer_t *bearer = NULL; + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; + ogs_pfcp_qer_t *qer = NULL; + ogs_assert(sess); ogs_assert(gx_message); ogs_assert(gtp_xact); @@ -63,12 +69,55 @@ void smf_gx_handle_cca_initial_request( return; } - if (sess->pdn.ambr.downlink || sess->pdn.ambr.uplink) { - smf_bearer_t *bearer = smf_default_bearer_in_sess(sess); - ogs_pfcp_pdr_t *pdr = NULL; - ogs_pfcp_qer_t *qer = NULL; - ogs_assert(bearer); + sess->num_of_pcc_rule = gx_message->num_of_pcc_rule; + for (i = 0; i < gx_message->num_of_pcc_rule; i++) + OGS_STORE_PCC_RULE(&sess->pcc_rule[i], &gx_message->pcc_rule[i]); + /* APN-AMBR + * if PCRF changes APN-AMBR, this should be included. */ + sess->gtp_5gc.create_session_response_apn_ambr = false; + if ((gx_message->pdn.ambr.uplink && + (sess->pdn.ambr.uplink / 1000) != + (gx_message->pdn.ambr.uplink / 1000)) || + (gx_message->pdn.ambr.downlink && + (sess->pdn.ambr.downlink / 1000) != + (gx_message->pdn.ambr.downlink / 1000))) { + + sess->pdn.ambr.downlink = gx_message->pdn.ambr.downlink; + sess->pdn.ambr.uplink = gx_message->pdn.ambr.uplink; + + sess->gtp_5gc.create_session_response_apn_ambr = true; + } + + /* Bearer QoS + * if PCRF changes Bearer QoS, this should be included. */ + sess->gtp_5gc.create_session_response_bearer_qos = false; + if ((gx_message->pdn.qos.qci && + sess->pdn.qos.qci != gx_message->pdn.qos.qci) || + (gx_message->pdn.qos.arp.priority_level && + sess->pdn.qos.arp.priority_level != + gx_message->pdn.qos.arp.priority_level) || + sess->pdn.qos.arp.pre_emption_capability != + gx_message->pdn.qos.arp.pre_emption_capability || + sess->pdn.qos.arp.pre_emption_vulnerability != + gx_message->pdn.qos.arp.pre_emption_vulnerability) { + + sess->pdn.qos.qci = gx_message->pdn.qos.qci; + sess->pdn.qos.arp.priority_level = + gx_message->pdn.qos.arp.priority_level; + sess->pdn.qos.arp.pre_emption_capability = + gx_message->pdn.qos.arp.pre_emption_capability; + sess->pdn.qos.arp.pre_emption_vulnerability = + gx_message->pdn.qos.arp.pre_emption_vulnerability; + + sess->gtp_5gc.create_session_response_bearer_qos = true; + } + + bearer = smf_default_bearer_in_sess(sess); + ogs_assert(bearer); + + /* Setup QER */ + if (sess->pdn.ambr.downlink || sess->pdn.ambr.uplink) { /* Only 1 QER is used per bearer */ qer = ogs_list_first(&bearer->pfcp.qer_list); if (!qer) { @@ -79,14 +128,35 @@ void smf_gx_handle_cca_initial_request( qer->mbr.uplink = sess->pdn.ambr.uplink; qer->mbr.downlink = sess->pdn.ambr.downlink; - - ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) - ogs_pfcp_pdr_associate_qer(pdr, qer); } - sess->num_of_pcc_rule = gx_message->num_of_pcc_rule; - for (i = 0; i < gx_message->num_of_pcc_rule; i++) - OGS_STORE_PCC_RULE(&sess->pcc_rule[i], &gx_message->pcc_rule[i]); + /* Setup FAR */ + ogs_list_for_each(&bearer->pfcp.far_list, far) { + + /* Set Outer Header Creation to the Default DL FAR */ + if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { + ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip, + &far->outer_header_creation, &far->outer_header_creation_len); + far->outer_header_creation.teid = bearer->sgw_s5u_teid; + } + } + + /* Setup PDR */ + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) { + + /* Set UE IP Address to the Default DL PDR */ + if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { + ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa, + &pdr->ue_ip_addr, &pdr->ue_ip_addr_len); + pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST; + } + + /* Default PDRs is set to lowest precedence(highest precedence value) */ + pdr->precedence = 0xffffffff; + + if (qer) + ogs_pfcp_pdr_associate_qer(pdr, qer); + } smf_epc_pfcp_send_session_establishment_request(sess, gtp_xact); } diff --git a/src/smf/n4-build.c b/src/smf/n4-build.c index 9f2381c39..ab28af956 100644 --- a/src/smf/n4-build.c +++ b/src/smf/n4-build.c @@ -87,7 +87,6 @@ ogs_pkbuf_t *smf_n4_build_association_setup_response(uint8_t type, } static struct { - ogs_pfcp_ue_ip_addr_t addr; ogs_pfcp_outer_header_removal_t outer_header_removal; ogs_pfcp_f_teid_t f_teid; char dnn[OGS_MAX_DNN_LEN]; @@ -164,25 +163,21 @@ static void build_create_pdr( } if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */ - if (smf_bearer_is_default(bearer)) { /* Default Bearer */ - ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa, - &pdrbuf[i].addr, &len); - pdrbuf[i].addr.sd = OGS_PFCP_UE_IP_DST; - + if (pdr->ue_ip_addr_len) { message->pdi.ue_ip_address.presence = 1; - message->pdi.ue_ip_address.data = &pdrbuf[i].addr; - message->pdi.ue_ip_address.len = len; + message->pdi.ue_ip_address.data = &pdr->ue_ip_addr; + message->pdi.ue_ip_address.len = pdr->ue_ip_addr_len; } } else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */ - ogs_pfcp_sockaddr_to_f_teid( - bearer->upf_addr, bearer->upf_addr6, - &pdrbuf[i].f_teid, &len); - pdrbuf[i].f_teid.teid = htobe32(bearer->upf_n3_teid); + 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->pdi.local_f_teid.presence = 1; - message->pdi.local_f_teid.data = &pdrbuf[i].f_teid; - message->pdi.local_f_teid.len = len; + message->pdi.local_f_teid.presence = 1; + message->pdi.local_f_teid.data = &pdrbuf[i].f_teid; + message->pdi.local_f_teid.len = pdr->f_teid_len; + } if (sess->pdn.paa.pdn_type == OGS_GTP_PDN_TYPE_IPV4) { pdrbuf[i].outer_header_removal.description = @@ -226,15 +221,11 @@ static void build_create_far( ogs_pfcp_tlv_create_far_t *message, int i, ogs_pfcp_far_t *far) { ogs_pfcp_sess_t *pfcp_sess = NULL; - smf_bearer_t *bearer = NULL; - int len; ogs_assert(message); ogs_assert(far); pfcp_sess = far->sess; ogs_assert(pfcp_sess); - bearer = SMF_BEARER(pfcp_sess); - ogs_assert(bearer); message->presence = 1; message->far_id.presence = 1; @@ -249,16 +240,17 @@ static void build_create_far( far->dst_if; if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */ - if (bearer->gnb_n3_ip.ipv4 || bearer->gnb_n3_ip.ipv6) { - ogs_pfcp_ip_to_outer_header_creation(&bearer->gnb_n3_ip, - &farbuf[i].outer_header_creation, &len); + 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(bearer->gnb_n3_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 = len; + message->forwarding_parameters.outer_header_creation.len = + far->outer_header_creation_len; } } } @@ -339,19 +331,14 @@ static void build_update_far(smf_sess_t *sess, ogs_pfcp_tlv_update_far_t *message, int i, ogs_pfcp_far_t *far) { ogs_pfcp_sess_t *pfcp_sess = NULL; - smf_bearer_t *bearer = NULL; - int len; ogs_assert(message); ogs_assert(far); pfcp_sess = far->sess; ogs_assert(pfcp_sess); - bearer = SMF_BEARER(pfcp_sess); - ogs_assert(bearer); - ogs_assert(sess); ogs_assert(far->dst_if == OGS_PFCP_INTERFACE_ACCESS); - ogs_assert(bearer->gnb_n3_ip.ipv4 || bearer->gnb_n3_ip.ipv6); + ogs_assert(far->outer_header_creation_len); message->presence = 1; message->far_id.presence = 1; @@ -359,10 +346,10 @@ static void build_update_far(smf_sess_t *sess, if (sess->ueUpCnxState == OpenAPI_up_cnx_state_ACTIVATED) { if (sess->pfcp_5gc_modify.outer_header_creation_update) { - ogs_pfcp_ip_to_outer_header_creation(&bearer->gnb_n3_ip, - &farbuf[i].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(bearer->gnb_n3_teid); + htobe32(far->outer_header_creation.teid); message->update_forwarding_parameters.presence = 1; message->update_forwarding_parameters. @@ -370,7 +357,7 @@ static void build_update_far(smf_sess_t *sess, message->update_forwarding_parameters. outer_header_creation.data = &farbuf[i].outer_header_creation; message->update_forwarding_parameters. - outer_header_creation.len = len; + outer_header_creation.len = far->outer_header_creation_len; } if (far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) { diff --git a/src/smf/ngap-build.c b/src/smf/ngap-build.c index a0a4b67a2..47e5529c9 100644 --- a/src/smf/ngap-build.c +++ b/src/smf/ngap-build.c @@ -22,7 +22,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( smf_sess_t *sess) { - smf_bearer_t *bearer = NULL; + smf_bearer_t *qos_flow = NULL; ogs_ip_t upf_n3_ip; NGAP_PDUSessionResourceSetupRequestTransfer_t message; @@ -41,8 +41,8 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( NGAP_AllocationAndRetentionPriority_t *allocationAndRetentionPriority; ogs_assert(sess); - bearer = smf_default_bearer_in_sess(sess); - ogs_assert(bearer); + qos_flow = smf_default_bearer_in_sess(sess); + ogs_assert(qos_flow); ogs_debug("PDUSessionResourceSetupRequestTransfer"); memset(&message, 0, sizeof(NGAP_PDUSessionResourceSetupRequestTransfer_t)); @@ -79,9 +79,9 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( NGAP_UPTransportLayerInformation_PR_gTPTunnel; UPTransportLayerInformation->choice.gTPTunnel = gTPTunnel; - ogs_sockaddr_to_ip(bearer->upf_addr, bearer->upf_addr6, &upf_n3_ip); + 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(bearer->upf_n3_teid, &gTPTunnel->gTP_TEID); + ogs_asn_uint32_to_OCTET_STRING(sess->upf_n3_teid, &gTPTunnel->gTP_TEID); ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupRequestTransferIEs_t)); ASN_SEQUENCE_ADD(&message.protocolIEs, ie); @@ -132,7 +132,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( qosCharacteristics->choice.nonDynamic5QI = nonDynamic5QI; qosCharacteristics->present = NGAP_QosCharacteristics_PR_nonDynamic5QI; - *qosFlowIdentifier = bearer->qfi; + *qosFlowIdentifier = qos_flow->qfi; nonDynamic5QI->fiveQI = sess->pdn.qos.qci; diff --git a/src/smf/ngap-handler.c b/src/smf/ngap-handler.c index eb5818105..b9e4ce9e0 100644 --- a/src/smf/ngap-handler.c +++ b/src/smf/ngap-handler.c @@ -26,11 +26,11 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( { ogs_sbi_session_t *session = NULL; smf_ue_t *smf_ue = NULL; - smf_bearer_t *bearer = NULL; + smf_bearer_t *qos_flow = NULL; int rv, i; - uint32_t gnb_n3_teid; - ogs_ip_t gnb_n3_ip; + uint32_t upf_n3_teid; + ogs_ip_t upf_n3_ip; ogs_pfcp_far_t *far = NULL; bool far_update = false; @@ -48,8 +48,6 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( ogs_assert(sess); session = sess->sbi.session; ogs_assert(session); - bearer = smf_default_bearer_in_sess(sess); - ogs_assert(bearer); smf_ue = sess->smf_ue; ogs_assert(smf_ue); @@ -90,10 +88,19 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( associatedQosFlowItem = (NGAP_AssociatedQosFlowItem_t *) associatedQosFlowList->list.array[i]; if (associatedQosFlowItem) { - /* TODO : associatedQosFlowItem->qosFlowIdentifier */ + qos_flow = smf_qos_flow_find_by_qfi(sess, + associatedQosFlowItem->qosFlowIdentifier); } } + if (!qos_flow) { + ogs_error("[%s:%d] No QoS flow", smf_ue->supi, sess->psi); + smf_sbi_send_sm_context_update_error(session, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, + "No QoS flow", smf_ue->supi, NULL, NULL); + goto cleanup; + } + gTPTunnel = uPTransportLayerInformation->choice.gTPTunnel; if (!gTPTunnel) { ogs_error("[%s:%d] No GTPTunnel", smf_ue->supi, sess->psi); @@ -104,20 +111,20 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( } ogs_asn_BIT_STRING_to_ip( - &gTPTunnel->transportLayerAddress, &gnb_n3_ip); - ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &gnb_n3_teid); + &gTPTunnel->transportLayerAddress, &upf_n3_ip); + ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &upf_n3_teid); - if (memcmp(&bearer->gnb_n3_ip, &gnb_n3_ip, - sizeof(bearer->gnb_n3_ip)) != 0 || - bearer->gnb_n3_teid != gnb_n3_teid) + if (memcmp(&sess->gnb_n3_ip, &upf_n3_ip, sizeof(sess->gnb_n3_ip)) != 0 || + sess->gnb_n3_teid != upf_n3_teid) sess->pfcp_5gc_modify.outer_header_creation_update = true; else sess->pfcp_5gc_modify.outer_header_creation_update = false; - memcpy(&bearer->gnb_n3_ip, &gnb_n3_ip, sizeof(bearer->gnb_n3_ip)); - bearer->gnb_n3_teid = gnb_n3_teid; + memcpy(&sess->gnb_n3_ip, &upf_n3_ip, sizeof(sess->gnb_n3_ip)); + sess->gnb_n3_teid = upf_n3_teid; - ogs_list_for_each(&bearer->pfcp.far_list, far) { + /* Need to Update? */ + ogs_list_for_each(&qos_flow->pfcp.far_list, far) { if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { if (sess->ueUpCnxState == OpenAPI_up_cnx_state_ACTIVATED) { if (far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) { @@ -129,6 +136,15 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( } } + /* Setup FAR */ + ogs_list_for_each(&qos_flow->pfcp.far_list, far) { + if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { + ogs_pfcp_ip_to_outer_header_creation(&sess->gnb_n3_ip, + &far->outer_header_creation, &far->outer_header_creation_len); + far->outer_header_creation.teid = sess->gnb_n3_teid; + } + } + if (far_update || sess->pfcp_5gc_modify.outer_header_creation_update) smf_5gc_pfcp_send_session_modification_request(sess); else diff --git a/src/smf/nudm-handler.c b/src/smf/nudm-handler.c index 4305c69d2..d67250b76 100644 --- a/src/smf/nudm-handler.c +++ b/src/smf/nudm-handler.c @@ -26,9 +26,9 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg) char buf2[OGS_ADDRSTRLEN]; smf_ue_t *smf_ue = NULL; - ogs_pfcp_subnet_t *subnet6 = NULL; - smf_bearer_t *bearer = NULL; + smf_bearer_t *qos_flow = NULL; + ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_qer_t *qer = NULL; @@ -225,6 +225,59 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg) return false; } + /* Select UPF based on UE Location Information */ + smf_sess_select_upf(sess); + + /* Check if selected UPF is associated with SMF */ + ogs_assert(sess->pfcp_node); + if (!OGS_FSM_CHECK(&sess->pfcp_node->sm, smf_pfcp_state_associated)) { + ogs_error("[%s] No associated UPF", smf_ue->supi); + 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 = UPF_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 + *********************************************************************/ + memset(&SmContextCreatedData, 0, sizeof(SmContextCreatedData)); memset(&sendmsg, 0, sizeof(sendmsg)); @@ -246,84 +299,44 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg) ogs_free(sendmsg.http.location); - sess->pdn.paa.pdn_type = sess->pdn.pdn_type; - ogs_assert(sess->pdn.pdn_type); - if (sess->ipv4) { - ogs_hash_set(smf_self()->ipv4_hash, - sess->ipv4->addr, OGS_IPV4_LEN, NULL); - ogs_pfcp_ue_ip_free(sess->ipv4); - } - if (sess->ipv6) { - ogs_hash_set(smf_self()->ipv6_hash, - sess->ipv6->addr, OGS_IPV6_LEN, NULL); - ogs_pfcp_ue_ip_free(sess->ipv6); + /********************************************************************* + * Send PFCP Session Establiashment Request to the UPF + *********************************************************************/ + + /* Remove all previous QoS flow */ + smf_bearer_remove_all(sess); + + /* Setup Default QoS flow */ + qos_flow = smf_qos_flow_add(sess); + ogs_assert(qos_flow); + + /* Setup QER */ + ogs_list_for_each(&qos_flow->pfcp.qer_list, qer) { + qer->mbr.uplink = sess->pdn.ambr.uplink; + qer->mbr.downlink = sess->pdn.ambr.downlink; } - 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); - 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); - ogs_assert(sess->ipv6); + /* Setup PDR */ + ogs_list_for_each(&qos_flow->pfcp.pdr_list, pdr) { - subnet6 = sess->ipv6->subnet; - ogs_assert(subnet6); + /* Set UE IP Address to the Default DL PDR */ + if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { + ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa, + &pdr->ue_ip_addr, &pdr->ue_ip_addr_len); + pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST; - sess->pdn.paa.len = subnet6->prefixlen; - memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN); - ogs_hash_set(smf_self()->ipv6_hash, - 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); - ogs_assert(sess->ipv4); - sess->ipv6 = ogs_pfcp_ue_ip_alloc( - AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6); - ogs_assert(sess->ipv6); + /* Set UPF-N3 TEID & ADDR to the Default UL PDR */ + } else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { + ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6, + &pdr->f_teid, &pdr->f_teid_len); + pdr->f_teid.teid = sess->upf_n3_teid; + } - subnet6 = sess->ipv6->subnet; - ogs_assert(subnet6); - - sess->pdn.paa.both.addr = sess->ipv4->addr[0]; - sess->pdn.paa.both.len = subnet6->prefixlen; - memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN); - ogs_hash_set(smf_self()->ipv4_hash, - sess->ipv4->addr, OGS_IPV4_LEN, sess); - ogs_hash_set(smf_self()->ipv6_hash, - sess->ipv6->addr, OGS_IPV6_LEN, sess); - } else - ogs_assert_if_reached(); - - ogs_info("UE SUPI:[%s] DNN:[%s] IPv4:[%s] IPv6:[%s]", - smf_ue->supi, sess->pdn.apn, - sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", - sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); - - bearer = smf_default_bearer_in_sess(sess); - ogs_assert(bearer); - - /* Only 1 QER is used per bearer */ - qer = ogs_list_first(&bearer->pfcp.qer_list); - if (!qer) { - qer = ogs_pfcp_qer_add(&bearer->pfcp); - ogs_assert(qer); - qer->id = OGS_NEXT_ID(sess->qer_id, 1, OGS_MAX_NUM_OF_QER+1); + /* Default PDRs is set to lowest precedence(highest precedence value) */ + pdr->precedence = 0xffffffff; } - qer->mbr.uplink = sess->pdn.ambr.uplink; - qer->mbr.downlink = sess->pdn.ambr.downlink; - - qer->qfi = bearer->qfi; - - ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) - ogs_pfcp_pdr_associate_qer(pdr, qer); - smf_5gc_pfcp_send_session_establishment_request(sess); return true; diff --git a/src/smf/s5c-build.c b/src/smf/s5c-build.c index 73cd1dd88..6c4ad59e7 100644 --- a/src/smf/s5c-build.c +++ b/src/smf/s5c-build.c @@ -32,7 +32,10 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( ogs_gtp_create_session_response_t *rsp = NULL; ogs_gtp_cause_t cause; - ogs_gtp_f_teid_t smf_s5c_teid, upf_n3_teid; + ogs_gtp_f_teid_t smf_s5c_teid, upf_s5u_teid; + ogs_gtp_ambr_t ambr; + ogs_gtp_bearer_qos_t bearer_qos; + char bearer_qos_buf[GTP_BEARER_QOS_LEN]; int len; uint8_t pco_buf[OGS_MAX_PCO_LEN]; int16_t pco_len; @@ -45,8 +48,8 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); - ogs_debug(" gNB_N3_TEID[0x%x] UPF_N3_TEID[0x%x]", - bearer->gnb_n3_teid, bearer->upf_n3_teid); + ogs_debug(" SGW_S5U_TEID[0x%x] UPF_S5U_TEID[0x%x]", + bearer->sgw_s5u_teid, bearer->upf_s5u_teid); rsp = >p_message.create_session_response; memset(>p_message, 0, sizeof(ogs_gtp_message_t)); @@ -88,8 +91,16 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( rsp->apn_restriction.presence = 1; rsp->apn_restriction.u8 = OGS_GTP_APN_NO_RESTRICTION; - /* TODO : APN-AMBR + /* APN-AMBR * if PCRF changes APN-AMBR, this should be included. */ + if (sess->gtp_5gc.create_session_response_apn_ambr == true) { + memset(&ambr, 0, sizeof(ogs_gtp_ambr_t)); + ambr.uplink = htobe32(sess->pdn.ambr.uplink / 1000); + ambr.downlink = htobe32(sess->pdn.ambr.downlink / 1000); + rsp->aggregate_maximum_bit_rate.presence = 1; + rsp->aggregate_maximum_bit_rate.data = &ambr; + rsp->aggregate_maximum_bit_rate.len = sizeof(ambr); + } /* PCO */ if (sess->gtp.ue_pco.presence && @@ -112,18 +123,31 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( rsp->bearer_contexts_created.cause.len = sizeof(cause); rsp->bearer_contexts_created.cause.data = &cause; - /* TODO : Bearer QoS + /* Bearer QoS * if PCRF changes Bearer QoS, this should be included. */ + if (sess->gtp_5gc.create_session_response_bearer_qos == true) { + memset(&bearer_qos, 0, sizeof(bearer_qos)); + bearer_qos.qci = sess->pdn.qos.qci; + bearer_qos.priority_level = sess->pdn.qos.arp.priority_level; + bearer_qos.pre_emption_capability = + sess->pdn.qos.arp.pre_emption_capability; + bearer_qos.pre_emption_vulnerability = + sess->pdn.qos.arp.pre_emption_vulnerability; + + rsp->bearer_contexts_created.bearer_level_qos.presence = 1; + ogs_gtp_build_bearer_qos(&rsp->bearer_contexts_created.bearer_level_qos, + &bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN); + } /* Data Plane(UL) : SMF-S5U */ - memset(&upf_n3_teid, 0, sizeof(ogs_gtp_f_teid_t)); - upf_n3_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; - upf_n3_teid.teid = htobe32(bearer->upf_n3_teid); + memset(&upf_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t)); + upf_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; + upf_s5u_teid.teid = htobe32(bearer->upf_s5u_teid); rv = ogs_gtp_sockaddr_to_f_teid( - bearer->upf_addr, bearer->upf_addr6, &upf_n3_teid, &len); + bearer->upf_s5u_addr, bearer->upf_s5u_addr6, &upf_s5u_teid, &len); ogs_assert(rv == OGS_OK); rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence = 1; - rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &upf_n3_teid; + rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &upf_s5u_teid; rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.len = len; gtp_message.h.type = type; @@ -182,7 +206,7 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request( ogs_gtp_message_t gtp_message; ogs_gtp_create_bearer_request_t *req = NULL; - ogs_gtp_f_teid_t upf_n3_teid; + ogs_gtp_f_teid_t upf_s5u_teid; ogs_gtp_bearer_qos_t bearer_qos; char bearer_qos_buf[GTP_BEARER_QOS_LEN]; int len; @@ -211,14 +235,14 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request( req->bearer_contexts.eps_bearer_id.u8 = bearer->ebi; /* Data Plane(UL) : SMF_S5U */ - memset(&upf_n3_teid, 0, sizeof(ogs_gtp_f_teid_t)); - upf_n3_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; - upf_n3_teid.teid = htobe32(bearer->upf_n3_teid); + memset(&upf_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t)); + upf_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; + upf_s5u_teid.teid = htobe32(bearer->upf_s5u_teid); rv = ogs_gtp_sockaddr_to_f_teid( - bearer->upf_addr, bearer->upf_addr6, &upf_n3_teid, &len); + bearer->upf_s5u_addr, bearer->upf_s5u_addr6, &upf_s5u_teid, &len); ogs_assert(rv == OGS_OK); req->bearer_contexts.s5_s8_u_sgw_f_teid.presence = 1; - req->bearer_contexts.s5_s8_u_sgw_f_teid.data = &upf_n3_teid; + req->bearer_contexts.s5_s8_u_sgw_f_teid.data = &upf_s5u_teid; req->bearer_contexts.s5_s8_u_sgw_f_teid.len = len; /* Bearer QoS */ diff --git a/src/smf/s5c-handler.c b/src/smf/s5c-handler.c index 7da3c29dc..fa2e2cc08 100644 --- a/src/smf/s5c-handler.c +++ b/src/smf/s5c-handler.c @@ -49,9 +49,18 @@ void smf_s5c_handle_create_session_request( smf_sess_t *sess, ogs_gtp_xact_t *xact, ogs_gtp_create_session_request_t *req) { + char buf1[OGS_ADDRSTRLEN]; + char buf2[OGS_ADDRSTRLEN]; + int rv; uint8_t cause_value = 0; - ogs_gtp_f_teid_t *sgw_s5c_teid, *gnb_n3_teid; + + char apn[OGS_MAX_APN_LEN]; + ogs_gtp_uli_t uli; + + smf_ue_t *smf_ue = NULL; + + ogs_gtp_f_teid_t *sgw_s5c_teid, *sgw_s5u_teid; smf_bearer_t *bearer = NULL; ogs_gtp_bearer_qos_t bearer_qos; ogs_gtp_ambr_t *ambr = NULL; @@ -64,12 +73,8 @@ void smf_s5c_handle_create_session_request( cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; - if (sess) { - bearer = smf_default_bearer_in_sess(sess); - ogs_assert(bearer); - } - if (!bearer) { - ogs_warn("No Context"); + if (!sess) { + ogs_error("No Context"); cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; } @@ -85,6 +90,10 @@ void smf_s5c_handle_create_session_request( ogs_error("No Bearer"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } if (req->bearer_contexts_to_be_created.bearer_level_qos.presence == 0) { ogs_error("No EPS Bearer QoS"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; @@ -93,6 +102,18 @@ void smf_s5c_handle_create_session_request( ogs_error("No TEID"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + if (req->pdn_type.presence == 0) { + ogs_error("No PDN Type"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (req->pdn_address_allocation.presence == 0) { + ogs_error("No PAA"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (req->user_location_information.presence == 0) { + ogs_error("No UE Location Information"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } if (!ogs_diam_peer_connected()) { ogs_error("No Diameter Peer"); @@ -104,28 +125,67 @@ void smf_s5c_handle_create_session_request( OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value); return; } - - /* Set IMSI */ - sess->imsi_len = req->imsi.len; - memcpy(sess->imsi, req->imsi.data, sess->imsi_len); - ogs_buffer_to_bcd(sess->imsi, sess->imsi_len, sess->imsi_bcd); + + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + /* UE Location Inforamtion*/ + ogs_gtp_parse_uli(&uli, &req->user_location_information); + memcpy(&sess->e_tai, &uli.tai, sizeof(sess->e_tai)); + memcpy(&sess->e_cgi, &uli.e_cgi, sizeof(sess->e_cgi)); + + /* Select UPF based on UE Location Information */ + smf_sess_select_upf(sess); + + /* Check if selected UPF is associated with SMF */ + ogs_assert(sess->pfcp_node); + if (!OGS_FSM_CHECK(&sess->pfcp_node->sm, smf_pfcp_state_associated)) { + ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, + OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING); + return; + } + + /* UE IP Address */ + ogs_assert(req->pdn_address_allocation.data); + sess->pdn.pdn_type = req->pdn_type.u8; + ogs_gtp_paa_to_ip( + (ogs_paa_t *)req->pdn_address_allocation.data, &sess->pdn.ue_ip); + + smf_sess_set_ue_ip(sess); + + ogs_info("UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]", + smf_ue->imsi_bcd, apn, + sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", + sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); + + /* Remove all previous bearer */ + smf_bearer_remove_all(sess); + + /* Setup Default Bearer */ + bearer = smf_bearer_add(sess); + ogs_assert(bearer); + + /* Set Bearer EBI */ + bearer->ebi = req->bearer_contexts_to_be_created.eps_bearer_id.u8; /* Control Plane(DL) : SGW-S5C */ sgw_s5c_teid = req->sender_f_teid_for_control_plane.data; ogs_assert(sgw_s5c_teid); sess->sgw_s5c_teid = be32toh(sgw_s5c_teid->teid); - /* Data Plane(DL) : gNB-N3 */ - gnb_n3_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data; - ogs_assert(gnb_n3_teid); - bearer->gnb_n3_teid = be32toh(gnb_n3_teid->teid); - rv = ogs_gtp_f_teid_to_ip(gnb_n3_teid, &bearer->gnb_n3_ip); + /* Data Plane(DL) : SGW-S5U */ + sgw_s5u_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data; + ogs_assert(sgw_s5u_teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); + rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); ogs_assert(rv == OGS_OK); ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); - ogs_debug(" gNB_N3_TEID[0x%x] UPF_N3_TEID[0x%x]", - bearer->gnb_n3_teid, bearer->upf_n3_teid); + ogs_debug(" SGW_S5U_TEID[0x%x] UPF_S5U_TEID[0x%x]", + bearer->sgw_s5u_teid, bearer->upf_s5u_teid); decoded = ogs_gtp_parse_bearer_qos(&bearer_qos, &req->bearer_contexts_to_be_created.bearer_level_qos); @@ -168,7 +228,7 @@ void smf_s5c_handle_create_session_request( if (req->ue_time_zone.presence) { OGS_TLV_STORE_DATA(&sess->gtp.ue_timezone, &req->ue_time_zone); } - + smf_gx_send_ccr(sess, xact, OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST); } @@ -214,8 +274,9 @@ void smf_s5c_handle_create_bearer_response( ogs_gtp_create_bearer_response_t *rsp) { int rv; - ogs_gtp_f_teid_t *gnb_n3_teid, *smf_s5u_teid; + ogs_gtp_f_teid_t *sgw_s5u_teid, *smf_s5u_teid; smf_bearer_t *bearer = NULL; + ogs_pfcp_far_t *far = NULL; ogs_assert(xact); ogs_assert(rsp); @@ -271,16 +332,26 @@ void smf_s5c_handle_create_bearer_response( /* Set EBI */ bearer->ebi = rsp->bearer_contexts.eps_bearer_id.u8; - /* Data Plane(DL) : gNB-N3 */ - gnb_n3_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data; - ogs_assert(gnb_n3_teid); - bearer->gnb_n3_teid = be32toh(gnb_n3_teid->teid); - rv = ogs_gtp_f_teid_to_ip(gnb_n3_teid, &bearer->gnb_n3_ip); + /* Data Plane(DL) : SGW-S5U */ + sgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data; + ogs_assert(sgw_s5u_teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); + rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); ogs_assert(rv == OGS_OK); ogs_debug("[SMF] Create Bearer Response : SGW[0x%x] --> SMF[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); + /* Setup FAR */ + ogs_list_for_each(&bearer->pfcp.far_list, far) { + if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { + ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip, + &far->outer_header_creation, &far->outer_header_creation_len); + 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_pdr_t *pdr = NULL; diff --git a/src/upf/context.c b/src/upf/context.c index 930d173a4..912bc60ed 100644 --- a/src/upf/context.c +++ b/src/upf/context.c @@ -28,19 +28,6 @@ static OGS_POOL(upf_sdf_filter_pool, upf_sdf_filter_t); static int context_initialized = 0; -int num_sessions = 0; -void stats_add_session(void) { - num_sessions = num_sessions + 1; - ogs_info("Added a session. Number of active sessions is now %d", - num_sessions); -} - -void stats_remove_session(void) { - num_sessions = num_sessions - 1; - ogs_info("Removed a session. Number of active sessions is now %d", - num_sessions); -} - void upf_context_init(void) { ogs_assert(context_initialized == 0); @@ -457,7 +444,7 @@ upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid, OGS_SETUP_DEFAULT_PDR(&sess->pfcp, ogs_pfcp_pdr_find_or_add(&sess->pfcp, default_pdr_id)); - ogs_info("UE F-SEID[CP:%ld,UP:%ld] " + ogs_info("UE F-SEID[CP:0x%lx,UP:0x%lx] " "APN[%s] PDN-Type[%d] IPv4[%s] IPv6[%s], Default PDR ID[%d]", (long)sess->upf_n4_seid, (long)sess->smf_n4_seid, apn, pdn_type, @@ -467,7 +454,8 @@ upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid, ogs_list_add(&self.sess_list, sess); - stats_add_session(); + ogs_info("Added a session. Number of active sessions is now %d", + ogs_list_count(&self.sess_list)); return sess; @@ -498,7 +486,8 @@ int upf_sess_remove(upf_sess_t *sess) ogs_pool_free(&upf_sess_pool, sess); - stats_remove_session(); + ogs_info("Removed a session. Number of active sessions is now %d", + ogs_list_count(&self.sess_list)); return OGS_OK; } diff --git a/src/upf/context.h b/src/upf/context.h index 4dbae0428..80b3f198a 100644 --- a/src/upf/context.h +++ b/src/upf/context.h @@ -120,9 +120,6 @@ upf_sdf_filter_t *upf_sdf_filter_add(ogs_pfcp_pdr_t *pdr); void upf_sdf_filter_remove(upf_sdf_filter_t *sdf_filter); void upf_sdf_filter_remove_all(upf_sess_t *sess); -void stats_add_session(void); -void stats_remove_session(void); - #ifdef __cplusplus } #endif diff --git a/src/upf/gtp-path.c b/src/upf/gtp-path.c index 53df581f7..4048b3062 100644 --- a/src/upf/gtp-path.c +++ b/src/upf/gtp-path.c @@ -41,7 +41,7 @@ #define UPF_GTP_HANDLED 1 -static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf); +static void upf_gtp_send_to_gnb(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf); static int upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf); static int upf_gtp_handle_slaac(upf_sess_t *sess, ogs_pkbuf_t *recvbuf); static int upf_gtp_handle_pdr(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf); @@ -94,6 +94,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) struct ip *ip_h = NULL; uint32_t teid; + uint8_t qfi; ogs_pfcp_pdr_t *pdr = NULL; upf_sess_t *sess = NULL; ogs_pfcp_subnet_t *subnet = NULL; @@ -166,6 +167,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_debug("[RECV] GPU-U from [%s] : TEID[0x%x]", OGS_ADDR(&from, buf), teid); + qfi = 0; if (gtp_h->flags & OGS_GTPU_FLAGS_E) { /* * TS29.281 @@ -184,6 +186,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) OGS_GTP_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) { ogs_debug(" QFI [0x%x]", extension_header->qos_flow_identifier); + qfi = extension_header->qos_flow_identifier; } } } @@ -200,9 +203,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ip_h = (struct ip *)pkbuf->data; ogs_assert(ip_h); - pdr = ogs_pfcp_pdr_find_by_teid(teid); + pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi); if (!pdr) { - ogs_warn("[DROP] Cannot find PDR : UPF-N3-TEID[0x%x]", teid); + ogs_warn("[DROP] Cannot find PDR : UPF-N3-TEID[0x%x] QFI[%d]", + teid, qfi); goto cleanup; } ogs_assert(pdr->sess); @@ -326,23 +330,25 @@ void upf_gtp_close(void) } } -void upf_gtp_send_buffered_packet(ogs_pfcp_far_t *far) +void upf_gtp_send_buffered_packet(ogs_pfcp_pdr_t *pdr) { + ogs_pfcp_far_t *far = NULL; int i; - ogs_assert(far); + ogs_assert(pdr); + far = pdr->far; - if (far->gnode) { + if (far && far->gnode) { if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { for (i = 0; i < far->num_of_buffered_packet; i++) { - upf_gtp_send_to_gnb(far, far->buffered_packet[i]); + upf_gtp_send_to_gnb(pdr, far->buffered_packet[i]); } far->num_of_buffered_packet = 0; } } } -static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf) +static void upf_gtp_send_to_gnb(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf) { char buf[OGS_ADDRSTRLEN]; int rv; @@ -350,10 +356,16 @@ static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf) ogs_gtp_extension_header_t *ext_h = NULL; ogs_gtp_node_t *gnode = NULL; - ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; ogs_pfcp_qer_t *qer = NULL; - ogs_assert(far); + ogs_assert(pdr); + + far = pdr->far; + if (!far) { + ogs_error("No FAR"); + return; + } if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) { ogs_error("FAR is NOT Downlink"); @@ -365,8 +377,6 @@ static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf) ogs_assert(gnode->sock); ogs_assert(sendbuf); - pdr = far->pdr; - ogs_assert(pdr); qer = pdr->qer; /* Add GTP-U header */ @@ -444,7 +454,7 @@ static int upf_gtp_handle_pdr(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf) } } else { if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { - upf_gtp_send_to_gnb(far, sendbuf); + upf_gtp_send_to_gnb(pdr, sendbuf); } else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) { if (far->num_of_buffered_packet < MAX_NUM_OF_PACKET_BUFFER) { far->buffered_packet[far->num_of_buffered_packet++] = sendbuf; diff --git a/src/upf/gtp-path.h b/src/upf/gtp-path.h index edfdc72c6..36de03294 100644 --- a/src/upf/gtp-path.h +++ b/src/upf/gtp-path.h @@ -30,7 +30,7 @@ extern "C" { int upf_gtp_open(void); void upf_gtp_close(void); -void upf_gtp_send_buffered_packet(ogs_pfcp_far_t *far); +void upf_gtp_send_buffered_packet(ogs_pfcp_pdr_t *pdr); #ifdef __cplusplus } diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index 0f86b7f84..864cb39b7 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -58,6 +58,40 @@ void upf_n4_handle_heartbeat_response( upf_timer_cfg(UPF_TIMER_HEARTBEAT)->duration); } +static void setup_gtp_node(ogs_pfcp_far_t *far, + ogs_pfcp_tlv_outer_header_creation_t *outer_header_creation) +{ + int rv; + ogs_ip_t ip; + ogs_gtp_node_t *gnode = NULL; + + ogs_assert(far); + ogs_assert(outer_header_creation); + ogs_assert(outer_header_creation->presence); + + memcpy(&far->outer_header_creation, + outer_header_creation->data, outer_header_creation->len); + far->outer_header_creation.teid = be32toh(far->outer_header_creation.teid); + + rv = ogs_pfcp_outer_header_creation_to_ip(&far->outer_header_creation, &ip); + ogs_assert(rv == OGS_OK); + + gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip); + if (!gnode) { + gnode = ogs_gtp_node_add_by_ip( + &upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port, + ogs_config()->parameter.no_ipv4, + ogs_config()->parameter.no_ipv6, + ogs_config()->parameter.prefer_ipv4); + ogs_assert(gnode); + + rv = ogs_gtp_connect( + upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode); + ogs_assert(rv == OGS_OK); + } + OGS_SETUP_GTP_NODE(far, gnode); +} + static ogs_pfcp_pdr_t *handle_create_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_tlv_create_pdr_t *message, uint8_t *cause_value, uint8_t *offending_ie_value) @@ -159,16 +193,13 @@ static ogs_pfcp_pdr_t *handle_create_pdr(ogs_pfcp_sess_t *sess, return NULL; } - memcpy(&pdr->f_teid, message->pdi.local_f_teid.data, - message->pdi.local_f_teid.len); + pdr->f_teid_len = message->pdi.local_f_teid.len; + memcpy(&pdr->f_teid, message->pdi.local_f_teid.data, pdr->f_teid_len); pdr->f_teid.teid = be32toh(pdr->f_teid.teid); + memcpy(&pdr->outer_header_removal, message->outer_header_removal.data, message->outer_header_removal.len); - - /* Setup UPF-N3-TEID */ - ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->f_teid.teid, - sizeof(pdr->f_teid.teid), pdr); } else { ogs_error("Invalid Source Interface[%d] in PDR", pdr->src_if); *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; @@ -264,40 +295,11 @@ static ogs_pfcp_far_t *handle_create_far(ogs_pfcp_sess_t *sess, far->dst_if = message->forwarding_parameters.destination_interface.u8; if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */ - int rv; - ogs_ip_t ip; - ogs_gtp_node_t *gnode = NULL; - if (message->forwarding_parameters.outer_header_creation.presence) { - memcpy(&far->outer_header_creation, - message->forwarding_parameters.outer_header_creation.data, - message->forwarding_parameters.outer_header_creation.len); - far->outer_header_creation.teid = - be32toh(far->outer_header_creation.teid); - - /* Setup GTP Node */ - rv = ogs_pfcp_outer_header_creation_to_ip( - &far->outer_header_creation, &ip); - ogs_assert(rv == OGS_OK); - - gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip); - if (!gnode) { - gnode = ogs_gtp_node_add_by_ip( - &upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port, - ogs_config()->parameter.no_ipv4, - ogs_config()->parameter.no_ipv6, - ogs_config()->parameter.prefer_ipv4); - ogs_assert(gnode); - - rv = ogs_gtp_connect( - upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode); - ogs_assert(rv == OGS_OK); - } - OGS_SETUP_GTP_NODE(far, gnode); + setup_gtp_node(far, + &message->forwarding_parameters.outer_header_creation); } - upf_gtp_send_buffered_packet(far); - } else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */ /* Nothing */ @@ -348,43 +350,12 @@ static ogs_pfcp_far_t *handle_update_far(ogs_pfcp_sess_t *sess, destination_interface.u8; if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */ - int rv; - ogs_ip_t ip; - ogs_gtp_node_t *gnode = NULL; - if (message->update_forwarding_parameters. outer_header_creation.presence) { - memcpy(&far->outer_header_creation, - message->update_forwarding_parameters. - outer_header_creation.data, - message->update_forwarding_parameters. - outer_header_creation.len); - far->outer_header_creation.teid = - be32toh(far->outer_header_creation.teid); - - /* Setup GTP Node */ - rv = ogs_pfcp_outer_header_creation_to_ip( - &far->outer_header_creation, &ip); - ogs_assert(rv == OGS_OK); - - gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip); - if (!gnode) { - gnode = ogs_gtp_node_add_by_ip( - &upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port, - ogs_config()->parameter.no_ipv4, - ogs_config()->parameter.no_ipv6, - ogs_config()->parameter.prefer_ipv4); - ogs_assert(gnode); - - rv = ogs_gtp_connect( - upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode); - ogs_assert(rv == OGS_OK); - } - OGS_SETUP_GTP_NODE(far, gnode); + setup_gtp_node(far, + &message->update_forwarding_parameters.outer_header_creation); } - upf_gtp_send_buffered_packet(far); - } else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */ /* Nothing */ @@ -547,6 +518,7 @@ void upf_n4_handle_session_establishment_request( upf_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_establishment_request_t *req) { + ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR]; int num_of_created_pdr = 0; uint8_t cause_value = 0; @@ -594,6 +566,24 @@ void upf_n4_handle_session_establishment_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + /* 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) + ogs_pfcp_pdr_hash_set(pdr); + } + } + + /* Send Buffered Packet to gNB/SGW */ + ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { + if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */ + upf_gtp_send_buffered_packet(pdr); + } + } + upf_pfcp_send_session_establishment_response( xact, sess, created_pdr, num_of_created_pdr); return; @@ -609,6 +599,7 @@ void upf_n4_handle_session_modification_request( upf_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_modification_request_t *req) { + ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR]; int num_of_created_pdr = 0; uint8_t cause_value = 0; @@ -696,6 +687,24 @@ void upf_n4_handle_session_modification_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + /* 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) + ogs_pfcp_pdr_hash_set(pdr); + } + } + + /* Send Buffered Packet to gNB/SGW */ + ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { + if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */ + upf_gtp_send_buffered_packet(pdr); + } + } + upf_pfcp_send_session_modification_response( xact, sess, created_pdr, num_of_created_pdr); return; diff --git a/tests/common/context.h b/tests/common/context.h index 6c1ad7213..5f2c13dbc 100644 --- a/tests/common/context.h +++ b/tests/common/context.h @@ -205,6 +205,8 @@ typedef struct test_sess_s { ogs_ip_t gnb_n3_ip; uint32_t gnb_n3_teid; + uint8_t qfi; + test_ul_nas_transport_param_t ul_nas_transport_param; test_ue_t *test_ue; diff --git a/tests/common/ngap-build.c b/tests/common/ngap-build.c index cab47dd4c..e5a2f8b31 100644 --- a/tests/common/ngap-build.c +++ b/tests/common/ngap-build.c @@ -977,7 +977,7 @@ static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_response_trasfer( CALLOC(1, sizeof(struct NGAP_AssociatedQosFlowItem)); ASN_SEQUENCE_ADD(&associatedQosFlowList->list, associatedQosFlowItem); - associatedQosFlowItem->qosFlowIdentifier = 1; + associatedQosFlowItem->qosFlowIdentifier = sess->qfi; return ogs_asn_encode( &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &message); diff --git a/tests/common/ngap-handler.c b/tests/common/ngap-handler.c index a8ba756b9..b8c23bdde 100644 --- a/tests/common/ngap-handler.c +++ b/tests/common/ngap-handler.c @@ -158,7 +158,7 @@ void testngap_handle_pdu_session_resource_setup_request( test_ue_t *test_ue, ogs_ngap_message_t *message) { test_sess_t *sess = NULL; - int rv, i, j, k; + int rv, i, j, k, l; char buf[OGS_ADDRSTRLEN]; NGAP_NGAP_PDU_t pdu; @@ -176,6 +176,8 @@ void testngap_handle_pdu_session_resource_setup_request( NGAP_UPTransportLayerInformation_t *UPTransportLayerInformation = NULL; NGAP_GTPTunnel_t *gTPTunnel = NULL; NGAP_PDUSessionType_t *PDUSessionType = NULL; + NGAP_QosFlowSetupRequestList_t *QosFlowSetupRequestList = NULL; + NGAP_QosFlowSetupRequestItem_t *QosFlowSetupRequestItem = NULL; OCTET_STRING_t *transfer = NULL; ogs_pkbuf_t *n2smbuf = NULL; @@ -219,6 +221,20 @@ void testngap_handle_pdu_session_resource_setup_request( for (k = 0; k < n2sm_message.protocolIEs.list.count; k++) { ie2 = n2sm_message.protocolIEs.list.array[k]; switch (ie2->id) { + case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: + QosFlowSetupRequestList = + &ie2->value.choice.QosFlowSetupRequestList; + ogs_assert(QosFlowSetupRequestList); + for (l = 0; + l < QosFlowSetupRequestList->list.count; l++) { + QosFlowSetupRequestItem = + (struct NGAP_QosFlowSetupRequestItem *) + QosFlowSetupRequestList->list.array[l]; + ogs_assert(QosFlowSetupRequestItem); + sess->qfi = + QosFlowSetupRequestItem->qosFlowIdentifier; + } + break; case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: UPTransportLayerInformation = &ie2->value.choice.UPTransportLayerInformation; @@ -231,6 +247,7 @@ void testngap_handle_pdu_session_resource_setup_request( &sess->upf_n3_ip); ogs_asn_OCTET_STRING_to_uint32( &gTPTunnel->gTP_TEID, &sess->upf_n3_teid); + break; default: break; }