aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-05-16 14:11:23 -0400
committerDavid S. Miller <davem@davemloft.net>2018-05-16 14:11:23 -0400
commitac22bfb15c83636c28df2754456fb0a00c6e82da (patch)
treebaef285c02d4616782e6c11976041e3f3889bcf0
parente1b505a60366399d735312ca38b0a6753a684123 (diff)
parent1942adf64214df370350aa46954ba27654456f68 (diff)
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: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/bcm_sf2_cfp.c36
1 files changed, 22 insertions, 14 deletions
diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c
index 23b45da784cb..b89acaee12d4 100644
--- a/drivers/net/dsa/bcm_sf2_cfp.c
+++ b/drivers/net/dsa/bcm_sf2_cfp.c
@@ -354,10 +354,13 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
354 /* Locate the first rule available */ 354 /* Locate the first rule available */
355 if (fs->location == RX_CLS_LOC_ANY) 355 if (fs->location == RX_CLS_LOC_ANY)
356 rule_index = find_first_zero_bit(priv->cfp.used, 356 rule_index = find_first_zero_bit(priv->cfp.used,
357 bcm_sf2_cfp_rule_size(priv)); 357 priv->num_cfp_rules);
358 else 358 else
359 rule_index = fs->location; 359 rule_index = fs->location;
360 360
361 if (rule_index > bcm_sf2_cfp_rule_size(priv))
362 return -ENOSPC;
363
361 layout = &udf_tcpip4_layout; 364 layout = &udf_tcpip4_layout;
362 /* We only use one UDF slice for now */ 365 /* We only use one UDF slice for now */
363 slice_num = bcm_sf2_get_slice_number(layout, 0); 366 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,
562 * first half because the HW search is by incrementing addresses. 565 * first half because the HW search is by incrementing addresses.
563 */ 566 */
564 if (fs->location == RX_CLS_LOC_ANY) 567 if (fs->location == RX_CLS_LOC_ANY)
565 rule_index[0] = find_first_zero_bit(priv->cfp.used, 568 rule_index[1] = find_first_zero_bit(priv->cfp.used,
566 bcm_sf2_cfp_rule_size(priv)); 569 priv->num_cfp_rules);
567 else 570 else
568 rule_index[0] = fs->location; 571 rule_index[1] = fs->location;
572 if (rule_index[1] > bcm_sf2_cfp_rule_size(priv))
573 return -ENOSPC;
569 574
570 /* Flag it as used (cleared on error path) such that we can immediately 575 /* Flag it as used (cleared on error path) such that we can immediately
571 * obtain a second one to chain from. 576 * obtain a second one to chain from.
572 */ 577 */
573 set_bit(rule_index[0], priv->cfp.used); 578 set_bit(rule_index[1], priv->cfp.used);
574 579
575 rule_index[1] = find_first_zero_bit(priv->cfp.used, 580 rule_index[0] = find_first_zero_bit(priv->cfp.used,
576 bcm_sf2_cfp_rule_size(priv)); 581 priv->num_cfp_rules);
577 if (rule_index[1] > bcm_sf2_cfp_rule_size(priv)) { 582 if (rule_index[0] > bcm_sf2_cfp_rule_size(priv)) {
578 ret = -ENOSPC; 583 ret = -ENOSPC;
579 goto out_err; 584 goto out_err;
580 } 585 }
@@ -712,14 +717,14 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
712 /* Flag the second half rule as being used now, return it as the 717 /* Flag the second half rule as being used now, return it as the
713 * location, and flag it as unique while dumping rules 718 * location, and flag it as unique while dumping rules
714 */ 719 */
715 set_bit(rule_index[1], priv->cfp.used); 720 set_bit(rule_index[0], priv->cfp.used);
716 set_bit(rule_index[1], priv->cfp.unique); 721 set_bit(rule_index[1], priv->cfp.unique);
717 fs->location = rule_index[1]; 722 fs->location = rule_index[1];
718 723
719 return ret; 724 return ret;
720 725
721out_err: 726out_err:
722 clear_bit(rule_index[0], priv->cfp.used); 727 clear_bit(rule_index[1], priv->cfp.used);
723 return ret; 728 return ret;
724} 729}
725 730
@@ -785,10 +790,6 @@ static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port,
785 int ret; 790 int ret;
786 u32 reg; 791 u32 reg;
787 792
788 /* Refuse deletion of unused rules, and the default reserved rule */
789 if (!test_bit(loc, priv->cfp.used) || loc == 0)
790 return -EINVAL;
791
792 /* Indicate which rule we want to read */ 793 /* Indicate which rule we want to read */
793 bcm_sf2_cfp_rule_addr_set(priv, loc); 794 bcm_sf2_cfp_rule_addr_set(priv, loc);
794 795
@@ -826,6 +827,13 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port,
826 u32 next_loc = 0; 827 u32 next_loc = 0;
827 int ret; 828 int ret;
828 829
830 /* Refuse deleting unused rules, and those that are not unique since
831 * that could leave IPv6 rules with one of the chained rule in the
832 * table.
833 */
834 if (!test_bit(loc, priv->cfp.unique) || loc == 0)
835 return -EINVAL;
836
829 ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc); 837 ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc);
830 if (ret) 838 if (ret)
831 return ret; 839 return ret;