#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)
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)
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);
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);