}
 }
 
+/**
+ * batadv_mcast_want_all_ip_count - count nodes with unspecific mcast interest
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ethhdr: ethernet header of a packet
+ *
+ * Returns the number of nodes which want all IPv4 multicast traffic if the
+ * given ethhdr is from an IPv4 packet or the number of nodes which want all
+ * IPv6 traffic if it matches an IPv6 packet.
+ */
+static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv,
+                                              struct ethhdr *ethhdr)
+{
+       switch (ntohs(ethhdr->h_proto)) {
+       case ETH_P_IP:
+               return atomic_read(&bat_priv->mcast.num_want_all_ipv4);
+       case ETH_P_IPV6:
+               return atomic_read(&bat_priv->mcast.num_want_all_ipv6);
+       default:
+               /* we shouldn't be here... */
+               return 0;
+       }
+}
+
 /**
  * batadv_mcast_forw_tt_node_get - get a multicast tt node
  * @bat_priv: the bat priv with all the soft interface information
                                        ethhdr->h_dest, BATADV_NO_FLAGS);
 }
 
+/**
+ * batadv_mcast_want_forw_ipv4_node_get - get a node with an ipv4 flag
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set and
+ * increases its refcount.
+ */
+static struct batadv_orig_node *
+batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv)
+{
+       struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp_orig_node,
+                                &bat_priv->mcast.want_all_ipv4_list,
+                                mcast_want_all_ipv4_node) {
+               if (!atomic_inc_not_zero(&orig_node->refcount))
+                       continue;
+
+               orig_node = tmp_orig_node;
+               break;
+       }
+       rcu_read_unlock();
+
+       return orig_node;
+}
+
+/**
+ * batadv_mcast_want_forw_ipv6_node_get - get a node with an ipv6 flag
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set
+ * and increases its refcount.
+ */
+static struct batadv_orig_node *
+batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv)
+{
+       struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp_orig_node,
+                                &bat_priv->mcast.want_all_ipv6_list,
+                                mcast_want_all_ipv6_node) {
+               if (!atomic_inc_not_zero(&orig_node->refcount))
+                       continue;
+
+               orig_node = tmp_orig_node;
+               break;
+       }
+       rcu_read_unlock();
+
+       return orig_node;
+}
+
+/**
+ * batadv_mcast_want_forw_ip_node_get - get a node with an ipv4/ipv6 flag
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ethhdr: an ethernet header to determine the protocol family from
+ *
+ * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or
+ * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, set and
+ * increases its refcount.
+ */
+static struct batadv_orig_node *
+batadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv,
+                             struct ethhdr *ethhdr)
+{
+       switch (ntohs(ethhdr->h_proto)) {
+       case ETH_P_IP:
+               return batadv_mcast_forw_ipv4_node_get(bat_priv);
+       case ETH_P_IPV6:
+               return batadv_mcast_forw_ipv6_node_get(bat_priv);
+       default:
+               /* we shouldn't be here... */
+               return NULL;
+       }
+}
+
 /**
  * batadv_mcast_want_forw_unsnoop_node_get - get a node with an unsnoopable flag
  * @bat_priv: the bat priv with all the soft interface information
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
                       struct batadv_orig_node **orig)
 {
-       int ret, tt_count, unsnoop_count, total_count;
+       int ret, tt_count, ip_count, unsnoop_count, total_count;
        bool is_unsnoopable = false;
        struct ethhdr *ethhdr;
 
 
        tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest,
                                               BATADV_NO_FLAGS);
+       ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
        unsnoop_count = !is_unsnoopable ? 0 :
                        atomic_read(&bat_priv->mcast.num_want_all_unsnoopables);
 
-       total_count = tt_count + unsnoop_count;
+       total_count = tt_count + ip_count + unsnoop_count;
 
        switch (total_count) {
        case 1:
                if (tt_count)
                        *orig = batadv_mcast_forw_tt_node_get(bat_priv, ethhdr);
+               else if (ip_count)
+                       *orig = batadv_mcast_forw_ip_node_get(bat_priv, ethhdr);
                else if (unsnoop_count)
                        *orig = batadv_mcast_forw_unsnoop_node_get(bat_priv);
 
        }
 }
 
+/**
+ * batadv_mcast_want_ipv4_update - update want-all-ipv4 counter and list
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: the orig_node which multicast state might have changed of
+ * @mcast_flags: flags indicating the new multicast state
+ *
+ * If the BATADV_MCAST_WANT_ALL_IPV4 flag of this originator, orig, has
+ * toggled then this method updates counter and list accordingly.
+ */
+static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
+                                         struct batadv_orig_node *orig,
+                                         uint8_t mcast_flags)
+{
+       /* switched from flag unset to set */
+       if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 &&
+           !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) {
+               atomic_inc(&bat_priv->mcast.num_want_all_ipv4);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_add_head_rcu(&orig->mcast_want_all_ipv4_node,
+                                  &bat_priv->mcast.want_all_ipv4_list);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       /* switched from flag set to unset */
+       } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) &&
+                  orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) {
+               atomic_dec(&bat_priv->mcast.num_want_all_ipv4);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_del_rcu(&orig->mcast_want_all_ipv4_node);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       }
+}
+
+/**
+ * batadv_mcast_want_ipv6_update - update want-all-ipv6 counter and list
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: the orig_node which multicast state might have changed of
+ * @mcast_flags: flags indicating the new multicast state
+ *
+ * If the BATADV_MCAST_WANT_ALL_IPV6 flag of this originator, orig, has
+ * toggled then this method updates counter and list accordingly.
+ */
+static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
+                                         struct batadv_orig_node *orig,
+                                         uint8_t mcast_flags)
+{
+       /* switched from flag unset to set */
+       if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 &&
+           !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) {
+               atomic_inc(&bat_priv->mcast.num_want_all_ipv6);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_add_head_rcu(&orig->mcast_want_all_ipv6_node,
+                                  &bat_priv->mcast.want_all_ipv6_list);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       /* switched from flag set to unset */
+       } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) &&
+                  orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) {
+               atomic_dec(&bat_priv->mcast.num_want_all_ipv6);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_del_rcu(&orig->mcast_want_all_ipv6_node);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       }
+}
+
 /**
  * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container
  * @bat_priv: the bat priv with all the soft interface information
                mcast_flags = *(uint8_t *)tvlv_value;
 
        batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags);
+       batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags);
+       batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags);
 
        orig->mcast_flags = mcast_flags;
 }
                atomic_dec(&bat_priv->mcast.num_disabled);
 
        batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
+       batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS);
+       batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS);
 }
 
  * @mcast_flags: multicast flags announced by the orig node
  * @mcast_want_all_unsnoop_node: a list node for the
  *  mcast.want_all_unsnoopables list
+ * @mcast_want_all_ipv4_node: a list node for the mcast.want_all_ipv4 list
+ * @mcast_want_all_ipv6_node: a list node for the mcast.want_all_ipv6 list
  * @capabilities: announced capabilities of this originator
  * @capa_initialized: bitfield to remember whether a capability was initialized
  * @last_ttvn: last seen translation table version number
 #ifdef CONFIG_BATMAN_ADV_MCAST
        uint8_t mcast_flags;
        struct hlist_node mcast_want_all_unsnoopables_node;
+       struct hlist_node mcast_want_all_ipv4_node;
+       struct hlist_node mcast_want_all_ipv6_node;
 #endif
        uint8_t capabilities;
        uint8_t capa_initialized;
  * @mla_list: list of multicast addresses we are currently announcing via TT
  * @want_all_unsnoopables_list: a list of orig_nodes wanting all unsnoopable
  *  multicast traffic
+ * @want_all_ipv4_list: a list of orig_nodes wanting all IPv4 multicast traffic
+ * @want_all_ipv6_list: a list of orig_nodes wanting all IPv6 multicast traffic
  * @flags: the flags we have last sent in our mcast tvlv
  * @enabled: whether the multicast tvlv is currently enabled
  * @num_disabled: number of nodes that have no mcast tvlv
  * @num_want_all_unsnoopables: number of nodes wanting unsnoopable IP traffic
+ * @num_want_all_ipv4: counter for items in want_all_ipv4_list
+ * @num_want_all_ipv6: counter for items in want_all_ipv6_list
  * @want_lists_lock: lock for protecting modifications to mcast want lists
  *  (traversals are rcu-locked)
  */
 struct batadv_priv_mcast {
        struct hlist_head mla_list;
        struct hlist_head want_all_unsnoopables_list;
+       struct hlist_head want_all_ipv4_list;
+       struct hlist_head want_all_ipv6_list;
        uint8_t flags;
        bool enabled;
        atomic_t num_disabled;
        atomic_t num_want_all_unsnoopables;
-       /* protects want_all_unsnoopables_list */
+       atomic_t num_want_all_ipv4;
+       atomic_t num_want_all_ipv6;
+       /* protects want_all_{unsnoopables,ipv4,ipv6}_list */
        spinlock_t want_lists_lock;
 };
 #endif