diff --git a/configs/open5gs/pcrf.yaml.in b/configs/open5gs/pcrf.yaml.in index a457270a4..118f15c76 100644 --- a/configs/open5gs/pcrf.yaml.in +++ b/configs/open5gs/pcrf.yaml.in @@ -40,11 +40,6 @@ pcrf: # o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. # prefer_ipv4: true # -# o Legacy support for pre-release LTE 11 devices to do calling -# - Replace IPv4/v6 local addr field in AAR Media-Subcomponent AVP -# by 'any local port' -# no_ipv4v6_local_addr_in_packet_filter: true -# parameter: # diff --git a/configs/open5gs/smf.yaml.in b/configs/open5gs/smf.yaml.in index ac862dfeb..c462b8e51 100644 --- a/configs/open5gs/smf.yaml.in +++ b/configs/open5gs/smf.yaml.in @@ -458,6 +458,10 @@ upf: # o Disable selection of UPF PFCP in Round-Robin manner # no_pfcp_rr_select: true # +# o Legacy support for pre-release LTE 11 devices +# - Omits adding local address in packet filters for compatibility +# no_ipv4v6_local_addr_in_packet_filter: true +# parameter: # diff --git a/lib/ipfw/ogs-ipfw.c b/lib/ipfw/ogs-ipfw.c index 203a9ed3d..0e0e2ced4 100644 --- a/lib/ipfw/ogs-ipfw.c +++ b/lib/ipfw/ogs-ipfw.c @@ -365,7 +365,8 @@ void ogs_ipfw_rule_swap(ogs_ipfw_rule_t *ipfw_rule) } void ogs_pf_content_from_ipfw_rule( - uint8_t direction, ogs_pf_content_t *content, ogs_ipfw_rule_t *rule) + uint8_t direction, ogs_pf_content_t *content, ogs_ipfw_rule_t *rule, + bool no_ipv4v6_local_addr_in_packet_filter) { int j, len; @@ -380,57 +381,112 @@ void ogs_pf_content_from_ipfw_rule( j++; len += 2; } - if (rule->ipv4_src) { - if (direction == OGS_FLOW_DOWNLINK_ONLY) - content->component[j].type = - OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE; - else - content->component[j].type = - OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE; + /* + * As per 3GPP TS 24.008, following Packet filter component type identifier + * are not supported on the LTE pre release-11 UEs: + * + * IPv4 local address type + * IPv6 remote address/prefix length type + * IPv6 local address/prefix length type + * + * And, + * IPv6 remote address/prefix length type and + * IPv6 local address/prefix length type shall be used when both MS and + * 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_dst) { - if (direction == OGS_FLOW_DOWNLINK_ONLY) - content->component[j].type = - OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE; - else - content->component[j].type = - OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE; + 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->ipv6_src) { - if (direction == OGS_FLOW_DOWNLINK_ONLY) - content->component[j].type = - OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE; - else - 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; + 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_dst) { - if (direction == OGS_FLOW_DOWNLINK_ONLY) + if (rule->ipv6_src && (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; - else + 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, + 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; + } + } + + if (rule->ipv6_src && (direction == 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; + } + } + + 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; + 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 = + 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; + } } if (rule->port.src.low) { diff --git a/lib/ipfw/ogs-ipfw.h b/lib/ipfw/ogs-ipfw.h index e45ec482f..24df8af5f 100644 --- a/lib/ipfw/ogs-ipfw.h +++ b/lib/ipfw/ogs-ipfw.h @@ -130,7 +130,8 @@ typedef struct ogs_pf_content_s { } ogs_pf_content_t; void ogs_pf_content_from_ipfw_rule( - uint8_t direction, ogs_pf_content_t *content, ogs_ipfw_rule_t *rule); + uint8_t direction, ogs_pf_content_t *content, ogs_ipfw_rule_t *rule, + bool no_ipv4v6_local_addr_in_packet_filter); #ifdef __cplusplus } diff --git a/src/pcrf/pcrf-rx-path.c b/src/pcrf/pcrf-rx-path.c index 7ef6a7cb8..df8cd4420 100644 --- a/src/pcrf/pcrf-rx-path.c +++ b/src/pcrf/pcrf-rx-path.c @@ -92,8 +92,6 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp, { int rv; int ret; - int len; - char *from_str, *to_str, *rx_flow, *to_port, *to_ip, *from_ip, *from_port; struct msg *ans, *qry; struct avp *avpch1, *avpch2, *avpch3; @@ -295,117 +293,10 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp, ogs_assert(sub->num_of_flow < OGS_MAX_NUM_OF_FLOW_IN_MEDIA_SUB_COMPONENT); flow = &sub->flow[sub->num_of_flow]; - - /* IE (IPV4-local-addr field ) is not supported on - * the LTE pre release-11 UEs. In order for the call - * to work the local address in packet filter must - * be replaced by 'any local port'. - */ - if (ogs_app()-> - parameter.no_ipv4v6_local_addr_in_packet_filter - == true) { - rx_flow = NULL; - rx_flow = (char*)hdr->avp_value->os.data; - len = hdr->avp_value->os.len; - - from_str = NULL; - to_str = NULL; - to_ip = NULL; - to_port = NULL; - from_ip = NULL; - from_port = NULL; - from_str = strstr(rx_flow, "from"); - ogs_assert(from_str); - to_str = strstr(rx_flow, "to"); - ogs_assert(to_str); - - if (!strncmp(rx_flow, - "permit out", strlen("permit out"))) { - - to_ip = strstr(to_str, " "); - ogs_assert(to_ip); - - // Exclude the starting whitespace - to_ip += 1; - - to_port = strstr(to_ip, " "); - // Test for no port - if (to_port != NULL) { - flow->description = ogs_calloc(1, - len - strlen(to_str) + - strlen("to any") - + strlen(to_port) + 1); - ogs_assert(flow->description); - } else { - flow->description = ogs_calloc(1, - len - strlen(to_str) + - strlen("to any") + 1); - ogs_assert(flow->description); - } - - ogs_assert(flow->description); - strncat(flow->description, - rx_flow, - len - strlen(to_str)); - strcat(flow->description, "to any"); - if (to_port != NULL) { - strncat(flow->description, - to_port, strlen(to_port)); - } - } else if (!strncmp(rx_flow, - "permit in", strlen("permit in"))) { - - from_ip = strstr(from_str, " "); - ogs_assert(from_ip); - - /* Exclude the starting whitespace */ - from_ip += 1; - - from_port = strstr(from_ip, " "); - /* Test for no port + - * whether from_port is at "to" - * without any from port */ - if (from_port != NULL && - strncmp(from_port, " to", 3)) { - flow->description = ogs_calloc(1, - len - strlen(from_str) + - strlen(to_str) - + strlen("from any") + 1 - + (strlen(from_port) - - strlen(to_str))); - ogs_assert(flow->description); - } else { - flow->description = ogs_calloc(1, - len - strlen(from_str) + - strlen(to_str) - + strlen("from any ") + 1); - ogs_assert(flow->description); - } - - ogs_assert(flow->description); - strncat(flow->description, - rx_flow, - len - strlen(from_str)); - if (from_port != NULL && - strncmp(from_port, " to", 3)) { - strcat(flow->description, "from any"); - strncat(flow->description, - from_port, - strlen(from_port) - strlen(to_str)); - } else { - strcat(flow->description, "from any "); - } - strncat(flow->description, - to_str, - strlen(to_str)); - } - } else { - flow->description = ogs_strndup( + flow->description = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(flow->description); - } - + ogs_assert(flow->description); sub->num_of_flow++; break; default: diff --git a/src/smf/binding.c b/src/smf/binding.c index 81f14f109..ea65197b2 100644 --- a/src/smf/binding.c +++ b/src/smf/binding.c @@ -101,7 +101,9 @@ static void encode_traffic_flow_template( tft->pf[i].precedence = pf->precedence - 1; ogs_pf_content_from_ipfw_rule( - pf->direction, &tft->pf[i].content, &pf->ipfw_rule); + pf->direction, &tft->pf[i].content, &pf->ipfw_rule, + ogs_app()-> + parameter.no_ipv4v6_local_addr_in_packet_filter); } i++; diff --git a/src/smf/gsm-build.c b/src/smf/gsm-build.c index d688f9666..970d222aa 100644 --- a/src/smf/gsm-build.c +++ b/src/smf/gsm-build.c @@ -282,7 +282,8 @@ static void encode_qos_rule_packet_filter( qos_rule->pf[i].identifier = pf->identifier; ogs_pf_content_from_ipfw_rule( - pf->direction, &qos_rule->pf[i].content, &pf->ipfw_rule); + pf->direction, &qos_rule->pf[i].content, &pf->ipfw_rule, + ogs_app()->parameter.no_ipv4v6_local_addr_in_packet_filter); i++; } qos_rule->num_of_packet_filter = i;