diff --git a/docs/_posts/2025-07-19-release-v2.7.6.md b/docs/_posts/2025-07-19-release-v2.7.6.md index 784fcad3a..b30bb4fcf 100644 --- a/docs/_posts/2025-07-19-release-v2.7.6.md +++ b/docs/_posts/2025-07-19-release-v2.7.6.md @@ -1,6 +1,6 @@ --- title: "v2.7.6 - Bug fixed" -date: 2025-03-30 22:05:00 +0900 +date: 2025-07-19 22:05:00 +0900 categories: - Release tags: diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index a8e24ce6a..9eb165412 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -303,6 +303,39 @@ bool ogs_pfcp_up_handle_pdr( sendhdr.pdu_type = OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION; sendhdr.qos_flow_identifier = pdr->qer->qfi; + } else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS && + far->dst_if == OGS_PFCP_INTERFACE_ACCESS && + recvhdr->qos_flow_identifier) { +/* + * HR Indirect Forwarding (source gNB -> V-UPF -> target gNB) + * + * Context: + * - Home-Routed roaming: the V-UPF is controlled by the V-SMF, which + * typically does not provision QER/QFI for the indirect path. + * - During Xn/N2 handover the source gNB may forward remaining DL data + * to the core using UL PDU Session Information (PSC PDU type = UL). + * + * Goal: + * - Preserve the PDU Session Container across the V-UPF hop and deliver + * it to the target gNB with PDU type = DL while keeping the same QFI. + * + * What we do here: + * - If this PDR has no QER/QFI and the path is Access->Access, derive + * PSC fields from the received header (recvhdr). + * - Force sendhdr.pdu_type = DL PDU Session Information. + * - Copy recvhdr->qos_flow_identifier into sendhdr.qos_flow_identifier. + * - The encapsulation routine will build a fresh GTP-U header and + * generate the PSC extension from sendhdr fields. This converts UL + * PSC to DL PSC and preserves the QFI for the target gNB. + * + * Why this is needed in HR: + * - With OHR+OHC, the incoming GTP-U (extensions included) is removed + * and a new one is created. Without recreating PSC from sendhdr.*, the + * extension header would be lost when QER is absent on the V-UPF. + */ + sendhdr.pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION; + sendhdr.qos_flow_identifier = recvhdr->qos_flow_identifier; } if (recvhdr) { @@ -962,6 +995,14 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_update_pdr(ogs_pfcp_sess_t *sess, } } + if (message->outer_header_removal.presence) { + pdr->outer_header_removal_len = + ogs_min(message->outer_header_removal.len, + sizeof(pdr->outer_header_removal)); + memcpy(&pdr->outer_header_removal, message->outer_header_removal.data, + pdr->outer_header_removal_len); + } + return pdr; } diff --git a/src/sgwu/sxa-handler.c b/src/sgwu/sxa-handler.c index 75bda0867..d55a6d0cd 100644 --- a/src/sgwu/sxa-handler.c +++ b/src/sgwu/sxa-handler.c @@ -198,6 +198,14 @@ void sgwu_sxa_handle_session_modification_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + if (ogs_pfcp_handle_update_pdr(&sess->pfcp, &req->update_pdr[i], + &cause_value, &offending_ie_value) == NULL) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { if (ogs_pfcp_handle_remove_pdr(&sess->pfcp, &req->remove_pdr[i], &cause_value, &offending_ie_value) == false)