|
|
@@ -7,6 +7,15 @@
|
|
|
|
|
|
#include "rtl83xx.h"
|
|
|
|
|
|
+static const u8 ipv4_ll_mcast_addr_base[ETH_ALEN] =
|
|
|
+{ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
|
|
|
+static const u8 ipv4_ll_mcast_addr_mask[ETH_ALEN] =
|
|
|
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
|
|
|
+static const u8 ipv6_all_hosts_mcast_addr_base[ETH_ALEN] =
|
|
|
+{ 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 };
|
|
|
+static const u8 ipv6_all_hosts_mcast_addr_mask[ETH_ALEN] =
|
|
|
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
|
+
|
|
|
extern struct rtl83xx_soc_info soc_info;
|
|
|
|
|
|
static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv)
|
|
|
@@ -1752,6 +1761,24 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static bool rtl83xx_mac_is_unsnoop(const unsigned char *addr)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * RFC4541, section 2.1.2.2 + section 3:
|
|
|
+ * Unsnoopable address ranges must always be flooded.
|
|
|
+ *
|
|
|
+ * mapped MAC for 224.0.0.x -> 01:00:5e:00:00:xx
|
|
|
+ * mapped MAC for ff02::1 -> 33:33:00:00:00:01
|
|
|
+ */
|
|
|
+ if (ether_addr_equal_masked(addr, ipv4_ll_mcast_addr_base,
|
|
|
+ ipv4_ll_mcast_addr_mask) ||
|
|
|
+ ether_addr_equal_masked(addr, ipv6_all_hosts_mcast_addr_base,
|
|
|
+ ipv6_all_hosts_mcast_addr_mask))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
|
|
|
const struct switchdev_obj_port_mdb *mdb,
|
|
|
const struct dsa_db db)
|
|
|
@@ -1774,6 +1801,13 @@ static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ if (rtl83xx_mac_is_unsnoop(mdb->addr)) {
|
|
|
+ dev_dbg(priv->dev,
|
|
|
+ "%s: %pM might belong to an unsnoopable IP. ignore\n",
|
|
|
+ __func__, mdb->addr);
|
|
|
+ return -EADDRNOTAVAIL;
|
|
|
+ }
|
|
|
+
|
|
|
mutex_lock(&priv->reg_mutex);
|
|
|
|
|
|
idx = rtl83xx_find_l2_hash_entry(priv, seed, false, &e);
|
|
|
@@ -1847,6 +1881,13 @@ int rtl83xx_port_mdb_del(struct dsa_switch *ds, int port,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ if (rtl83xx_mac_is_unsnoop(mdb->addr)) {
|
|
|
+ dev_dbg(priv->dev,
|
|
|
+ "%s: %pM might belong to an unsnoopable IP. ignore\n",
|
|
|
+ __func__, mdb->addr);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
mutex_lock(&priv->reg_mutex);
|
|
|
|
|
|
idx = rtl83xx_find_l2_hash_entry(priv, seed, true, &e);
|