batman-adv: introduce capability initialization bitfield
[cascardo/linux.git] / net / batman-adv / translation-table.c
index 959dde7..f641dfe 100644 (file)
@@ -24,6 +24,7 @@
 #include "originator.h"
 #include "routing.h"
 #include "bridge_loop_avoidance.h"
+#include "multicast.h"
 
 #include <linux/crc32c.h>
 
@@ -96,7 +97,7 @@ batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr,
        if (!hash)
                return NULL;
 
-       memcpy(to_search.addr, addr, ETH_ALEN);
+       ether_addr_copy(to_search.addr, addr);
        to_search.vid = vid;
 
        index = batadv_choose_tt(&to_search, hash->size);
@@ -333,7 +334,7 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
        tt_change_node->change.flags = flags;
        memset(tt_change_node->change.reserved, 0,
               sizeof(tt_change_node->change.reserved));
-       memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN);
+       ether_addr_copy(tt_change_node->change.addr, common->addr);
        tt_change_node->change.vid = htons(common->vid);
 
        del_op_requested = flags & BATADV_TT_CLIENT_DEL;
@@ -484,7 +485,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 {
        struct batadv_priv *bat_priv = netdev_priv(soft_iface);
        struct batadv_tt_local_entry *tt_local;
-       struct batadv_tt_global_entry *tt_global;
+       struct batadv_tt_global_entry *tt_global = NULL;
        struct net_device *in_dev = NULL;
        struct hlist_head *head;
        struct batadv_tt_orig_list_entry *orig_entry;
@@ -497,7 +498,9 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
                in_dev = dev_get_by_index(&init_net, ifindex);
 
        tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
-       tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
+
+       if (!is_multicast_ether_addr(addr))
+               tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
 
        if (tt_local) {
                tt_local->last_seen = jiffies;
@@ -549,7 +552,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
                   addr, BATADV_PRINT_VID(vid),
                   (uint8_t)atomic_read(&bat_priv->tt.vn));
 
-       memcpy(tt_local->common.addr, addr, ETH_ALEN);
+       ether_addr_copy(tt_local->common.addr, addr);
        /* The local entry has to be marked as NEW to avoid to send it in
         * a full table response going out before the next ttvn increment
         * (consistency check)
@@ -562,8 +565,11 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
        tt_local->last_seen = jiffies;
        tt_local->common.added_at = tt_local->last_seen;
 
-       /* the batman interface mac address should never be purged */
-       if (batadv_compare_eth(addr, soft_iface->dev_addr))
+       /* the batman interface mac and multicast addresses should never be
+        * purged
+        */
+       if (batadv_compare_eth(addr, soft_iface->dev_addr) ||
+           is_multicast_ether_addr(addr))
                tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
 
        hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
@@ -1277,7 +1283,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
                        goto out;
 
                common = &tt_global_entry->common;
-               memcpy(common->addr, tt_addr, ETH_ALEN);
+               ether_addr_copy(common->addr, tt_addr);
                common->vid = vid;
 
                common->flags = flags;
@@ -1361,6 +1367,11 @@ add_orig_entry:
        ret = true;
 
 out_remove:
+       /* Do not remove multicast addresses from the local hash on
+        * global additions
+        */
+       if (is_multicast_ether_addr(tt_addr))
+               goto out;
 
        /* remove address from local hash if present */
        local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
@@ -1763,7 +1774,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
                }
                spin_unlock_bh(list_lock);
        }
-       orig_node->tt_initialised = false;
+       orig_node->capa_initialized &= ~BATADV_ORIG_CAPA_HAS_TT;
 }
 
 static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
@@ -2160,7 +2171,7 @@ batadv_new_tt_req_node(struct batadv_priv *bat_priv,
        if (!tt_req_node)
                goto unlock;
 
-       memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
+       ether_addr_copy(tt_req_node->addr, orig_node->orig);
        tt_req_node->issued_at = jiffies;
 
        list_add(&tt_req_node->list, &bat_priv->tt.req_list);
@@ -2240,8 +2251,7 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
                        if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
                                continue;
 
-                       memcpy(tt_change->addr, tt_common_entry->addr,
-                              ETH_ALEN);
+                       ether_addr_copy(tt_change->addr, tt_common_entry->addr);
                        tt_change->flags = tt_common_entry->flags;
                        tt_change->vid = htons(tt_common_entry->vid);
                        memset(tt_change->reserved, 0,
@@ -2724,7 +2734,7 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
                                return;
                }
        }
-       orig_node->tt_initialised = true;
+       orig_node->capa_initialized |= BATADV_ORIG_CAPA_HAS_TT;
 }
 
 static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
@@ -2932,7 +2942,7 @@ static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv,
                tt_roam_node->first_time = jiffies;
                atomic_set(&tt_roam_node->counter,
                           BATADV_ROAMING_MAX_COUNT - 1);
-               memcpy(tt_roam_node->addr, client, ETH_ALEN);
+               ether_addr_copy(tt_roam_node->addr, client);
 
                list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
                ret = true;
@@ -3121,6 +3131,9 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
  */
 static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
 {
+       /* Update multicast addresses in local translation table */
+       batadv_mcast_mla_update(bat_priv);
+
        if (atomic_read(&bat_priv->tt.local_changes) < 1) {
                if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
                        batadv_tt_tvlv_container_update(bat_priv);
@@ -3211,13 +3224,15 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
        uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
        struct batadv_tvlv_tt_vlan_data *tt_vlan;
        bool full_table = true;
+       bool has_tt_init;
 
        tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
+       has_tt_init = orig_node->capa_initialized & BATADV_ORIG_CAPA_HAS_TT;
+
        /* orig table not initialised AND first diff is in the OGM OR the ttvn
         * increased by one -> we can apply the attached changes
         */
-       if ((!orig_node->tt_initialised && ttvn == 1) ||
-           ttvn - orig_ttvn == 1) {
+       if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) {
                /* the OGM could not contain the changes due to their size or
                 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
                 * times.
@@ -3257,7 +3272,7 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
                /* if we missed more than one change or our tables are not
                 * in sync anymore -> request fresh tt data
                 */
-               if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
+               if (!has_tt_init || ttvn != orig_ttvn ||
                    !batadv_tt_global_check_crc(orig_node, tt_vlan,
                                                tt_num_vlan)) {
 request_table: