summaryrefslogtreecommitdiff
path: root/net/batman-adv
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/translation-table.c40
1 files changed, 37 insertions, 3 deletions
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 074936f2d30a..d82766bfd264 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -157,7 +157,9 @@ batadv_tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry)
static void batadv_tt_local_event(struct bat_priv *bat_priv,
const uint8_t *addr, uint8_t flags)
{
- struct tt_change_node *tt_change_node;
+ struct tt_change_node *tt_change_node, *entry, *safe;
+ bool event_removed = false;
+ bool del_op_requested, del_op_entry;
tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
@@ -167,13 +169,45 @@ static void batadv_tt_local_event(struct bat_priv *bat_priv,
tt_change_node->change.flags = flags;
memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
+ del_op_requested = flags & TT_CLIENT_DEL;
+
+ /* check for ADD+DEL or DEL+ADD events */
spin_lock_bh(&bat_priv->tt_changes_list_lock);
+ list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
+ list) {
+ if (!batadv_compare_eth(entry->change.addr, addr))
+ continue;
+
+ /* DEL+ADD in the same orig interval have no effect and can be
+ * removed to avoid silly behaviour on the receiver side. The
+ * other way around (ADD+DEL) can happen in case of roaming of
+ * a client still in the NEW state. Roaming of NEW clients is
+ * now possible due to automatically recognition of "temporary"
+ * clients
+ */
+ del_op_entry = entry->change.flags & TT_CLIENT_DEL;
+ if (!del_op_requested && del_op_entry)
+ goto del;
+ if (del_op_requested && !del_op_entry)
+ goto del;
+ continue;
+del:
+ list_del(&entry->list);
+ kfree(entry);
+ event_removed = true;
+ goto unlock;
+ }
+
/* track the change in the OGMinterval list */
list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
- atomic_inc(&bat_priv->tt_local_changes);
+
+unlock:
spin_unlock_bh(&bat_priv->tt_changes_list_lock);
- atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
+ if (event_removed)
+ atomic_dec(&bat_priv->tt_local_changes);
+ else
+ atomic_inc(&bat_priv->tt_local_changes);
}
int batadv_tt_len(int changes_num)