Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac22bfb1 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dsa-bcm_sf2-CFP-fixes'



Florian Fainelli says:

====================
net: dsa: bcm_sf2: CFP fixes

This patch series fixes a number of usability issues with the SF2 Compact Field
Processor code:

- we would not be properly bound checking the location when we let the kernel
  automatically place rules with RX_CLS_LOC_ANY

- when using IPv6 rules and user space specifies a location identifier we
  would be off by one in what the chain ID (within the Broadcom tag) indicates

- it would be possible to delete one of the two slices of an IPv6 while leaving
  the other one programming leading to various problems
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e1b505a6 1942adf6
Loading
Loading
Loading
Loading
+22 −14
Original line number Diff line number Diff line
@@ -354,10 +354,13 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
	/* Locate the first rule available */
	if (fs->location == RX_CLS_LOC_ANY)
		rule_index = find_first_zero_bit(priv->cfp.used,
						 bcm_sf2_cfp_rule_size(priv));
						 priv->num_cfp_rules);
	else
		rule_index = fs->location;

	if (rule_index > bcm_sf2_cfp_rule_size(priv))
		return -ENOSPC;

	layout = &udf_tcpip4_layout;
	/* We only use one UDF slice for now */
	slice_num = bcm_sf2_get_slice_number(layout, 0);
@@ -562,19 +565,21 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
	 * first half because the HW search is by incrementing addresses.
	 */
	if (fs->location == RX_CLS_LOC_ANY)
		rule_index[0] = find_first_zero_bit(priv->cfp.used,
						    bcm_sf2_cfp_rule_size(priv));
		rule_index[1] = find_first_zero_bit(priv->cfp.used,
						    priv->num_cfp_rules);
	else
		rule_index[0] = fs->location;
		rule_index[1] = fs->location;
	if (rule_index[1] > bcm_sf2_cfp_rule_size(priv))
		return -ENOSPC;

	/* Flag it as used (cleared on error path) such that we can immediately
	 * obtain a second one to chain from.
	 */
	set_bit(rule_index[0], priv->cfp.used);
	set_bit(rule_index[1], priv->cfp.used);

	rule_index[1] = find_first_zero_bit(priv->cfp.used,
					    bcm_sf2_cfp_rule_size(priv));
	if (rule_index[1] > bcm_sf2_cfp_rule_size(priv)) {
	rule_index[0] = find_first_zero_bit(priv->cfp.used,
					    priv->num_cfp_rules);
	if (rule_index[0] > bcm_sf2_cfp_rule_size(priv)) {
		ret = -ENOSPC;
		goto out_err;
	}
@@ -712,14 +717,14 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
	/* Flag the second half rule as being used now, return it as the
	 * location, and flag it as unique while dumping rules
	 */
	set_bit(rule_index[1], priv->cfp.used);
	set_bit(rule_index[0], priv->cfp.used);
	set_bit(rule_index[1], priv->cfp.unique);
	fs->location = rule_index[1];

	return ret;

out_err:
	clear_bit(rule_index[0], priv->cfp.used);
	clear_bit(rule_index[1], priv->cfp.used);
	return ret;
}

@@ -785,10 +790,6 @@ static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port,
	int ret;
	u32 reg;

	/* Refuse deletion of unused rules, and the default reserved rule */
	if (!test_bit(loc, priv->cfp.used) || loc == 0)
		return -EINVAL;

	/* Indicate which rule we want to read */
	bcm_sf2_cfp_rule_addr_set(priv, loc);

@@ -826,6 +827,13 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port,
	u32 next_loc = 0;
	int ret;

	/* Refuse deleting unused rules, and those that are not unique since
	 * that could leave IPv6 rules with one of the chained rule in the
	 * table.
	 */
	if (!test_bit(loc, priv->cfp.unique) || loc == 0)
		return -EINVAL;

	ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc);
	if (ret)
		return ret;