forked from acouzens/open5gs
[PFCP] Implement the Restoration Indication
This commit is contained in:
parent
642d9e2e18
commit
d2e2a58232
|
@ -446,17 +446,15 @@ bool ogs_pfcp_build_created_pdr(
|
|||
|
||||
ogs_assert(pdr);
|
||||
|
||||
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);
|
||||
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;
|
||||
message->local_f_teid.presence = 1;
|
||||
message->local_f_teid.data = &pdrbuf[i].f_teid;
|
||||
message->local_f_teid.len = pdr->f_teid_len;
|
||||
|
||||
pdr_presence = true;
|
||||
}
|
||||
pdr_presence = true;
|
||||
}
|
||||
|
||||
if (pdr_presence == true) {
|
||||
|
|
|
@ -27,19 +27,23 @@ static int context_initialized = 0;
|
|||
static OGS_POOL(ogs_pfcp_node_pool, ogs_pfcp_node_t);
|
||||
|
||||
static OGS_POOL(ogs_pfcp_sess_pool, ogs_pfcp_sess_t);
|
||||
static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t);
|
||||
static OGS_POOL(ogs_pfcp_pdr_teid_pool, ogs_pool_id_t);
|
||||
static OGS_POOL(ogs_pfcp_far_pool, ogs_pfcp_far_t);
|
||||
static OGS_POOL(ogs_pfcp_urr_pool, ogs_pfcp_urr_t);
|
||||
static OGS_POOL(ogs_pfcp_qer_pool, ogs_pfcp_qer_t);
|
||||
static OGS_POOL(ogs_pfcp_bar_pool, ogs_pfcp_bar_t);
|
||||
|
||||
static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t);
|
||||
static OGS_POOL(ogs_pfcp_pdr_teid_pool, ogs_pool_id_t);
|
||||
static ogs_pool_id_t *pdr_random_to_index;
|
||||
|
||||
static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t);
|
||||
|
||||
static OGS_POOL(ogs_pfcp_dev_pool, ogs_pfcp_dev_t);
|
||||
static OGS_POOL(ogs_pfcp_subnet_pool, ogs_pfcp_subnet_t);
|
||||
static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t);
|
||||
|
||||
void ogs_pfcp_context_init(void)
|
||||
{
|
||||
int i;
|
||||
ogs_assert(context_initialized == 0);
|
||||
|
||||
/* Initialize SMF context */
|
||||
|
@ -53,11 +57,6 @@ void ogs_pfcp_context_init(void)
|
|||
|
||||
ogs_pool_init(&ogs_pfcp_sess_pool, ogs_app()->pool.sess);
|
||||
|
||||
ogs_pool_init(&ogs_pfcp_pdr_pool,
|
||||
ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR);
|
||||
ogs_pool_init(&ogs_pfcp_pdr_teid_pool,
|
||||
ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR);
|
||||
ogs_pool_random_id_generate(&ogs_pfcp_pdr_teid_pool);
|
||||
ogs_pool_init(&ogs_pfcp_far_pool,
|
||||
ogs_app()->pool.sess * OGS_MAX_NUM_OF_FAR);
|
||||
ogs_pool_init(&ogs_pfcp_urr_pool,
|
||||
|
@ -67,6 +66,17 @@ void ogs_pfcp_context_init(void)
|
|||
ogs_pool_init(&ogs_pfcp_bar_pool,
|
||||
ogs_app()->pool.sess * OGS_MAX_NUM_OF_BAR);
|
||||
|
||||
ogs_pool_init(&ogs_pfcp_pdr_pool,
|
||||
ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR);
|
||||
ogs_pool_init(&ogs_pfcp_pdr_teid_pool, ogs_pfcp_pdr_pool.size);
|
||||
ogs_pool_random_id_generate(&ogs_pfcp_pdr_teid_pool);
|
||||
|
||||
pdr_random_to_index = ogs_calloc(
|
||||
sizeof(ogs_pool_id_t), ogs_pfcp_pdr_pool.size);
|
||||
ogs_assert(pdr_random_to_index);
|
||||
for (i = 0; i < ogs_pfcp_pdr_pool.size; i++)
|
||||
pdr_random_to_index[ogs_pfcp_pdr_teid_pool.array[i]] = i;
|
||||
|
||||
ogs_pool_init(&ogs_pfcp_rule_pool,
|
||||
ogs_app()->pool.sess *
|
||||
OGS_MAX_NUM_OF_PDR * OGS_MAX_NUM_OF_FLOW_IN_PDR);
|
||||
|
@ -102,9 +112,11 @@ void ogs_pfcp_context_final(void)
|
|||
ogs_pool_final(&ogs_pfcp_subnet_pool);
|
||||
ogs_pool_final(&ogs_pfcp_rule_pool);
|
||||
|
||||
ogs_pool_final(&ogs_pfcp_sess_pool);
|
||||
ogs_pool_final(&ogs_pfcp_pdr_pool);
|
||||
ogs_pool_final(&ogs_pfcp_pdr_teid_pool);
|
||||
ogs_free(pdr_random_to_index);
|
||||
|
||||
ogs_pool_final(&ogs_pfcp_sess_pool);
|
||||
ogs_pool_final(&ogs_pfcp_far_pool);
|
||||
ogs_pool_final(&ogs_pfcp_urr_pool);
|
||||
ogs_pool_final(&ogs_pfcp_qer_pool);
|
||||
|
@ -955,12 +967,88 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
|
|||
return pdr;
|
||||
}
|
||||
|
||||
void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
ogs_assert(pdr);
|
||||
ogs_assert(pdr->f_teid.teid > 0 &&
|
||||
pdr->f_teid.teid <= ogs_pfcp_pdr_teid_pool.size);
|
||||
|
||||
/* Find out the Array Index for the restored TEID. */
|
||||
i = pdr_random_to_index[pdr->f_teid.teid];
|
||||
ogs_assert(i < ogs_pfcp_pdr_teid_pool.size);
|
||||
|
||||
ogs_assert(pdr->teid_node);
|
||||
/*
|
||||
* If SWAP has already done this, it will not try this again.
|
||||
* This situation can occur when multiple PDRs are restored
|
||||
* with the same TEID.
|
||||
*/
|
||||
if (pdr->f_teid.teid == ogs_pfcp_pdr_teid_pool.array[i]) {
|
||||
ogs_pfcp_pdr_teid_pool.array[i] = *(pdr->teid_node);
|
||||
*(pdr->teid_node) = pdr->f_teid.teid;
|
||||
}
|
||||
}
|
||||
|
||||
void ogs_pfcp_object_teid_hash_set(
|
||||
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr)
|
||||
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr,
|
||||
bool restoration_indication)
|
||||
{
|
||||
ogs_assert(type);
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) {
|
||||
|
||||
ogs_pfcp_pdr_t *choosed_pdr = NULL;
|
||||
|
||||
if (pdr->f_teid.chid) {
|
||||
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
|
||||
pdr->sess, pdr->f_teid.choose_id);
|
||||
if (!choosed_pdr) {
|
||||
pdr->chid = true;
|
||||
pdr->choose_id = pdr->f_teid.choose_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (choosed_pdr) {
|
||||
pdr->f_teid_len = choosed_pdr->f_teid_len;
|
||||
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
|
||||
|
||||
} else {
|
||||
ogs_gtpu_resource_t *resource = NULL;
|
||||
resource = ogs_pfcp_find_gtpu_resource(
|
||||
&ogs_gtp_self()->gtpu_resource_list,
|
||||
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
|
||||
if (resource) {
|
||||
ogs_assert(
|
||||
(resource->info.v4 && pdr->f_teid.ipv4) ||
|
||||
(resource->info.v6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
|
||||
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
|
||||
if (resource->info.teidri)
|
||||
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
|
||||
pdr->teid, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
} else {
|
||||
ogs_assert(
|
||||
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
|
||||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_sockaddr_to_f_teid(
|
||||
pdr->f_teid.ipv4 ?
|
||||
ogs_gtp_self()->gtpu_addr : NULL,
|
||||
pdr->f_teid.ipv6 ?
|
||||
ogs_gtp_self()->gtpu_addr6 : NULL,
|
||||
&pdr->f_teid, &pdr->f_teid_len));
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pdr->hash.teid.len)
|
||||
ogs_hash_set(self.object_teid_hash,
|
||||
&pdr->hash.teid.key, pdr->hash.teid.len, NULL);
|
||||
|
|
|
@ -401,8 +401,11 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
|
|||
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_swap_teid(ogs_pfcp_pdr_t *pdr);
|
||||
|
||||
void ogs_pfcp_object_teid_hash_set(
|
||||
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr);
|
||||
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr,
|
||||
bool restoration_indication);
|
||||
ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid);
|
||||
int ogs_pfcp_object_count_by_teid(ogs_pfcp_sess_t *sess, uint32_t teid);
|
||||
|
||||
|
|
|
@ -320,6 +320,7 @@ bool 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,
|
||||
ogs_pfcp_sereq_flags_t *sereq_flags,
|
||||
uint8_t *cause_value, uint8_t *offending_ie_value)
|
||||
{
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
|
@ -376,6 +377,18 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
|
|||
*offending_ie_value = OGS_PFCP_F_TEID_TYPE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (f_teid.ch == 0) {
|
||||
if (sereq_flags && sereq_flags->restoration_indication == 1) {
|
||||
f_teid.teid = be32toh(f_teid.teid);
|
||||
if (ogs_pfcp_object_find_by_teid(f_teid.teid)) {
|
||||
ogs_error("TEID:%x had already been allocated", f_teid.teid);
|
||||
*cause_value = OGS_PFCP_CAUSE_INVALID_F_TEID_ALLOCATION_OPTION;
|
||||
*offending_ie_value = OGS_PFCP_F_TEID_TYPE;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pdr->src_if = message->pdi.source_interface.u8;
|
||||
|
@ -398,7 +411,6 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
|
|||
if (sdf_filter.bid) {
|
||||
oppsite_direction_rule = ogs_pfcp_rule_find_by_sdf_filter_id(
|
||||
sess, sdf_filter.sdf_filter_id);
|
||||
|
||||
}
|
||||
|
||||
if (!oppsite_direction_rule && !sdf_filter.fd) {
|
||||
|
|
|
@ -53,6 +53,7 @@ bool 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,
|
||||
ogs_pfcp_sereq_flags_t *sereq_flags,
|
||||
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,
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
/*******************************************************************************
|
||||
* This file had been created by pfcp-tlv.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2023-03-05 22:26:11.716006 by acetcom
|
||||
* Created on: 2023-04-09 20:37:00.518388 by acetcom
|
||||
* from 29244-h71-modified.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -1546,10 +1546,10 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_cp_pfcp_entity_ip_address =
|
|||
|
||||
ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsereq_flags =
|
||||
{
|
||||
OGS_TLV_VAR_STR,
|
||||
OGS_TLV_UINT8,
|
||||
"PFCPSEReq-Flags",
|
||||
OGS_PFCP_PFCPSEREQ_FLAGS_TYPE,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
sizeof(ogs_pfcp_tlv_pfcpsereq_flags_t),
|
||||
{ NULL }
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
/*******************************************************************************
|
||||
* This file had been created by pfcp-tlv.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2023-03-05 22:26:11.698310 by acetcom
|
||||
* Created on: 2023-04-09 20:37:00.506639 by acetcom
|
||||
* from 29244-h71-modified.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -903,7 +903,7 @@ typedef ogs_tlv_uint32_t ogs_pfcp_tlv_quota_validity_time_t;
|
|||
typedef ogs_tlv_octet_t ogs_pfcp_tlv_number_of_reports_t;
|
||||
typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpasrsp_flags_t;
|
||||
typedef ogs_tlv_octet_t ogs_pfcp_tlv_cp_pfcp_entity_ip_address_t;
|
||||
typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpsereq_flags_t;
|
||||
typedef ogs_tlv_uint8_t ogs_pfcp_tlv_pfcpsereq_flags_t;
|
||||
typedef ogs_tlv_octet_t ogs_pfcp_tlv_ip_multicast_address_t;
|
||||
typedef ogs_tlv_octet_t ogs_pfcp_tlv_source_ip_address_t;
|
||||
typedef ogs_tlv_octet_t ogs_pfcp_tlv_packet_rate_status_t;
|
||||
|
|
|
@ -519,6 +519,7 @@ type_list["Paging Policy Indicator"]["size"] = 1 # Type 158
|
|||
type_list["PFCPSRReq-Flags"]["size"] = 1 # Type 161
|
||||
type_list["PFCPAUReq-Flags"]["size"] = 1 # Type 162
|
||||
type_list["Quota Validity Time"]["size"] = 4 # Type 181
|
||||
type_list["PFCPSEReq-Flags"]["size"] = 1 # Type 186
|
||||
type_list["Data Status"]["size"] = 1 # Type 260
|
||||
|
||||
f = open(outdir + 'message.h', 'w')
|
||||
|
|
|
@ -1651,6 +1651,28 @@ int16_t ogs_pfcp_build_user_id(
|
|||
ogs_tlv_octet_t *octet, ogs_pfcp_user_id_t *user_id,
|
||||
void *data, int data_len);
|
||||
|
||||
/*
|
||||
* 8.2.136 PFCPSEReq-Flags
|
||||
*
|
||||
* The following bits within Octet 5 shall indicate:
|
||||
* - Bit 1 – RESTI (Restoration Indication): if this bit is set to "1",
|
||||
* it indicates to the UP function that the PFCP session to be established is
|
||||
* to restore an existing PFCP session.
|
||||
* - Bit 2 – SUMPC (Stop of Usage Measurement to Pause Charging):
|
||||
* if this bit is set to "1", it indicates that the UP function shall
|
||||
* stop the usage measurement for all URRs with the "ASPOC" flag set to "1".
|
||||
*/
|
||||
typedef struct ogs_pfcp_sereq_flags_s {
|
||||
union {
|
||||
struct {
|
||||
ED3(uint8_t spare:6;,
|
||||
uint8_t stop_of_usage_measurement_to_pause_charging:1;,
|
||||
uint8_t restoration_indication:1;)
|
||||
};
|
||||
uint8_t value;
|
||||
};
|
||||
} __attribute__ ((packed)) ogs_pfcp_sereq_flags_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -78,6 +78,9 @@ typedef struct ogs_pfcp_xact_s {
|
|||
|
||||
bool epc; /**< EPC or 5GC */
|
||||
|
||||
#define OGS_PFCP_CREATE_RESTORATION_INDICATION ((uint64_t)1<<0)
|
||||
uint64_t create_flags;
|
||||
|
||||
#define OGS_PFCP_MODIFY_SESSION ((uint64_t)1<<0)
|
||||
#define OGS_PFCP_MODIFY_DL_ONLY ((uint64_t)1<<1)
|
||||
#define OGS_PFCP_MODIFY_UL_ONLY ((uint64_t)1<<2)
|
||||
|
@ -110,7 +113,6 @@ typedef struct ogs_pfcp_xact_s {
|
|||
#define OGS_PFCP_MODIFY_URR_TIME_QUOTA ((uint64_t)1<<29)
|
||||
#define OGS_PFCP_MODIFY_URR_VOLUME_THRESH ((uint64_t)1<<30)
|
||||
#define OGS_PFCP_MODIFY_URR_TIME_THRESH ((uint64_t)1<<31)
|
||||
|
||||
uint64_t modify_flags;
|
||||
|
||||
#define OGS_PFCP_DELETE_TRIGGER_LOCAL_INITIATED 1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -238,7 +238,8 @@ int sgwc_pfcp_send_bearer_to_modify_list(
|
|||
}
|
||||
|
||||
int sgwc_pfcp_send_session_establishment_request(
|
||||
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf)
|
||||
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf,
|
||||
uint64_t flags)
|
||||
{
|
||||
int rv;
|
||||
ogs_pkbuf_t *sxabuf = NULL;
|
||||
|
@ -262,9 +263,40 @@ int sgwc_pfcp_send_session_establishment_request(
|
|||
}
|
||||
}
|
||||
xact->local_seid = sess->sgwc_sxa_seid;
|
||||
xact->create_flags = flags;
|
||||
|
||||
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
||||
h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE;
|
||||
|
||||
/*
|
||||
* 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header
|
||||
*
|
||||
* If a peer's SEID is not available, the SEID field shall still be present
|
||||
* in the header and its value shall be set to "0" in the following messages:
|
||||
*
|
||||
* - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4;
|
||||
*
|
||||
* - If a node receives a message for which it has no session, i.e.
|
||||
* if SEID in the PFCP header is not known, it shall respond
|
||||
* with "Session context not found" cause in the corresponding
|
||||
* response message to the sender, the SEID used in the PFCP header
|
||||
* in the response message shall be then set to "0";
|
||||
*
|
||||
* - If a node receives a request message containing protocol error,
|
||||
* e.g. Mandatory IE missing, which requires the receiver
|
||||
* to reject the message as specified in clause 7.6, it shall reject
|
||||
* the request message. For the response message, the node should look up
|
||||
* the remote peer's SEID and accordingly set SEID in the PFCP header
|
||||
* and the message cause code. As an implementation option,
|
||||
* the node may not look up the remote peer's SEID and
|
||||
* set the PFCP header SEID to "0" in the response message.
|
||||
* However in this case, the cause value shall not be set
|
||||
* to "Session not found".
|
||||
*
|
||||
* - When the UP function sends PFCP Session Report Request message
|
||||
* over N4 towards another SMF or another PFCP entity in the SMF
|
||||
* as specified in clause 5.22.2 and clause 5.22.3.
|
||||
*/
|
||||
h.seid = sess->sgwu_sxa_seid;
|
||||
|
||||
sxabuf = sgwc_sxa_build_session_establishment_request(h.type, sess);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -33,7 +33,8 @@ int sgwc_pfcp_send_bearer_to_modify_list(
|
|||
sgwc_sess_t *sess, ogs_pfcp_xact_t *xact);
|
||||
|
||||
int sgwc_pfcp_send_session_establishment_request(
|
||||
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf);
|
||||
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf,
|
||||
uint64_t flags);
|
||||
|
||||
int sgwc_pfcp_send_session_modification_request(
|
||||
sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "pfcp-path.h"
|
||||
#include "sxa-handler.h"
|
||||
|
||||
static void pfcp_restoration(ogs_pfcp_node_t *node);
|
||||
static void node_timeout(ogs_pfcp_xact_t *xact, void *data);
|
||||
|
||||
void sgwc_pfcp_state_initial(ogs_fsm_t *s, sgwc_event_t *e)
|
||||
|
@ -188,6 +189,7 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
|
|||
ogs_pfcp_send_heartbeat_request(node, node_timeout));
|
||||
|
||||
if (node->restoration_required == true) {
|
||||
pfcp_restoration(node);
|
||||
node->restoration_required = false;
|
||||
ogs_error("PFCP restoration");
|
||||
}
|
||||
|
@ -220,11 +222,56 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
|
|||
ogs_expect(true ==
|
||||
ogs_pfcp_handle_heartbeat_request(node, xact,
|
||||
&message->pfcp_heartbeat_request));
|
||||
if (node->restoration_required == true) {
|
||||
if (node->t_association) {
|
||||
/*
|
||||
* node->t_association that the PFCP entity attempts an association.
|
||||
*
|
||||
* In this case, even if Remote PFCP entity is restarted,
|
||||
* PFCP restoration must be performed after PFCP association.
|
||||
*
|
||||
* Otherwise, Session related PFCP cannot be initiated
|
||||
* because the peer PFCP entity is in a de-associated state.
|
||||
*/
|
||||
OGS_FSM_TRAN(s, sgwc_pfcp_state_will_associate);
|
||||
} else {
|
||||
|
||||
/*
|
||||
* If the peer PFCP entity is performing the association,
|
||||
* Restoration can be performed immediately.
|
||||
*/
|
||||
pfcp_restoration(node);
|
||||
node->restoration_required = false;
|
||||
ogs_error("PFCP restoration");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE:
|
||||
ogs_expect(true ==
|
||||
ogs_pfcp_handle_heartbeat_response(node, xact,
|
||||
&message->pfcp_heartbeat_response));
|
||||
if (node->restoration_required == true) {
|
||||
/*
|
||||
* node->t_association that the PFCP entity attempts an association.
|
||||
*
|
||||
* In this case, even if Remote PFCP entity is restarted,
|
||||
* PFCP restoration must be performed after PFCP association.
|
||||
*
|
||||
* Otherwise, Session related PFCP cannot be initiated
|
||||
* because the peer PFCP entity is in a de-associated state.
|
||||
*/
|
||||
if (node->t_association) {
|
||||
OGS_FSM_TRAN(s, sgwc_pfcp_state_will_associate);
|
||||
} else {
|
||||
/*
|
||||
* If the peer PFCP entity is performing the association,
|
||||
* Restoration can be performed immediately.
|
||||
*/
|
||||
pfcp_restoration(node);
|
||||
node->restoration_required = false;
|
||||
ogs_error("PFCP restoration");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
|
||||
ogs_warn("PFCP[REQ] has already been associated [%s]:%d",
|
||||
|
@ -243,9 +290,24 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
|
|||
case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE:
|
||||
if (!message->h.seid_presence) ogs_error("No SEID");
|
||||
|
||||
sgwc_sxa_handle_session_establishment_response(
|
||||
sess, xact, e->gtp_message,
|
||||
&message->pfcp_session_establishment_response);
|
||||
if ((xact->create_flags &
|
||||
OGS_PFCP_CREATE_RESTORATION_INDICATION)) {
|
||||
ogs_pfcp_session_establishment_response_t *rsp = NULL;
|
||||
ogs_pfcp_f_seid_t *up_f_seid = NULL;
|
||||
|
||||
rsp = &message->pfcp_session_establishment_response;
|
||||
if (rsp->up_f_seid.presence == 0) {
|
||||
ogs_error("No UP F-SEID");
|
||||
break;
|
||||
}
|
||||
up_f_seid = rsp->up_f_seid.data;
|
||||
ogs_assert(up_f_seid);
|
||||
sess->sgwu_sxa_seid = be64toh(up_f_seid->seid);
|
||||
} else {
|
||||
sgwc_sxa_handle_session_establishment_response(
|
||||
sess, xact, e->gtp_message,
|
||||
&message->pfcp_session_establishment_response);
|
||||
}
|
||||
break;
|
||||
|
||||
case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE:
|
||||
|
@ -326,6 +388,29 @@ void sgwc_pfcp_state_exception(ogs_fsm_t *s, sgwc_event_t *e)
|
|||
}
|
||||
}
|
||||
|
||||
static void pfcp_restoration(ogs_pfcp_node_t *node)
|
||||
{
|
||||
sgwc_ue_t *sgwc_ue = NULL;
|
||||
|
||||
ogs_list_for_each(&sgwc_self()->sgw_ue_list, sgwc_ue) {
|
||||
sgwc_sess_t *sess = NULL;
|
||||
ogs_assert(sgwc_ue);
|
||||
|
||||
ogs_list_for_each(&sgwc_ue->sess_list, sess) {
|
||||
ogs_assert(sess);
|
||||
|
||||
if (node == sess->pfcp_node) {
|
||||
ogs_info("UE IMSI[%s] APN[%s]",
|
||||
sgwc_ue->imsi_bcd, sess->session.name);
|
||||
ogs_assert(OGS_OK ==
|
||||
sgwc_pfcp_send_session_establishment_request(
|
||||
sess, NULL, NULL,
|
||||
OGS_PFCP_CREATE_RESTORATION_INDICATION));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void node_timeout(ogs_pfcp_xact_t *xact, void *data)
|
||||
{
|
||||
int rv;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -234,6 +234,8 @@ void sgwc_s11_handle_create_session_request(
|
|||
sess = sgwc_sess_add(sgwc_ue, apn);
|
||||
ogs_assert(sess);
|
||||
|
||||
ogs_info("UE IMSI[%s] APN[%s]", sgwc_ue->imsi_bcd, sess->session.name);
|
||||
|
||||
/* Set User Location Information */
|
||||
if (req->user_location_information.presence == 1) {
|
||||
decoded = ogs_gtp2_parse_uli(&uli, &req->user_location_information);
|
||||
|
@ -376,7 +378,8 @@ void sgwc_s11_handle_create_session_request(
|
|||
sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid);
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
sgwc_pfcp_send_session_establishment_request(sess, s11_xact, gtpbuf));
|
||||
sgwc_pfcp_send_session_establishment_request(
|
||||
sess, s11_xact, gtpbuf, 0));
|
||||
}
|
||||
|
||||
void sgwc_s11_handle_modify_bearer_request(
|
||||
|
|
|
@ -255,7 +255,10 @@ sgwu_sess_t *sgwu_sess_add_by_message(ogs_pfcp_message_t *message)
|
|||
sess = sgwu_sess_find_by_sgwc_sxa_f_seid(f_seid);
|
||||
if (!sess) {
|
||||
sess = sgwu_sess_add(f_seid);
|
||||
if (!sess) return NULL;
|
||||
if (!sess) {
|
||||
ogs_error("No Session Context");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ogs_assert(sess);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -203,6 +203,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
ogs_assert(pdr);
|
||||
break;
|
||||
case OGS_PFCP_OBJ_SESS_TYPE:
|
||||
/* SGWU does not use SESS TYPE */
|
||||
ogs_assert_if_reached();
|
||||
pfcp_sess = (ogs_pfcp_sess_t *)pfcp_object;
|
||||
ogs_assert(pfcp_sess);
|
||||
|
||||
|
|
|
@ -205,7 +205,6 @@ int sgwu_pfcp_send_session_modification_response(
|
|||
ogs_pfcp_header_t h;
|
||||
|
||||
ogs_assert(xact);
|
||||
ogs_assert(created_pdr);
|
||||
|
||||
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
||||
h.type = OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE;
|
||||
|
|
|
@ -277,12 +277,9 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e)
|
|||
&message->pfcp_association_setup_response);
|
||||
break;
|
||||
case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE:
|
||||
if (message->h.seid_presence && message->h.seid == 0) {
|
||||
ogs_expect(!sess);
|
||||
sess = sgwu_sess_add_by_message(message);
|
||||
if (sess)
|
||||
OGS_SETUP_PFCP_NODE(sess, node);
|
||||
}
|
||||
sess = sgwu_sess_add_by_message(message);
|
||||
if (sess)
|
||||
OGS_SETUP_PFCP_NODE(sess, node);
|
||||
sgwu_sxa_handle_session_establishment_request(
|
||||
sess, xact, &message->pfcp_session_establishment_request);
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -33,6 +33,9 @@ void sgwu_sxa_handle_session_establishment_request(
|
|||
uint8_t offending_ie_value = 0;
|
||||
int i;
|
||||
|
||||
ogs_pfcp_sereq_flags_t sereq_flags;
|
||||
bool restoration_indication = false;
|
||||
|
||||
ogs_assert(xact);
|
||||
ogs_assert(req);
|
||||
|
||||
|
@ -48,9 +51,16 @@ void sgwu_sxa_handle_session_establishment_request(
|
|||
return;
|
||||
}
|
||||
|
||||
/* PFCPSEReq-Flags */
|
||||
memset(&sereq_flags, 0, sizeof(sereq_flags));
|
||||
if (req->pfcpsereq_flags.presence == 1) {
|
||||
sereq_flags.value = req->pfcpsereq_flags.u8;
|
||||
}
|
||||
|
||||
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
|
||||
created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp,
|
||||
&req->create_pdr[i], &cause_value, &offending_ie_value);
|
||||
&req->create_pdr[i], &sereq_flags,
|
||||
&cause_value, &offending_ie_value);
|
||||
if (created_pdr[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
@ -79,6 +89,18 @@ void sgwu_sxa_handle_session_establishment_request(
|
|||
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
|
||||
goto cleanup;
|
||||
|
||||
/* PFCPSEReq-Flags */
|
||||
if (sereq_flags.restoration_indication == 1) {
|
||||
for (i = 0; i < num_of_created_pdr; i++) {
|
||||
pdr = created_pdr[i];
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->f_teid_len)
|
||||
ogs_pfcp_pdr_swap_teid(pdr);
|
||||
}
|
||||
restoration_indication = true;
|
||||
}
|
||||
|
||||
/* Setup GTP Node */
|
||||
ogs_list_for_each(&sess->pfcp.far_list, far) {
|
||||
ogs_assert(OGS_ERROR != ogs_pfcp_setup_far_gtpu_node(far));
|
||||
|
@ -86,70 +108,14 @@ void sgwu_sxa_handle_session_establishment_request(
|
|||
ogs_pfcp_far_f_teid_hash_set(far);
|
||||
}
|
||||
|
||||
/* Setup TEID Hash */
|
||||
for (i = 0; i < num_of_created_pdr; i++) {
|
||||
pdr = created_pdr[i];
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->f_teid_len) {
|
||||
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE;
|
||||
|
||||
if (ogs_pfcp_self()->up_function_features.ftup &&
|
||||
pdr->f_teid.ch) {
|
||||
|
||||
ogs_pfcp_pdr_t *choosed_pdr = NULL;
|
||||
|
||||
if (pdr->f_teid.chid) {
|
||||
type = OGS_PFCP_OBJ_SESS_TYPE;
|
||||
|
||||
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
|
||||
&sess->pfcp, pdr->f_teid.choose_id);
|
||||
if (!choosed_pdr) {
|
||||
pdr->chid = true;
|
||||
pdr->choose_id = pdr->f_teid.choose_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (choosed_pdr) {
|
||||
pdr->f_teid_len = choosed_pdr->f_teid_len;
|
||||
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
|
||||
|
||||
} else {
|
||||
ogs_gtpu_resource_t *resource = NULL;
|
||||
resource = ogs_pfcp_find_gtpu_resource(
|
||||
&ogs_gtp_self()->gtpu_resource_list,
|
||||
pdr->apn, OGS_PFCP_INTERFACE_ACCESS);
|
||||
if (resource) {
|
||||
ogs_assert(
|
||||
(resource->info.v4 && pdr->f_teid.ipv4) ||
|
||||
(resource->info.v6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
|
||||
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
|
||||
if (resource->info.teidri)
|
||||
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
|
||||
pdr->teid, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
} else {
|
||||
ogs_assert(
|
||||
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
|
||||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_sockaddr_to_f_teid(
|
||||
pdr->f_teid.ipv4 ?
|
||||
ogs_gtp_self()->gtpu_addr : NULL,
|
||||
pdr->f_teid.ipv6 ?
|
||||
ogs_gtp_self()->gtpu_addr6 : NULL,
|
||||
&pdr->f_teid, &pdr->f_teid_len));
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pfcp_object_teid_hash_set(type, pdr);
|
||||
}
|
||||
/* Setup TEID Hash */
|
||||
if (pdr->f_teid_len)
|
||||
ogs_pfcp_object_teid_hash_set(
|
||||
OGS_PFCP_OBJ_PDR_TYPE, pdr, restoration_indication);
|
||||
}
|
||||
|
||||
/* Send Buffered Packet to gNB */
|
||||
|
@ -159,9 +125,15 @@ void sgwu_sxa_handle_session_establishment_request(
|
|||
}
|
||||
}
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
sgwu_pfcp_send_session_establishment_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr));
|
||||
if (restoration_indication == true ||
|
||||
ogs_pfcp_self()->up_function_features.ftup == 0)
|
||||
ogs_assert(OGS_OK ==
|
||||
sgwu_pfcp_send_session_establishment_response(
|
||||
xact, sess, NULL, 0));
|
||||
else
|
||||
ogs_assert(OGS_OK ==
|
||||
sgwu_pfcp_send_session_establishment_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr));
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
|
@ -200,7 +172,7 @@ void sgwu_sxa_handle_session_modification_request(
|
|||
|
||||
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
|
||||
created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp,
|
||||
&req->create_pdr[i], &cause_value, &offending_ie_value);
|
||||
&req->create_pdr[i], NULL, &cause_value, &offending_ie_value);
|
||||
if (created_pdr[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
@ -301,70 +273,13 @@ void sgwu_sxa_handle_session_modification_request(
|
|||
ogs_pfcp_far_f_teid_hash_set(far);
|
||||
}
|
||||
|
||||
/* Setup TEID Hash */
|
||||
for (i = 0; i < num_of_created_pdr; i++) {
|
||||
pdr = created_pdr[i];
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->f_teid_len) {
|
||||
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE;
|
||||
|
||||
if (ogs_pfcp_self()->up_function_features.ftup &&
|
||||
pdr->f_teid.ch) {
|
||||
|
||||
ogs_pfcp_pdr_t *choosed_pdr = NULL;
|
||||
|
||||
if (pdr->f_teid.chid) {
|
||||
type = OGS_PFCP_OBJ_SESS_TYPE;
|
||||
|
||||
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
|
||||
&sess->pfcp, pdr->f_teid.choose_id);
|
||||
if (!choosed_pdr) {
|
||||
pdr->chid = true;
|
||||
pdr->choose_id = pdr->f_teid.choose_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (choosed_pdr) {
|
||||
pdr->f_teid_len = choosed_pdr->f_teid_len;
|
||||
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
|
||||
|
||||
} else {
|
||||
ogs_gtpu_resource_t *resource = NULL;
|
||||
resource = ogs_pfcp_find_gtpu_resource(
|
||||
&ogs_gtp_self()->gtpu_resource_list,
|
||||
pdr->apn, OGS_PFCP_INTERFACE_ACCESS);
|
||||
if (resource) {
|
||||
ogs_assert(
|
||||
(resource->info.v4 && pdr->f_teid.ipv4) ||
|
||||
(resource->info.v6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
|
||||
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
|
||||
if (resource->info.teidri)
|
||||
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
|
||||
pdr->teid, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
} else {
|
||||
ogs_assert(
|
||||
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
|
||||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_sockaddr_to_f_teid(
|
||||
pdr->f_teid.ipv4 ?
|
||||
ogs_gtp_self()->gtpu_addr : NULL,
|
||||
pdr->f_teid.ipv6 ?
|
||||
ogs_gtp_self()->gtpu_addr6 : NULL,
|
||||
&pdr->f_teid, &pdr->f_teid_len));
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pfcp_object_teid_hash_set(type, pdr);
|
||||
}
|
||||
/* Setup TEID Hash */
|
||||
if (pdr->f_teid_len)
|
||||
ogs_pfcp_object_teid_hash_set(OGS_PFCP_OBJ_PDR_TYPE, pdr, false);
|
||||
}
|
||||
|
||||
/* Send Buffered Packet to gNB */
|
||||
|
@ -374,9 +289,14 @@ void sgwu_sxa_handle_session_modification_request(
|
|||
}
|
||||
}
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
sgwu_pfcp_send_session_modification_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr));
|
||||
if (ogs_pfcp_self()->up_function_features.ftup == 0)
|
||||
ogs_assert(OGS_OK ==
|
||||
sgwu_pfcp_send_session_modification_response(
|
||||
xact, sess, NULL, 0));
|
||||
else
|
||||
ogs_assert(OGS_OK ==
|
||||
sgwu_pfcp_send_session_modification_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr));
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
|
|
|
@ -2142,37 +2142,51 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess)
|
|||
pdr->f_teid.choose_id = OGS_PFCP_INDIRECT_DATA_FORWARDING_CHOOSE_ID;
|
||||
pdr->f_teid_len = 2;
|
||||
} else {
|
||||
ogs_gtpu_resource_t *resource = NULL;
|
||||
/*
|
||||
* CHOOSE_ID is set in INDIRECT so that all PDRs must be set
|
||||
* to the same TEID.
|
||||
*
|
||||
* If sess->handover.upf_dl_teid is set in the PDR of
|
||||
* the first QoS flow, the PDRs of the remaining QoS flows use
|
||||
* the same TEID.
|
||||
*/
|
||||
if (ogs_list_first(&sess->bearer_list) == qos_flow) {
|
||||
ogs_gtpu_resource_t *resource = NULL;
|
||||
|
||||
if (sess->handover.upf_dl_addr)
|
||||
ogs_freeaddrinfo(sess->handover.upf_dl_addr);
|
||||
if (sess->handover.upf_dl_addr6)
|
||||
ogs_freeaddrinfo(sess->handover.upf_dl_addr6);
|
||||
if (sess->handover.upf_dl_addr)
|
||||
ogs_freeaddrinfo(sess->handover.upf_dl_addr);
|
||||
if (sess->handover.upf_dl_addr6)
|
||||
ogs_freeaddrinfo(sess->handover.upf_dl_addr6);
|
||||
|
||||
resource = ogs_pfcp_find_gtpu_resource(
|
||||
&sess->pfcp_node->gtpu_resource_list,
|
||||
sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
|
||||
resource = ogs_pfcp_find_gtpu_resource(
|
||||
&sess->pfcp_node->gtpu_resource_list,
|
||||
sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
|
||||
|
||||
if (resource) {
|
||||
ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info,
|
||||
&sess->handover.upf_dl_addr,
|
||||
&sess->handover.upf_dl_addr6);
|
||||
if (resource->info.teidri)
|
||||
sess->handover.upf_dl_teid =
|
||||
OGS_PFCP_GTPU_INDEX_TO_TEID(
|
||||
pdr->teid, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
sess->handover.upf_dl_teid = pdr->teid;
|
||||
} else {
|
||||
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
|
||||
ogs_assert(OGS_OK == ogs_copyaddrinfo(
|
||||
&sess->handover.upf_dl_addr,
|
||||
&sess->pfcp_node->addr));
|
||||
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
|
||||
ogs_assert(OGS_OK == ogs_copyaddrinfo(
|
||||
&sess->handover.upf_dl_addr6,
|
||||
&sess->pfcp_node->addr));
|
||||
else
|
||||
ogs_assert_if_reached();
|
||||
|
||||
if (resource) {
|
||||
ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info,
|
||||
&sess->handover.upf_dl_addr, &sess->handover.upf_dl_addr6);
|
||||
if (resource->info.teidri)
|
||||
sess->handover.upf_dl_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
|
||||
pdr->teid, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
sess->handover.upf_dl_teid = pdr->teid;
|
||||
} else {
|
||||
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
|
||||
ogs_assert(OGS_OK == ogs_copyaddrinfo(
|
||||
&sess->handover.upf_dl_addr, &sess->pfcp_node->addr));
|
||||
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
|
||||
ogs_assert(OGS_OK == ogs_copyaddrinfo(
|
||||
&sess->handover.upf_dl_addr6, &sess->pfcp_node->addr));
|
||||
else
|
||||
ogs_assert_if_reached();
|
||||
|
||||
sess->handover.upf_dl_teid = pdr->teid;
|
||||
}
|
||||
}
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2022 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -452,7 +452,7 @@ test_can_proceed:
|
|||
OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_establishment);
|
||||
ogs_assert(OGS_OK ==
|
||||
smf_epc_pfcp_send_session_establishment_request(
|
||||
sess, e->gtp_xact));
|
||||
sess, e->gtp_xact, 0));
|
||||
} else {
|
||||
/* FIXME: tear down Gx/Gy session
|
||||
* if its sm_data.*init_err == ER_DIAMETER_SUCCESS */
|
||||
|
@ -671,21 +671,28 @@ void smf_gsm_state_wait_pfcp_establishment(ogs_fsm_t *s, smf_event_t *e)
|
|||
send_gtp_create_err_msg(sess, e->gtp_xact, gtp_cause);
|
||||
return;
|
||||
}
|
||||
switch (gtp_xact->gtp_version) {
|
||||
case 1:
|
||||
rv = smf_gtp1_send_create_pdp_context_response(sess, gtp_xact);
|
||||
break;
|
||||
case 2:
|
||||
rv = smf_gtp2_send_create_session_response(sess, gtp_xact);
|
||||
break;
|
||||
default:
|
||||
rv = OGS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* If no CreatePDPCtxResp can be sent, then tear down the session: */
|
||||
if (rv != OGS_OK) {
|
||||
OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion);
|
||||
return;
|
||||
|
||||
gtp_xact = pfcp_xact->assoc_xact;
|
||||
if (gtp_xact) {
|
||||
switch (gtp_xact->gtp_version) {
|
||||
case 1:
|
||||
rv = smf_gtp1_send_create_pdp_context_response(
|
||||
sess, gtp_xact);
|
||||
break;
|
||||
case 2:
|
||||
rv = smf_gtp2_send_create_session_response(
|
||||
sess, gtp_xact);
|
||||
break;
|
||||
default:
|
||||
rv = OGS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* If no CreatePDPCtxResp can be sent,
|
||||
* then tear down the session: */
|
||||
if (rv != OGS_OK) {
|
||||
OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (sess->gtp_rat_type == OGS_GTP2_RAT_TYPE_WLAN) {
|
||||
|
@ -739,6 +746,9 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
smf_sess_t *sess = NULL;
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
|
||||
ogs_pfcp_xact_t *pfcp_xact = NULL;
|
||||
ogs_pfcp_message_t *pfcp_message = NULL;
|
||||
|
||||
ogs_nas_5gs_message_t *nas_message = NULL;
|
||||
|
||||
ogs_sbi_stream_t *stream = NULL;
|
||||
|
@ -815,6 +825,38 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
}
|
||||
break;
|
||||
|
||||
case SMF_EVT_N4_MESSAGE:
|
||||
pfcp_xact = e->pfcp_xact;
|
||||
ogs_assert(pfcp_xact);
|
||||
pfcp_message = e->pfcp_message;
|
||||
ogs_assert(pfcp_message);
|
||||
|
||||
switch (pfcp_message->h.type) {
|
||||
case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE:
|
||||
if ((pfcp_xact->create_flags &
|
||||
OGS_PFCP_CREATE_RESTORATION_INDICATION)) {
|
||||
ogs_pfcp_session_establishment_response_t *rsp = NULL;
|
||||
ogs_pfcp_f_seid_t *up_f_seid = NULL;
|
||||
|
||||
rsp = &pfcp_message->pfcp_session_establishment_response;
|
||||
if (rsp->up_f_seid.presence == 0) {
|
||||
ogs_error("No UP F-SEID");
|
||||
break;
|
||||
}
|
||||
up_f_seid = rsp->up_f_seid.data;
|
||||
ogs_assert(up_f_seid);
|
||||
sess->upf_n4_seid = be64toh(up_f_seid->seid);
|
||||
} else {
|
||||
ogs_error("cannot handle PFCP Session Establishment Response");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ogs_error("cannot handle PFCP message type[%d]",
|
||||
pfcp_message->h.type);
|
||||
}
|
||||
break;
|
||||
|
||||
case OGS_EVENT_SBI_SERVER:
|
||||
sbi_message = e->h.sbi.message;
|
||||
ogs_assert(sbi_message);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "n4-build.h"
|
||||
|
||||
ogs_pkbuf_t *smf_n4_build_session_establishment_request(
|
||||
uint8_t type, smf_sess_t *sess)
|
||||
uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact)
|
||||
{
|
||||
ogs_pfcp_message_t *pfcp_message = NULL;
|
||||
ogs_pfcp_session_establishment_request_t *req = NULL;
|
||||
|
@ -46,6 +46,7 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request(
|
|||
ogs_assert(sess);
|
||||
smf_ue = sess->smf_ue;
|
||||
ogs_assert(smf_ue);
|
||||
ogs_assert(xact);
|
||||
|
||||
pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
|
||||
if (!pfcp_message) {
|
||||
|
@ -159,6 +160,16 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request(
|
|||
req->s_nssai.data = &sess->s_nssai;
|
||||
}
|
||||
|
||||
/* Restoration Indication */
|
||||
if (xact->create_flags & OGS_PFCP_CREATE_RESTORATION_INDICATION) {
|
||||
ogs_pfcp_sereq_flags_t sereq_flags;
|
||||
sereq_flags.value = 0;
|
||||
|
||||
sereq_flags.restoration_indication = 1;
|
||||
req->pfcpsereq_flags.presence = 1;
|
||||
req->pfcpsereq_flags.u8 = sereq_flags.value;
|
||||
}
|
||||
|
||||
pfcp_message->h.type = type;
|
||||
pkbuf = ogs_pfcp_build_msg(pfcp_message);
|
||||
ogs_expect(pkbuf);
|
||||
|
|
|
@ -27,7 +27,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
ogs_pkbuf_t *smf_n4_build_session_establishment_request(
|
||||
uint8_t type, smf_sess_t *sess);
|
||||
uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact);
|
||||
ogs_pkbuf_t *smf_n4_build_pdr_to_modify_list(
|
||||
uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact);
|
||||
ogs_pkbuf_t *smf_n4_build_qos_flow_to_modify_list(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -148,8 +148,6 @@ uint8_t smf_5gc_n4_handle_session_establishment_response(
|
|||
{
|
||||
int i;
|
||||
|
||||
ogs_sbi_stream_t *stream = NULL;
|
||||
|
||||
uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
|
||||
uint8_t offending_ie_value = 0;
|
||||
|
||||
|
@ -164,9 +162,6 @@ uint8_t smf_5gc_n4_handle_session_establishment_response(
|
|||
|
||||
ogs_debug("Session Establishment Response [5gc]");
|
||||
|
||||
stream = xact->assoc_stream;
|
||||
ogs_assert(stream);
|
||||
|
||||
ogs_pfcp_xact_commit(xact);
|
||||
|
||||
if (rsp->up_f_seid.presence == 0) {
|
||||
|
@ -732,7 +727,6 @@ uint8_t smf_epc_n4_handle_session_establishment_response(
|
|||
uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
|
||||
|
||||
smf_bearer_t *bearer = NULL;
|
||||
ogs_gtp_xact_t *gtp_xact = NULL;
|
||||
|
||||
ogs_pfcp_f_seid_t *up_f_seid = NULL;
|
||||
|
||||
|
@ -742,9 +736,6 @@ uint8_t smf_epc_n4_handle_session_establishment_response(
|
|||
|
||||
ogs_debug("Session Establishment Response [epc]");
|
||||
|
||||
gtp_xact = xact->assoc_xact;
|
||||
ogs_assert(gtp_xact);
|
||||
|
||||
ogs_pfcp_xact_commit(xact);
|
||||
|
||||
if (rsp->up_f_seid.presence == 0) {
|
||||
|
|
|
@ -630,7 +630,7 @@ bool smf_npcf_smpolicycontrol_handle_create(
|
|||
up2cp_pdr->precedence = OGS_PFCP_UP2CP_PDR_PRECEDENCE;
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
smf_5gc_pfcp_send_session_establishment_request(sess, stream));
|
||||
smf_5gc_pfcp_send_session_establishment_request(sess, 0));
|
||||
|
||||
return true;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -362,7 +362,7 @@ int smf_pfcp_send_modify_list(
|
|||
}
|
||||
|
||||
int smf_5gc_pfcp_send_session_establishment_request(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream)
|
||||
smf_sess_t *sess, uint64_t flags)
|
||||
{
|
||||
int rv;
|
||||
ogs_pkbuf_t *n4buf = NULL;
|
||||
|
@ -370,7 +370,6 @@ int smf_5gc_pfcp_send_session_establishment_request(
|
|||
ogs_pfcp_xact_t *xact = NULL;
|
||||
|
||||
ogs_assert(sess);
|
||||
ogs_assert(stream);
|
||||
|
||||
xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_5gc_timeout, sess);
|
||||
if (!xact) {
|
||||
|
@ -378,14 +377,44 @@ int smf_5gc_pfcp_send_session_establishment_request(
|
|||
return OGS_ERROR;
|
||||
}
|
||||
|
||||
xact->assoc_stream = stream;
|
||||
xact->local_seid = sess->smf_n4_seid;
|
||||
xact->create_flags = flags;
|
||||
|
||||
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
||||
h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE;
|
||||
|
||||
/*
|
||||
* 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header
|
||||
*
|
||||
* If a peer's SEID is not available, the SEID field shall still be present
|
||||
* in the header and its value shall be set to "0" in the following messages:
|
||||
*
|
||||
* - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4;
|
||||
*
|
||||
* - If a node receives a message for which it has no session, i.e.
|
||||
* if SEID in the PFCP header is not known, it shall respond
|
||||
* with "Session context not found" cause in the corresponding
|
||||
* response message to the sender, the SEID used in the PFCP header
|
||||
* in the response message shall be then set to "0";
|
||||
*
|
||||
* - If a node receives a request message containing protocol error,
|
||||
* e.g. Mandatory IE missing, which requires the receiver
|
||||
* to reject the message as specified in clause 7.6, it shall reject
|
||||
* the request message. For the response message, the node should look up
|
||||
* the remote peer's SEID and accordingly set SEID in the PFCP header
|
||||
* and the message cause code. As an implementation option,
|
||||
* the node may not look up the remote peer's SEID and
|
||||
* set the PFCP header SEID to "0" in the response message.
|
||||
* However in this case, the cause value shall not be set
|
||||
* to "Session not found".
|
||||
*
|
||||
* - When the UP function sends PFCP Session Report Request message
|
||||
* over N4 towards another SMF or another PFCP entity in the SMF
|
||||
* as specified in clause 5.22.2 and clause 5.22.3.
|
||||
*/
|
||||
h.seid = sess->upf_n4_seid;
|
||||
|
||||
n4buf = smf_n4_build_session_establishment_request(h.type, sess);
|
||||
n4buf = smf_n4_build_session_establishment_request(h.type, sess, xact);
|
||||
if (!n4buf) {
|
||||
ogs_error("smf_n4_build_session_establishment_request() failed");
|
||||
return OGS_ERROR;
|
||||
|
@ -506,7 +535,7 @@ int smf_5gc_pfcp_send_session_deletion_request(
|
|||
}
|
||||
|
||||
int smf_epc_pfcp_send_session_establishment_request(
|
||||
smf_sess_t *sess, void *gtp_xact)
|
||||
smf_sess_t *sess, void *gtp_xact, uint64_t flags)
|
||||
{
|
||||
int rv;
|
||||
ogs_pkbuf_t *n4buf = NULL;
|
||||
|
@ -524,12 +553,43 @@ int smf_epc_pfcp_send_session_establishment_request(
|
|||
xact->epc = true; /* EPC PFCP transaction */
|
||||
xact->assoc_xact = gtp_xact;
|
||||
xact->local_seid = sess->smf_n4_seid;
|
||||
xact->create_flags = flags;
|
||||
|
||||
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
||||
h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE;
|
||||
|
||||
/*
|
||||
* 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header
|
||||
*
|
||||
* If a peer's SEID is not available, the SEID field shall still be present
|
||||
* in the header and its value shall be set to "0" in the following messages:
|
||||
*
|
||||
* - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4;
|
||||
*
|
||||
* - If a node receives a message for which it has no session, i.e.
|
||||
* if SEID in the PFCP header is not known, it shall respond
|
||||
* with "Session context not found" cause in the corresponding
|
||||
* response message to the sender, the SEID used in the PFCP header
|
||||
* in the response message shall be then set to "0";
|
||||
*
|
||||
* - If a node receives a request message containing protocol error,
|
||||
* e.g. Mandatory IE missing, which requires the receiver
|
||||
* to reject the message as specified in clause 7.6, it shall reject
|
||||
* the request message. For the response message, the node should look up
|
||||
* the remote peer's SEID and accordingly set SEID in the PFCP header
|
||||
* and the message cause code. As an implementation option,
|
||||
* the node may not look up the remote peer's SEID and
|
||||
* set the PFCP header SEID to "0" in the response message.
|
||||
* However in this case, the cause value shall not be set
|
||||
* to "Session not found".
|
||||
*
|
||||
* - When the UP function sends PFCP Session Report Request message
|
||||
* over N4 towards another SMF or another PFCP entity in the SMF
|
||||
* as specified in clause 5.22.2 and clause 5.22.3.
|
||||
*/
|
||||
h.seid = sess->upf_n4_seid;
|
||||
|
||||
n4buf = smf_n4_build_session_establishment_request(h.type, sess);
|
||||
n4buf = smf_n4_build_session_establishment_request(h.type, sess, xact);
|
||||
if (!n4buf) {
|
||||
ogs_error("smf_n4_build_session_establishment_request() failed");
|
||||
return OGS_ERROR;
|
||||
|
|
|
@ -36,7 +36,7 @@ int smf_pfcp_send_modify_list(
|
|||
ogs_pfcp_xact_t *xact, ogs_time_t duration);
|
||||
|
||||
int smf_5gc_pfcp_send_session_establishment_request(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream);
|
||||
smf_sess_t *sess, uint64_t flags);
|
||||
int smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream,
|
||||
uint64_t flags, ogs_time_t duration);
|
||||
|
@ -47,7 +47,7 @@ int smf_5gc_pfcp_send_session_deletion_request(
|
|||
smf_sess_t *sess, ogs_sbi_stream_t *stream, int trigger);
|
||||
|
||||
int smf_epc_pfcp_send_session_establishment_request(
|
||||
smf_sess_t *sess, void *gtp_xact);
|
||||
smf_sess_t *sess, void *gtp_xact, uint64_t flags);
|
||||
int smf_epc_pfcp_send_all_pdr_modification_request(
|
||||
smf_sess_t *sess, void *gtp_xact, ogs_pkbuf_t *gtpbuf,
|
||||
uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "n4-handler.h"
|
||||
|
||||
static void pfcp_restoration(ogs_pfcp_node_t *node);
|
||||
static void reselect_upf(ogs_pfcp_node_t *node);
|
||||
static void node_timeout(ogs_pfcp_xact_t *xact, void *data);
|
||||
|
||||
|
@ -191,7 +192,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
|
|||
ogs_pfcp_send_heartbeat_request(node, node_timeout));
|
||||
|
||||
if (node->restoration_required == true) {
|
||||
/* PFCP Restoration is being performed after PFCP association */
|
||||
pfcp_restoration(node);
|
||||
node->restoration_required = false;
|
||||
ogs_error("PFCP restoration");
|
||||
}
|
||||
|
@ -244,6 +245,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
|
|||
* If the peer PFCP entity is performing the association,
|
||||
* Restoration can be performed immediately.
|
||||
*/
|
||||
pfcp_restoration(node);
|
||||
node->restoration_required = false;
|
||||
ogs_error("PFCP restoration");
|
||||
}
|
||||
|
@ -270,6 +272,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
|
|||
* If the peer PFCP entity is performing the association,
|
||||
* Restoration can be performed immediately.
|
||||
*/
|
||||
pfcp_restoration(node);
|
||||
node->restoration_required = false;
|
||||
ogs_error("PFCP restoration");
|
||||
}
|
||||
|
@ -409,10 +412,52 @@ void smf_pfcp_state_exception(ogs_fsm_t *s, smf_event_t *e)
|
|||
}
|
||||
}
|
||||
|
||||
static void pfcp_restoration(ogs_pfcp_node_t *node)
|
||||
{
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
char buf1[OGS_ADDRSTRLEN];
|
||||
char buf2[OGS_ADDRSTRLEN];
|
||||
|
||||
ogs_list_for_each(&smf_self()->smf_ue_list, smf_ue) {
|
||||
smf_sess_t *sess = NULL;
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
ogs_list_for_each(&smf_ue->sess_list, sess) {
|
||||
ogs_assert(sess);
|
||||
|
||||
if (node == sess->pfcp_node) {
|
||||
if (sess->epc) {
|
||||
ogs_info("UE IMSI[%s] APN[%s] IPv4[%s] IPv6[%s]",
|
||||
smf_ue->imsi_bcd, sess->session.name,
|
||||
sess->ipv4 ?
|
||||
OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
|
||||
sess->ipv6 ?
|
||||
OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
|
||||
ogs_assert(OGS_OK ==
|
||||
smf_epc_pfcp_send_session_establishment_request(
|
||||
sess, NULL,
|
||||
OGS_PFCP_CREATE_RESTORATION_INDICATION));
|
||||
} else {
|
||||
ogs_info("UE SUPI[%s] DNN[%s] IPv4[%s] IPv6[%s]",
|
||||
smf_ue->supi, sess->session.name,
|
||||
sess->ipv4 ?
|
||||
OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
|
||||
sess->ipv6 ?
|
||||
OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
|
||||
ogs_assert(OGS_OK ==
|
||||
smf_5gc_pfcp_send_session_establishment_request(
|
||||
sess, OGS_PFCP_CREATE_RESTORATION_INDICATION));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reselect_upf(ogs_pfcp_node_t *node)
|
||||
{
|
||||
int r;
|
||||
smf_ue_t *smf_ue = NULL, *next_ue = NULL;;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
ogs_pfcp_node_t *iter = NULL;
|
||||
|
||||
ogs_assert(node);
|
||||
|
@ -434,19 +479,18 @@ static void reselect_upf(ogs_pfcp_node_t *node)
|
|||
return;
|
||||
}
|
||||
|
||||
ogs_list_for_each_safe(&smf_self()->smf_ue_list, next_ue, smf_ue) {
|
||||
smf_sess_t *sess = NULL, *next_sess = NULL;;
|
||||
ogs_list_for_each(&smf_self()->smf_ue_list, smf_ue) {
|
||||
smf_sess_t *sess = NULL;
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
ogs_list_for_each_safe(&smf_ue->sess_list, next_sess, sess) {
|
||||
ogs_list_for_each(&smf_ue->sess_list, sess) {
|
||||
ogs_assert(sess);
|
||||
if (sess->epc) {
|
||||
ogs_error("[%s:%s] EPC restoration is not implemented",
|
||||
smf_ue->imsi_bcd, sess->session.name);
|
||||
} else {
|
||||
ogs_assert(sess->sm_context_ref);
|
||||
|
||||
if (node == sess->pfcp_node) {
|
||||
if (node == sess->pfcp_node) {
|
||||
if (sess->epc) {
|
||||
ogs_error("[%s:%s] EPC restoration is not implemented",
|
||||
smf_ue->imsi_bcd, sess->session.name);
|
||||
} else {
|
||||
smf_npcf_smpolicycontrol_param_t param;
|
||||
|
||||
ogs_info("[%s:%d] SMF-initiated Deletion",
|
||||
|
@ -479,18 +523,6 @@ static void node_timeout(ogs_pfcp_xact_t *xact, void *data)
|
|||
switch (type) {
|
||||
case OGS_PFCP_HEARTBEAT_REQUEST_TYPE:
|
||||
ogs_assert(data);
|
||||
|
||||
|
||||
/*
|
||||
* The code below is not secure.
|
||||
* Session does not differentiate between EPC and 5GC.
|
||||
* And, it does not check whether there are other PFCP Nodes.
|
||||
*
|
||||
* So, UPF redundancy will be implemented later.
|
||||
*
|
||||
* We plan to do this again after testing with restoration first
|
||||
* in case peer PFCP restarts.
|
||||
*/
|
||||
reselect_upf(data);
|
||||
|
||||
e = smf_event_new(SMF_EVT_N4_NO_HEARTBEAT);
|
||||
|
|
|
@ -367,7 +367,10 @@ upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message)
|
|||
sess = upf_sess_find_by_smf_n4_f_seid(f_seid);
|
||||
if (!sess) {
|
||||
sess = upf_sess_add(f_seid);
|
||||
if (!sess) return NULL;
|
||||
if (!sess) {
|
||||
ogs_error("No Session Context");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ogs_assert(sess);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -425,6 +425,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
|
||||
switch(pfcp_object->type) {
|
||||
case OGS_PFCP_OBJ_PDR_TYPE:
|
||||
/* UPF does not use PDR TYPE */
|
||||
ogs_assert_if_reached();
|
||||
pdr = (ogs_pfcp_pdr_t *)pfcp_object;
|
||||
ogs_assert(pdr);
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
@ -55,6 +55,9 @@ void upf_n4_handle_session_establishment_request(
|
|||
uint8_t offending_ie_value = 0;
|
||||
int i;
|
||||
|
||||
ogs_pfcp_sereq_flags_t sereq_flags;
|
||||
bool restoration_indication = false;
|
||||
|
||||
upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_SM_N4SESSIONESTABREQ);
|
||||
|
||||
ogs_assert(xact);
|
||||
|
@ -74,9 +77,14 @@ void upf_n4_handle_session_establishment_request(
|
|||
return;
|
||||
}
|
||||
|
||||
memset(&sereq_flags, 0, sizeof(sereq_flags));
|
||||
if (req->pfcpsereq_flags.presence == 1)
|
||||
sereq_flags.value = req->pfcpsereq_flags.u8;
|
||||
|
||||
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
|
||||
created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp,
|
||||
&req->create_pdr[i], &cause_value, &offending_ie_value);
|
||||
&req->create_pdr[i], &sereq_flags,
|
||||
&cause_value, &offending_ie_value);
|
||||
if (created_pdr[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
@ -116,6 +124,18 @@ void upf_n4_handle_session_establishment_request(
|
|||
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
|
||||
goto cleanup;
|
||||
|
||||
/* PFCPSEReq-Flags */
|
||||
if (sereq_flags.restoration_indication == 1) {
|
||||
for (i = 0; i < num_of_created_pdr; i++) {
|
||||
pdr = created_pdr[i];
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->f_teid_len)
|
||||
ogs_pfcp_pdr_swap_teid(pdr);
|
||||
}
|
||||
restoration_indication = true;
|
||||
}
|
||||
|
||||
/* Setup GTP Node */
|
||||
ogs_list_for_each(&sess->pfcp.far_list, far) {
|
||||
ogs_assert(OGS_ERROR != ogs_pfcp_setup_far_gtpu_node(far));
|
||||
|
@ -155,65 +175,9 @@ void upf_n4_handle_session_establishment_request(
|
|||
}
|
||||
|
||||
/* Setup UPF-N3-TEID & QFI Hash */
|
||||
if (pdr->f_teid_len) {
|
||||
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_SESS_TYPE;
|
||||
|
||||
if (ogs_pfcp_self()->up_function_features.ftup &&
|
||||
pdr->f_teid.ch) {
|
||||
|
||||
ogs_pfcp_pdr_t *choosed_pdr = NULL;
|
||||
|
||||
if (pdr->f_teid.chid) {
|
||||
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
|
||||
&sess->pfcp, pdr->f_teid.choose_id);
|
||||
if (!choosed_pdr) {
|
||||
pdr->chid = true;
|
||||
pdr->choose_id = pdr->f_teid.choose_id;
|
||||
}
|
||||
} else {
|
||||
type = OGS_PFCP_OBJ_PDR_TYPE;
|
||||
}
|
||||
|
||||
if (choosed_pdr) {
|
||||
pdr->f_teid_len = choosed_pdr->f_teid_len;
|
||||
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
|
||||
|
||||
} else {
|
||||
ogs_gtpu_resource_t *resource = NULL;
|
||||
resource = ogs_pfcp_find_gtpu_resource(
|
||||
&ogs_gtp_self()->gtpu_resource_list,
|
||||
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
|
||||
if (resource) {
|
||||
ogs_assert(
|
||||
(resource->info.v4 && pdr->f_teid.ipv4) ||
|
||||
(resource->info.v6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
|
||||
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
|
||||
if (resource->info.teidri)
|
||||
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
|
||||
pdr->teid, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
} else {
|
||||
ogs_assert(
|
||||
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
|
||||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_sockaddr_to_f_teid(
|
||||
pdr->f_teid.ipv4 ?
|
||||
ogs_gtp_self()->gtpu_addr : NULL,
|
||||
pdr->f_teid.ipv6 ?
|
||||
ogs_gtp_self()->gtpu_addr6 : NULL,
|
||||
&pdr->f_teid, &pdr->f_teid_len));
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pfcp_object_teid_hash_set(type, pdr);
|
||||
}
|
||||
if (pdr->f_teid_len)
|
||||
ogs_pfcp_object_teid_hash_set(
|
||||
OGS_PFCP_OBJ_SESS_TYPE, pdr, restoration_indication);
|
||||
}
|
||||
|
||||
/* Send Buffered Packet to gNB/SGW */
|
||||
|
@ -223,9 +187,16 @@ void upf_n4_handle_session_establishment_request(
|
|||
}
|
||||
}
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
upf_pfcp_send_session_establishment_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr));
|
||||
if (restoration_indication == true ||
|
||||
ogs_pfcp_self()->up_function_features.ftup == 0)
|
||||
ogs_assert(OGS_OK ==
|
||||
upf_pfcp_send_session_establishment_response(
|
||||
xact, sess, NULL, 0));
|
||||
else
|
||||
ogs_assert(OGS_OK ==
|
||||
upf_pfcp_send_session_establishment_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr));
|
||||
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
|
@ -266,7 +237,7 @@ void upf_n4_handle_session_modification_request(
|
|||
|
||||
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
|
||||
created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp,
|
||||
&req->create_pdr[i], &cause_value, &offending_ie_value);
|
||||
&req->create_pdr[i], NULL, &cause_value, &offending_ie_value);
|
||||
if (created_pdr[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
@ -399,70 +370,13 @@ void upf_n4_handle_session_modification_request(
|
|||
ogs_pfcp_far_f_teid_hash_set(far);
|
||||
}
|
||||
|
||||
/* Setup UPF-N3-TEID & QFI Hash */
|
||||
for (i = 0; i < num_of_created_pdr; i++) {
|
||||
pdr = created_pdr[i];
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->f_teid_len) {
|
||||
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_SESS_TYPE;
|
||||
|
||||
if (ogs_pfcp_self()->up_function_features.ftup &&
|
||||
pdr->f_teid.ch) {
|
||||
|
||||
ogs_pfcp_pdr_t *choosed_pdr = NULL;
|
||||
|
||||
if (pdr->f_teid.chid) {
|
||||
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
|
||||
&sess->pfcp, pdr->f_teid.choose_id);
|
||||
if (!choosed_pdr) {
|
||||
pdr->chid = true;
|
||||
pdr->choose_id = pdr->f_teid.choose_id;
|
||||
}
|
||||
} else {
|
||||
type = OGS_PFCP_OBJ_PDR_TYPE;
|
||||
}
|
||||
|
||||
if (choosed_pdr) {
|
||||
pdr->f_teid_len = choosed_pdr->f_teid_len;
|
||||
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
|
||||
|
||||
} else {
|
||||
ogs_gtpu_resource_t *resource = NULL;
|
||||
resource = ogs_pfcp_find_gtpu_resource(
|
||||
&ogs_gtp_self()->gtpu_resource_list,
|
||||
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
|
||||
if (resource) {
|
||||
ogs_assert(
|
||||
(resource->info.v4 && pdr->f_teid.ipv4) ||
|
||||
(resource->info.v6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
|
||||
&resource->info, &pdr->f_teid, &pdr->f_teid_len));
|
||||
if (resource->info.teidri)
|
||||
pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
|
||||
pdr->teid, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
} else {
|
||||
ogs_assert(
|
||||
(ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
|
||||
(ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6));
|
||||
ogs_assert(OGS_OK ==
|
||||
ogs_pfcp_sockaddr_to_f_teid(
|
||||
pdr->f_teid.ipv4 ?
|
||||
ogs_gtp_self()->gtpu_addr : NULL,
|
||||
pdr->f_teid.ipv6 ?
|
||||
ogs_gtp_self()->gtpu_addr6 : NULL,
|
||||
&pdr->f_teid, &pdr->f_teid_len));
|
||||
pdr->f_teid.teid = pdr->teid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pfcp_object_teid_hash_set(type, pdr);
|
||||
}
|
||||
/* Setup UPF-N3-TEID & QFI Hash */
|
||||
if (pdr->f_teid_len)
|
||||
ogs_pfcp_object_teid_hash_set(OGS_PFCP_OBJ_SESS_TYPE, pdr, false);
|
||||
}
|
||||
|
||||
/* Send Buffered Packet to gNB/SGW */
|
||||
|
@ -472,9 +386,14 @@ void upf_n4_handle_session_modification_request(
|
|||
}
|
||||
}
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
upf_pfcp_send_session_modification_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr));
|
||||
if (ogs_pfcp_self()->up_function_features.ftup == 0)
|
||||
ogs_assert(OGS_OK ==
|
||||
upf_pfcp_send_session_modification_response(
|
||||
xact, sess, NULL, 0));
|
||||
else
|
||||
ogs_assert(OGS_OK ==
|
||||
upf_pfcp_send_session_modification_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr));
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
|
|
|
@ -208,7 +208,6 @@ int upf_pfcp_send_session_modification_response(
|
|||
ogs_pfcp_header_t h;
|
||||
|
||||
ogs_assert(xact);
|
||||
ogs_assert(created_pdr);
|
||||
|
||||
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
||||
h.type = OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE;
|
||||
|
|
|
@ -281,12 +281,9 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e)
|
|||
&message->pfcp_association_setup_response);
|
||||
break;
|
||||
case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE:
|
||||
if (message->h.seid_presence && message->h.seid == 0) {
|
||||
ogs_expect(!sess);
|
||||
sess = upf_sess_add_by_message(message);
|
||||
if (sess)
|
||||
OGS_SETUP_PFCP_NODE(sess, node);
|
||||
}
|
||||
sess = upf_sess_add_by_message(message);
|
||||
if (sess)
|
||||
OGS_SETUP_PFCP_NODE(sess, node);
|
||||
upf_n4_handle_session_establishment_request(
|
||||
sess, xact, &message->pfcp_session_establishment_request);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue