Correct .gbs.conf settings
[platform/adaptation/renesas_rcar/renesas_kernel.git] / net / batman-adv / soft-interface.c
index a8f99d1..f82c267 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -121,7 +119,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
                batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS,
                                       "mac address changed", false);
                batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS,
-                                   BATADV_NULL_IFINDEX);
+                                   BATADV_NULL_IFINDEX, BATADV_NO_MARK);
        }
 
        return 0;
@@ -162,6 +160,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
                                                   0x00, 0x00};
        static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
                                                    0x00, 0x00};
+       enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;
+       uint8_t *dst_hint = NULL, chaddr[ETH_ALEN];
        struct vlan_ethhdr *vhdr;
        unsigned int header_len = 0;
        int data_len = skb->len, ret;
@@ -169,6 +169,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
        bool do_bcast = false, client_added;
        unsigned short vid;
        uint32_t seqno;
+       int gw_mode;
 
        if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
                goto dropped;
@@ -198,7 +199,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
        /* Register the client MAC in the transtable */
        if (!is_multicast_ether_addr(ethhdr->h_source)) {
                client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source,
-                                                  vid, skb->skb_iif);
+                                                  vid, skb->skb_iif,
+                                                  skb->mark);
                if (!client_added)
                        goto dropped;
        }
@@ -215,36 +217,39 @@ static int batadv_interface_tx(struct sk_buff *skb,
        if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
                goto dropped;
 
+       gw_mode = atomic_read(&bat_priv->gw_mode);
        if (is_multicast_ether_addr(ethhdr->h_dest)) {
-               do_bcast = true;
-
-               switch (atomic_read(&bat_priv->gw_mode)) {
-               case BATADV_GW_MODE_SERVER:
-                       /* gateway servers should not send dhcp
-                        * requests into the mesh
-                        */
-                       ret = batadv_gw_is_dhcp_target(skb, &header_len);
-                       if (ret)
-                               goto dropped;
-                       break;
-               case BATADV_GW_MODE_CLIENT:
-                       /* gateway clients should send dhcp requests
-                        * via unicast to their gateway
-                        */
-                       ret = batadv_gw_is_dhcp_target(skb, &header_len);
-                       if (ret)
-                               do_bcast = false;
-                       break;
-               case BATADV_GW_MODE_OFF:
-               default:
-                       break;
+               /* if gw mode is off, broadcast every packet */
+               if (gw_mode == BATADV_GW_MODE_OFF) {
+                       do_bcast = true;
+                       goto send;
                }
 
-               /* reminder: ethhdr might have become unusable from here on
-                * (batadv_gw_is_dhcp_target() might have reallocated skb data)
+               dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len,
+                                                       chaddr);
+               /* skb->data may have been modified by
+                * batadv_gw_dhcp_recipient_get()
                 */
+               ethhdr = (struct ethhdr *)skb->data;
+               /* if gw_mode is on, broadcast any non-DHCP message.
+                * All the DHCP packets are going to be sent as unicast
+                */
+               if (dhcp_rcp == BATADV_DHCP_NO) {
+                       do_bcast = true;
+                       goto send;
+               }
+
+               if (dhcp_rcp == BATADV_DHCP_TO_CLIENT)
+                       dst_hint = chaddr;
+               else if ((gw_mode == BATADV_GW_MODE_SERVER) &&
+                        (dhcp_rcp == BATADV_DHCP_TO_SERVER))
+                       /* gateways should not forward any DHCP message if
+                        * directed to a DHCP server
+                        */
+                       goto dropped;
        }
 
+send:
        batadv_skb_set_priority(skb, 0);
 
        /* ethernet packet should be broadcasted */
@@ -290,22 +295,22 @@ static int batadv_interface_tx(struct sk_buff *skb,
 
        /* unicast packet */
        } else {
-               if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) {
+               /* DHCP packets going to a server will use the GW feature */
+               if (dhcp_rcp == BATADV_DHCP_TO_SERVER) {
                        ret = batadv_gw_out_of_range(bat_priv, skb);
                        if (ret)
                                goto dropped;
-               }
-
-               if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
-                       goto dropped;
-
-               batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
-
-               if (is_multicast_ether_addr(ethhdr->h_dest))
                        ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
-               else
-                       ret = batadv_send_skb_via_tt(bat_priv, skb, vid);
+               } else {
+                       if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
+                                                                 skb))
+                               goto dropped;
 
+                       batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
+
+                       ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint,
+                                                    vid);
+               }
                if (ret == NET_XMIT_DROP)
                        goto dropped_freed;
        }
@@ -394,9 +399,23 @@ void batadv_interface_rx(struct net_device *soft_iface,
                batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
                                                     ethhdr->h_source, vid);
 
-       if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest,
-                                 vid))
+       if (is_multicast_ether_addr(ethhdr->h_dest)) {
+               /* set the mark on broadcast packets if AP isolation is ON and
+                * the packet is coming from an "isolated" client
+                */
+               if (batadv_vlan_ap_isola_get(bat_priv, vid) &&
+                   batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source,
+                                                vid)) {
+                       /* save bits in skb->mark not covered by the mask and
+                        * apply the mark on the rest
+                        */
+                       skb->mark &= ~bat_priv->isolation_mark_mask;
+                       skb->mark |= bat_priv->isolation_mark;
+               }
+       } else if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source,
+                                        ethhdr->h_dest, vid)) {
                goto dropped;
+       }
 
        netif_rx(skb);
        goto out;
@@ -485,7 +504,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
         */
        batadv_tt_local_add(bat_priv->soft_iface,
                            bat_priv->soft_iface->dev_addr, vid,
-                           BATADV_NULL_IFINDEX);
+                           BATADV_NULL_IFINDEX, BATADV_NO_MARK);
 
        spin_lock_bh(&bat_priv->softif_vlan_list_lock);
        hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
@@ -678,7 +697,7 @@ static int batadv_softif_init_late(struct net_device *dev)
        atomic_set(&bat_priv->gw.bandwidth_down, 100);
        atomic_set(&bat_priv->gw.bandwidth_up, 20);
        atomic_set(&bat_priv->orig_interval, 1000);
-       atomic_set(&bat_priv->hop_penalty, 30);
+       atomic_set(&bat_priv->hop_penalty, 15);
 #ifdef CONFIG_BATMAN_ADV_DEBUG
        atomic_set(&bat_priv->log_level, 0);
 #endif
@@ -697,6 +716,8 @@ static int batadv_softif_init_late(struct net_device *dev)
 #endif
        bat_priv->tt.last_changeset = NULL;
        bat_priv->tt.last_changeset_len = 0;
+       bat_priv->isolation_mark = 0;
+       bat_priv->isolation_mark_mask = 0;
 
        /* randomize initial seqno to avoid collision */
        get_random_bytes(&random_seqno, sizeof(random_seqno));