diff --git a/batman-adv/multicast.c b/batman-adv/multicast.c
index fefef41..685d3f3 100644
--- a/batman-adv/multicast.c
+++ b/batman-adv/multicast.c
@@ -23,6 +23,7 @@
 #include "multicast.h"
 #include "hash.h"
 #include "send.h"
+#include "soft-interface.h"
 #include "hard-interface.h"
 #include "originator.h"
 #include "compat.h"
@@ -1139,6 +1140,170 @@ int mcast_forw_table_seq_print_text(struct seq_file *seq, void *offset)
 	return 0;
 }
 
+static inline void nexthops_from_if_list(struct hlist_head *mcast_if_list,
+					 struct list_head *nexthop_list,
+					 struct bat_priv *bat_priv)
+{
+	struct batman_if *batman_if;
+	struct mcast_forw_if_entry *if_entry;
+	struct mcast_forw_nexthop_entry *nexthop_entry;
+	struct hlist_node *node, *node2;
+	struct dest_entries_list *dest_entry;
+	int mcast_fanout = atomic_read(&bat_priv->mcast_fanout);
+
+	hlist_for_each_entry(if_entry, node, mcast_if_list, list) {
+		rcu_read_lock();
+		batman_if = if_num_to_batman_if(if_entry->if_num);
+		if (!batman_if) {
+			rcu_read_unlock();
+			continue;
+		}
+
+		kref_get(&batman_if->refcount);
+		rcu_read_unlock();
+
+
+		/* send via broadcast */
+		if (if_entry->num_nexthops > mcast_fanout) {
+			dest_entry = kmalloc(sizeof(struct dest_entries_list),
+					     GFP_ATOMIC);
+			memcpy(dest_entry->dest, broadcast_addr, ETH_ALEN);
+			dest_entry->batman_if = batman_if;
+			list_add(&dest_entry->list, nexthop_list);
+			continue;
+		}
+
+		/* send separate unicast packets */
+		hlist_for_each_entry(nexthop_entry, node2,
+				     &if_entry->mcast_nexthop_list, list) {
+			if (!get_remaining_timeout(nexthop_entry, bat_priv))
+				continue;
+
+			dest_entry = kmalloc(sizeof(struct dest_entries_list),
+					     GFP_ATOMIC);
+			memcpy(dest_entry->dest, nexthop_entry->neigh_addr,
+			       ETH_ALEN);
+
+			kref_get(&batman_if->refcount);
+			dest_entry->batman_if = batman_if;
+			list_add(&dest_entry->list, nexthop_list);
+		}
+		kref_put(&batman_if->refcount, hardif_free_ref);
+	}
+}
+
+static inline void nexthops_from_orig_list(uint8_t *orig,
+					   struct hlist_head *mcast_orig_list,
+					   struct list_head *nexthop_list,
+					   struct bat_priv *bat_priv)
+{
+	struct mcast_forw_orig_entry *orig_entry;
+	struct hlist_node *node;
+
+	hlist_for_each_entry(orig_entry, node, mcast_orig_list, list) {
+		if (memcmp(orig, orig_entry->orig, ETH_ALEN))
+			continue;
+
+		nexthops_from_if_list(&orig_entry->mcast_if_list, nexthop_list,
+				      bat_priv);
+		break;
+	}
+}
+
+static inline void nexthops_from_table(uint8_t *dest, uint8_t *orig,
+				       struct hlist_head *mcast_forw_table,
+				       struct list_head *nexthop_list,
+				       struct bat_priv *bat_priv)
+{
+	struct mcast_forw_table_entry *table_entry;
+	struct hlist_node *node;
+
+	hlist_for_each_entry(table_entry, node, mcast_forw_table, list) {
+		if (memcmp(dest, table_entry->mcast_addr, ETH_ALEN))
+			continue;
+
+		nexthops_from_orig_list(orig, &table_entry->mcast_orig_list,
+					nexthop_list, bat_priv);
+		break;
+	}
+}
+
+static void route_mcast_packet(struct sk_buff *skb, struct bat_priv *bat_priv)
+{
+	struct sk_buff *skb1;
+	struct mcast_packet *mcast_packet;
+	struct ethhdr *ethhdr;
+	int num_bcasts = 3, i;
+	struct list_head nexthop_list;
+	struct dest_entries_list *dest_entry, *tmp;
+
+	mcast_packet = (struct mcast_packet *)skb->data;
+	ethhdr = (struct ethhdr *)(mcast_packet + 1);
+
+	INIT_LIST_HEAD(&nexthop_list);
+
+	mcast_packet->ttl--;
+
+	spin_lock_bh(&bat_priv->mcast_forw_table_lock);
+	nexthops_from_table(ethhdr->h_dest, mcast_packet->orig,
+			    &bat_priv->mcast_forw_table, &nexthop_list,
+			    bat_priv);
+	spin_unlock_bh(&bat_priv->mcast_forw_table_lock);
+
+	list_for_each_entry_safe(dest_entry, tmp, &nexthop_list, list) {
+		if (is_broadcast_ether_addr(dest_entry->dest)) {
+			for (i = 0; i < num_bcasts; i++) {
+				skb1 = skb_clone(skb, GFP_ATOMIC);
+				send_skb_packet(skb1, dest_entry->batman_if,
+						dest_entry->dest);
+			}
+		} else {
+			skb1 = skb_clone(skb, GFP_ATOMIC);
+			send_skb_packet(skb1, dest_entry->batman_if,
+					dest_entry->dest);
+		}
+		kref_put(&dest_entry->batman_if->refcount, hardif_free_ref);
+		list_del(&dest_entry->list);
+		kfree(dest_entry);
+	}
+}
+
+int mcast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
+{
+	struct mcast_packet *mcast_packet;
+
+	if (!bat_priv->primary_if)
+		goto dropped;
+
+	if (my_skb_head_push(skb, sizeof(struct mcast_packet)) < 0)
+		goto dropped;
+
+	mcast_packet = (struct mcast_packet *)skb->data;
+	mcast_packet->version = COMPAT_VERSION;
+	mcast_packet->ttl = TTL;
+
+	/* batman packet type: broadcast */
+	mcast_packet->packet_type = BAT_MCAST;
+
+	/* hw address of first interface is the orig mac because only
+	 * this mac is known throughout the mesh */
+	memcpy(mcast_packet->orig,
+	       bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+
+	/* set broadcast sequence number */
+	mcast_packet->seqno =
+		htonl(atomic_inc_return(&bat_priv->mcast_seqno));
+
+	route_mcast_packet(skb, bat_priv);
+
+	kfree_skb(skb);
+	return 0;
+
+dropped:
+	kfree_skb(skb);
+	return 1;
+}
+
 int mcast_init(struct bat_priv *bat_priv)
 {
 	INIT_DELAYED_WORK(&bat_priv->mcast_tracker_work, mcast_tracker_timer);
diff --git a/batman-adv/multicast.h b/batman-adv/multicast.h
index 40f9da0..2fe9910 100644
--- a/batman-adv/multicast.h
+++ b/batman-adv/multicast.h
@@ -31,6 +31,7 @@ void route_mcast_tracker_packet(struct sk_buff *tracker_packet,
 				struct bat_priv *bat_priv);
 void purge_mcast_forw_table(struct bat_priv *bat_priv);
 int mcast_forw_table_seq_print_text(struct seq_file *seq, void *offset);
+int mcast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
 int mcast_init(struct bat_priv *bat_priv);
 void mcast_free(struct bat_priv *bat_priv);
 
diff --git a/batman-adv/packet.h b/batman-adv/packet.h
index 6f42a2f..daa5d54 100644
--- a/batman-adv/packet.h
+++ b/batman-adv/packet.h
@@ -31,6 +31,7 @@
 #define BAT_VIS           0x05
 #define BAT_UNICAST_FRAG  0x06
 #define BAT_MCAST_TRACKER 0x07
+#define BAT_MCAST         0x08
 
 /* this file is included by batctl which needs these defines */
 #define COMPAT_VERSION 14
@@ -126,6 +127,14 @@ struct bcast_packet {
 	uint32_t seqno;
 } __packed;
 
+struct mcast_packet {
+        uint8_t  packet_type;    /* BAT_MCAST */
+        uint8_t  version;        /* batman version field */
+        uint8_t  orig[6];
+        uint32_t seqno;
+        uint8_t  ttl;
+} __packed;
+
 /* marks the path for multicast streams */
 struct mcast_tracker_packet {
         uint8_t  packet_type;    /* BAT_MCAST_TRACKER */
diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c
index f25fe9d..3e16522 100644
--- a/batman-adv/soft-interface.c
+++ b/batman-adv/soft-interface.c
@@ -38,6 +38,7 @@
 #include <linux/if_vlan.h>
 #include "unicast.h"
 #include "routing.h"
+#include "multicast.h"
 
 
 static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
@@ -347,7 +348,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	struct vlan_ethhdr *vhdr;
 	int data_len = skb->len, ret;
 	short vid = -1;
-	bool do_bcast = false;
+	bool bcast_dst = false, mcast_dst = false;
 
 	if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
 		goto dropped;
@@ -384,12 +385,22 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		if (ret < 0)
 			goto dropped;
 
-		if (ret == 0)
-			do_bcast = true;
+		/* dhcp request, which should be sent to the gateway
+		 * directly? */
+		if (ret)
+			goto unicast;
+
+		if (is_broadcast_ether_addr(ethhdr->h_dest))
+			bcast_dst = true;
+		else if (atomic_read(&bat_priv->mcast_mode) ==
+			 MCAST_MODE_PROACT_TRACKING)
+			mcast_dst = true;
+		else
+			bcast_dst = true;
 	}
 
 	/* ethernet packet should be broadcasted */
-	if (do_bcast) {
+	if (bcast_dst) {
 		if (!bat_priv->primary_if)
 			goto dropped;
 
@@ -418,8 +429,15 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		 * the original skb. */
 		kfree_skb(skb);
 
+	/* multicast data with path optimization */
+	} else if (mcast_dst) {
+		ret = mcast_send_skb(skb, bat_priv);
+		if (ret != 0)
+			goto dropped_freed;
+
 	/* unicast packet */
 	} else {
+unicast:
 		ret = unicast_send_skb(skb, bat_priv);
 		if (ret != 0)
 			goto dropped_freed;
@@ -608,6 +626,7 @@ struct net_device *softif_create(char *name)
 
 	atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
 	atomic_set(&bat_priv->bcast_seqno, 1);
+	atomic_set(&bat_priv->mcast_seqno, 1);
 	atomic_set(&bat_priv->hna_local_changed, 0);
 
 	bat_priv->primary_if = NULL;
diff --git a/batman-adv/types.h b/batman-adv/types.h
index 0acfd2e..c3dde7c 100644
--- a/batman-adv/types.h
+++ b/batman-adv/types.h
@@ -147,6 +147,7 @@ struct bat_priv {
 	atomic_t mcast_fanout;		/* uint */
 	atomic_t log_level;		/* uint */
 	atomic_t bcast_seqno;
+	atomic_t mcast_seqno;
 	atomic_t bcast_queue_left;
 	atomic_t batman_queue_left;
 	char num_ifaces;
