[SMF] Added Bi-Directional Flow (#2909)

For bi-directions, the rules are created in the same form as for downlink
as shown below, so to apply them for uplink, we need to swap the rules
according to the interface.

RX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
PFCP : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>

RX : permit in from <UE_IP> <UE_PORT> to <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
PFCP : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
RULE : Source <UE_IP> <UE_PORT> Destination <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
This commit is contained in:
Sukchan Lee 2024-02-17 20:40:08 +01:00
parent 843c4950ac
commit 41d8934677
19 changed files with 1037 additions and 138 deletions

View File

@ -1,5 +1,5 @@
/* Gx Interface, 3GPP TS 29.212 section 4
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -43,6 +43,7 @@ extern "C" {
#define OGS_DIAM_GX_AVP_CODE_FLOW_STATUS (511)
#define OGS_DIAM_GX_AVP_CODE_QOS_INFORMATION (1016)
#define OGS_DIAM_GX_AVP_CODE_PRECEDENCE (1010)
#define OGS_DIAM_GX_AVP_CODE_RATING_GROUP (432)
extern struct dict_object *ogs_diam_gx_application;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -395,117 +395,167 @@ void ogs_pf_content_from_ipfw_rule(
* Network support Local Address in TFTs.
*/
if (rule->ipv4_src && (direction == OGS_FLOW_DOWNLINK_ONLY)) {
content->component[j].type = OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.src.addr[0];
content->component[j].ipv4.mask = rule->ip.src.mask[0];
j++; len += 9;
}
if (rule->ipv4_src && (direction == OGS_FLOW_UPLINK_ONLY) &&
!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type = OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.src.addr[0];
content->component[j].ipv4.mask = rule->ip.src.mask[0];
j++; len += 9;
}
if (rule->ipv4_dst && (direction == OGS_FLOW_DOWNLINK_ONLY) &&
!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type = OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.dst.addr[0];
content->component[j].ipv4.mask = rule->ip.dst.mask[0];
j++; len += 9;
}
if (rule->ipv4_dst && (direction == OGS_FLOW_UPLINK_ONLY)) {
content->component[j].type = OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.dst.addr[0];
content->component[j].ipv4.mask = rule->ip.dst.mask[0];
j++; len += 9;
}
if (rule->ipv6_src && (direction == OGS_FLOW_DOWNLINK_ONLY)) {
if (no_ipv4v6_local_addr_in_packet_filter) {
if (rule->ipv4_src) {
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE;
memcpy(content->component[j].ipv6_mask.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
memcpy(content->component[j].ipv6_mask.mask,
rule->ip.src.mask, sizeof rule->ip.src.mask);
j++; len += 33;
} else {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.src.mask, 128);
j++; len += 18;
OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.src.addr[0];
content->component[j].ipv4.mask = rule->ip.src.mask[0];
j++; len += 9;
break;
case OGS_FLOW_UPLINK_ONLY:
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.src.addr[0];
content->component[j].ipv4.mask = rule->ip.src.mask[0];
j++; len += 9;
}
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
}
if (rule->ipv6_src && (direction == OGS_FLOW_UPLINK_ONLY)) {
if (!no_ipv4v6_local_addr_in_packet_filter) {
if (rule->ipv4_dst) {
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.dst.addr[0];
content->component[j].ipv4.mask = rule->ip.dst.mask[0];
j++; len += 9;
}
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.src.mask, 128);
j++; len += 18;
OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.dst.addr[0];
content->component[j].ipv4.mask = rule->ip.dst.mask[0];
j++; len += 9;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
}
if (rule->ipv6_dst && (direction == OGS_FLOW_DOWNLINK_ONLY)) {
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.dst.mask, 128);
j++; len += 18;
}
}
if (rule->ipv6_dst && (direction == OGS_FLOW_UPLINK_ONLY)) {
if (no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
if (rule->ipv6_src) {
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
if (no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE;
memcpy(content->component[j].ipv6_mask.addr,
memcpy(content->component[j].ipv6_mask.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
memcpy(content->component[j].ipv6_mask.mask,
rule->ip.src.mask, sizeof rule->ip.src.mask);
j++; len += 33;
} else {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.src.mask, 128);
j++; len += 18;
}
break;
case OGS_FLOW_UPLINK_ONLY:
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.src.mask, 128);
j++; len += 18;
}
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
}
if (rule->ipv6_dst) {
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
memcpy(content->component[j].ipv6_mask.mask,
rule->ip.dst.mask, sizeof rule->ip.dst.mask);
j++; len += 33;
} else {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.dst.mask, 128);
j++; len += 18;
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.dst.mask, 128);
j++; len += 18;
}
break;
case OGS_FLOW_UPLINK_ONLY:
if (no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE;
memcpy(content->component[j].ipv6_mask.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
memcpy(content->component[j].ipv6_mask.mask,
rule->ip.dst.mask, sizeof rule->ip.dst.mask);
j++; len += 33;
} else {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.dst.mask, 128);
j++; len += 18;
}
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
}
if (rule->port.src.low) {
if (rule->port.src.low == rule->port.src.high) {
if (direction == OGS_FLOW_DOWNLINK_ONLY)
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE;
else
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
content->component[j].port.low = rule->port.src.low;
j++; len += 3;
} else {
if (direction == OGS_FLOW_DOWNLINK_ONLY)
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE;
else
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
content->component[j].port.low = rule->port.src.low;
content->component[j].port.high = rule->port.src.high;
j++; len += 5;
@ -514,21 +564,37 @@ void ogs_pf_content_from_ipfw_rule(
if (rule->port.dst.low) {
if (rule->port.dst.low == rule->port.dst.high) {
if (direction == OGS_FLOW_DOWNLINK_ONLY)
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE;
else
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
content->component[j].port.low = rule->port.dst.low;
j++; len += 3;
} else {
if (direction == OGS_FLOW_DOWNLINK_ONLY)
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE;
else
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
content->component[j].port.low = rule->port.dst.low;
content->component[j].port.high = rule->port.dst.high;
j++; len += 5;
@ -538,4 +604,3 @@ void ogs_pf_content_from_ipfw_rule(
content->num_of_component = j;
content->length = len;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -68,7 +68,7 @@ char *ogs_ipfw_encode_flow_description(ogs_ipfw_rule_t *ipfw_rule);
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>>
* RX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* PFCP : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -364,10 +364,19 @@ void ogs_pfcp_build_create_pdr(
memset(pfcp_sdf_filter, 0, sizeof(pfcp_sdf_filter));
for (j = 0; j < pdr->num_of_flow && j < OGS_MAX_NUM_OF_FLOW_IN_PDR; j++) {
pfcp_sdf_filter[j].fd = 1;
pfcp_sdf_filter[j].flow_description_len =
strlen(pdr->flow_description[j]);
pfcp_sdf_filter[j].flow_description = pdr->flow_description[j];
ogs_assert(pdr->flow[j].fd || pdr->flow[j].bid);
if (pdr->flow[j].fd) {
pfcp_sdf_filter[j].fd = 1;
pfcp_sdf_filter[j].flow_description_len =
strlen(pdr->flow[j].description);
pfcp_sdf_filter[j].flow_description = pdr->flow[j].description;
}
if (pdr->flow[j].bid) {
pfcp_sdf_filter[j].bid = 1;
pfcp_sdf_filter[j].sdf_filter_id = pdr->flow[j].sdf_filter_id;
}
len = sizeof(ogs_pfcp_sdf_filter_t) +
pfcp_sdf_filter[j].flow_description_len;
@ -493,10 +502,19 @@ void ogs_pfcp_build_update_pdr(
memset(pfcp_sdf_filter, 0, sizeof(pfcp_sdf_filter));
for (j = 0; j < pdr->num_of_flow && j < OGS_MAX_NUM_OF_FLOW_IN_PDR; j++) {
pfcp_sdf_filter[j].fd = 1;
pfcp_sdf_filter[j].flow_description_len =
strlen(pdr->flow_description[j]);
pfcp_sdf_filter[j].flow_description = pdr->flow_description[j];
ogs_assert(pdr->flow[j].fd || pdr->flow[j].bid);
if (pdr->flow[j].fd) {
pfcp_sdf_filter[j].fd = 1;
pfcp_sdf_filter[j].flow_description_len =
strlen(pdr->flow[j].description);
pfcp_sdf_filter[j].flow_description = pdr->flow[j].description;
}
if (pdr->flow[j].bid) {
pfcp_sdf_filter[j].bid = 1;
pfcp_sdf_filter[j].sdf_filter_id = pdr->flow[j].sdf_filter_id;
}
len = sizeof(ogs_pfcp_sdf_filter_t) +
pfcp_sdf_filter[j].flow_description_len;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -186,7 +186,21 @@ typedef struct ogs_pfcp_pdr_s {
ogs_pfcp_qer_t *qer;
int num_of_flow;
char *flow_description[OGS_MAX_NUM_OF_FLOW_IN_PDR];
struct {
union {
struct {
ED6(uint8_t spare1:3;,
uint8_t bid:1;,
uint8_t fl:1;,
uint8_t spi:1;,
uint8_t ttc:1;,
uint8_t fd:1;)
};
uint8_t flags;
};
char *description;
uint32_t sdf_filter_id;
} flow[OGS_MAX_NUM_OF_FLOW_IN_PDR];;
ogs_list_t rule_list; /* Rule List */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -459,9 +459,40 @@ typedef struct ogs_qos_s {
int ogs_check_qos_conf(ogs_qos_t *qos);
/**********************************
* Flow Structure */
* TS29.212
* Ch 5.3.65 Flow-Direction AVP
*
* The Flow-Direction AVP (AVP code 1080) is of type Enumerated.
* It indicates the direction/directions that a filter is applicable,
* downlink only, uplink only or both down- and uplink (bidirectional).
*
* UNSPECIFIED (0)
* The corresponding filter applies for traffic to the UE (downlink),
* but has no specific direction declared. The service data flow detection
* shall apply the filter for uplink traffic as if the filter was
* bidirectional. The PCRF shall not use the value UNSPECIFIED
* in filters created by the network in NW-initiated procedures.
* The PCRF shall only include the value UNSPECIFIED in filters
* in UE-initiated procedures if the same value is received from
* in the CCR request from the PCEF.
*
* DOWNLINK (1)
* The corresponding filter applies for traffic to the UE.
*
* UPLINK (2)
* The corresponding filter applies for traffic from the UE.
*
* BIDIRECTIONAL (3)
* The corresponding filter applies for traffic both to and from the UE.
*
* NOTE: The corresponding filter data is unidirectional. The filter
* for the opposite direction has the same parameters, but having
* the source and destination address/port parameters swapped.
*/
#define OGS_FLOW_UNSPECIFIED 0
#define OGS_FLOW_DOWNLINK_ONLY 1
#define OGS_FLOW_UPLINK_ONLY 2
#define OGS_FLOW_BIDIRECTIONAL 3
typedef struct ogs_flow_s {
uint8_t direction;
char *description;
@ -477,7 +508,11 @@ typedef struct ogs_flow_s {
} while(0)
/**********************************
* PCC Rule Structure */
* TS29.212
* Ch 5.3.2 Charging-Rule-Install AVP
*
* PCC Rule Structure
*/
typedef struct ogs_pcc_rule_s {
#define OGS_PCC_RULE_TYPE_INSTALL 1
#define OGS_PCC_RULE_TYPE_REMOVE 2
@ -491,6 +526,7 @@ typedef struct ogs_pcc_rule_s {
int flow_status;
uint32_t precedence;
uint32_t rating_group;
ogs_qos_t qos;
} ogs_pcc_rule_t;

View File

@ -1466,6 +1466,9 @@ OpenAPI_pcc_rule_t *ogs_sbi_build_pcc_rule(
else if (flow->direction == OGS_FLOW_DOWNLINK_ONLY)
FlowInformation->flow_direction =
OpenAPI_flow_direction_DOWNLINK;
else if (flow->direction == OGS_FLOW_BIDIRECTIONAL)
FlowInformation->flow_direction =
OpenAPI_flow_direction_BIDIRECTIONAL;
else {
ogs_fatal("Unsupported direction [%d]", flow->direction);
ogs_assert_if_reached();

View File

@ -65,7 +65,7 @@ static void gtp_bearer_timeout(ogs_gtp_xact_t *xact, void *data)
/*
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
* TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
*
@ -303,7 +303,7 @@ void smf_bearer_binding(smf_sess_t *sess)
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* -->
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
@ -632,7 +632,7 @@ void smf_qos_flow_binding(smf_sess_t *sess)
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* -->
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -2569,16 +2569,28 @@ void smf_bearer_tft_update(smf_bearer_t *bearer)
ogs_list_for_each(&bearer->pf_list, pf) {
if (pf->direction == OGS_FLOW_DOWNLINK_ONLY) {
dl_pdr->flow_description[dl_pdr->num_of_flow++] =
dl_pdr->flow[dl_pdr->num_of_flow].fd = 1;
dl_pdr->flow[dl_pdr->num_of_flow].description =
pf->flow_description;
dl_pdr->num_of_flow++;
} else if (pf->direction == OGS_FLOW_UPLINK_ONLY) {
ul_pdr->flow_description[ul_pdr->num_of_flow++] =
ul_pdr->flow[ul_pdr->num_of_flow].fd = 1;
ul_pdr->flow[ul_pdr->num_of_flow].description =
pf->flow_description;
ul_pdr->num_of_flow++;
} else if (pf->direction == OGS_FLOW_BIDIRECTIONAL) {
dl_pdr->flow[dl_pdr->num_of_flow].fd = 1;
dl_pdr->flow[dl_pdr->num_of_flow].description =
pf->flow_description;
dl_pdr->flow[dl_pdr->num_of_flow].bid = 1;
dl_pdr->flow[dl_pdr->num_of_flow].sdf_filter_id = pf->sdf_filter_id;
dl_pdr->num_of_flow++;
ul_pdr->flow[ul_pdr->num_of_flow].bid = 1;
ul_pdr->flow[ul_pdr->num_of_flow].sdf_filter_id = pf->sdf_filter_id;
ul_pdr->num_of_flow++;
} else {
ogs_fatal("Unsupported direction [%d]", pf->direction);
ogs_assert_if_reached();
ogs_fatal("Flow Bidirectional is not supported[%d]",
pf->direction);
}
}
}
@ -2677,6 +2689,9 @@ smf_pf_t *smf_pf_add(smf_bearer_t *bearer)
ogs_assert(pf->precedence > 0 && pf->precedence <=
(OGS_MAX_NUM_OF_BEARER * OGS_MAX_NUM_OF_FLOW_IN_BEARER));
/* Re-use 'pf_precedence_pool' to generate SDF Filter ID */
pf->sdf_filter_id = *(pf->precedence_node);
pf->bearer = bearer;
ogs_list_add(&bearer->pf_list, pf);

View File

@ -161,6 +161,8 @@ ED3(uint8_t spare:2;,
uint8_t precedence; /* Only used in EPC */
uint32_t sdf_filter_id; /* SDF Filter ID */
uint8_t *identifier_node; /* Pool-Node for Identifier */
uint8_t *precedence_node; /* Pool-Node for Precedence */

View File

@ -261,7 +261,7 @@ int gsm_handle_pdu_session_modification_request(
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
* -->
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
@ -280,7 +280,7 @@ int gsm_handle_pdu_session_modification_request(
/*
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
* -->
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
@ -336,7 +336,7 @@ int gsm_handle_pdu_session_modification_request(
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
* -->
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
@ -355,7 +355,7 @@ int gsm_handle_pdu_session_modification_request(
/*
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
* -->
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>

View File

@ -1,5 +1,5 @@
/* Gx Interface, 3GPP TS 29.212 section 4
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* This file is part of Open5GS.
@ -162,8 +162,11 @@ uint32_t smf_gx_handle_cca_initial_request(
&ul_pdr->ue_ip_addr, &ul_pdr->ue_ip_addr_len));
/* Set UE-to-CP Flow-Description and Outer-Header-Creation */
up2cp_pdr->flow_description[up2cp_pdr->num_of_flow++] =
up2cp_pdr->flow[up2cp_pdr->num_of_flow].fd = 1;
up2cp_pdr->flow[up2cp_pdr->num_of_flow].description =
(char *)"permit out 58 from ff02::2/128 to assigned";
up2cp_pdr->num_of_flow++;
ogs_assert(OGS_OK ==
ogs_pfcp_ip_to_outer_header_creation(
&ogs_gtp_self()->gtpu_ip,

View File

@ -1,5 +1,5 @@
/* Gx Interface, 3GPP TS 29.212 section 4
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -1570,6 +1570,9 @@ static int decode_pcc_rule_definition(
case OGS_DIAM_GX_AVP_CODE_PRECEDENCE:
pcc_rule->precedence = hdr->avp_value->i32;
break;
case OGS_DIAM_GX_AVP_CODE_RATING_GROUP:
pcc_rule->rating_group = hdr->avp_value->i32;
break;
default:
ogs_error("Not implemented(%d)", hdr->avp_code);
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -197,10 +197,13 @@ static void update_authorized_pcc_rule_and_qos(
else if (FlowInformation->flow_direction ==
OpenAPI_flow_direction_DOWNLINK)
flow->direction = OGS_FLOW_DOWNLINK_ONLY;
else if (FlowInformation->flow_direction ==
OpenAPI_flow_direction_BIDIRECTIONAL)
flow->direction = OGS_FLOW_BIDIRECTIONAL;
else {
ogs_fatal("Unsupported direction [%d]",
ogs_error("Unsupported direction [%d]",
FlowInformation->flow_direction);
ogs_assert_if_reached();
continue;
}
flow->description =
@ -542,8 +545,11 @@ bool smf_npcf_smpolicycontrol_handle_create(
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
/* Set UE-to-CP Flow-Description and Outer-Header-Creation */
up2cp_pdr->flow_description[up2cp_pdr->num_of_flow++] =
up2cp_pdr->flow[up2cp_pdr->num_of_flow].fd = 1;
up2cp_pdr->flow[up2cp_pdr->num_of_flow].description =
(char *)"permit out 58 from ff02::2/128 to assigned";
up2cp_pdr->num_of_flow++;
ogs_assert(OGS_OK ==
ogs_pfcp_ip_to_outer_header_creation(
&ogs_gtp_self()->gtpu_ip,

View File

@ -1242,7 +1242,7 @@ void smf_s5c_handle_bearer_resource_command(
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
* -->
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
@ -1260,7 +1260,7 @@ void smf_s5c_handle_bearer_resource_command(
/*
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
* -->
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
@ -1311,7 +1311,7 @@ void smf_s5c_handle_bearer_resource_command(
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
* -->
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
@ -1330,7 +1330,7 @@ void smf_s5c_handle_bearer_resource_command(
/*
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
* -->
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>

View File

@ -1671,6 +1671,107 @@ bson_t *test_db_new_qos_flow(test_ue_t *test_ue)
return doc;
}
bson_t *test_db_new_qos_flow_bi_directional(test_ue_t *test_ue)
{
bson_t *doc = NULL;
ogs_assert(test_ue);
doc = BCON_NEW(
"imsi", BCON_UTF8(test_ue->imsi),
"msisdn", "[",
BCON_UTF8(TEST_MSISDN),
BCON_UTF8(TEST_ADDITIONAL_MSISDN),
"]",
"ambr", "{",
"downlink", "{",
"value", BCON_INT32(1),
"unit", BCON_INT32(3),
"}",
"uplink", "{",
"value", BCON_INT32(1),
"unit", BCON_INT32(3),
"}",
"}",
"slice", "[", "{",
"sst", BCON_INT32(1),
"default_indicator", BCON_BOOL(true),
"session", "[", "{",
"name", BCON_UTF8("internet"),
"type", BCON_INT32(3),
"ambr", "{",
"downlink", "{",
"value", BCON_INT32(1),
"unit", BCON_INT32(3),
"}",
"uplink", "{",
"value", BCON_INT32(1),
"unit", BCON_INT32(3),
"}",
"}",
"qos", "{",
"index", BCON_INT32(9),
"arp", "{",
"priority_level", BCON_INT32(8),
"pre_emption_vulnerability", BCON_INT32(1),
"pre_emption_capability", BCON_INT32(1),
"}",
"}",
"pcc_rule", "[", "{",
"qos", "{",
"index", BCON_INT32(1),
"arp", "{",
"priority_level", BCON_INT32(2),
"pre_emption_vulnerability", BCON_INT32(2),
"pre_emption_capability", BCON_INT32(2),
"}",
"mbr", "{",
"downlink", "{",
"value", BCON_INT32(64),
"unit", BCON_INT32(1),
"}",
"uplink", "{",
"value", BCON_INT32(44),
"unit", BCON_INT32(1),
"}",
"}",
"gbr", "{",
"downlink", "{",
"value", BCON_INT32(64),
"unit", BCON_INT32(1),
"}",
"uplink", "{",
"value", BCON_INT32(44),
"unit", BCON_INT32(1),
"}",
"}",
"}",
"flow", "[",
"{", "direction", BCON_INT32(3),
"description", BCON_UTF8("permit out icmp from any to assigned"), "}",
"{", "direction", BCON_INT32(3),
"description", BCON_UTF8("permit out udp from 10.200.136.98/32 23455 to assigned 1-65535"), "}",
"]",
"}", "]",
"}", "]",
"}", "]",
"security", "{",
"k", BCON_UTF8(test_ue->k_string),
"opc", BCON_UTF8(test_ue->opc_string),
"amf", BCON_UTF8("8000"),
"sqn", BCON_INT64(64),
"}",
"subscribed_rau_tau_timer", BCON_INT32(12),
"network_access_mode", BCON_INT32(0),
"subscriber_status", BCON_INT32(0),
"operator_determined_barring", BCON_INT32(0),
"access_restriction_data", BCON_INT32(32)
);
ogs_assert(doc);
return doc;
}
bson_t *test_db_new_session(test_ue_t *test_ue)
{
bson_t *doc = NULL;

View File

@ -530,6 +530,7 @@ int test_db_remove_ue(test_ue_t *test_ue);
bson_t *test_db_new_simple(test_ue_t *test_ue);
bson_t *test_db_new_qos_flow(test_ue_t *test_ue);
bson_t *test_db_new_qos_flow_bi_directional(test_ue_t *test_ue);
bson_t *test_db_new_session(test_ue_t *test_ue);
bson_t *test_db_new_ims(test_ue_t *test_ue);
bson_t *test_db_new_slice_with_same_dnn(test_ue_t *test_ue);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -19,7 +19,7 @@
#include "test-common.h"
static void test1_func(abts_case *tc, void *data)
static void uni_directional_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *s1ap;
@ -262,11 +262,255 @@ static void test1_func(abts_case *tc, void *data)
test_ue_remove(test_ue);
}
static void bi_directional_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *s1ap;
ogs_socknode_t *gtpu;
ogs_pkbuf_t *emmbuf;
ogs_pkbuf_t *esmbuf;
ogs_pkbuf_t *sendbuf;
ogs_pkbuf_t *recvbuf;
ogs_s1ap_message_t message;
ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci;
test_ue_t *test_ue = NULL;
test_sess_t *sess = NULL;
test_bearer_t *bearer = NULL;
bson_t *doc = NULL;
/* Setup Test UE & Session Context */
memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci));
mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI;
mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI;
mobile_identity_suci.routing_indicator1 = 0;
mobile_identity_suci.routing_indicator2 = 0xf;
mobile_identity_suci.routing_indicator3 = 0xf;
mobile_identity_suci.routing_indicator4 = 0xf;
mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL;
mobile_identity_suci.home_network_pki_value = 0;
test_ue = test_ue_add_by_suci(&mobile_identity_suci, "1032548691");
ogs_assert(test_ue);
test_ue->e_cgi.cell_id = 0x1079baf;
test_ue->nas.ksi = 0;
test_ue->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH;
test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc";
test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca";
sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP2_RAT_TYPE_EUTRAN);
ogs_assert(sess);
/* eNB connects to MME */
s1ap = tests1ap_client(AF_INET);
ABTS_PTR_NOTNULL(tc, s1ap);
/* eNB connects to SGW */
gtpu = test_gtpu_server(1, AF_INET);
ABTS_PTR_NOTNULL(tc, gtpu);
/* Send S1-Setup Reqeust */
sendbuf = test_s1ap_build_s1_setup_request(
S1AP_ENB_ID_PR_macroENB_ID, 0x54f64);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive S1-Setup Response */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(NULL, recvbuf);
/********** Insert Subscriber in Database */
doc = test_db_new_qos_flow_bi_directional(test_ue);
ABTS_PTR_NOTNULL(tc, doc);
ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc));
/* Send Attach Request */
memset(&sess->pdn_connectivity_param,
0, sizeof(sess->pdn_connectivity_param));
sess->pdn_connectivity_param.eit = 1;
sess->pdn_connectivity_param.request_type =
OGS_NAS_EPS_REQUEST_TYPE_INITIAL;
esmbuf = testesm_build_pdn_connectivity_request(sess, false);
ABTS_PTR_NOTNULL(tc, esmbuf);
memset(&test_ue->attach_request_param,
0, sizeof(test_ue->attach_request_param));
test_ue->attach_request_param.drx_parameter = 1;
test_ue->attach_request_param.ms_network_capability = 1;
test_ue->attach_request_param.tmsi_status = 1;
test_ue->attach_request_param.mobile_station_classmark_2 = 1;
test_ue->attach_request_param.ue_usage_setting = 1;
emmbuf = testemm_build_attach_request(test_ue, esmbuf, false, false);
ABTS_PTR_NOTNULL(tc, emmbuf);
memset(&test_ue->initial_ue_param, 0, sizeof(test_ue->initial_ue_param));
sendbuf = test_s1ap_build_initial_ue_message(
test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Signalling, false);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Authentication Request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send Authentication response */
emmbuf = testemm_build_authentication_response(test_ue);
ABTS_PTR_NOTNULL(tc, emmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Security mode Command */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send Security mode complete */
test_ue->mobile_identity_imeisv_presence = true;
emmbuf = testemm_build_security_mode_complete(test_ue);
ABTS_PTR_NOTNULL(tc, emmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive ESM Information Request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send ESM Information Response */
sess->esm_information_param.pco = 1;
esmbuf = testesm_build_esm_information_response(sess);
ABTS_PTR_NOTNULL(tc, esmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Initial Context Setup Request +
* Attach Accept +
* Activate Default Bearer Context Request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send UE Capability Info Indication */
sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Initial Context Setup Response */
sendbuf = test_s1ap_build_initial_context_setup_response(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Attach Complete + Activate default EPS bearer cotext accept */
test_ue->nr_cgi.cell_id = 0x1234502;
bearer = test_bearer_find_by_ue_ebi(test_ue, 5);
ogs_assert(bearer);
esmbuf = testesm_build_activate_default_eps_bearer_context_accept(
bearer, false);
ABTS_PTR_NOTNULL(tc, esmbuf);
emmbuf = testemm_build_attach_complete(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, emmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive EMM information */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Receive E-RABSetupRequest +
* Activate dedicated EPS bearer context request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
S1AP_ProcedureCode_id_E_RABSetup,
test_ue->s1ap_procedure_code);
/* Send E-RABSetupResponse */
bearer = test_bearer_find_by_ue_ebi(test_ue, 6);
ogs_assert(bearer);
sendbuf = test_s1ap_build_e_rab_setup_response(bearer);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Activate dedicated EPS bearer context accept */
esmbuf = testesm_build_activate_dedicated_eps_bearer_context_accept(bearer);
ABTS_PTR_NOTNULL(tc, esmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
ogs_msleep(100);
/* Send GTP-U ICMP Packet */
bearer = test_bearer_find_by_ue_ebi(test_ue, 6);
ogs_assert(bearer);
rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send UE Context Release Request */
sendbuf = test_s1ap_build_ue_context_release_request(test_ue,
S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_user_inactivity);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive UE Context Release Command */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send UE Context Release Complete */
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
ogs_msleep(300);
/********** Remove Subscriber in Database */
ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue));
/* eNB disonncect from MME */
testenb_s1ap_close(s1ap);
/* eNB disonncect from SGW */
test_gtpu_close(gtpu);
test_ue_remove(test_ue);
}
abts_suite *test_bearer(abts_suite *suite)
{
suite = ADD_SUITE(suite)
abts_run_test(suite, test1_func, NULL);
abts_run_test(suite, uni_directional_func, NULL);
abts_run_test(suite, bi_directional_func, NULL);
return suite;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -19,7 +19,7 @@
#include "test-common.h"
static void test1_func(abts_case *tc, void *data)
static void uni_directional_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *ngap;
@ -411,11 +411,398 @@ static void test1_func(abts_case *tc, void *data)
test_ue_remove(test_ue);
}
static void bi_directional_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *ngap;
ogs_socknode_t *gtpu;
ogs_pkbuf_t *gmmbuf;
ogs_pkbuf_t *gsmbuf;
ogs_pkbuf_t *nasbuf;
ogs_pkbuf_t *sendbuf;
ogs_pkbuf_t *recvbuf;
ogs_ngap_message_t message;
int i;
uint8_t tmp[OGS_HUGE_LEN];
char *_gtp_payload = "34ff0024"
"0000000100000085 010002004500001c 0c0b000040015a7a 0a2d00010a2d0002"
"00000964cd7c291f";
ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci;
test_ue_t *test_ue = NULL;
test_sess_t *sess = NULL;
test_bearer_t *qos_flow = NULL;
bson_t *doc = NULL;
/* Setup Test UE & Session Context */
memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci));
mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI;
mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI;
mobile_identity_suci.routing_indicator1 = 0;
mobile_identity_suci.routing_indicator2 = 0xf;
mobile_identity_suci.routing_indicator3 = 0xf;
mobile_identity_suci.routing_indicator4 = 0xf;
mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL;
mobile_identity_suci.home_network_pki_value = 0;
test_ue = test_ue_add_by_suci(&mobile_identity_suci, "0000203190");
ogs_assert(test_ue);
test_ue->nr_cgi.cell_id = 0x40001;
test_ue->nas.registration.tsc = 0;
test_ue->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE;
test_ue->nas.registration.follow_on_request = 1;
test_ue->nas.registration.value = OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL;
test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc";
test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca";
/* gNB connects to AMF */
ngap = testngap_client(AF_INET);
ABTS_PTR_NOTNULL(tc, ngap);
/* gNB connects to UPF */
gtpu = test_gtpu_server(1, AF_INET);
ABTS_PTR_NOTNULL(tc, gtpu);
/* Send NG-Setup Reqeust */
sendbuf = testngap_build_ng_setup_request(0x4000, 22);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive NG-Setup Response */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/********** Insert Subscriber in Database */
doc = test_db_new_qos_flow_bi_directional(test_ue);
ABTS_PTR_NOTNULL(tc, doc);
ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc));
/* Send Registration request */
test_ue->registration_request_param.guti = 1;
gmmbuf = testgmm_build_registration_request(test_ue, NULL, false, false);
ABTS_PTR_NOTNULL(tc, gmmbuf);
test_ue->registration_request_param.gmm_capability = 1;
test_ue->registration_request_param.requested_nssai = 1;
test_ue->registration_request_param.last_visited_registered_tai = 1;
test_ue->registration_request_param.ue_usage_setting = 1;
nasbuf = testgmm_build_registration_request(test_ue, NULL, false, false);
ABTS_PTR_NOTNULL(tc, nasbuf);
sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf,
NGAP_RRCEstablishmentCause_mo_Signalling, false, true);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Identity request */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Identity response */
gmmbuf = testgmm_build_identity_response(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Authentication request */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Authentication response */
gmmbuf = testgmm_build_authentication_response(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Security mode command */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Security mode complete */
gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive InitialContextSetupRequest +
* Registration accept */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_InitialContextSetup,
test_ue->ngap_procedure_code);
/* Send UERadioCapabilityInfoIndication */
sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send InitialContextSetupResponse */
sendbuf = testngap_build_initial_context_setup_response(test_ue, false);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send Registration complete */
gmmbuf = testgmm_build_registration_complete(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Configuration update command */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send PDU session establishment request */
sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5);
ogs_assert(sess);
sess->ul_nas_transport_param.request_type =
OGS_NAS_5GS_REQUEST_TYPE_INITIAL;
sess->ul_nas_transport_param.dnn = 1;
sess->ul_nas_transport_param.s_nssai = 1;
sess->pdu_session_establishment_param.ssc_mode = 1;
sess->pdu_session_establishment_param.epco = 1;
gsmbuf = testgsm_build_pdu_session_establishment_request(sess);
ABTS_PTR_NOTNULL(tc, gsmbuf);
gmmbuf = testgmm_build_ul_nas_transport(sess,
OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive PDUSessionResourceSetupRequest +
* DL NAS transport +
* PDU session establishment accept */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_PDUSessionResourceSetup,
test_ue->ngap_procedure_code);
/* Send GTP-U ICMP Packet */
qos_flow = test_qos_flow_find_by_qfi(sess, 1);
ogs_assert(qos_flow);
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send PDUSessionResourceSetupResponse */
sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = testgnb_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = testgnb_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Receive PDUSessionResourceModifyRequest +
* DL NAS transport +
* PDU session modification command */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_PDUSessionResourceModify,
test_ue->ngap_procedure_code);
/* Send PDU session resource modify response */
qos_flow = test_qos_flow_find_by_qfi(sess, 2);
ogs_assert(qos_flow);
sendbuf = testngap_build_qos_flow_resource_modify_response(qos_flow);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Send PDU session resource modify complete */
sess->ul_nas_transport_param.request_type =
OGS_NAS_5GS_REQUEST_TYPE_MODIFICATION_REQUEST;
sess->ul_nas_transport_param.dnn = 0;
sess->ul_nas_transport_param.s_nssai = 0;
sess->pdu_session_establishment_param.ssc_mode = 0;
sess->pdu_session_establishment_param.epco = 0;
gsmbuf = testgsm_build_pdu_session_modification_complete(sess);
ABTS_PTR_NOTNULL(tc, gsmbuf);
gmmbuf = testgmm_build_ul_nas_transport(sess,
OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Waiting for creating dedicated QoS flow in PFCP protocol */
ogs_msleep(100);
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = testgnb_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send UEContextReleaseRequest */
sendbuf = testngap_build_ue_context_release_request(test_ue,
NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity,
true);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive UEContextReleaseCommand */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_UEContextRelease,
test_ue->ngap_procedure_code);
/* Send UEContextReleaseComplete */
sendbuf = testngap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/*
* Send InitialUEMessage +
* Service request
* - Uplink Data Status
*/
test_ue->service_request_param.uplink_data_status = 1;
test_ue->service_request_param.psimask.uplink_data_status = 1 << sess->psi;
test_ue->service_request_param.pdu_session_status = 0;
nasbuf = testgmm_build_service_request(
test_ue, OGS_NAS_SERVICE_TYPE_DATA, NULL, false, false);
ABTS_PTR_NOTNULL(tc, nasbuf);
test_ue->service_request_param.uplink_data_status = 0;
test_ue->service_request_param.pdu_session_status = 0;
gmmbuf = testgmm_build_service_request(
test_ue, OGS_NAS_SERVICE_TYPE_DATA, nasbuf, true, false);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf,
NGAP_RRCEstablishmentCause_mo_Signalling, true, true);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive InitialContextSetupRequest +
* Service accept */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_InitialContextSetup,
test_ue->ngap_procedure_code);
ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_status);
ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result);
/* Send InitialContextSetupResponse */
sendbuf = testngap_build_initial_context_setup_response(test_ue, true);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Wait to setup N3 data connection.
* Otherwise, network-triggered service request is initiated */
ogs_msleep(100);
/* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive GTP-U ICMP Packet */
recvbuf = testgnb_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
/* Send De-registration request */
gmmbuf = testgmm_build_de_registration_request(test_ue, 1, true, true);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive UEContextReleaseCommand */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_UEContextRelease,
test_ue->ngap_procedure_code);
/* Send UEContextReleaseComplete */
sendbuf = testngap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
ogs_msleep(300);
/********** Remove Subscriber in Database */
ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue));
/* gNB disonncect from UPF */
testgnb_gtpu_close(gtpu);
/* gNB disonncect from AMF */
testgnb_ngap_close(ngap);
/* Clear Test UE Context */
test_ue_remove(test_ue);
}
abts_suite *test_qos_flow(abts_suite *suite)
{
suite = ADD_SUITE(suite)
abts_run_test(suite, test1_func, NULL);
abts_run_test(suite, uni_directional_func, NULL);
abts_run_test(suite, bi_directional_func, NULL);
return suite;
}