--- /dev/null
+From: Linus Lüssing <linus.luessing@c0d3.blue>
+Date: Thu, 10 May 2018 19:44:28 +0200
+Subject: [PATCH] batman-adv: Fix TT sync flags for intermediate TT responses
+
+The previous TT sync fix so far only fixed TT responses issued by the
+target node directly. So far, TT responses issued by intermediate nodes
+still lead to the wrong flags being added, leading to CRC mismatches.
+
+This behaviour was observed at Freifunk Hannover in a 800 nodes setup
+where a considerable amount of nodes were still infected with 'WI'
+TT flags even with (most) nodes having the previous TT sync fix applied.
+
+I was able to reproduce the issue with intermediate TT responses in a
+four node test setup and this patch fixes this issue by ensuring to
+use the per originator instead of the summarized, OR'd ones.
+
+Fixes: fa614fd04692 ("batman-adv: fix tt_global_entries flags update")
+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/d65daee8617b29c1ddcc949ce3a5ec24f7a1e1af
+---
+ net/batman-adv/translation-table.c | 61 +++++++++++++++++++++++++-----
+ 1 file changed, 51 insertions(+), 10 deletions(-)
+
+diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
+index 7fa3a0a0524a1da63e92d081b443c302900bf0c3..23f9c212ab1e27be429645a85f7b5d6a02585de9 100644
+--- a/net/batman-adv/translation-table.c
++++ b/net/batman-adv/translation-table.c
+@@ -1538,6 +1538,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
+ * handled by a given originator
+ * @entry: the TT global entry to check
+ * @orig_node: the originator to search in the list
++ * @flags: a pointer to store TT flags for the given @entry received
++ * from @orig_node
+ *
+ * find out if an orig_node is already in the list of a tt_global_entry.
+ *
+@@ -1545,7 +1547,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
+ */
+ static bool
+ batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
+- const struct batadv_orig_node *orig_node)
++ const struct batadv_orig_node *orig_node,
++ u8 *flags)
+ {
+ struct batadv_tt_orig_list_entry *orig_entry;
+ bool found = false;
+@@ -1553,6 +1556,10 @@ batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
+ orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
+ if (orig_entry) {
+ found = true;
++
++ if (flags)
++ *flags = orig_entry->flags;
++
+ batadv_tt_orig_list_entry_put(orig_entry);
+ }
+
+@@ -1731,7 +1738,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
+ if (!(common->flags & BATADV_TT_CLIENT_TEMP))
+ goto out;
+ if (batadv_tt_global_entry_has_orig(tt_global_entry,
+- orig_node))
++ orig_node, NULL))
+ goto out_remove;
+ batadv_tt_global_del_orig_list(tt_global_entry);
+ goto add_orig_entry;
+@@ -2880,23 +2887,46 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv,
+ }
+
+ /**
+- * batadv_tt_local_valid() - verify that given tt entry is a valid one
++ * batadv_tt_local_valid() - verify local tt entry and get flags
+ * @entry_ptr: to be checked local tt entry
+ * @data_ptr: not used but definition required to satisfy the callback prototype
++ * @flags: a pointer to store TT flags for this client to
++ *
++ * Checks the validity of the given local TT entry. If it is, then the provided
++ * flags pointer is updated.
+ *
+ * Return: true if the entry is a valid, false otherwise.
+ */
+-static bool batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr)
++static bool batadv_tt_local_valid(const void *entry_ptr,
++ const void *data_ptr,
++ u8 *flags)
+ {
+ const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
+
+ if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
+ return false;
++
++ if (flags)
++ *flags = tt_common_entry->flags;
++
+ return true;
+ }
+
++/**
++ * batadv_tt_global_valid() - verify global tt entry and get flags
++ * @entry_ptr: to be checked global tt entry
++ * @data_ptr: an orig_node object (may be NULL)
++ * @flags: a pointer to store TT flags for this client to
++ *
++ * Checks the validity of the given global TT entry. If it is, then the provided
++ * flags pointer is updated either with the common (summed) TT flags if data_ptr
++ * is NULL or the specific, per originator TT flags otherwise.
++ *
++ * Return: true if the entry is a valid, false otherwise.
++ */
+ static bool batadv_tt_global_valid(const void *entry_ptr,
+- const void *data_ptr)
++ const void *data_ptr,
++ u8 *flags)
+ {
+ const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
+ const struct batadv_tt_global_entry *tt_global_entry;
+@@ -2910,7 +2940,8 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
+ struct batadv_tt_global_entry,
+ common);
+
+- return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node);
++ return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node,
++ flags);
+ }
+
+ /**
+@@ -2920,25 +2951,34 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
+ * @hash: hash table containing the tt entries
+ * @tt_len: expected tvlv tt data buffer length in number of bytes
+ * @tvlv_buff: pointer to the buffer to fill with the TT data
+- * @valid_cb: function to filter tt change entries
++ * @valid_cb: function to filter tt change entries and to return TT flags
+ * @cb_data: data passed to the filter function as argument
++ *
++ * Fills the tvlv buff with the tt entries from the specified hash. If valid_cb
++ * is not provided then this becomes a no-op.
+ */
+ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
+ struct batadv_hashtable *hash,
+ void *tvlv_buff, u16 tt_len,
+ bool (*valid_cb)(const void *,
+- const void *),
++ const void *,
++ u8 *flags),
+ void *cb_data)
+ {
+ struct batadv_tt_common_entry *tt_common_entry;
+ struct batadv_tvlv_tt_change *tt_change;
+ struct hlist_head *head;
+ u16 tt_tot, tt_num_entries = 0;
++ u8 flags;
++ bool ret;
+ u32 i;
+
+ tt_tot = batadv_tt_entries(tt_len);
+ tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff;
+
++ if (!valid_cb)
++ return;
++
+ rcu_read_lock();
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+@@ -2948,11 +2988,12 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
+ if (tt_tot == tt_num_entries)
+ break;
+
+- if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
++ ret = valid_cb(tt_common_entry, cb_data, &flags);
++ if (!ret)
+ continue;
+
+ ether_addr_copy(tt_change->addr, tt_common_entry->addr);
+- tt_change->flags = tt_common_entry->flags;
++ tt_change->flags = flags;
+ tt_change->vid = htons(tt_common_entry->vid);
+ memset(tt_change->reserved, 0,
+ sizeof(tt_change->reserved));