drivers/net/ethernet/aquantia/atlantic/aq_filters.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/aquantia/atlantic/aq_filters.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/aquantia/atlantic/aq_filters.c
Extension
.c
Size
23697 bytes
Lines
916
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

switch (fsp->h_u.usr_ip4_spec.proto) {
		case IPPROTO_TCP:
		case IPPROTO_UDP:
		case IPPROTO_SCTP:
		case IPPROTO_IP:
			return true;
		default:
			return false;
			}
	case IPV6_USER_FLOW:
		switch (fsp->h_u.usr_ip6_spec.l4_proto) {
		case IPPROTO_TCP:
		case IPPROTO_UDP:
		case IPPROTO_SCTP:
		case IPPROTO_IP:
			return true;
		default:
			return false;
			}
	default:
		return false;
	}

	return false;
}

static bool __must_check
aq_match_filter(struct ethtool_rx_flow_spec *fsp1,
		struct ethtool_rx_flow_spec *fsp2)
{
	if (fsp1->flow_type != fsp2->flow_type ||
	    memcmp(&fsp1->h_u, &fsp2->h_u, sizeof(fsp2->h_u)) ||
	    memcmp(&fsp1->h_ext, &fsp2->h_ext, sizeof(fsp2->h_ext)) ||
	    memcmp(&fsp1->m_u, &fsp2->m_u, sizeof(fsp2->m_u)) ||
	    memcmp(&fsp1->m_ext, &fsp2->m_ext, sizeof(fsp2->m_ext)))
		return false;

	return true;
}

static bool __must_check
aq_rule_already_exists(struct aq_nic_s *aq_nic,
		       struct ethtool_rx_flow_spec *fsp)
{
	struct aq_rx_filter *rule;
	struct hlist_node *aq_node2;
	struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);

	hlist_for_each_entry_safe(rule, aq_node2,
				  &rx_fltrs->filter_list, aq_node) {
		if (rule->aq_fsp.location == fsp->location)
			continue;
		if (aq_match_filter(&rule->aq_fsp, fsp)) {
			netdev_err(aq_nic->ndev,
				   "ethtool: This filter is already set\n");
			return true;
		}
	}

	return false;
}

static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
				  struct aq_hw_rx_fltrs_s *rx_fltrs,
				  struct ethtool_rx_flow_spec *fsp)
{
	u32 last_location = AQ_RX_LAST_LOC_FL3L4 -
			    aq_nic->aq_hw_rx_fltrs.fl3l4.reserved_count;

	if (fsp->location < AQ_RX_FIRST_LOC_FL3L4 ||
	    fsp->location > last_location) {
		netdev_err(aq_nic->ndev,
			   "ethtool: location must be in range [%d, %d]",
			   AQ_RX_FIRST_LOC_FL3L4, last_location);
		return -EINVAL;
	}
	if (rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv4) {
		rx_fltrs->fl3l4.is_ipv6 = false;
		netdev_err(aq_nic->ndev,
			   "ethtool: mixing ipv4 and ipv6 is not allowed");
		return -EINVAL;
	} else if (!rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv6) {
		rx_fltrs->fl3l4.is_ipv6 = true;
		netdev_err(aq_nic->ndev,
			   "ethtool: mixing ipv4 and ipv6 is not allowed");
		return -EINVAL;
	} else if (rx_fltrs->fl3l4.is_ipv6		      &&
		   fsp->location != AQ_RX_FIRST_LOC_FL3L4 + 4 &&
		   fsp->location != AQ_RX_FIRST_LOC_FL3L4) {
		netdev_err(aq_nic->ndev,

Annotation

Implementation Notes