#include <linux/errno.h>
 #include <linux/etherdevice.h>
 #include <linux/fs.h>
+#include <linux/icmpv6.h>
 #include <linux/if_ether.h>
-#include <linux/in6.h>
+#include <linux/igmp.h>
 #include <linux/in.h>
+#include <linux/in6.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/kref.h>
        if (batadv_mcast_has_bridge(bat_priv)) {
                if (bat_priv->mcast.enabled) {
                        batadv_tvlv_container_unregister(bat_priv,
-                                                        BATADV_TVLV_MCAST, 1);
+                                                        BATADV_TVLV_MCAST, 2);
                        bat_priv->mcast.enabled = false;
                }
 
 
        if (!bat_priv->mcast.enabled ||
            mcast_data.flags != bat_priv->mcast.flags) {
-               batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1,
+               batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 2,
                                               &mcast_data, sizeof(mcast_data));
                bat_priv->mcast.flags = mcast_data.flags;
                bat_priv->mcast.enabled = true;
        batadv_mcast_mla_list_free(bat_priv, &mcast_list);
 }
 
+/**
+ * batadv_mcast_is_report_ipv4 - check for IGMP reports
+ * @skb: the ethernet frame destined for the mesh
+ *
+ * This call might reallocate skb data.
+ *
+ * Checks whether the given frame is a valid IGMP report.
+ *
+ * Return: If so then true, otherwise false.
+ */
+static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
+{
+       if (ip_mc_check_igmp(skb, NULL) < 0)
+               return false;
+
+       switch (igmp_hdr(skb)->type) {
+       case IGMP_HOST_MEMBERSHIP_REPORT:
+       case IGMPV2_HOST_MEMBERSHIP_REPORT:
+       case IGMPV3_HOST_MEMBERSHIP_REPORT:
+               return true;
+       }
+
+       return false;
+}
+
 /**
  * batadv_mcast_forw_mode_check_ipv4 - check for optimized forwarding potential
  * @bat_priv: the bat priv with all the soft interface information
        if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr)))
                return -ENOMEM;
 
+       if (batadv_mcast_is_report_ipv4(skb))
+               return -EINVAL;
+
        iphdr = ip_hdr(skb);
 
        /* TODO: Implement Multicast Router Discovery (RFC4286),
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+/**
+ * batadv_mcast_is_report_ipv6 - check for MLD reports
+ * @skb: the ethernet frame destined for the mesh
+ *
+ * This call might reallocate skb data.
+ *
+ * Checks whether the given frame is a valid MLD report.
+ *
+ * Return: If so then true, otherwise false.
+ */
+static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
+{
+       if (ipv6_mc_check_mld(skb, NULL) < 0)
+               return false;
+
+       switch (icmp6_hdr(skb)->icmp6_type) {
+       case ICMPV6_MGM_REPORT:
+       case ICMPV6_MLD2_REPORT:
+               return true;
+       }
+
+       return false;
+}
+
 /**
  * batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential
  * @bat_priv: the bat priv with all the soft interface information
        if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
                return -ENOMEM;
 
+       if (batadv_mcast_is_report_ipv6(skb))
+               return -EINVAL;
+
        ip6hdr = ipv6_hdr(skb);
 
        /* TODO: Implement Multicast Router Discovery (RFC4286),
 
        return 0;
 }
+#endif
 
 /**
  * batadv_mcast_forw_mode_check - check for optimized forwarding potential
        case ETH_P_IP:
                return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
                                                         is_unsnoopable);
+#if IS_ENABLED(CONFIG_IPV6)
        case ETH_P_IPV6:
                return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
                                                         is_unsnoopable);
+#endif
        default:
                return -EINVAL;
        }
 }
 
 /**
- * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container
+ * batadv_mcast_tvlv_ogm_handler - process incoming multicast tvlv container
  * @bat_priv: the bat priv with all the soft interface information
  * @orig: the orig_node of the ogm
  * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
  * @tvlv_value: tvlv buffer containing the multicast data
  * @tvlv_value_len: tvlv buffer length
  */
-static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
-                                            struct batadv_orig_node *orig,
-                                            u8 flags,
-                                            void *tvlv_value,
-                                            u16 tvlv_value_len)
+static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
+                                         struct batadv_orig_node *orig,
+                                         u8 flags,
+                                         void *tvlv_value,
+                                         u16 tvlv_value_len)
 {
        bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
        u8 mcast_flags = BATADV_NO_FLAGS;
  */
 void batadv_mcast_init(struct batadv_priv *bat_priv)
 {
-       batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler_v1,
-                                    NULL, BATADV_TVLV_MCAST, 1,
+       batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
+                                    NULL, BATADV_TVLV_MCAST, 2,
                                     BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 }
 
  */
 void batadv_mcast_free(struct batadv_priv *bat_priv)
 {
-       batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
-       batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
+       batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
+       batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
 
        spin_lock_bh(&bat_priv->tt.commit_lock);
        batadv_mcast_mla_tt_retract(bat_priv, NULL);