batman-adv: Send multicast packets to nodes with a WANT_ALL flag
[cascardo/linux.git] / net / batman-adv / soft-interface.c
index f82c267..744a59b 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
 #include <linux/if_vlan.h>
+#include "multicast.h"
 #include "bridge_loop_avoidance.h"
 #include "network-coding.h"
 
@@ -111,8 +112,8 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       memcpy(old_addr, dev->dev_addr, ETH_ALEN);
-       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+       ether_addr_copy(old_addr, dev->dev_addr);
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
 
        /* only modify transtable if it has been initialized before */
        if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) {
@@ -170,17 +171,19 @@ static int batadv_interface_tx(struct sk_buff *skb,
        unsigned short vid;
        uint32_t seqno;
        int gw_mode;
+       enum batadv_forw_mode forw_mode;
+       struct batadv_orig_node *mcast_single_orig = NULL;
 
        if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
                goto dropped;
 
        soft_iface->trans_start = jiffies;
        vid = batadv_get_vid(skb, 0);
-       ethhdr = (struct ethhdr *)skb->data;
+       ethhdr = eth_hdr(skb);
 
        switch (ntohs(ethhdr->h_proto)) {
        case ETH_P_8021Q:
-               vhdr = (struct vlan_ethhdr *)skb->data;
+               vhdr = vlan_eth_hdr(skb);
 
                if (vhdr->h_vlan_encapsulated_proto != ethertype)
                        break;
@@ -194,7 +197,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
                goto dropped;
 
        /* skb->data might have been reallocated by batadv_bla_tx() */
-       ethhdr = (struct ethhdr *)skb->data;
+       ethhdr = eth_hdr(skb);
 
        /* Register the client MAC in the transtable */
        if (!is_multicast_ether_addr(ethhdr->h_source)) {
@@ -230,7 +233,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
                /* skb->data may have been modified by
                 * batadv_gw_dhcp_recipient_get()
                 */
-               ethhdr = (struct ethhdr *)skb->data;
+               ethhdr = eth_hdr(skb);
                /* if gw_mode is on, broadcast any non-DHCP message.
                 * All the DHCP packets are going to be sent as unicast
                 */
@@ -247,9 +250,19 @@ static int batadv_interface_tx(struct sk_buff *skb,
                         * directed to a DHCP server
                         */
                        goto dropped;
-       }
 
 send:
+               if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
+                       forw_mode = batadv_mcast_forw_mode(bat_priv, skb,
+                                                          &mcast_single_orig);
+                       if (forw_mode == BATADV_FORW_NONE)
+                               goto dropped;
+
+                       if (forw_mode == BATADV_FORW_SINGLE)
+                               do_bcast = false;
+               }
+       }
+
        batadv_skb_set_priority(skb, 0);
 
        /* ethernet packet should be broadcasted */
@@ -279,8 +292,8 @@ send:
                /* hw address of first interface is the orig mac because only
                 * this mac is known throughout the mesh
                 */
-               memcpy(bcast_packet->orig,
-                      primary_if->net_dev->dev_addr, ETH_ALEN);
+               ether_addr_copy(bcast_packet->orig,
+                               primary_if->net_dev->dev_addr);
 
                /* set broadcast sequence number */
                seqno = atomic_inc_return(&bat_priv->bcast_seqno);
@@ -301,6 +314,10 @@ send:
                        if (ret)
                                goto dropped;
                        ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
+               } else if (mcast_single_orig) {
+                       ret = batadv_send_skb_unicast(bat_priv, skb,
+                                                     BATADV_UNICAST, 0,
+                                                     mcast_single_orig, vid);
                } else {
                        if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
                                                                  skb))
@@ -652,10 +669,7 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
        }
 
        batadv_sysfs_del_meshif(soft_iface);
-
-       rtnl_lock();
-       unregister_netdevice(soft_iface);
-       rtnl_unlock();
+       unregister_netdev(soft_iface);
 }
 
 /**
@@ -691,6 +705,14 @@ static int batadv_softif_init_late(struct net_device *dev)
 #endif
 #ifdef CONFIG_BATMAN_ADV_DAT
        atomic_set(&bat_priv->distributed_arp_table, 1);
+#endif
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       bat_priv->mcast.flags = BATADV_NO_FLAGS;
+       atomic_set(&bat_priv->multicast_mode, 1);
+       atomic_set(&bat_priv->mcast.num_disabled, 0);
+       atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0);
+       atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0);
+       atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0);
 #endif
        atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF);
        atomic_set(&bat_priv->gw_sel_class, 20);