162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2020, Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* flow director ethtool support for iavf */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "iavf.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define GTPU_PORT	2152
962306a36Sopenharmony_ci#define NAT_T_ESP_PORT	4500
1062306a36Sopenharmony_ci#define PFCP_PORT	8805
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic const struct in6_addr ipv6_addr_full_mask = {
1362306a36Sopenharmony_ci	.in6_u = {
1462306a36Sopenharmony_ci		.u6_addr8 = {
1562306a36Sopenharmony_ci			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1662306a36Sopenharmony_ci			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1762306a36Sopenharmony_ci		}
1862306a36Sopenharmony_ci	}
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic const struct in6_addr ipv6_addr_zero_mask = {
2262306a36Sopenharmony_ci	.in6_u = {
2362306a36Sopenharmony_ci		.u6_addr8 = {
2462306a36Sopenharmony_ci			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2562306a36Sopenharmony_ci		}
2662306a36Sopenharmony_ci	}
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/**
3062306a36Sopenharmony_ci * iavf_validate_fdir_fltr_masks - validate Flow Director filter fields masks
3162306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
3262306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * Returns 0 if all masks of packet fields are either full or empty. Returns
3562306a36Sopenharmony_ci * error on at least one partial mask.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ciint iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,
3862306a36Sopenharmony_ci				  struct iavf_fdir_fltr *fltr)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	if (fltr->eth_mask.etype && fltr->eth_mask.etype != htons(U16_MAX))
4162306a36Sopenharmony_ci		goto partial_mask;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (fltr->ip_ver == 4) {
4462306a36Sopenharmony_ci		if (fltr->ip_mask.v4_addrs.src_ip &&
4562306a36Sopenharmony_ci		    fltr->ip_mask.v4_addrs.src_ip != htonl(U32_MAX))
4662306a36Sopenharmony_ci			goto partial_mask;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci		if (fltr->ip_mask.v4_addrs.dst_ip &&
4962306a36Sopenharmony_ci		    fltr->ip_mask.v4_addrs.dst_ip != htonl(U32_MAX))
5062306a36Sopenharmony_ci			goto partial_mask;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		if (fltr->ip_mask.tos && fltr->ip_mask.tos != U8_MAX)
5362306a36Sopenharmony_ci			goto partial_mask;
5462306a36Sopenharmony_ci	} else if (fltr->ip_ver == 6) {
5562306a36Sopenharmony_ci		if (memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_zero_mask,
5662306a36Sopenharmony_ci			   sizeof(struct in6_addr)) &&
5762306a36Sopenharmony_ci		    memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
5862306a36Sopenharmony_ci			   sizeof(struct in6_addr)))
5962306a36Sopenharmony_ci			goto partial_mask;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		if (memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_zero_mask,
6262306a36Sopenharmony_ci			   sizeof(struct in6_addr)) &&
6362306a36Sopenharmony_ci		    memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
6462306a36Sopenharmony_ci			   sizeof(struct in6_addr)))
6562306a36Sopenharmony_ci			goto partial_mask;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		if (fltr->ip_mask.tclass && fltr->ip_mask.tclass != U8_MAX)
6862306a36Sopenharmony_ci			goto partial_mask;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (fltr->ip_mask.proto && fltr->ip_mask.proto != U8_MAX)
7262306a36Sopenharmony_ci		goto partial_mask;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (fltr->ip_mask.src_port && fltr->ip_mask.src_port != htons(U16_MAX))
7562306a36Sopenharmony_ci		goto partial_mask;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (fltr->ip_mask.dst_port && fltr->ip_mask.dst_port != htons(U16_MAX))
7862306a36Sopenharmony_ci		goto partial_mask;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (fltr->ip_mask.spi && fltr->ip_mask.spi != htonl(U32_MAX))
8162306a36Sopenharmony_ci		goto partial_mask;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (fltr->ip_mask.l4_header &&
8462306a36Sopenharmony_ci	    fltr->ip_mask.l4_header != htonl(U32_MAX))
8562306a36Sopenharmony_ci		goto partial_mask;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return 0;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cipartial_mask:
9062306a36Sopenharmony_ci	dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, partial masks are not supported\n");
9162306a36Sopenharmony_ci	return -EOPNOTSUPP;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/**
9562306a36Sopenharmony_ci * iavf_pkt_udp_no_pay_len - the length of UDP packet without payload
9662306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_cistatic u16 iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr *fltr)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	return sizeof(struct ethhdr) +
10162306a36Sopenharmony_ci	       (fltr->ip_ver == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) +
10262306a36Sopenharmony_ci	       sizeof(struct udphdr);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/**
10662306a36Sopenharmony_ci * iavf_fill_fdir_gtpu_hdr - fill the GTP-U protocol header
10762306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
10862306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
10962306a36Sopenharmony_ci *
11062306a36Sopenharmony_ci * Returns 0 if the GTP-U protocol header is set successfully
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_cistatic int
11362306a36Sopenharmony_ciiavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr *fltr,
11462306a36Sopenharmony_ci			struct virtchnl_proto_hdrs *proto_hdrs)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
11762306a36Sopenharmony_ci	struct virtchnl_proto_hdr *ghdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
11862306a36Sopenharmony_ci	struct virtchnl_proto_hdr *ehdr = NULL; /* Extension Header if it exists */
11962306a36Sopenharmony_ci	u16 adj_offs, hdr_offs;
12062306a36Sopenharmony_ci	int i;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(ghdr, GTPU_IP);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	adj_offs = iavf_pkt_udp_no_pay_len(fltr);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	for (i = 0; i < fltr->flex_cnt; i++) {
12762306a36Sopenharmony_ci#define IAVF_GTPU_HDR_TEID_OFFS0	4
12862306a36Sopenharmony_ci#define IAVF_GTPU_HDR_TEID_OFFS1	6
12962306a36Sopenharmony_ci#define IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS	10
13062306a36Sopenharmony_ci#define IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK		0x00FF /* skip N_PDU */
13162306a36Sopenharmony_ci/* PDU Session Container Extension Header (PSC) */
13262306a36Sopenharmony_ci#define IAVF_GTPU_PSC_EXTHDR_TYPE			0x85
13362306a36Sopenharmony_ci#define IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS		13
13462306a36Sopenharmony_ci#define IAVF_GTPU_HDR_PSC_PDU_QFI_MASK			0x3F /* skip Type */
13562306a36Sopenharmony_ci#define IAVF_GTPU_EH_QFI_IDX				1
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		if (fltr->flex_words[i].offset < adj_offs)
13862306a36Sopenharmony_ci			return -EINVAL;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		hdr_offs = fltr->flex_words[i].offset - adj_offs;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		switch (hdr_offs) {
14362306a36Sopenharmony_ci		case IAVF_GTPU_HDR_TEID_OFFS0:
14462306a36Sopenharmony_ci		case IAVF_GTPU_HDR_TEID_OFFS1: {
14562306a36Sopenharmony_ci			__be16 *pay_word = (__be16 *)ghdr->buffer;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci			pay_word[hdr_offs >> 1] = htons(fltr->flex_words[i].word);
14862306a36Sopenharmony_ci			VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ghdr, GTPU_IP, TEID);
14962306a36Sopenharmony_ci			}
15062306a36Sopenharmony_ci			break;
15162306a36Sopenharmony_ci		case IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS:
15262306a36Sopenharmony_ci			if ((fltr->flex_words[i].word &
15362306a36Sopenharmony_ci			     IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK) !=
15462306a36Sopenharmony_ci						IAVF_GTPU_PSC_EXTHDR_TYPE)
15562306a36Sopenharmony_ci				return -EOPNOTSUPP;
15662306a36Sopenharmony_ci			if (!ehdr)
15762306a36Sopenharmony_ci				ehdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
15862306a36Sopenharmony_ci			VIRTCHNL_SET_PROTO_HDR_TYPE(ehdr, GTPU_EH);
15962306a36Sopenharmony_ci			break;
16062306a36Sopenharmony_ci		case IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS:
16162306a36Sopenharmony_ci			if (!ehdr)
16262306a36Sopenharmony_ci				return -EINVAL;
16362306a36Sopenharmony_ci			ehdr->buffer[IAVF_GTPU_EH_QFI_IDX] =
16462306a36Sopenharmony_ci					fltr->flex_words[i].word &
16562306a36Sopenharmony_ci						IAVF_GTPU_HDR_PSC_PDU_QFI_MASK;
16662306a36Sopenharmony_ci			VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ehdr, GTPU_EH, QFI);
16762306a36Sopenharmony_ci			break;
16862306a36Sopenharmony_ci		default:
16962306a36Sopenharmony_ci			return -EINVAL;
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return 0;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/**
17962306a36Sopenharmony_ci * iavf_fill_fdir_pfcp_hdr - fill the PFCP protocol header
18062306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
18162306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * Returns 0 if the PFCP protocol header is set successfully
18462306a36Sopenharmony_ci */
18562306a36Sopenharmony_cistatic int
18662306a36Sopenharmony_ciiavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr *fltr,
18762306a36Sopenharmony_ci			struct virtchnl_proto_hdrs *proto_hdrs)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
19062306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
19162306a36Sopenharmony_ci	u16 adj_offs, hdr_offs;
19262306a36Sopenharmony_ci	int i;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, PFCP);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	adj_offs = iavf_pkt_udp_no_pay_len(fltr);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	for (i = 0; i < fltr->flex_cnt; i++) {
19962306a36Sopenharmony_ci#define IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS	0
20062306a36Sopenharmony_ci		if (fltr->flex_words[i].offset < adj_offs)
20162306a36Sopenharmony_ci			return -EINVAL;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		hdr_offs = fltr->flex_words[i].offset - adj_offs;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		switch (hdr_offs) {
20662306a36Sopenharmony_ci		case IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS:
20762306a36Sopenharmony_ci			hdr->buffer[0] = (fltr->flex_words[i].word >> 8) & 0xff;
20862306a36Sopenharmony_ci			VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, PFCP, S_FIELD);
20962306a36Sopenharmony_ci			break;
21062306a36Sopenharmony_ci		default:
21162306a36Sopenharmony_ci			return -EINVAL;
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return 0;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/**
22162306a36Sopenharmony_ci * iavf_fill_fdir_nat_t_esp_hdr - fill the NAT-T-ESP protocol header
22262306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
22362306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
22462306a36Sopenharmony_ci *
22562306a36Sopenharmony_ci * Returns 0 if the NAT-T-ESP protocol header is set successfully
22662306a36Sopenharmony_ci */
22762306a36Sopenharmony_cistatic int
22862306a36Sopenharmony_ciiavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr *fltr,
22962306a36Sopenharmony_ci			     struct virtchnl_proto_hdrs *proto_hdrs)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
23262306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
23362306a36Sopenharmony_ci	u16 adj_offs, hdr_offs;
23462306a36Sopenharmony_ci	u32 spi = 0;
23562306a36Sopenharmony_ci	int i;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	adj_offs = iavf_pkt_udp_no_pay_len(fltr);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	for (i = 0; i < fltr->flex_cnt; i++) {
24262306a36Sopenharmony_ci#define IAVF_NAT_T_ESP_SPI_OFFS0	0
24362306a36Sopenharmony_ci#define IAVF_NAT_T_ESP_SPI_OFFS1	2
24462306a36Sopenharmony_ci		if (fltr->flex_words[i].offset < adj_offs)
24562306a36Sopenharmony_ci			return -EINVAL;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		hdr_offs = fltr->flex_words[i].offset - adj_offs;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		switch (hdr_offs) {
25062306a36Sopenharmony_ci		case IAVF_NAT_T_ESP_SPI_OFFS0:
25162306a36Sopenharmony_ci			spi |= fltr->flex_words[i].word << 16;
25262306a36Sopenharmony_ci			break;
25362306a36Sopenharmony_ci		case IAVF_NAT_T_ESP_SPI_OFFS1:
25462306a36Sopenharmony_ci			spi |= fltr->flex_words[i].word;
25562306a36Sopenharmony_ci			break;
25662306a36Sopenharmony_ci		default:
25762306a36Sopenharmony_ci			return -EINVAL;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (!spi)
26262306a36Sopenharmony_ci		return -EOPNOTSUPP; /* Not support IKE Header Format with SPI 0 */
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	*(__be32 *)hdr->buffer = htonl(spi);
26562306a36Sopenharmony_ci	VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return 0;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/**
27362306a36Sopenharmony_ci * iavf_fill_fdir_udp_flex_pay_hdr - fill the UDP payload header
27462306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
27562306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * Returns 0 if the UDP payload defined protocol header is set successfully
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_cistatic int
28062306a36Sopenharmony_ciiavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr *fltr,
28162306a36Sopenharmony_ci				struct virtchnl_proto_hdrs *proto_hdrs)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	int err;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	switch (ntohs(fltr->ip_data.dst_port)) {
28662306a36Sopenharmony_ci	case GTPU_PORT:
28762306a36Sopenharmony_ci		err = iavf_fill_fdir_gtpu_hdr(fltr, proto_hdrs);
28862306a36Sopenharmony_ci		break;
28962306a36Sopenharmony_ci	case NAT_T_ESP_PORT:
29062306a36Sopenharmony_ci		err = iavf_fill_fdir_nat_t_esp_hdr(fltr, proto_hdrs);
29162306a36Sopenharmony_ci		break;
29262306a36Sopenharmony_ci	case PFCP_PORT:
29362306a36Sopenharmony_ci		err = iavf_fill_fdir_pfcp_hdr(fltr, proto_hdrs);
29462306a36Sopenharmony_ci		break;
29562306a36Sopenharmony_ci	default:
29662306a36Sopenharmony_ci		err = -EOPNOTSUPP;
29762306a36Sopenharmony_ci		break;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return err;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/**
30462306a36Sopenharmony_ci * iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header
30562306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
30662306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
30762306a36Sopenharmony_ci *
30862306a36Sopenharmony_ci * Returns 0 if the IPv4 protocol header is set successfully
30962306a36Sopenharmony_ci */
31062306a36Sopenharmony_cistatic int
31162306a36Sopenharmony_ciiavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr,
31262306a36Sopenharmony_ci		       struct virtchnl_proto_hdrs *proto_hdrs)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
31562306a36Sopenharmony_ci	struct iphdr *iph = (struct iphdr *)hdr->buffer;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (fltr->ip_mask.tos == U8_MAX) {
32062306a36Sopenharmony_ci		iph->tos = fltr->ip_data.tos;
32162306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DSCP);
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (fltr->ip_mask.proto == U8_MAX) {
32562306a36Sopenharmony_ci		iph->protocol = fltr->ip_data.proto;
32662306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, PROT);
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (fltr->ip_mask.v4_addrs.src_ip == htonl(U32_MAX)) {
33062306a36Sopenharmony_ci		iph->saddr = fltr->ip_data.v4_addrs.src_ip;
33162306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (fltr->ip_mask.v4_addrs.dst_ip == htonl(U32_MAX)) {
33562306a36Sopenharmony_ci		iph->daddr = fltr->ip_data.v4_addrs.dst_ip;
33662306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	return 0;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci/**
34362306a36Sopenharmony_ci * iavf_fill_fdir_ip6_hdr - fill the IPv6 protocol header
34462306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
34562306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
34662306a36Sopenharmony_ci *
34762306a36Sopenharmony_ci * Returns 0 if the IPv6 protocol header is set successfully
34862306a36Sopenharmony_ci */
34962306a36Sopenharmony_cistatic int
35062306a36Sopenharmony_ciiavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr,
35162306a36Sopenharmony_ci		       struct virtchnl_proto_hdrs *proto_hdrs)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
35462306a36Sopenharmony_ci	struct ipv6hdr *iph = (struct ipv6hdr *)hdr->buffer;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (fltr->ip_mask.tclass == U8_MAX) {
35962306a36Sopenharmony_ci		iph->priority = (fltr->ip_data.tclass >> 4) & 0xF;
36062306a36Sopenharmony_ci		iph->flow_lbl[0] = (fltr->ip_data.tclass << 4) & 0xF0;
36162306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC);
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (fltr->ip_mask.proto == U8_MAX) {
36562306a36Sopenharmony_ci		iph->nexthdr = fltr->ip_data.proto;
36662306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, PROT);
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (!memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
37062306a36Sopenharmony_ci		    sizeof(struct in6_addr))) {
37162306a36Sopenharmony_ci		memcpy(&iph->saddr, &fltr->ip_data.v6_addrs.src_ip,
37262306a36Sopenharmony_ci		       sizeof(struct in6_addr));
37362306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (!memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
37762306a36Sopenharmony_ci		    sizeof(struct in6_addr))) {
37862306a36Sopenharmony_ci		memcpy(&iph->daddr, &fltr->ip_data.v6_addrs.dst_ip,
37962306a36Sopenharmony_ci		       sizeof(struct in6_addr));
38062306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return 0;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/**
38762306a36Sopenharmony_ci * iavf_fill_fdir_tcp_hdr - fill the TCP protocol header
38862306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
38962306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
39062306a36Sopenharmony_ci *
39162306a36Sopenharmony_ci * Returns 0 if the TCP protocol header is set successfully
39262306a36Sopenharmony_ci */
39362306a36Sopenharmony_cistatic int
39462306a36Sopenharmony_ciiavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr *fltr,
39562306a36Sopenharmony_ci		       struct virtchnl_proto_hdrs *proto_hdrs)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
39862306a36Sopenharmony_ci	struct tcphdr *tcph = (struct tcphdr *)hdr->buffer;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (fltr->ip_mask.src_port == htons(U16_MAX)) {
40362306a36Sopenharmony_ci		tcph->source = fltr->ip_data.src_port;
40462306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
40862306a36Sopenharmony_ci		tcph->dest = fltr->ip_data.dst_port;
40962306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return 0;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * iavf_fill_fdir_udp_hdr - fill the UDP protocol header
41762306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
41862306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
41962306a36Sopenharmony_ci *
42062306a36Sopenharmony_ci * Returns 0 if the UDP protocol header is set successfully
42162306a36Sopenharmony_ci */
42262306a36Sopenharmony_cistatic int
42362306a36Sopenharmony_ciiavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr *fltr,
42462306a36Sopenharmony_ci		       struct virtchnl_proto_hdrs *proto_hdrs)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
42762306a36Sopenharmony_ci	struct udphdr *udph = (struct udphdr *)hdr->buffer;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	if (fltr->ip_mask.src_port == htons(U16_MAX)) {
43262306a36Sopenharmony_ci		udph->source = fltr->ip_data.src_port;
43362306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
43762306a36Sopenharmony_ci		udph->dest = fltr->ip_data.dst_port;
43862306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	if (!fltr->flex_cnt)
44262306a36Sopenharmony_ci		return 0;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return iavf_fill_fdir_udp_flex_pay_hdr(fltr, proto_hdrs);
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci/**
44862306a36Sopenharmony_ci * iavf_fill_fdir_sctp_hdr - fill the SCTP protocol header
44962306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
45062306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
45162306a36Sopenharmony_ci *
45262306a36Sopenharmony_ci * Returns 0 if the SCTP protocol header is set successfully
45362306a36Sopenharmony_ci */
45462306a36Sopenharmony_cistatic int
45562306a36Sopenharmony_ciiavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr *fltr,
45662306a36Sopenharmony_ci			struct virtchnl_proto_hdrs *proto_hdrs)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
45962306a36Sopenharmony_ci	struct sctphdr *sctph = (struct sctphdr *)hdr->buffer;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (fltr->ip_mask.src_port == htons(U16_MAX)) {
46462306a36Sopenharmony_ci		sctph->source = fltr->ip_data.src_port;
46562306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
46962306a36Sopenharmony_ci		sctph->dest = fltr->ip_data.dst_port;
47062306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	return 0;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci/**
47762306a36Sopenharmony_ci * iavf_fill_fdir_ah_hdr - fill the AH protocol header
47862306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
47962306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
48062306a36Sopenharmony_ci *
48162306a36Sopenharmony_ci * Returns 0 if the AH protocol header is set successfully
48262306a36Sopenharmony_ci */
48362306a36Sopenharmony_cistatic int
48462306a36Sopenharmony_ciiavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr *fltr,
48562306a36Sopenharmony_ci		      struct virtchnl_proto_hdrs *proto_hdrs)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
48862306a36Sopenharmony_ci	struct ip_auth_hdr *ah = (struct ip_auth_hdr *)hdr->buffer;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, AH);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	if (fltr->ip_mask.spi == htonl(U32_MAX)) {
49362306a36Sopenharmony_ci		ah->spi = fltr->ip_data.spi;
49462306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, AH, SPI);
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return 0;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci/**
50162306a36Sopenharmony_ci * iavf_fill_fdir_esp_hdr - fill the ESP protocol header
50262306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
50362306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
50462306a36Sopenharmony_ci *
50562306a36Sopenharmony_ci * Returns 0 if the ESP protocol header is set successfully
50662306a36Sopenharmony_ci */
50762306a36Sopenharmony_cistatic int
50862306a36Sopenharmony_ciiavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr *fltr,
50962306a36Sopenharmony_ci		       struct virtchnl_proto_hdrs *proto_hdrs)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
51262306a36Sopenharmony_ci	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)hdr->buffer;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (fltr->ip_mask.spi == htonl(U32_MAX)) {
51762306a36Sopenharmony_ci		esph->spi = fltr->ip_data.spi;
51862306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return 0;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/**
52562306a36Sopenharmony_ci * iavf_fill_fdir_l4_hdr - fill the L4 protocol header
52662306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
52762306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
52862306a36Sopenharmony_ci *
52962306a36Sopenharmony_ci * Returns 0 if the L4 protocol header is set successfully
53062306a36Sopenharmony_ci */
53162306a36Sopenharmony_cistatic int
53262306a36Sopenharmony_ciiavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr *fltr,
53362306a36Sopenharmony_ci		      struct virtchnl_proto_hdrs *proto_hdrs)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr;
53662306a36Sopenharmony_ci	__be32 *l4_4_data;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if (!fltr->ip_mask.proto) /* IPv4/IPv6 header only */
53962306a36Sopenharmony_ci		return 0;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
54262306a36Sopenharmony_ci	l4_4_data = (__be32 *)hdr->buffer;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* L2TPv3 over IP with 'Session ID' */
54562306a36Sopenharmony_ci	if (fltr->ip_data.proto == 115 && fltr->ip_mask.l4_header == htonl(U32_MAX)) {
54662306a36Sopenharmony_ci		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, L2TPV3);
54762306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, L2TPV3, SESS_ID);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		*l4_4_data = fltr->ip_data.l4_header;
55062306a36Sopenharmony_ci	} else {
55162306a36Sopenharmony_ci		return -EOPNOTSUPP;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	return 0;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/**
55862306a36Sopenharmony_ci * iavf_fill_fdir_eth_hdr - fill the Ethernet protocol header
55962306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
56062306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure
56162306a36Sopenharmony_ci *
56262306a36Sopenharmony_ci * Returns 0 if the Ethernet protocol header is set successfully
56362306a36Sopenharmony_ci */
56462306a36Sopenharmony_cistatic int
56562306a36Sopenharmony_ciiavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr *fltr,
56662306a36Sopenharmony_ci		       struct virtchnl_proto_hdrs *proto_hdrs)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
56962306a36Sopenharmony_ci	struct ethhdr *ehdr = (struct ethhdr *)hdr->buffer;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ETH);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (fltr->eth_mask.etype == htons(U16_MAX)) {
57462306a36Sopenharmony_ci		if (fltr->eth_data.etype == htons(ETH_P_IP) ||
57562306a36Sopenharmony_ci		    fltr->eth_data.etype == htons(ETH_P_IPV6))
57662306a36Sopenharmony_ci			return -EOPNOTSUPP;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		ehdr->h_proto = fltr->eth_data.etype;
57962306a36Sopenharmony_ci		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ETH, ETHERTYPE);
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	return 0;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci/**
58662306a36Sopenharmony_ci * iavf_fill_fdir_add_msg - fill the Flow Director filter into virtchnl message
58762306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
58862306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
58962306a36Sopenharmony_ci *
59062306a36Sopenharmony_ci * Returns 0 if the add Flow Director virtchnl message is filled successfully
59162306a36Sopenharmony_ci */
59262306a36Sopenharmony_ciint iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	struct virtchnl_fdir_add *vc_msg = &fltr->vc_add_msg;
59562306a36Sopenharmony_ci	struct virtchnl_proto_hdrs *proto_hdrs;
59662306a36Sopenharmony_ci	int err;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	proto_hdrs = &vc_msg->rule_cfg.proto_hdrs;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	err = iavf_fill_fdir_eth_hdr(fltr, proto_hdrs); /* L2 always exists */
60162306a36Sopenharmony_ci	if (err)
60262306a36Sopenharmony_ci		return err;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	switch (fltr->flow_type) {
60562306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_TCP:
60662306a36Sopenharmony_ci		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
60762306a36Sopenharmony_ci		      iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
60862306a36Sopenharmony_ci		break;
60962306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_UDP:
61062306a36Sopenharmony_ci		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
61162306a36Sopenharmony_ci		      iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
61262306a36Sopenharmony_ci		break;
61362306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_SCTP:
61462306a36Sopenharmony_ci		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
61562306a36Sopenharmony_ci		      iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
61662306a36Sopenharmony_ci		break;
61762306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_AH:
61862306a36Sopenharmony_ci		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
61962306a36Sopenharmony_ci		      iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
62062306a36Sopenharmony_ci		break;
62162306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_ESP:
62262306a36Sopenharmony_ci		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
62362306a36Sopenharmony_ci		      iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
62462306a36Sopenharmony_ci		break;
62562306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_OTHER:
62662306a36Sopenharmony_ci		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
62762306a36Sopenharmony_ci		      iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
62862306a36Sopenharmony_ci		break;
62962306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_TCP:
63062306a36Sopenharmony_ci		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
63162306a36Sopenharmony_ci		      iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
63262306a36Sopenharmony_ci		break;
63362306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_UDP:
63462306a36Sopenharmony_ci		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
63562306a36Sopenharmony_ci		      iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
63662306a36Sopenharmony_ci		break;
63762306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_SCTP:
63862306a36Sopenharmony_ci		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
63962306a36Sopenharmony_ci		      iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
64062306a36Sopenharmony_ci		break;
64162306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_AH:
64262306a36Sopenharmony_ci		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
64362306a36Sopenharmony_ci		      iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
64462306a36Sopenharmony_ci		break;
64562306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_ESP:
64662306a36Sopenharmony_ci		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
64762306a36Sopenharmony_ci		      iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
64862306a36Sopenharmony_ci		break;
64962306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_OTHER:
65062306a36Sopenharmony_ci		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
65162306a36Sopenharmony_ci		      iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
65262306a36Sopenharmony_ci		break;
65362306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_NON_IP_L2:
65462306a36Sopenharmony_ci		break;
65562306a36Sopenharmony_ci	default:
65662306a36Sopenharmony_ci		err = -EINVAL;
65762306a36Sopenharmony_ci		break;
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (err)
66162306a36Sopenharmony_ci		return err;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	vc_msg->vsi_id = adapter->vsi.id;
66462306a36Sopenharmony_ci	vc_msg->rule_cfg.action_set.count = 1;
66562306a36Sopenharmony_ci	vc_msg->rule_cfg.action_set.actions[0].type = fltr->action;
66662306a36Sopenharmony_ci	vc_msg->rule_cfg.action_set.actions[0].act_conf.queue.index = fltr->q_index;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return 0;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci/**
67262306a36Sopenharmony_ci * iavf_fdir_flow_proto_name - get the flow protocol name
67362306a36Sopenharmony_ci * @flow_type: Flow Director filter flow type
67462306a36Sopenharmony_ci **/
67562306a36Sopenharmony_cistatic const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	switch (flow_type) {
67862306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_TCP:
67962306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_TCP:
68062306a36Sopenharmony_ci		return "TCP";
68162306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_UDP:
68262306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_UDP:
68362306a36Sopenharmony_ci		return "UDP";
68462306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_SCTP:
68562306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_SCTP:
68662306a36Sopenharmony_ci		return "SCTP";
68762306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_AH:
68862306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_AH:
68962306a36Sopenharmony_ci		return "AH";
69062306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_ESP:
69162306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_ESP:
69262306a36Sopenharmony_ci		return "ESP";
69362306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_OTHER:
69462306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_OTHER:
69562306a36Sopenharmony_ci		return "Other";
69662306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_NON_IP_L2:
69762306a36Sopenharmony_ci		return "Ethernet";
69862306a36Sopenharmony_ci	default:
69962306a36Sopenharmony_ci		return NULL;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci/**
70462306a36Sopenharmony_ci * iavf_print_fdir_fltr
70562306a36Sopenharmony_ci * @adapter: adapter structure
70662306a36Sopenharmony_ci * @fltr: Flow Director filter to print
70762306a36Sopenharmony_ci *
70862306a36Sopenharmony_ci * Print the Flow Director filter
70962306a36Sopenharmony_ci **/
71062306a36Sopenharmony_civoid iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	const char *proto = iavf_fdir_flow_proto_name(fltr->flow_type);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (!proto)
71562306a36Sopenharmony_ci		return;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	switch (fltr->flow_type) {
71862306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_TCP:
71962306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_UDP:
72062306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_SCTP:
72162306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: dst_port %hu src_port %hu\n",
72262306a36Sopenharmony_ci			 fltr->loc,
72362306a36Sopenharmony_ci			 &fltr->ip_data.v4_addrs.dst_ip,
72462306a36Sopenharmony_ci			 &fltr->ip_data.v4_addrs.src_ip,
72562306a36Sopenharmony_ci			 proto,
72662306a36Sopenharmony_ci			 ntohs(fltr->ip_data.dst_port),
72762306a36Sopenharmony_ci			 ntohs(fltr->ip_data.src_port));
72862306a36Sopenharmony_ci		break;
72962306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_AH:
73062306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_ESP:
73162306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: SPI %u\n",
73262306a36Sopenharmony_ci			 fltr->loc,
73362306a36Sopenharmony_ci			 &fltr->ip_data.v4_addrs.dst_ip,
73462306a36Sopenharmony_ci			 &fltr->ip_data.v4_addrs.src_ip,
73562306a36Sopenharmony_ci			 proto,
73662306a36Sopenharmony_ci			 ntohl(fltr->ip_data.spi));
73762306a36Sopenharmony_ci		break;
73862306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_OTHER:
73962306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 proto: %u L4_bytes: 0x%x\n",
74062306a36Sopenharmony_ci			 fltr->loc,
74162306a36Sopenharmony_ci			 &fltr->ip_data.v4_addrs.dst_ip,
74262306a36Sopenharmony_ci			 &fltr->ip_data.v4_addrs.src_ip,
74362306a36Sopenharmony_ci			 fltr->ip_data.proto,
74462306a36Sopenharmony_ci			 ntohl(fltr->ip_data.l4_header));
74562306a36Sopenharmony_ci		break;
74662306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_TCP:
74762306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_UDP:
74862306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_SCTP:
74962306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: dst_port %hu src_port %hu\n",
75062306a36Sopenharmony_ci			 fltr->loc,
75162306a36Sopenharmony_ci			 &fltr->ip_data.v6_addrs.dst_ip,
75262306a36Sopenharmony_ci			 &fltr->ip_data.v6_addrs.src_ip,
75362306a36Sopenharmony_ci			 proto,
75462306a36Sopenharmony_ci			 ntohs(fltr->ip_data.dst_port),
75562306a36Sopenharmony_ci			 ntohs(fltr->ip_data.src_port));
75662306a36Sopenharmony_ci		break;
75762306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_AH:
75862306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_ESP:
75962306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: SPI %u\n",
76062306a36Sopenharmony_ci			 fltr->loc,
76162306a36Sopenharmony_ci			 &fltr->ip_data.v6_addrs.dst_ip,
76262306a36Sopenharmony_ci			 &fltr->ip_data.v6_addrs.src_ip,
76362306a36Sopenharmony_ci			 proto,
76462306a36Sopenharmony_ci			 ntohl(fltr->ip_data.spi));
76562306a36Sopenharmony_ci		break;
76662306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_OTHER:
76762306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 proto: %u L4_bytes: 0x%x\n",
76862306a36Sopenharmony_ci			 fltr->loc,
76962306a36Sopenharmony_ci			 &fltr->ip_data.v6_addrs.dst_ip,
77062306a36Sopenharmony_ci			 &fltr->ip_data.v6_addrs.src_ip,
77162306a36Sopenharmony_ci			 fltr->ip_data.proto,
77262306a36Sopenharmony_ci			 ntohl(fltr->ip_data.l4_header));
77362306a36Sopenharmony_ci		break;
77462306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_NON_IP_L2:
77562306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Rule ID: %u eth_type: 0x%x\n",
77662306a36Sopenharmony_ci			 fltr->loc,
77762306a36Sopenharmony_ci			 ntohs(fltr->eth_data.etype));
77862306a36Sopenharmony_ci		break;
77962306a36Sopenharmony_ci	default:
78062306a36Sopenharmony_ci		break;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci/**
78562306a36Sopenharmony_ci * iavf_fdir_is_dup_fltr - test if filter is already in list
78662306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
78762306a36Sopenharmony_ci * @fltr: Flow Director filter data structure
78862306a36Sopenharmony_ci *
78962306a36Sopenharmony_ci * Returns true if the filter is found in the list
79062306a36Sopenharmony_ci */
79162306a36Sopenharmony_cibool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	struct iavf_fdir_fltr *tmp;
79462306a36Sopenharmony_ci	bool ret = false;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	spin_lock_bh(&adapter->fdir_fltr_lock);
79762306a36Sopenharmony_ci	list_for_each_entry(tmp, &adapter->fdir_list_head, list) {
79862306a36Sopenharmony_ci		if (tmp->flow_type != fltr->flow_type)
79962306a36Sopenharmony_ci			continue;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		if (!memcmp(&tmp->eth_data, &fltr->eth_data,
80262306a36Sopenharmony_ci			    sizeof(fltr->eth_data)) &&
80362306a36Sopenharmony_ci		    !memcmp(&tmp->ip_data, &fltr->ip_data,
80462306a36Sopenharmony_ci			    sizeof(fltr->ip_data)) &&
80562306a36Sopenharmony_ci		    !memcmp(&tmp->ext_data, &fltr->ext_data,
80662306a36Sopenharmony_ci			    sizeof(fltr->ext_data))) {
80762306a36Sopenharmony_ci			ret = true;
80862306a36Sopenharmony_ci			break;
80962306a36Sopenharmony_ci		}
81062306a36Sopenharmony_ci	}
81162306a36Sopenharmony_ci	spin_unlock_bh(&adapter->fdir_fltr_lock);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return ret;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/**
81762306a36Sopenharmony_ci * iavf_find_fdir_fltr_by_loc - find filter with location
81862306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
81962306a36Sopenharmony_ci * @loc: location to find.
82062306a36Sopenharmony_ci *
82162306a36Sopenharmony_ci * Returns pointer to Flow Director filter if found or null
82262306a36Sopenharmony_ci */
82362306a36Sopenharmony_cistruct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct iavf_fdir_fltr *rule;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	list_for_each_entry(rule, &adapter->fdir_list_head, list)
82862306a36Sopenharmony_ci		if (rule->loc == loc)
82962306a36Sopenharmony_ci			return rule;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	return NULL;
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci/**
83562306a36Sopenharmony_ci * iavf_fdir_list_add_fltr - add a new node to the flow director filter list
83662306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
83762306a36Sopenharmony_ci * @fltr: filter node to add to structure
83862306a36Sopenharmony_ci */
83962306a36Sopenharmony_civoid iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	struct iavf_fdir_fltr *rule, *parent = NULL;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	list_for_each_entry(rule, &adapter->fdir_list_head, list) {
84462306a36Sopenharmony_ci		if (rule->loc >= fltr->loc)
84562306a36Sopenharmony_ci			break;
84662306a36Sopenharmony_ci		parent = rule;
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (parent)
85062306a36Sopenharmony_ci		list_add(&fltr->list, &parent->list);
85162306a36Sopenharmony_ci	else
85262306a36Sopenharmony_ci		list_add(&fltr->list, &adapter->fdir_list_head);
85362306a36Sopenharmony_ci}
854