10b873931SAntonio Quartulli /* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
2c6c8fea2SSven Eckelmann  *
335c133a0SAntonio Quartulli  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
4c6c8fea2SSven Eckelmann  *
5c6c8fea2SSven Eckelmann  * This program is free software; you can redistribute it and/or
6c6c8fea2SSven Eckelmann  * modify it under the terms of version 2 of the GNU General Public
7c6c8fea2SSven Eckelmann  * License as published by the Free Software Foundation.
8c6c8fea2SSven Eckelmann  *
9c6c8fea2SSven Eckelmann  * This program is distributed in the hope that it will be useful, but
10c6c8fea2SSven Eckelmann  * WITHOUT ANY WARRANTY; without even the implied warranty of
11c6c8fea2SSven Eckelmann  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12c6c8fea2SSven Eckelmann  * General Public License for more details.
13c6c8fea2SSven Eckelmann  *
14c6c8fea2SSven Eckelmann  * You should have received a copy of the GNU General Public License
15c6c8fea2SSven Eckelmann  * along with this program; if not, write to the Free Software
16c6c8fea2SSven Eckelmann  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17c6c8fea2SSven Eckelmann  * 02110-1301, USA
18c6c8fea2SSven Eckelmann  */
19c6c8fea2SSven Eckelmann 
20c6c8fea2SSven Eckelmann #include "main.h"
21c6c8fea2SSven Eckelmann #include "translation-table.h"
22c6c8fea2SSven Eckelmann #include "soft-interface.h"
2332ae9b22SMarek Lindner #include "hard-interface.h"
24a73105b8SAntonio Quartulli #include "send.h"
25c6c8fea2SSven Eckelmann #include "hash.h"
26c6c8fea2SSven Eckelmann #include "originator.h"
27a73105b8SAntonio Quartulli #include "routing.h"
2820ff9d59SSimon Wunderlich #include "bridge_loop_avoidance.h"
29c6c8fea2SSven Eckelmann 
30a73105b8SAntonio Quartulli #include <linux/crc16.h>
31a73105b8SAntonio Quartulli 
32dec05074SAntonio Quartulli /* hash class keys */
33dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_local_hash_lock_class_key;
34dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_global_hash_lock_class_key;
35dec05074SAntonio Quartulli 
3656303d34SSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
3756303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node);
38a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work);
39a513088dSSven Eckelmann static void
4056303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
4130cfd02bSAntonio Quartulli static void batadv_tt_global_del(struct batadv_priv *bat_priv,
4230cfd02bSAntonio Quartulli 				 struct batadv_orig_node *orig_node,
4330cfd02bSAntonio Quartulli 				 const unsigned char *addr,
4430cfd02bSAntonio Quartulli 				 const char *message, bool roaming);
45c6c8fea2SSven Eckelmann 
467aadf889SMarek Lindner /* returns 1 if they are the same mac addr */
47a513088dSSven Eckelmann static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
487aadf889SMarek Lindner {
4956303d34SSven Eckelmann 	const void *data1 = container_of(node, struct batadv_tt_common_entry,
50747e4221SSven Eckelmann 					 hash_entry);
517aadf889SMarek Lindner 
527aadf889SMarek Lindner 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
537aadf889SMarek Lindner }
547aadf889SMarek Lindner 
5556303d34SSven Eckelmann static struct batadv_tt_common_entry *
565bf74e9cSSven Eckelmann batadv_tt_hash_find(struct batadv_hashtable *hash, const void *data)
577aadf889SMarek Lindner {
587aadf889SMarek Lindner 	struct hlist_head *head;
5956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
6056303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry_tmp = NULL;
61c90681b8SAntonio Quartulli 	uint32_t index;
627aadf889SMarek Lindner 
637aadf889SMarek Lindner 	if (!hash)
647aadf889SMarek Lindner 		return NULL;
657aadf889SMarek Lindner 
66da641193SSven Eckelmann 	index = batadv_choose_orig(data, hash->size);
677aadf889SMarek Lindner 	head = &hash->table[index];
687aadf889SMarek Lindner 
697aadf889SMarek Lindner 	rcu_read_lock();
70b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(tt_common_entry, head, hash_entry) {
711eda58bfSSven Eckelmann 		if (!batadv_compare_eth(tt_common_entry, data))
727aadf889SMarek Lindner 			continue;
737aadf889SMarek Lindner 
7448100bacSAntonio Quartulli 		if (!atomic_inc_not_zero(&tt_common_entry->refcount))
757683fdc1SAntonio Quartulli 			continue;
767683fdc1SAntonio Quartulli 
7748100bacSAntonio Quartulli 		tt_common_entry_tmp = tt_common_entry;
787aadf889SMarek Lindner 		break;
797aadf889SMarek Lindner 	}
807aadf889SMarek Lindner 	rcu_read_unlock();
817aadf889SMarek Lindner 
8248100bacSAntonio Quartulli 	return tt_common_entry_tmp;
8348100bacSAntonio Quartulli }
8448100bacSAntonio Quartulli 
8556303d34SSven Eckelmann static struct batadv_tt_local_entry *
8656303d34SSven Eckelmann batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data)
8748100bacSAntonio Quartulli {
8856303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
8956303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry = NULL;
9048100bacSAntonio Quartulli 
91807736f6SSven Eckelmann 	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, data);
9248100bacSAntonio Quartulli 	if (tt_common_entry)
9348100bacSAntonio Quartulli 		tt_local_entry = container_of(tt_common_entry,
9456303d34SSven Eckelmann 					      struct batadv_tt_local_entry,
9556303d34SSven Eckelmann 					      common);
9648100bacSAntonio Quartulli 	return tt_local_entry;
977aadf889SMarek Lindner }
987aadf889SMarek Lindner 
9956303d34SSven Eckelmann static struct batadv_tt_global_entry *
10056303d34SSven Eckelmann batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const void *data)
1017aadf889SMarek Lindner {
10256303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
10356303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry = NULL;
1047aadf889SMarek Lindner 
105807736f6SSven Eckelmann 	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, data);
10648100bacSAntonio Quartulli 	if (tt_common_entry)
10748100bacSAntonio Quartulli 		tt_global_entry = container_of(tt_common_entry,
10856303d34SSven Eckelmann 					       struct batadv_tt_global_entry,
10956303d34SSven Eckelmann 					       common);
11048100bacSAntonio Quartulli 	return tt_global_entry;
1117aadf889SMarek Lindner }
1127aadf889SMarek Lindner 
113a513088dSSven Eckelmann static void
11456303d34SSven Eckelmann batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry)
1157683fdc1SAntonio Quartulli {
11648100bacSAntonio Quartulli 	if (atomic_dec_and_test(&tt_local_entry->common.refcount))
11748100bacSAntonio Quartulli 		kfree_rcu(tt_local_entry, common.rcu);
1187683fdc1SAntonio Quartulli }
1197683fdc1SAntonio Quartulli 
120a513088dSSven Eckelmann static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu)
121531027fcSSimon Wunderlich {
12256303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
12356303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
124531027fcSSimon Wunderlich 
12556303d34SSven Eckelmann 	tt_common_entry = container_of(rcu, struct batadv_tt_common_entry, rcu);
12656303d34SSven Eckelmann 	tt_global_entry = container_of(tt_common_entry,
12756303d34SSven Eckelmann 				       struct batadv_tt_global_entry, common);
128531027fcSSimon Wunderlich 
129531027fcSSimon Wunderlich 	kfree(tt_global_entry);
130531027fcSSimon Wunderlich }
131531027fcSSimon Wunderlich 
132a513088dSSven Eckelmann static void
13356303d34SSven Eckelmann batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry)
1347683fdc1SAntonio Quartulli {
135db08e6e5SSimon Wunderlich 	if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
136a513088dSSven Eckelmann 		batadv_tt_global_del_orig_list(tt_global_entry);
13748100bacSAntonio Quartulli 		call_rcu(&tt_global_entry->common.rcu,
138a513088dSSven Eckelmann 			 batadv_tt_global_entry_free_rcu);
1397683fdc1SAntonio Quartulli 	}
140db08e6e5SSimon Wunderlich }
141db08e6e5SSimon Wunderlich 
142a513088dSSven Eckelmann static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
143db08e6e5SSimon Wunderlich {
14456303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
145db08e6e5SSimon Wunderlich 
14656303d34SSven Eckelmann 	orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu);
14772822225SLinus Lüssing 
14872822225SLinus Lüssing 	/* We are in an rcu callback here, therefore we cannot use
14972822225SLinus Lüssing 	 * batadv_orig_node_free_ref() and its call_rcu():
15072822225SLinus Lüssing 	 * An rcu_barrier() wouldn't wait for that to finish
15172822225SLinus Lüssing 	 */
15272822225SLinus Lüssing 	batadv_orig_node_free_ref_now(orig_entry->orig_node);
153db08e6e5SSimon Wunderlich 	kfree(orig_entry);
154db08e6e5SSimon Wunderlich }
155db08e6e5SSimon Wunderlich 
156a513088dSSven Eckelmann static void
15756303d34SSven Eckelmann batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
158db08e6e5SSimon Wunderlich {
159d657e621SAntonio Quartulli 	if (!atomic_dec_and_test(&orig_entry->refcount))
160d657e621SAntonio Quartulli 		return;
16129cb99deSAntonio Quartulli 	/* to avoid race conditions, immediately decrease the tt counter */
16229cb99deSAntonio Quartulli 	atomic_dec(&orig_entry->orig_node->tt_size);
163a513088dSSven Eckelmann 	call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
164db08e6e5SSimon Wunderlich }
1657683fdc1SAntonio Quartulli 
1663abe4adbSAntonio Quartulli /**
1673abe4adbSAntonio Quartulli  * batadv_tt_local_event - store a local TT event (ADD/DEL)
1683abe4adbSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
1693abe4adbSAntonio Quartulli  * @tt_local_entry: the TT entry involved in the event
1703abe4adbSAntonio Quartulli  * @event_flags: flags to store in the event structure
1713abe4adbSAntonio Quartulli  */
17256303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv,
1733abe4adbSAntonio Quartulli 				  struct batadv_tt_local_entry *tt_local_entry,
1743abe4adbSAntonio Quartulli 				  uint8_t event_flags)
175a73105b8SAntonio Quartulli {
17656303d34SSven Eckelmann 	struct batadv_tt_change_node *tt_change_node, *entry, *safe;
1773abe4adbSAntonio Quartulli 	struct batadv_tt_common_entry *common = &tt_local_entry->common;
1783abe4adbSAntonio Quartulli 	uint8_t flags = common->flags | event_flags;
1793b643de5SAntonio Quartulli 	bool event_removed = false;
1803b643de5SAntonio Quartulli 	bool del_op_requested, del_op_entry;
181a73105b8SAntonio Quartulli 
182a73105b8SAntonio Quartulli 	tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
183a73105b8SAntonio Quartulli 	if (!tt_change_node)
184a73105b8SAntonio Quartulli 		return;
185a73105b8SAntonio Quartulli 
186ff66c975SAntonio Quartulli 	tt_change_node->change.flags = flags;
187e1bf0c14SMarek Lindner 	tt_change_node->change.reserved = 0;
1883abe4adbSAntonio Quartulli 	memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN);
189a73105b8SAntonio Quartulli 
190acd34afaSSven Eckelmann 	del_op_requested = flags & BATADV_TT_CLIENT_DEL;
1913b643de5SAntonio Quartulli 
1923b643de5SAntonio Quartulli 	/* check for ADD+DEL or DEL+ADD events */
193807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
194807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
1953b643de5SAntonio Quartulli 				 list) {
1963abe4adbSAntonio Quartulli 		if (!batadv_compare_eth(entry->change.addr, common->addr))
1973b643de5SAntonio Quartulli 			continue;
1983b643de5SAntonio Quartulli 
1993b643de5SAntonio Quartulli 		/* DEL+ADD in the same orig interval have no effect and can be
2003b643de5SAntonio Quartulli 		 * removed to avoid silly behaviour on the receiver side. The
2013b643de5SAntonio Quartulli 		 * other way around (ADD+DEL) can happen in case of roaming of
2023b643de5SAntonio Quartulli 		 * a client still in the NEW state. Roaming of NEW clients is
2033b643de5SAntonio Quartulli 		 * now possible due to automatically recognition of "temporary"
2043b643de5SAntonio Quartulli 		 * clients
2053b643de5SAntonio Quartulli 		 */
206acd34afaSSven Eckelmann 		del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
2073b643de5SAntonio Quartulli 		if (!del_op_requested && del_op_entry)
2083b643de5SAntonio Quartulli 			goto del;
2093b643de5SAntonio Quartulli 		if (del_op_requested && !del_op_entry)
2103b643de5SAntonio Quartulli 			goto del;
2113b643de5SAntonio Quartulli 		continue;
2123b643de5SAntonio Quartulli del:
2133b643de5SAntonio Quartulli 		list_del(&entry->list);
2143b643de5SAntonio Quartulli 		kfree(entry);
215155e4e12SJesper Juhl 		kfree(tt_change_node);
2163b643de5SAntonio Quartulli 		event_removed = true;
2173b643de5SAntonio Quartulli 		goto unlock;
2183b643de5SAntonio Quartulli 	}
2193b643de5SAntonio Quartulli 
220a73105b8SAntonio Quartulli 	/* track the change in the OGMinterval list */
221807736f6SSven Eckelmann 	list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list);
2223b643de5SAntonio Quartulli 
2233b643de5SAntonio Quartulli unlock:
224807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
225a73105b8SAntonio Quartulli 
2263b643de5SAntonio Quartulli 	if (event_removed)
227807736f6SSven Eckelmann 		atomic_dec(&bat_priv->tt.local_changes);
2283b643de5SAntonio Quartulli 	else
229807736f6SSven Eckelmann 		atomic_inc(&bat_priv->tt.local_changes);
230a73105b8SAntonio Quartulli }
231a73105b8SAntonio Quartulli 
232335fbe0fSMarek Lindner /**
233335fbe0fSMarek Lindner  * batadv_tt_len - compute length in bytes of given number of tt changes
234335fbe0fSMarek Lindner  * @changes_num: number of tt changes
235335fbe0fSMarek Lindner  *
236335fbe0fSMarek Lindner  * Returns computed length in bytes.
237335fbe0fSMarek Lindner  */
238335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num)
239a73105b8SAntonio Quartulli {
240335fbe0fSMarek Lindner 	return changes_num * sizeof(struct batadv_tvlv_tt_change);
241a73105b8SAntonio Quartulli }
242a73105b8SAntonio Quartulli 
24356303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv)
244c6c8fea2SSven Eckelmann {
245807736f6SSven Eckelmann 	if (bat_priv->tt.local_hash)
2465346c35eSSven Eckelmann 		return 0;
247c6c8fea2SSven Eckelmann 
248807736f6SSven Eckelmann 	bat_priv->tt.local_hash = batadv_hash_new(1024);
249c6c8fea2SSven Eckelmann 
250807736f6SSven Eckelmann 	if (!bat_priv->tt.local_hash)
2515346c35eSSven Eckelmann 		return -ENOMEM;
252c6c8fea2SSven Eckelmann 
253dec05074SAntonio Quartulli 	batadv_hash_set_lock_class(bat_priv->tt.local_hash,
254dec05074SAntonio Quartulli 				   &batadv_tt_local_hash_lock_class_key);
255dec05074SAntonio Quartulli 
2565346c35eSSven Eckelmann 	return 0;
257c6c8fea2SSven Eckelmann }
258c6c8fea2SSven Eckelmann 
259068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv,
260068ee6e2SAntonio Quartulli 				  struct batadv_tt_global_entry *tt_global,
261068ee6e2SAntonio Quartulli 				  const char *message)
262068ee6e2SAntonio Quartulli {
263068ee6e2SAntonio Quartulli 	batadv_dbg(BATADV_DBG_TT, bat_priv,
264068ee6e2SAntonio Quartulli 		   "Deleting global tt entry %pM: %s\n",
265068ee6e2SAntonio Quartulli 		   tt_global->common.addr, message);
266068ee6e2SAntonio Quartulli 
267068ee6e2SAntonio Quartulli 	batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
268068ee6e2SAntonio Quartulli 			   batadv_choose_orig, tt_global->common.addr);
269068ee6e2SAntonio Quartulli 	batadv_tt_global_entry_free_ref(tt_global);
270068ee6e2SAntonio Quartulli }
271068ee6e2SAntonio Quartulli 
27208c36d3eSSven Eckelmann void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
273bc279080SAntonio Quartulli 			 int ifindex)
274c6c8fea2SSven Eckelmann {
27556303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
276170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
277170173bfSSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
278db08e6e5SSimon Wunderlich 	struct hlist_head *head;
27956303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
28080b3f58cSSimon Wunderlich 	int hash_added;
281068ee6e2SAntonio Quartulli 	bool roamed_back = false;
282c6c8fea2SSven Eckelmann 
28347c94655SAntonio Quartulli 	tt_local = batadv_tt_local_hash_find(bat_priv, addr);
284068ee6e2SAntonio Quartulli 	tt_global = batadv_tt_global_hash_find(bat_priv, addr);
285c6c8fea2SSven Eckelmann 
28647c94655SAntonio Quartulli 	if (tt_local) {
28747c94655SAntonio Quartulli 		tt_local->last_seen = jiffies;
288068ee6e2SAntonio Quartulli 		if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
289068ee6e2SAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
290068ee6e2SAntonio Quartulli 				   "Re-adding pending client %pM\n", addr);
291068ee6e2SAntonio Quartulli 			/* whatever the reason why the PENDING flag was set,
292068ee6e2SAntonio Quartulli 			 * this is a client which was enqueued to be removed in
293068ee6e2SAntonio Quartulli 			 * this orig_interval. Since it popped up again, the
294068ee6e2SAntonio Quartulli 			 * flag can be reset like it was never enqueued
295068ee6e2SAntonio Quartulli 			 */
29647c94655SAntonio Quartulli 			tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
297068ee6e2SAntonio Quartulli 			goto add_event;
298068ee6e2SAntonio Quartulli 		}
299068ee6e2SAntonio Quartulli 
300068ee6e2SAntonio Quartulli 		if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
301068ee6e2SAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
302068ee6e2SAntonio Quartulli 				   "Roaming client %pM came back to its original location\n",
303068ee6e2SAntonio Quartulli 				   addr);
304068ee6e2SAntonio Quartulli 			/* the ROAM flag is set because this client roamed away
305068ee6e2SAntonio Quartulli 			 * and the node got a roaming_advertisement message. Now
306068ee6e2SAntonio Quartulli 			 * that the client popped up again at its original
307068ee6e2SAntonio Quartulli 			 * location such flag can be unset
308068ee6e2SAntonio Quartulli 			 */
309068ee6e2SAntonio Quartulli 			tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
310068ee6e2SAntonio Quartulli 			roamed_back = true;
311068ee6e2SAntonio Quartulli 		}
312068ee6e2SAntonio Quartulli 		goto check_roaming;
313c6c8fea2SSven Eckelmann 	}
314c6c8fea2SSven Eckelmann 
31547c94655SAntonio Quartulli 	tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
31647c94655SAntonio Quartulli 	if (!tt_local)
3177683fdc1SAntonio Quartulli 		goto out;
318a73105b8SAntonio Quartulli 
31939c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
320a73105b8SAntonio Quartulli 		   "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
321807736f6SSven Eckelmann 		   (uint8_t)atomic_read(&bat_priv->tt.vn));
322c6c8fea2SSven Eckelmann 
32347c94655SAntonio Quartulli 	memcpy(tt_local->common.addr, addr, ETH_ALEN);
3248425ec6aSAntonio Quartulli 	/* The local entry has to be marked as NEW to avoid to send it in
3258425ec6aSAntonio Quartulli 	 * a full table response going out before the next ttvn increment
3268425ec6aSAntonio Quartulli 	 * (consistency check)
3278425ec6aSAntonio Quartulli 	 */
3288425ec6aSAntonio Quartulli 	tt_local->common.flags = BATADV_TT_CLIENT_NEW;
3299563877eSSven Eckelmann 	if (batadv_is_wifi_iface(ifindex))
33047c94655SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
33147c94655SAntonio Quartulli 	atomic_set(&tt_local->common.refcount, 2);
33247c94655SAntonio Quartulli 	tt_local->last_seen = jiffies;
33347c94655SAntonio Quartulli 	tt_local->common.added_at = tt_local->last_seen;
334c6c8fea2SSven Eckelmann 
335c6c8fea2SSven Eckelmann 	/* the batman interface mac address should never be purged */
3361eda58bfSSven Eckelmann 	if (batadv_compare_eth(addr, soft_iface->dev_addr))
33747c94655SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
338c6c8fea2SSven Eckelmann 
339807736f6SSven Eckelmann 	hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
34047c94655SAntonio Quartulli 				     batadv_choose_orig, &tt_local->common,
34147c94655SAntonio Quartulli 				     &tt_local->common.hash_entry);
34280b3f58cSSimon Wunderlich 
34380b3f58cSSimon Wunderlich 	if (unlikely(hash_added != 0)) {
34480b3f58cSSimon Wunderlich 		/* remove the reference for the hash */
34547c94655SAntonio Quartulli 		batadv_tt_local_entry_free_ref(tt_local);
34680b3f58cSSimon Wunderlich 		goto out;
34780b3f58cSSimon Wunderlich 	}
34880b3f58cSSimon Wunderlich 
349068ee6e2SAntonio Quartulli add_event:
3503abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
351ff66c975SAntonio Quartulli 
352068ee6e2SAntonio Quartulli check_roaming:
353068ee6e2SAntonio Quartulli 	/* Check whether it is a roaming, but don't do anything if the roaming
354068ee6e2SAntonio Quartulli 	 * process has already been handled
355068ee6e2SAntonio Quartulli 	 */
356068ee6e2SAntonio Quartulli 	if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
357db08e6e5SSimon Wunderlich 		/* These node are probably going to update their tt table */
35847c94655SAntonio Quartulli 		head = &tt_global->orig_list;
359db08e6e5SSimon Wunderlich 		rcu_read_lock();
360b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(orig_entry, head, list) {
36147c94655SAntonio Quartulli 			batadv_send_roam_adv(bat_priv, tt_global->common.addr,
362db08e6e5SSimon Wunderlich 					     orig_entry->orig_node);
363db08e6e5SSimon Wunderlich 		}
364db08e6e5SSimon Wunderlich 		rcu_read_unlock();
365068ee6e2SAntonio Quartulli 		if (roamed_back) {
366068ee6e2SAntonio Quartulli 			batadv_tt_global_free(bat_priv, tt_global,
367068ee6e2SAntonio Quartulli 					      "Roaming canceled");
368068ee6e2SAntonio Quartulli 			tt_global = NULL;
369068ee6e2SAntonio Quartulli 		} else {
370db08e6e5SSimon Wunderlich 			/* The global entry has to be marked as ROAMING and
371db08e6e5SSimon Wunderlich 			 * has to be kept for consistency purpose
372db08e6e5SSimon Wunderlich 			 */
37347c94655SAntonio Quartulli 			tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
37447c94655SAntonio Quartulli 			tt_global->roam_at = jiffies;
3757683fdc1SAntonio Quartulli 		}
376068ee6e2SAntonio Quartulli 	}
377068ee6e2SAntonio Quartulli 
3787683fdc1SAntonio Quartulli out:
37947c94655SAntonio Quartulli 	if (tt_local)
38047c94655SAntonio Quartulli 		batadv_tt_local_entry_free_ref(tt_local);
38147c94655SAntonio Quartulli 	if (tt_global)
38247c94655SAntonio Quartulli 		batadv_tt_global_entry_free_ref(tt_global);
383c6c8fea2SSven Eckelmann }
384c6c8fea2SSven Eckelmann 
385e1bf0c14SMarek Lindner /**
386e1bf0c14SMarek Lindner  * batadv_tt_tvlv_container_update - update the translation table tvlv container
387e1bf0c14SMarek Lindner  *  after local tt changes have been committed
388e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
389e1bf0c14SMarek Lindner  */
390e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
391c6c8fea2SSven Eckelmann {
392e1bf0c14SMarek Lindner 	struct batadv_tt_change_node *entry, *safe;
393e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
394e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
395e1bf0c14SMarek Lindner 	int tt_diff_len = 0, tt_change_len = 0;
396e1bf0c14SMarek Lindner 	int tt_diff_entries_num = 0, tt_diff_entries_count = 0;
397c6c8fea2SSven Eckelmann 
398e1bf0c14SMarek Lindner 	tt_diff_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes));
399be9aa4c1SMarek Lindner 
400be9aa4c1SMarek Lindner 	/* if we have too many changes for one packet don't send any
401be9aa4c1SMarek Lindner 	 * and wait for the tt table request which will be fragmented
402be9aa4c1SMarek Lindner 	 */
403e1bf0c14SMarek Lindner 	if (tt_diff_len > bat_priv->soft_iface->mtu)
404e1bf0c14SMarek Lindner 		tt_diff_len = 0;
405be9aa4c1SMarek Lindner 
406e1bf0c14SMarek Lindner 	tt_data = kzalloc(sizeof(*tt_data) + tt_diff_len, GFP_ATOMIC);
407e1bf0c14SMarek Lindner 	if (!tt_data)
408e1bf0c14SMarek Lindner 		return;
409be9aa4c1SMarek Lindner 
410e1bf0c14SMarek Lindner 	tt_data->flags = BATADV_TT_OGM_DIFF;
411e1bf0c14SMarek Lindner 	tt_data->ttvn = atomic_read(&bat_priv->tt.vn);
412e1bf0c14SMarek Lindner 	tt_data->crc = htons(bat_priv->tt.local_crc);
413be9aa4c1SMarek Lindner 
414e1bf0c14SMarek Lindner 	if (tt_diff_len == 0)
415e1bf0c14SMarek Lindner 		goto container_register;
416be9aa4c1SMarek Lindner 
417e1bf0c14SMarek Lindner 	tt_diff_entries_num = tt_diff_len / batadv_tt_len(1);
418c6c8fea2SSven Eckelmann 
419807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
420807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.local_changes, 0);
421c6c8fea2SSven Eckelmann 
422e1bf0c14SMarek Lindner 	tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1);
423e1bf0c14SMarek Lindner 
424807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
425a73105b8SAntonio Quartulli 				 list) {
426e1bf0c14SMarek Lindner 		if (tt_diff_entries_count < tt_diff_entries_num) {
427e1bf0c14SMarek Lindner 			memcpy(tt_change + tt_diff_entries_count,
428e1bf0c14SMarek Lindner 			       &entry->change,
429e1bf0c14SMarek Lindner 			       sizeof(struct batadv_tvlv_tt_change));
430e1bf0c14SMarek Lindner 			tt_diff_entries_count++;
431c6c8fea2SSven Eckelmann 		}
432a73105b8SAntonio Quartulli 		list_del(&entry->list);
433a73105b8SAntonio Quartulli 		kfree(entry);
434c6c8fea2SSven Eckelmann 	}
435807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
436c6c8fea2SSven Eckelmann 
437a73105b8SAntonio Quartulli 	/* Keep the buffer for possible tt_request */
438807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.last_changeset_lock);
439807736f6SSven Eckelmann 	kfree(bat_priv->tt.last_changeset);
440807736f6SSven Eckelmann 	bat_priv->tt.last_changeset_len = 0;
441807736f6SSven Eckelmann 	bat_priv->tt.last_changeset = NULL;
442e1bf0c14SMarek Lindner 	tt_change_len = batadv_tt_len(tt_diff_entries_count);
443be9aa4c1SMarek Lindner 	/* check whether this new OGM has no changes due to size problems */
444e1bf0c14SMarek Lindner 	if (tt_diff_entries_count > 0) {
445be9aa4c1SMarek Lindner 		/* if kmalloc() fails we will reply with the full table
446a73105b8SAntonio Quartulli 		 * instead of providing the diff
447a73105b8SAntonio Quartulli 		 */
448e1bf0c14SMarek Lindner 		bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC);
449807736f6SSven Eckelmann 		if (bat_priv->tt.last_changeset) {
450e1bf0c14SMarek Lindner 			memcpy(bat_priv->tt.last_changeset,
451e1bf0c14SMarek Lindner 			       tt_change, tt_change_len);
452e1bf0c14SMarek Lindner 			bat_priv->tt.last_changeset_len = tt_diff_len;
453a73105b8SAntonio Quartulli 		}
454a73105b8SAntonio Quartulli 	}
455807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
456c6c8fea2SSven Eckelmann 
457e1bf0c14SMarek Lindner container_register:
458e1bf0c14SMarek Lindner 	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
459e1bf0c14SMarek Lindner 				       sizeof(*tt_data) + tt_change_len);
460e1bf0c14SMarek Lindner 	kfree(tt_data);
461c6c8fea2SSven Eckelmann }
462c6c8fea2SSven Eckelmann 
46308c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
464c6c8fea2SSven Eckelmann {
465c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
46656303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(net_dev);
467807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
46856303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
46985766a82SAntonio Quartulli 	struct batadv_tt_local_entry *tt_local;
47056303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if;
471c6c8fea2SSven Eckelmann 	struct hlist_head *head;
472c90681b8SAntonio Quartulli 	uint32_t i;
47385766a82SAntonio Quartulli 	int last_seen_secs;
47485766a82SAntonio Quartulli 	int last_seen_msecs;
47585766a82SAntonio Quartulli 	unsigned long last_seen_jiffies;
47685766a82SAntonio Quartulli 	bool no_purge;
47785766a82SAntonio Quartulli 	uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE;
478c6c8fea2SSven Eckelmann 
47930da63a6SMarek Lindner 	primary_if = batadv_seq_print_text_primary_if_get(seq);
48030da63a6SMarek Lindner 	if (!primary_if)
48132ae9b22SMarek Lindner 		goto out;
482c6c8fea2SSven Eckelmann 
48386ceb360SSven Eckelmann 	seq_printf(seq,
484f9d8a537SAntonio Quartulli 		   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.4x):\n",
485f9d8a537SAntonio Quartulli 		   net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn),
486f9d8a537SAntonio Quartulli 		   bat_priv->tt.local_crc);
48785766a82SAntonio Quartulli 	seq_printf(seq, "       %-13s %-7s %-10s\n", "Client", "Flags",
48885766a82SAntonio Quartulli 		   "Last seen");
489c6c8fea2SSven Eckelmann 
490c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
491c6c8fea2SSven Eckelmann 		head = &hash->table[i];
492c6c8fea2SSven Eckelmann 
4937aadf889SMarek Lindner 		rcu_read_lock();
494b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
4957aadf889SMarek Lindner 					 head, hash_entry) {
49685766a82SAntonio Quartulli 			tt_local = container_of(tt_common_entry,
49785766a82SAntonio Quartulli 						struct batadv_tt_local_entry,
49885766a82SAntonio Quartulli 						common);
49985766a82SAntonio Quartulli 			last_seen_jiffies = jiffies - tt_local->last_seen;
50085766a82SAntonio Quartulli 			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
50185766a82SAntonio Quartulli 			last_seen_secs = last_seen_msecs / 1000;
50285766a82SAntonio Quartulli 			last_seen_msecs = last_seen_msecs % 1000;
50385766a82SAntonio Quartulli 
50485766a82SAntonio Quartulli 			no_purge = tt_common_entry->flags & np_flag;
50585766a82SAntonio Quartulli 
50685766a82SAntonio Quartulli 			seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n",
50748100bacSAntonio Quartulli 				   tt_common_entry->addr,
50848100bacSAntonio Quartulli 				   (tt_common_entry->flags &
509acd34afaSSven Eckelmann 				    BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
51085766a82SAntonio Quartulli 				   no_purge ? 'P' : '.',
51148100bacSAntonio Quartulli 				   (tt_common_entry->flags &
512acd34afaSSven Eckelmann 				    BATADV_TT_CLIENT_NEW ? 'N' : '.'),
51348100bacSAntonio Quartulli 				   (tt_common_entry->flags &
514acd34afaSSven Eckelmann 				    BATADV_TT_CLIENT_PENDING ? 'X' : '.'),
51548100bacSAntonio Quartulli 				   (tt_common_entry->flags &
51685766a82SAntonio Quartulli 				    BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
517a7966d90SAntonio Quartulli 				   no_purge ? 0 : last_seen_secs,
518a7966d90SAntonio Quartulli 				   no_purge ? 0 : last_seen_msecs);
519c6c8fea2SSven Eckelmann 		}
5207aadf889SMarek Lindner 		rcu_read_unlock();
521c6c8fea2SSven Eckelmann 	}
52232ae9b22SMarek Lindner out:
52332ae9b22SMarek Lindner 	if (primary_if)
524e5d89254SSven Eckelmann 		batadv_hardif_free_ref(primary_if);
52530da63a6SMarek Lindner 	return 0;
526c6c8fea2SSven Eckelmann }
527c6c8fea2SSven Eckelmann 
52856303d34SSven Eckelmann static void
52956303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
53056303d34SSven Eckelmann 			    struct batadv_tt_local_entry *tt_local_entry,
531c566dbbeSAntonio Quartulli 			    uint16_t flags, const char *message)
532c6c8fea2SSven Eckelmann {
5333abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local_entry, flags);
534c6c8fea2SSven Eckelmann 
535015758d0SAntonio Quartulli 	/* The local client has to be marked as "pending to be removed" but has
536015758d0SAntonio Quartulli 	 * to be kept in the table in order to send it in a full table
5379cfc7bd6SSven Eckelmann 	 * response issued before the net ttvn increment (consistency check)
5389cfc7bd6SSven Eckelmann 	 */
539acd34afaSSven Eckelmann 	tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
540c566dbbeSAntonio Quartulli 
54139c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
54286ceb360SSven Eckelmann 		   "Local tt entry (%pM) pending to be removed: %s\n",
54386ceb360SSven Eckelmann 		   tt_local_entry->common.addr, message);
544c6c8fea2SSven Eckelmann }
545c6c8fea2SSven Eckelmann 
5467f91d06cSAntonio Quartulli /**
5477f91d06cSAntonio Quartulli  * batadv_tt_local_remove - logically remove an entry from the local table
5487f91d06cSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
5497f91d06cSAntonio Quartulli  * @addr: the MAC address of the client to remove
5507f91d06cSAntonio Quartulli  * @message: message to append to the log on deletion
5517f91d06cSAntonio Quartulli  * @roaming: true if the deletion is due to a roaming event
5527f91d06cSAntonio Quartulli  *
5537f91d06cSAntonio Quartulli  * Returns the flags assigned to the local entry before being deleted
5547f91d06cSAntonio Quartulli  */
5557f91d06cSAntonio Quartulli uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
5567f91d06cSAntonio Quartulli 				const uint8_t *addr, const char *message,
5577f91d06cSAntonio Quartulli 				bool roaming)
558c6c8fea2SSven Eckelmann {
559170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
5607f91d06cSAntonio Quartulli 	uint16_t flags, curr_flags = BATADV_NO_FLAGS;
561c6c8fea2SSven Eckelmann 
562a513088dSSven Eckelmann 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
5637683fdc1SAntonio Quartulli 	if (!tt_local_entry)
5647683fdc1SAntonio Quartulli 		goto out;
5657683fdc1SAntonio Quartulli 
5667f91d06cSAntonio Quartulli 	curr_flags = tt_local_entry->common.flags;
5677f91d06cSAntonio Quartulli 
568acd34afaSSven Eckelmann 	flags = BATADV_TT_CLIENT_DEL;
569068ee6e2SAntonio Quartulli 	/* if this global entry addition is due to a roaming, the node has to
570068ee6e2SAntonio Quartulli 	 * mark the local entry as "roamed" in order to correctly reroute
571068ee6e2SAntonio Quartulli 	 * packets later
572068ee6e2SAntonio Quartulli 	 */
5737c1fd91dSAntonio Quartulli 	if (roaming) {
574acd34afaSSven Eckelmann 		flags |= BATADV_TT_CLIENT_ROAM;
5757c1fd91dSAntonio Quartulli 		/* mark the local client as ROAMed */
5767c1fd91dSAntonio Quartulli 		tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
5777c1fd91dSAntonio Quartulli 	}
57842d0b044SSven Eckelmann 
579068ee6e2SAntonio Quartulli 	if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
580068ee6e2SAntonio Quartulli 		batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
581068ee6e2SAntonio Quartulli 					    message);
582068ee6e2SAntonio Quartulli 		goto out;
583068ee6e2SAntonio Quartulli 	}
584068ee6e2SAntonio Quartulli 	/* if this client has been added right now, it is possible to
585068ee6e2SAntonio Quartulli 	 * immediately purge it
586068ee6e2SAntonio Quartulli 	 */
5873abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
588068ee6e2SAntonio Quartulli 	hlist_del_rcu(&tt_local_entry->common.hash_entry);
589068ee6e2SAntonio Quartulli 	batadv_tt_local_entry_free_ref(tt_local_entry);
5907f91d06cSAntonio Quartulli 
5917683fdc1SAntonio Quartulli out:
5927683fdc1SAntonio Quartulli 	if (tt_local_entry)
593a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(tt_local_entry);
5947f91d06cSAntonio Quartulli 
5957f91d06cSAntonio Quartulli 	return curr_flags;
596c6c8fea2SSven Eckelmann }
597c6c8fea2SSven Eckelmann 
59856303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
599acd34afaSSven Eckelmann 				       struct hlist_head *head)
600c6c8fea2SSven Eckelmann {
60156303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
60256303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
603b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
604acd34afaSSven Eckelmann 
605b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
606acd34afaSSven Eckelmann 				  hash_entry) {
607acd34afaSSven Eckelmann 		tt_local_entry = container_of(tt_common_entry,
60856303d34SSven Eckelmann 					      struct batadv_tt_local_entry,
60956303d34SSven Eckelmann 					      common);
610acd34afaSSven Eckelmann 		if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
611acd34afaSSven Eckelmann 			continue;
612acd34afaSSven Eckelmann 
613acd34afaSSven Eckelmann 		/* entry already marked for deletion */
614acd34afaSSven Eckelmann 		if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
615acd34afaSSven Eckelmann 			continue;
616acd34afaSSven Eckelmann 
617acd34afaSSven Eckelmann 		if (!batadv_has_timed_out(tt_local_entry->last_seen,
618acd34afaSSven Eckelmann 					  BATADV_TT_LOCAL_TIMEOUT))
619acd34afaSSven Eckelmann 			continue;
620acd34afaSSven Eckelmann 
621acd34afaSSven Eckelmann 		batadv_tt_local_set_pending(bat_priv, tt_local_entry,
622acd34afaSSven Eckelmann 					    BATADV_TT_CLIENT_DEL, "timed out");
623acd34afaSSven Eckelmann 	}
624acd34afaSSven Eckelmann }
625acd34afaSSven Eckelmann 
62656303d34SSven Eckelmann static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
627acd34afaSSven Eckelmann {
628807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
629c6c8fea2SSven Eckelmann 	struct hlist_head *head;
6307683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
631c90681b8SAntonio Quartulli 	uint32_t i;
632c6c8fea2SSven Eckelmann 
633c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
634c6c8fea2SSven Eckelmann 		head = &hash->table[i];
6357683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
636c6c8fea2SSven Eckelmann 
6377683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
638acd34afaSSven Eckelmann 		batadv_tt_local_purge_list(bat_priv, head);
6397683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
640c6c8fea2SSven Eckelmann 	}
641c6c8fea2SSven Eckelmann }
642c6c8fea2SSven Eckelmann 
64356303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
644c6c8fea2SSven Eckelmann {
6455bf74e9cSSven Eckelmann 	struct batadv_hashtable *hash;
646a73105b8SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
64756303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
64856303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
649b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
6507683fdc1SAntonio Quartulli 	struct hlist_head *head;
651c90681b8SAntonio Quartulli 	uint32_t i;
652a73105b8SAntonio Quartulli 
653807736f6SSven Eckelmann 	if (!bat_priv->tt.local_hash)
654c6c8fea2SSven Eckelmann 		return;
655c6c8fea2SSven Eckelmann 
656807736f6SSven Eckelmann 	hash = bat_priv->tt.local_hash;
657a73105b8SAntonio Quartulli 
658a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
659a73105b8SAntonio Quartulli 		head = &hash->table[i];
660a73105b8SAntonio Quartulli 		list_lock = &hash->list_locks[i];
661a73105b8SAntonio Quartulli 
662a73105b8SAntonio Quartulli 		spin_lock_bh(list_lock);
663b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, node_tmp,
664a73105b8SAntonio Quartulli 					  head, hash_entry) {
665b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common_entry->hash_entry);
66656303d34SSven Eckelmann 			tt_local = container_of(tt_common_entry,
66756303d34SSven Eckelmann 						struct batadv_tt_local_entry,
66848100bacSAntonio Quartulli 						common);
66956303d34SSven Eckelmann 			batadv_tt_local_entry_free_ref(tt_local);
670a73105b8SAntonio Quartulli 		}
671a73105b8SAntonio Quartulli 		spin_unlock_bh(list_lock);
672a73105b8SAntonio Quartulli 	}
673a73105b8SAntonio Quartulli 
6741a8eaf07SSven Eckelmann 	batadv_hash_destroy(hash);
675a73105b8SAntonio Quartulli 
676807736f6SSven Eckelmann 	bat_priv->tt.local_hash = NULL;
677c6c8fea2SSven Eckelmann }
678c6c8fea2SSven Eckelmann 
67956303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv)
680c6c8fea2SSven Eckelmann {
681807736f6SSven Eckelmann 	if (bat_priv->tt.global_hash)
6825346c35eSSven Eckelmann 		return 0;
683c6c8fea2SSven Eckelmann 
684807736f6SSven Eckelmann 	bat_priv->tt.global_hash = batadv_hash_new(1024);
685c6c8fea2SSven Eckelmann 
686807736f6SSven Eckelmann 	if (!bat_priv->tt.global_hash)
6875346c35eSSven Eckelmann 		return -ENOMEM;
688c6c8fea2SSven Eckelmann 
689dec05074SAntonio Quartulli 	batadv_hash_set_lock_class(bat_priv->tt.global_hash,
690dec05074SAntonio Quartulli 				   &batadv_tt_global_hash_lock_class_key);
691dec05074SAntonio Quartulli 
6925346c35eSSven Eckelmann 	return 0;
693c6c8fea2SSven Eckelmann }
694c6c8fea2SSven Eckelmann 
69556303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
696a73105b8SAntonio Quartulli {
69756303d34SSven Eckelmann 	struct batadv_tt_change_node *entry, *safe;
698a73105b8SAntonio Quartulli 
699807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
700a73105b8SAntonio Quartulli 
701807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
702a73105b8SAntonio Quartulli 				 list) {
703a73105b8SAntonio Quartulli 		list_del(&entry->list);
704a73105b8SAntonio Quartulli 		kfree(entry);
705a73105b8SAntonio Quartulli 	}
706a73105b8SAntonio Quartulli 
707807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.local_changes, 0);
708807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
709a73105b8SAntonio Quartulli }
710a73105b8SAntonio Quartulli 
711d657e621SAntonio Quartulli /* retrieves the orig_tt_list_entry belonging to orig_node from the
712d657e621SAntonio Quartulli  * batadv_tt_global_entry list
713d657e621SAntonio Quartulli  *
714d657e621SAntonio Quartulli  * returns it with an increased refcounter, NULL if not found
715d657e621SAntonio Quartulli  */
716d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry *
717d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
718d657e621SAntonio Quartulli 				 const struct batadv_orig_node *orig_node)
719d657e621SAntonio Quartulli {
720d657e621SAntonio Quartulli 	struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
721d657e621SAntonio Quartulli 	const struct hlist_head *head;
722d657e621SAntonio Quartulli 
723d657e621SAntonio Quartulli 	rcu_read_lock();
724d657e621SAntonio Quartulli 	head = &entry->orig_list;
725b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(tmp_orig_entry, head, list) {
726d657e621SAntonio Quartulli 		if (tmp_orig_entry->orig_node != orig_node)
727d657e621SAntonio Quartulli 			continue;
728d657e621SAntonio Quartulli 		if (!atomic_inc_not_zero(&tmp_orig_entry->refcount))
729d657e621SAntonio Quartulli 			continue;
730d657e621SAntonio Quartulli 
731d657e621SAntonio Quartulli 		orig_entry = tmp_orig_entry;
732d657e621SAntonio Quartulli 		break;
733d657e621SAntonio Quartulli 	}
734d657e621SAntonio Quartulli 	rcu_read_unlock();
735d657e621SAntonio Quartulli 
736d657e621SAntonio Quartulli 	return orig_entry;
737d657e621SAntonio Quartulli }
738d657e621SAntonio Quartulli 
739db08e6e5SSimon Wunderlich /* find out if an orig_node is already in the list of a tt_global_entry.
740d657e621SAntonio Quartulli  * returns true if found, false otherwise
741db08e6e5SSimon Wunderlich  */
74256303d34SSven Eckelmann static bool
74356303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
74456303d34SSven Eckelmann 				const struct batadv_orig_node *orig_node)
745db08e6e5SSimon Wunderlich {
746d657e621SAntonio Quartulli 	struct batadv_tt_orig_list_entry *orig_entry;
747db08e6e5SSimon Wunderlich 	bool found = false;
748db08e6e5SSimon Wunderlich 
749d657e621SAntonio Quartulli 	orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
750d657e621SAntonio Quartulli 	if (orig_entry) {
751db08e6e5SSimon Wunderlich 		found = true;
752d657e621SAntonio Quartulli 		batadv_tt_orig_list_entry_free_ref(orig_entry);
753db08e6e5SSimon Wunderlich 	}
754d657e621SAntonio Quartulli 
755db08e6e5SSimon Wunderlich 	return found;
756db08e6e5SSimon Wunderlich }
757db08e6e5SSimon Wunderlich 
758a513088dSSven Eckelmann static void
759d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
76056303d34SSven Eckelmann 				struct batadv_orig_node *orig_node, int ttvn)
761db08e6e5SSimon Wunderlich {
76256303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
763db08e6e5SSimon Wunderlich 
764d657e621SAntonio Quartulli 	orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
76530cfd02bSAntonio Quartulli 	if (orig_entry) {
76630cfd02bSAntonio Quartulli 		/* refresh the ttvn: the current value could be a bogus one that
76730cfd02bSAntonio Quartulli 		 * was added during a "temporary client detection"
76830cfd02bSAntonio Quartulli 		 */
76930cfd02bSAntonio Quartulli 		orig_entry->ttvn = ttvn;
770d657e621SAntonio Quartulli 		goto out;
77130cfd02bSAntonio Quartulli 	}
772d657e621SAntonio Quartulli 
773db08e6e5SSimon Wunderlich 	orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
774db08e6e5SSimon Wunderlich 	if (!orig_entry)
775d657e621SAntonio Quartulli 		goto out;
776db08e6e5SSimon Wunderlich 
777db08e6e5SSimon Wunderlich 	INIT_HLIST_NODE(&orig_entry->list);
778db08e6e5SSimon Wunderlich 	atomic_inc(&orig_node->refcount);
779db08e6e5SSimon Wunderlich 	atomic_inc(&orig_node->tt_size);
780db08e6e5SSimon Wunderlich 	orig_entry->orig_node = orig_node;
781db08e6e5SSimon Wunderlich 	orig_entry->ttvn = ttvn;
782d657e621SAntonio Quartulli 	atomic_set(&orig_entry->refcount, 2);
783db08e6e5SSimon Wunderlich 
784d657e621SAntonio Quartulli 	spin_lock_bh(&tt_global->list_lock);
785db08e6e5SSimon Wunderlich 	hlist_add_head_rcu(&orig_entry->list,
786d657e621SAntonio Quartulli 			   &tt_global->orig_list);
787d657e621SAntonio Quartulli 	spin_unlock_bh(&tt_global->list_lock);
788d657e621SAntonio Quartulli out:
789d657e621SAntonio Quartulli 	if (orig_entry)
790d657e621SAntonio Quartulli 		batadv_tt_orig_list_entry_free_ref(orig_entry);
791db08e6e5SSimon Wunderlich }
792db08e6e5SSimon Wunderlich 
793d4ff40f6SAntonio Quartulli /**
794d4ff40f6SAntonio Quartulli  * batadv_tt_global_add - add a new TT global entry or update an existing one
795d4ff40f6SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
796d4ff40f6SAntonio Quartulli  * @orig_node: the originator announcing the client
797d4ff40f6SAntonio Quartulli  * @tt_addr: the mac address of the non-mesh client
798d4ff40f6SAntonio Quartulli  * @flags: TT flags that have to be set for this non-mesh client
799d4ff40f6SAntonio Quartulli  * @ttvn: the tt version number ever announcing this non-mesh client
800d4ff40f6SAntonio Quartulli  *
801d4ff40f6SAntonio Quartulli  * Add a new TT global entry for the given originator. If the entry already
802d4ff40f6SAntonio Quartulli  * exists add a new reference to the given originator (a global entry can have
803d4ff40f6SAntonio Quartulli  * references to multiple originators) and adjust the flags attribute to reflect
804d4ff40f6SAntonio Quartulli  * the function argument.
805d4ff40f6SAntonio Quartulli  * If a TT local entry exists for this non-mesh client remove it.
806d4ff40f6SAntonio Quartulli  *
807d4ff40f6SAntonio Quartulli  * The caller must hold orig_node refcount.
808d4ff40f6SAntonio Quartulli  */
80956303d34SSven Eckelmann int batadv_tt_global_add(struct batadv_priv *bat_priv,
81056303d34SSven Eckelmann 			 struct batadv_orig_node *orig_node,
811d4ff40f6SAntonio Quartulli 			 const unsigned char *tt_addr, uint16_t flags,
812d4f44692SAntonio Quartulli 			 uint8_t ttvn)
813c6c8fea2SSven Eckelmann {
814170173bfSSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
815170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
8167683fdc1SAntonio Quartulli 	int ret = 0;
81780b3f58cSSimon Wunderlich 	int hash_added;
81856303d34SSven Eckelmann 	struct batadv_tt_common_entry *common;
8197f91d06cSAntonio Quartulli 	uint16_t local_flags;
820c6c8fea2SSven Eckelmann 
821a513088dSSven Eckelmann 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr);
822068ee6e2SAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr);
823068ee6e2SAntonio Quartulli 
824068ee6e2SAntonio Quartulli 	/* if the node already has a local client for this entry, it has to wait
825068ee6e2SAntonio Quartulli 	 * for a roaming advertisement instead of manually messing up the global
826068ee6e2SAntonio Quartulli 	 * table
827068ee6e2SAntonio Quartulli 	 */
828068ee6e2SAntonio Quartulli 	if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
829068ee6e2SAntonio Quartulli 	    !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
830068ee6e2SAntonio Quartulli 		goto out;
831c6c8fea2SSven Eckelmann 
8322dafb49dSAntonio Quartulli 	if (!tt_global_entry) {
833d4f44692SAntonio Quartulli 		tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC);
8342dafb49dSAntonio Quartulli 		if (!tt_global_entry)
8357683fdc1SAntonio Quartulli 			goto out;
8367683fdc1SAntonio Quartulli 
837c0a55929SSven Eckelmann 		common = &tt_global_entry->common;
838c0a55929SSven Eckelmann 		memcpy(common->addr, tt_addr, ETH_ALEN);
839db08e6e5SSimon Wunderlich 
840d4f44692SAntonio Quartulli 		common->flags = flags;
841cc47f66eSAntonio Quartulli 		tt_global_entry->roam_at = 0;
842fdf79320SAntonio Quartulli 		/* node must store current time in case of roaming. This is
843fdf79320SAntonio Quartulli 		 * needed to purge this entry out on timeout (if nobody claims
844fdf79320SAntonio Quartulli 		 * it)
845fdf79320SAntonio Quartulli 		 */
846fdf79320SAntonio Quartulli 		if (flags & BATADV_TT_CLIENT_ROAM)
847fdf79320SAntonio Quartulli 			tt_global_entry->roam_at = jiffies;
848c0a55929SSven Eckelmann 		atomic_set(&common->refcount, 2);
84930cfd02bSAntonio Quartulli 		common->added_at = jiffies;
850db08e6e5SSimon Wunderlich 
851db08e6e5SSimon Wunderlich 		INIT_HLIST_HEAD(&tt_global_entry->orig_list);
852db08e6e5SSimon Wunderlich 		spin_lock_init(&tt_global_entry->list_lock);
8537683fdc1SAntonio Quartulli 
854807736f6SSven Eckelmann 		hash_added = batadv_hash_add(bat_priv->tt.global_hash,
855a513088dSSven Eckelmann 					     batadv_compare_tt,
856a513088dSSven Eckelmann 					     batadv_choose_orig, common,
857a513088dSSven Eckelmann 					     &common->hash_entry);
85880b3f58cSSimon Wunderlich 
85980b3f58cSSimon Wunderlich 		if (unlikely(hash_added != 0)) {
86080b3f58cSSimon Wunderlich 			/* remove the reference for the hash */
861a513088dSSven Eckelmann 			batadv_tt_global_entry_free_ref(tt_global_entry);
86280b3f58cSSimon Wunderlich 			goto out_remove;
86380b3f58cSSimon Wunderlich 		}
864a73105b8SAntonio Quartulli 	} else {
865068ee6e2SAntonio Quartulli 		common = &tt_global_entry->common;
86630cfd02bSAntonio Quartulli 		/* If there is already a global entry, we can use this one for
86730cfd02bSAntonio Quartulli 		 * our processing.
868068ee6e2SAntonio Quartulli 		 * But if we are trying to add a temporary client then here are
869068ee6e2SAntonio Quartulli 		 * two options at this point:
870068ee6e2SAntonio Quartulli 		 * 1) the global client is not a temporary client: the global
871068ee6e2SAntonio Quartulli 		 *    client has to be left as it is, temporary information
872068ee6e2SAntonio Quartulli 		 *    should never override any already known client state
873068ee6e2SAntonio Quartulli 		 * 2) the global client is a temporary client: purge the
874068ee6e2SAntonio Quartulli 		 *    originator list and add the new one orig_entry
87530cfd02bSAntonio Quartulli 		 */
876068ee6e2SAntonio Quartulli 		if (flags & BATADV_TT_CLIENT_TEMP) {
877068ee6e2SAntonio Quartulli 			if (!(common->flags & BATADV_TT_CLIENT_TEMP))
87830cfd02bSAntonio Quartulli 				goto out;
879068ee6e2SAntonio Quartulli 			if (batadv_tt_global_entry_has_orig(tt_global_entry,
880068ee6e2SAntonio Quartulli 							    orig_node))
881068ee6e2SAntonio Quartulli 				goto out_remove;
882068ee6e2SAntonio Quartulli 			batadv_tt_global_del_orig_list(tt_global_entry);
883068ee6e2SAntonio Quartulli 			goto add_orig_entry;
884068ee6e2SAntonio Quartulli 		}
88530cfd02bSAntonio Quartulli 
88630cfd02bSAntonio Quartulli 		/* if the client was temporary added before receiving the first
88730cfd02bSAntonio Quartulli 		 * OGM announcing it, we have to clear the TEMP flag
88830cfd02bSAntonio Quartulli 		 */
889068ee6e2SAntonio Quartulli 		common->flags &= ~BATADV_TT_CLIENT_TEMP;
890db08e6e5SSimon Wunderlich 
891e9c00136SAntonio Quartulli 		/* the change can carry possible "attribute" flags like the
892e9c00136SAntonio Quartulli 		 * TT_CLIENT_WIFI, therefore they have to be copied in the
893e9c00136SAntonio Quartulli 		 * client entry
894e9c00136SAntonio Quartulli 		 */
895e9c00136SAntonio Quartulli 		tt_global_entry->common.flags |= flags;
896e9c00136SAntonio Quartulli 
897acd34afaSSven Eckelmann 		/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
898acd34afaSSven Eckelmann 		 * one originator left in the list and we previously received a
899db08e6e5SSimon Wunderlich 		 * delete + roaming change for this originator.
900db08e6e5SSimon Wunderlich 		 *
901db08e6e5SSimon Wunderlich 		 * We should first delete the old originator before adding the
902db08e6e5SSimon Wunderlich 		 * new one.
903db08e6e5SSimon Wunderlich 		 */
904068ee6e2SAntonio Quartulli 		if (common->flags & BATADV_TT_CLIENT_ROAM) {
905a513088dSSven Eckelmann 			batadv_tt_global_del_orig_list(tt_global_entry);
906068ee6e2SAntonio Quartulli 			common->flags &= ~BATADV_TT_CLIENT_ROAM;
907cc47f66eSAntonio Quartulli 			tt_global_entry->roam_at = 0;
908c6c8fea2SSven Eckelmann 		}
909db08e6e5SSimon Wunderlich 	}
910068ee6e2SAntonio Quartulli add_orig_entry:
91130cfd02bSAntonio Quartulli 	/* add the new orig_entry (if needed) or update it */
912d657e621SAntonio Quartulli 	batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
913db08e6e5SSimon Wunderlich 
91439c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
915a73105b8SAntonio Quartulli 		   "Creating new global tt entry: %pM (via %pM)\n",
916068ee6e2SAntonio Quartulli 		   common->addr, orig_node->orig);
917c10dba05SAntonio Quartulli 	ret = 1;
918a73105b8SAntonio Quartulli 
91980b3f58cSSimon Wunderlich out_remove:
9207f91d06cSAntonio Quartulli 
921c6c8fea2SSven Eckelmann 	/* remove address from local hash if present */
9227f91d06cSAntonio Quartulli 	local_flags = batadv_tt_local_remove(bat_priv, tt_addr,
923acd34afaSSven Eckelmann 					     "global tt received",
924c1d07431SAntonio Quartulli 					     flags & BATADV_TT_CLIENT_ROAM);
9257f91d06cSAntonio Quartulli 	tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
9267f91d06cSAntonio Quartulli 
927068ee6e2SAntonio Quartulli 	if (!(flags & BATADV_TT_CLIENT_ROAM))
928068ee6e2SAntonio Quartulli 		/* this is a normal global add. Therefore the client is not in a
929068ee6e2SAntonio Quartulli 		 * roaming state anymore.
930068ee6e2SAntonio Quartulli 		 */
931068ee6e2SAntonio Quartulli 		tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
932068ee6e2SAntonio Quartulli 
9337683fdc1SAntonio Quartulli out:
9347683fdc1SAntonio Quartulli 	if (tt_global_entry)
935a513088dSSven Eckelmann 		batadv_tt_global_entry_free_ref(tt_global_entry);
936068ee6e2SAntonio Quartulli 	if (tt_local_entry)
937068ee6e2SAntonio Quartulli 		batadv_tt_local_entry_free_ref(tt_local_entry);
9387683fdc1SAntonio Quartulli 	return ret;
939c6c8fea2SSven Eckelmann }
940c6c8fea2SSven Eckelmann 
941981d8900SSven Eckelmann /* batadv_transtable_best_orig - Get best originator list entry from tt entry
942981d8900SSven Eckelmann  * @tt_global_entry: global translation table entry to be analyzed
943981d8900SSven Eckelmann  *
944981d8900SSven Eckelmann  * This functon assumes the caller holds rcu_read_lock().
945981d8900SSven Eckelmann  * Returns best originator list entry or NULL on errors.
946981d8900SSven Eckelmann  */
947981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry *
948981d8900SSven Eckelmann batadv_transtable_best_orig(struct batadv_tt_global_entry *tt_global_entry)
949981d8900SSven Eckelmann {
950981d8900SSven Eckelmann 	struct batadv_neigh_node *router = NULL;
951981d8900SSven Eckelmann 	struct hlist_head *head;
952981d8900SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL;
953981d8900SSven Eckelmann 	int best_tq = 0;
954981d8900SSven Eckelmann 
955981d8900SSven Eckelmann 	head = &tt_global_entry->orig_list;
956b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(orig_entry, head, list) {
957981d8900SSven Eckelmann 		router = batadv_orig_node_get_router(orig_entry->orig_node);
958981d8900SSven Eckelmann 		if (!router)
959981d8900SSven Eckelmann 			continue;
960981d8900SSven Eckelmann 
961981d8900SSven Eckelmann 		if (router->tq_avg > best_tq) {
962981d8900SSven Eckelmann 			best_entry = orig_entry;
963981d8900SSven Eckelmann 			best_tq = router->tq_avg;
964981d8900SSven Eckelmann 		}
965981d8900SSven Eckelmann 
966981d8900SSven Eckelmann 		batadv_neigh_node_free_ref(router);
967981d8900SSven Eckelmann 	}
968981d8900SSven Eckelmann 
969981d8900SSven Eckelmann 	return best_entry;
970981d8900SSven Eckelmann }
971981d8900SSven Eckelmann 
972981d8900SSven Eckelmann /* batadv_tt_global_print_entry - print all orig nodes who announce the address
973981d8900SSven Eckelmann  * for this global entry
974981d8900SSven Eckelmann  * @tt_global_entry: global translation table entry to be printed
975981d8900SSven Eckelmann  * @seq: debugfs table seq_file struct
976981d8900SSven Eckelmann  *
977981d8900SSven Eckelmann  * This functon assumes the caller holds rcu_read_lock().
978db08e6e5SSimon Wunderlich  */
979a513088dSSven Eckelmann static void
98056303d34SSven Eckelmann batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry,
981db08e6e5SSimon Wunderlich 			     struct seq_file *seq)
982db08e6e5SSimon Wunderlich {
983db08e6e5SSimon Wunderlich 	struct hlist_head *head;
984981d8900SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
98556303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
986db08e6e5SSimon Wunderlich 	uint16_t flags;
987db08e6e5SSimon Wunderlich 	uint8_t last_ttvn;
988db08e6e5SSimon Wunderlich 
989db08e6e5SSimon Wunderlich 	tt_common_entry = &tt_global_entry->common;
990981d8900SSven Eckelmann 	flags = tt_common_entry->flags;
991981d8900SSven Eckelmann 
992981d8900SSven Eckelmann 	best_entry = batadv_transtable_best_orig(tt_global_entry);
993981d8900SSven Eckelmann 	if (best_entry) {
994981d8900SSven Eckelmann 		last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
995f9d8a537SAntonio Quartulli 		seq_printf(seq,
996f9d8a537SAntonio Quartulli 			   " %c %pM  (%3u) via %pM     (%3u)   (%#.4x) [%c%c%c]\n",
997981d8900SSven Eckelmann 			   '*', tt_global_entry->common.addr,
998981d8900SSven Eckelmann 			   best_entry->ttvn, best_entry->orig_node->orig,
999f9d8a537SAntonio Quartulli 			   last_ttvn, best_entry->orig_node->tt_crc,
1000981d8900SSven Eckelmann 			   (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
1001981d8900SSven Eckelmann 			   (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
1002981d8900SSven Eckelmann 			   (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
1003981d8900SSven Eckelmann 	}
1004db08e6e5SSimon Wunderlich 
1005db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
1006db08e6e5SSimon Wunderlich 
1007b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(orig_entry, head, list) {
1008981d8900SSven Eckelmann 		if (best_entry == orig_entry)
1009981d8900SSven Eckelmann 			continue;
1010981d8900SSven Eckelmann 
1011db08e6e5SSimon Wunderlich 		last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
1012981d8900SSven Eckelmann 		seq_printf(seq,	" %c %pM  (%3u) via %pM     (%3u)   [%c%c%c]\n",
1013981d8900SSven Eckelmann 			   '+', tt_global_entry->common.addr,
1014981d8900SSven Eckelmann 			   orig_entry->ttvn, orig_entry->orig_node->orig,
1015981d8900SSven Eckelmann 			   last_ttvn,
1016acd34afaSSven Eckelmann 			   (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
101730cfd02bSAntonio Quartulli 			   (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
101830cfd02bSAntonio Quartulli 			   (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
1019db08e6e5SSimon Wunderlich 	}
1020db08e6e5SSimon Wunderlich }
1021db08e6e5SSimon Wunderlich 
102208c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
1023c6c8fea2SSven Eckelmann {
1024c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
102556303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(net_dev);
1026807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
102756303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
102856303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
102956303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if;
1030c6c8fea2SSven Eckelmann 	struct hlist_head *head;
1031c90681b8SAntonio Quartulli 	uint32_t i;
1032c6c8fea2SSven Eckelmann 
103330da63a6SMarek Lindner 	primary_if = batadv_seq_print_text_primary_if_get(seq);
103430da63a6SMarek Lindner 	if (!primary_if)
103532ae9b22SMarek Lindner 		goto out;
1036c6c8fea2SSven Eckelmann 
10372dafb49dSAntonio Quartulli 	seq_printf(seq,
10382dafb49dSAntonio Quartulli 		   "Globally announced TT entries received via the mesh %s\n",
1039c6c8fea2SSven Eckelmann 		   net_dev->name);
1040f9d8a537SAntonio Quartulli 	seq_printf(seq, "       %-13s %s       %-15s %s (%-6s) %s\n",
1041f9d8a537SAntonio Quartulli 		   "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC",
1042f9d8a537SAntonio Quartulli 		   "Flags");
1043c6c8fea2SSven Eckelmann 
1044c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
1045c6c8fea2SSven Eckelmann 		head = &hash->table[i];
1046c6c8fea2SSven Eckelmann 
10477aadf889SMarek Lindner 		rcu_read_lock();
1048b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
10497aadf889SMarek Lindner 					 head, hash_entry) {
105056303d34SSven Eckelmann 			tt_global = container_of(tt_common_entry,
105156303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
105248100bacSAntonio Quartulli 						 common);
105356303d34SSven Eckelmann 			batadv_tt_global_print_entry(tt_global, seq);
1054c6c8fea2SSven Eckelmann 		}
10557aadf889SMarek Lindner 		rcu_read_unlock();
1056c6c8fea2SSven Eckelmann 	}
105732ae9b22SMarek Lindner out:
105832ae9b22SMarek Lindner 	if (primary_if)
1059e5d89254SSven Eckelmann 		batadv_hardif_free_ref(primary_if);
106030da63a6SMarek Lindner 	return 0;
1061c6c8fea2SSven Eckelmann }
1062c6c8fea2SSven Eckelmann 
1063db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */
1064a513088dSSven Eckelmann static void
106556303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
1066db08e6e5SSimon Wunderlich {
1067db08e6e5SSimon Wunderlich 	struct hlist_head *head;
1068b67bfe0dSSasha Levin 	struct hlist_node *safe;
106956303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
1070db08e6e5SSimon Wunderlich 
1071db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
1072db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
1073b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(orig_entry, safe, head, list) {
1074b67bfe0dSSasha Levin 		hlist_del_rcu(&orig_entry->list);
1075a513088dSSven Eckelmann 		batadv_tt_orig_list_entry_free_ref(orig_entry);
1076db08e6e5SSimon Wunderlich 	}
1077db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
1078db08e6e5SSimon Wunderlich }
1079db08e6e5SSimon Wunderlich 
1080a513088dSSven Eckelmann static void
108156303d34SSven Eckelmann batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv,
108256303d34SSven Eckelmann 				struct batadv_tt_global_entry *tt_global_entry,
108356303d34SSven Eckelmann 				struct batadv_orig_node *orig_node,
1084db08e6e5SSimon Wunderlich 				const char *message)
1085db08e6e5SSimon Wunderlich {
1086db08e6e5SSimon Wunderlich 	struct hlist_head *head;
1087b67bfe0dSSasha Levin 	struct hlist_node *safe;
108856303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
1089db08e6e5SSimon Wunderlich 
1090db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
1091db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
1092b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(orig_entry, safe, head, list) {
1093db08e6e5SSimon Wunderlich 		if (orig_entry->orig_node == orig_node) {
109439c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
1095db08e6e5SSimon Wunderlich 				   "Deleting %pM from global tt entry %pM: %s\n",
10961eda58bfSSven Eckelmann 				   orig_node->orig,
10971eda58bfSSven Eckelmann 				   tt_global_entry->common.addr, message);
1098b67bfe0dSSasha Levin 			hlist_del_rcu(&orig_entry->list);
1099a513088dSSven Eckelmann 			batadv_tt_orig_list_entry_free_ref(orig_entry);
1100db08e6e5SSimon Wunderlich 		}
1101db08e6e5SSimon Wunderlich 	}
1102db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
1103db08e6e5SSimon Wunderlich }
1104db08e6e5SSimon Wunderlich 
1105db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry
1106acd34afaSSven Eckelmann  * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
1107acd34afaSSven Eckelmann  * timer, otherwise we simply remove the originator scheduled for deletion.
1108db08e6e5SSimon Wunderlich  */
1109a513088dSSven Eckelmann static void
111056303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
111156303d34SSven Eckelmann 			     struct batadv_tt_global_entry *tt_global_entry,
111256303d34SSven Eckelmann 			     struct batadv_orig_node *orig_node,
111356303d34SSven Eckelmann 			     const char *message)
1114db08e6e5SSimon Wunderlich {
1115db08e6e5SSimon Wunderlich 	bool last_entry = true;
1116db08e6e5SSimon Wunderlich 	struct hlist_head *head;
111756303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
1118db08e6e5SSimon Wunderlich 
1119db08e6e5SSimon Wunderlich 	/* no local entry exists, case 1:
1120db08e6e5SSimon Wunderlich 	 * Check if this is the last one or if other entries exist.
1121db08e6e5SSimon Wunderlich 	 */
1122db08e6e5SSimon Wunderlich 
1123db08e6e5SSimon Wunderlich 	rcu_read_lock();
1124db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
1125b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(orig_entry, head, list) {
1126db08e6e5SSimon Wunderlich 		if (orig_entry->orig_node != orig_node) {
1127db08e6e5SSimon Wunderlich 			last_entry = false;
1128db08e6e5SSimon Wunderlich 			break;
1129db08e6e5SSimon Wunderlich 		}
1130db08e6e5SSimon Wunderlich 	}
1131db08e6e5SSimon Wunderlich 	rcu_read_unlock();
1132db08e6e5SSimon Wunderlich 
1133db08e6e5SSimon Wunderlich 	if (last_entry) {
1134db08e6e5SSimon Wunderlich 		/* its the last one, mark for roaming. */
1135acd34afaSSven Eckelmann 		tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
1136db08e6e5SSimon Wunderlich 		tt_global_entry->roam_at = jiffies;
1137db08e6e5SSimon Wunderlich 	} else
1138db08e6e5SSimon Wunderlich 		/* there is another entry, we can simply delete this
1139db08e6e5SSimon Wunderlich 		 * one and can still use the other one.
1140db08e6e5SSimon Wunderlich 		 */
1141a513088dSSven Eckelmann 		batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
1142db08e6e5SSimon Wunderlich 						orig_node, message);
1143db08e6e5SSimon Wunderlich }
1144db08e6e5SSimon Wunderlich 
1145db08e6e5SSimon Wunderlich 
1146db08e6e5SSimon Wunderlich 
114756303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv,
114856303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node,
1149de7aae65SSven Eckelmann 				 const unsigned char *addr,
1150cc47f66eSAntonio Quartulli 				 const char *message, bool roaming)
1151a73105b8SAntonio Quartulli {
1152170173bfSSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
115356303d34SSven Eckelmann 	struct batadv_tt_local_entry *local_entry = NULL;
1154a73105b8SAntonio Quartulli 
1155a513088dSSven Eckelmann 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
1156db08e6e5SSimon Wunderlich 	if (!tt_global_entry)
11577683fdc1SAntonio Quartulli 		goto out;
1158a73105b8SAntonio Quartulli 
1159db08e6e5SSimon Wunderlich 	if (!roaming) {
1160a513088dSSven Eckelmann 		batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
1161a513088dSSven Eckelmann 						orig_node, message);
116292f90f56SSven Eckelmann 
1163db08e6e5SSimon Wunderlich 		if (hlist_empty(&tt_global_entry->orig_list))
1164be73b488SAntonio Quartulli 			batadv_tt_global_free(bat_priv, tt_global_entry,
1165db08e6e5SSimon Wunderlich 					      message);
1166db08e6e5SSimon Wunderlich 
1167cc47f66eSAntonio Quartulli 		goto out;
1168cc47f66eSAntonio Quartulli 	}
116992f90f56SSven Eckelmann 
1170db08e6e5SSimon Wunderlich 	/* if we are deleting a global entry due to a roam
1171db08e6e5SSimon Wunderlich 	 * event, there are two possibilities:
1172db08e6e5SSimon Wunderlich 	 * 1) the client roamed from node A to node B => if there
1173db08e6e5SSimon Wunderlich 	 *    is only one originator left for this client, we mark
1174acd34afaSSven Eckelmann 	 *    it with BATADV_TT_CLIENT_ROAM, we start a timer and we
1175db08e6e5SSimon Wunderlich 	 *    wait for node B to claim it. In case of timeout
1176db08e6e5SSimon Wunderlich 	 *    the entry is purged.
1177db08e6e5SSimon Wunderlich 	 *
1178db08e6e5SSimon Wunderlich 	 *    If there are other originators left, we directly delete
1179db08e6e5SSimon Wunderlich 	 *    the originator.
1180db08e6e5SSimon Wunderlich 	 * 2) the client roamed to us => we can directly delete
11819cfc7bd6SSven Eckelmann 	 *    the global entry, since it is useless now.
11829cfc7bd6SSven Eckelmann 	 */
1183a513088dSSven Eckelmann 	local_entry = batadv_tt_local_hash_find(bat_priv,
1184db08e6e5SSimon Wunderlich 						tt_global_entry->common.addr);
1185a513088dSSven Eckelmann 	if (local_entry) {
1186db08e6e5SSimon Wunderlich 		/* local entry exists, case 2: client roamed to us. */
1187a513088dSSven Eckelmann 		batadv_tt_global_del_orig_list(tt_global_entry);
1188be73b488SAntonio Quartulli 		batadv_tt_global_free(bat_priv, tt_global_entry, message);
1189db08e6e5SSimon Wunderlich 	} else
1190db08e6e5SSimon Wunderlich 		/* no local entry exists, case 1: check for roaming */
1191a513088dSSven Eckelmann 		batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
1192a513088dSSven Eckelmann 					     orig_node, message);
1193db08e6e5SSimon Wunderlich 
119492f90f56SSven Eckelmann 
1195cc47f66eSAntonio Quartulli out:
11967683fdc1SAntonio Quartulli 	if (tt_global_entry)
1197a513088dSSven Eckelmann 		batadv_tt_global_entry_free_ref(tt_global_entry);
1198a513088dSSven Eckelmann 	if (local_entry)
1199a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(local_entry);
1200a73105b8SAntonio Quartulli }
1201a73105b8SAntonio Quartulli 
120256303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
120356303d34SSven Eckelmann 			       struct batadv_orig_node *orig_node,
120456303d34SSven Eckelmann 			       const char *message)
1205c6c8fea2SSven Eckelmann {
120656303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
120756303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
1208c90681b8SAntonio Quartulli 	uint32_t i;
1209807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
1210b67bfe0dSSasha Levin 	struct hlist_node *safe;
1211a73105b8SAntonio Quartulli 	struct hlist_head *head;
12127683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
1213c6c8fea2SSven Eckelmann 
12146e801494SSimon Wunderlich 	if (!hash)
12156e801494SSimon Wunderlich 		return;
12166e801494SSimon Wunderlich 
1217a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1218a73105b8SAntonio Quartulli 		head = &hash->table[i];
12197683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
1220c6c8fea2SSven Eckelmann 
12217683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
1222b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, safe,
1223a73105b8SAntonio Quartulli 					  head, hash_entry) {
122456303d34SSven Eckelmann 			tt_global = container_of(tt_common_entry,
122556303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
122648100bacSAntonio Quartulli 						 common);
1227db08e6e5SSimon Wunderlich 
122856303d34SSven Eckelmann 			batadv_tt_global_del_orig_entry(bat_priv, tt_global,
1229db08e6e5SSimon Wunderlich 							orig_node, message);
1230db08e6e5SSimon Wunderlich 
123156303d34SSven Eckelmann 			if (hlist_empty(&tt_global->orig_list)) {
123239c75a51SSven Eckelmann 				batadv_dbg(BATADV_DBG_TT, bat_priv,
1233db08e6e5SSimon Wunderlich 					   "Deleting global tt entry %pM: %s\n",
123456303d34SSven Eckelmann 					   tt_global->common.addr, message);
1235b67bfe0dSSasha Levin 				hlist_del_rcu(&tt_common_entry->hash_entry);
123656303d34SSven Eckelmann 				batadv_tt_global_entry_free_ref(tt_global);
1237c6c8fea2SSven Eckelmann 			}
1238a73105b8SAntonio Quartulli 		}
12397683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
12407683fdc1SAntonio Quartulli 	}
124117071578SAntonio Quartulli 	orig_node->tt_initialised = false;
1242c6c8fea2SSven Eckelmann }
1243c6c8fea2SSven Eckelmann 
124430cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
124530cfd02bSAntonio Quartulli 				      char **msg)
1246cc47f66eSAntonio Quartulli {
124730cfd02bSAntonio Quartulli 	bool purge = false;
124830cfd02bSAntonio Quartulli 	unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT;
124930cfd02bSAntonio Quartulli 	unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
1250cc47f66eSAntonio Quartulli 
125130cfd02bSAntonio Quartulli 	if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
125230cfd02bSAntonio Quartulli 	    batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
125330cfd02bSAntonio Quartulli 		purge = true;
125430cfd02bSAntonio Quartulli 		*msg = "Roaming timeout\n";
125542d0b044SSven Eckelmann 	}
125642d0b044SSven Eckelmann 
125730cfd02bSAntonio Quartulli 	if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
125830cfd02bSAntonio Quartulli 	    batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
125930cfd02bSAntonio Quartulli 		purge = true;
126030cfd02bSAntonio Quartulli 		*msg = "Temporary client timeout\n";
126130cfd02bSAntonio Quartulli 	}
126230cfd02bSAntonio Quartulli 
126330cfd02bSAntonio Quartulli 	return purge;
126430cfd02bSAntonio Quartulli }
126530cfd02bSAntonio Quartulli 
126630cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
126742d0b044SSven Eckelmann {
1268807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
126942d0b044SSven Eckelmann 	struct hlist_head *head;
1270b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
127142d0b044SSven Eckelmann 	spinlock_t *list_lock; /* protects write access to the hash lists */
127242d0b044SSven Eckelmann 	uint32_t i;
127330cfd02bSAntonio Quartulli 	char *msg = NULL;
127430cfd02bSAntonio Quartulli 	struct batadv_tt_common_entry *tt_common;
127530cfd02bSAntonio Quartulli 	struct batadv_tt_global_entry *tt_global;
127642d0b044SSven Eckelmann 
127742d0b044SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
127842d0b044SSven Eckelmann 		head = &hash->table[i];
127942d0b044SSven Eckelmann 		list_lock = &hash->list_locks[i];
128042d0b044SSven Eckelmann 
128142d0b044SSven Eckelmann 		spin_lock_bh(list_lock);
1282b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common, node_tmp, head,
128330cfd02bSAntonio Quartulli 					  hash_entry) {
128430cfd02bSAntonio Quartulli 			tt_global = container_of(tt_common,
128530cfd02bSAntonio Quartulli 						 struct batadv_tt_global_entry,
128630cfd02bSAntonio Quartulli 						 common);
128730cfd02bSAntonio Quartulli 
128830cfd02bSAntonio Quartulli 			if (!batadv_tt_global_to_purge(tt_global, &msg))
128930cfd02bSAntonio Quartulli 				continue;
129030cfd02bSAntonio Quartulli 
129130cfd02bSAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
129230cfd02bSAntonio Quartulli 				   "Deleting global tt entry (%pM): %s\n",
129330cfd02bSAntonio Quartulli 				   tt_global->common.addr, msg);
129430cfd02bSAntonio Quartulli 
1295b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common->hash_entry);
129630cfd02bSAntonio Quartulli 
129730cfd02bSAntonio Quartulli 			batadv_tt_global_entry_free_ref(tt_global);
129830cfd02bSAntonio Quartulli 		}
12997683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
1300cc47f66eSAntonio Quartulli 	}
1301cc47f66eSAntonio Quartulli }
1302cc47f66eSAntonio Quartulli 
130356303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
1304c6c8fea2SSven Eckelmann {
13055bf74e9cSSven Eckelmann 	struct batadv_hashtable *hash;
13067683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
130756303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
130856303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
1309b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
13107683fdc1SAntonio Quartulli 	struct hlist_head *head;
1311c90681b8SAntonio Quartulli 	uint32_t i;
13127683fdc1SAntonio Quartulli 
1313807736f6SSven Eckelmann 	if (!bat_priv->tt.global_hash)
1314c6c8fea2SSven Eckelmann 		return;
1315c6c8fea2SSven Eckelmann 
1316807736f6SSven Eckelmann 	hash = bat_priv->tt.global_hash;
13177683fdc1SAntonio Quartulli 
13187683fdc1SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
13197683fdc1SAntonio Quartulli 		head = &hash->table[i];
13207683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
13217683fdc1SAntonio Quartulli 
13227683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
1323b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, node_tmp,
13247683fdc1SAntonio Quartulli 					  head, hash_entry) {
1325b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common_entry->hash_entry);
132656303d34SSven Eckelmann 			tt_global = container_of(tt_common_entry,
132756303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
132848100bacSAntonio Quartulli 						 common);
132956303d34SSven Eckelmann 			batadv_tt_global_entry_free_ref(tt_global);
13307683fdc1SAntonio Quartulli 		}
13317683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
13327683fdc1SAntonio Quartulli 	}
13337683fdc1SAntonio Quartulli 
13341a8eaf07SSven Eckelmann 	batadv_hash_destroy(hash);
13357683fdc1SAntonio Quartulli 
1336807736f6SSven Eckelmann 	bat_priv->tt.global_hash = NULL;
1337c6c8fea2SSven Eckelmann }
1338c6c8fea2SSven Eckelmann 
133956303d34SSven Eckelmann static bool
134056303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
134156303d34SSven Eckelmann 		       struct batadv_tt_global_entry *tt_global_entry)
134259b699cdSAntonio Quartulli {
134359b699cdSAntonio Quartulli 	bool ret = false;
134459b699cdSAntonio Quartulli 
1345acd34afaSSven Eckelmann 	if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
1346acd34afaSSven Eckelmann 	    tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
134759b699cdSAntonio Quartulli 		ret = true;
134859b699cdSAntonio Quartulli 
134959b699cdSAntonio Quartulli 	return ret;
135059b699cdSAntonio Quartulli }
135159b699cdSAntonio Quartulli 
135256303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
135308c36d3eSSven Eckelmann 						  const uint8_t *src,
135408c36d3eSSven Eckelmann 						  const uint8_t *addr)
1355c6c8fea2SSven Eckelmann {
135656303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry = NULL;
135756303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry = NULL;
135856303d34SSven Eckelmann 	struct batadv_orig_node *orig_node = NULL;
1359981d8900SSven Eckelmann 	struct batadv_tt_orig_list_entry *best_entry;
1360c6c8fea2SSven Eckelmann 
13613d393e47SAntonio Quartulli 	if (src && atomic_read(&bat_priv->ap_isolation)) {
1362a513088dSSven Eckelmann 		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src);
1363068ee6e2SAntonio Quartulli 		if (!tt_local_entry ||
1364068ee6e2SAntonio Quartulli 		    (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
13653d393e47SAntonio Quartulli 			goto out;
13663d393e47SAntonio Quartulli 	}
13677aadf889SMarek Lindner 
1368a513088dSSven Eckelmann 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
13692dafb49dSAntonio Quartulli 	if (!tt_global_entry)
13707b36e8eeSMarek Lindner 		goto out;
1371c6c8fea2SSven Eckelmann 
13723d393e47SAntonio Quartulli 	/* check whether the clients should not communicate due to AP
13739cfc7bd6SSven Eckelmann 	 * isolation
13749cfc7bd6SSven Eckelmann 	 */
1375a513088dSSven Eckelmann 	if (tt_local_entry &&
1376a513088dSSven Eckelmann 	    _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
13773d393e47SAntonio Quartulli 		goto out;
13783d393e47SAntonio Quartulli 
1379db08e6e5SSimon Wunderlich 	rcu_read_lock();
1380981d8900SSven Eckelmann 	best_entry = batadv_transtable_best_orig(tt_global_entry);
1381db08e6e5SSimon Wunderlich 	/* found anything? */
1382981d8900SSven Eckelmann 	if (best_entry)
1383981d8900SSven Eckelmann 		orig_node = best_entry->orig_node;
1384db08e6e5SSimon Wunderlich 	if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
1385db08e6e5SSimon Wunderlich 		orig_node = NULL;
1386db08e6e5SSimon Wunderlich 	rcu_read_unlock();
1387981d8900SSven Eckelmann 
13887b36e8eeSMarek Lindner out:
13893d393e47SAntonio Quartulli 	if (tt_global_entry)
1390a513088dSSven Eckelmann 		batadv_tt_global_entry_free_ref(tt_global_entry);
13913d393e47SAntonio Quartulli 	if (tt_local_entry)
1392a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(tt_local_entry);
13933d393e47SAntonio Quartulli 
13947b36e8eeSMarek Lindner 	return orig_node;
1395c6c8fea2SSven Eckelmann }
1396a73105b8SAntonio Quartulli 
1397a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */
139856303d34SSven Eckelmann static uint16_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
139956303d34SSven Eckelmann 				     struct batadv_orig_node *orig_node)
1400a73105b8SAntonio Quartulli {
1401a73105b8SAntonio Quartulli 	uint16_t total = 0, total_one;
1402807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
140356303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
140456303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
1405a73105b8SAntonio Quartulli 	struct hlist_head *head;
1406c90681b8SAntonio Quartulli 	uint32_t i;
1407c90681b8SAntonio Quartulli 	int j;
1408a73105b8SAntonio Quartulli 
1409a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1410a73105b8SAntonio Quartulli 		head = &hash->table[i];
1411a73105b8SAntonio Quartulli 
1412a73105b8SAntonio Quartulli 		rcu_read_lock();
1413b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
141456303d34SSven Eckelmann 			tt_global = container_of(tt_common,
141556303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
141648100bacSAntonio Quartulli 						 common);
1417cc47f66eSAntonio Quartulli 			/* Roaming clients are in the global table for
1418cc47f66eSAntonio Quartulli 			 * consistency only. They don't have to be
1419cc47f66eSAntonio Quartulli 			 * taken into account while computing the
1420db08e6e5SSimon Wunderlich 			 * global crc
1421db08e6e5SSimon Wunderlich 			 */
1422acd34afaSSven Eckelmann 			if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
1423cc47f66eSAntonio Quartulli 				continue;
142430cfd02bSAntonio Quartulli 			/* Temporary clients have not been announced yet, so
142530cfd02bSAntonio Quartulli 			 * they have to be skipped while computing the global
142630cfd02bSAntonio Quartulli 			 * crc
142730cfd02bSAntonio Quartulli 			 */
142830cfd02bSAntonio Quartulli 			if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
142930cfd02bSAntonio Quartulli 				continue;
1430db08e6e5SSimon Wunderlich 
1431db08e6e5SSimon Wunderlich 			/* find out if this global entry is announced by this
1432db08e6e5SSimon Wunderlich 			 * originator
1433db08e6e5SSimon Wunderlich 			 */
143456303d34SSven Eckelmann 			if (!batadv_tt_global_entry_has_orig(tt_global,
1435db08e6e5SSimon Wunderlich 							     orig_node))
1436db08e6e5SSimon Wunderlich 				continue;
1437db08e6e5SSimon Wunderlich 
1438a73105b8SAntonio Quartulli 			total_one = 0;
1439a73105b8SAntonio Quartulli 			for (j = 0; j < ETH_ALEN; j++)
1440a73105b8SAntonio Quartulli 				total_one = crc16_byte(total_one,
1441acd34afaSSven Eckelmann 						       tt_common->addr[j]);
1442a73105b8SAntonio Quartulli 			total ^= total_one;
1443a73105b8SAntonio Quartulli 		}
1444a73105b8SAntonio Quartulli 		rcu_read_unlock();
1445a73105b8SAntonio Quartulli 	}
1446a73105b8SAntonio Quartulli 
1447a73105b8SAntonio Quartulli 	return total;
1448a73105b8SAntonio Quartulli }
1449a73105b8SAntonio Quartulli 
1450a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */
145156303d34SSven Eckelmann static uint16_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
1452a73105b8SAntonio Quartulli {
1453a73105b8SAntonio Quartulli 	uint16_t total = 0, total_one;
1454807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
145556303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
1456a73105b8SAntonio Quartulli 	struct hlist_head *head;
1457c90681b8SAntonio Quartulli 	uint32_t i;
1458c90681b8SAntonio Quartulli 	int j;
1459a73105b8SAntonio Quartulli 
1460a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1461a73105b8SAntonio Quartulli 		head = &hash->table[i];
1462a73105b8SAntonio Quartulli 
1463a73105b8SAntonio Quartulli 		rcu_read_lock();
1464b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
1465058d0e26SAntonio Quartulli 			/* not yet committed clients have not to be taken into
14669cfc7bd6SSven Eckelmann 			 * account while computing the CRC
14679cfc7bd6SSven Eckelmann 			 */
1468acd34afaSSven Eckelmann 			if (tt_common->flags & BATADV_TT_CLIENT_NEW)
1469058d0e26SAntonio Quartulli 				continue;
1470a73105b8SAntonio Quartulli 			total_one = 0;
1471a73105b8SAntonio Quartulli 			for (j = 0; j < ETH_ALEN; j++)
1472a73105b8SAntonio Quartulli 				total_one = crc16_byte(total_one,
1473acd34afaSSven Eckelmann 						       tt_common->addr[j]);
1474a73105b8SAntonio Quartulli 			total ^= total_one;
1475a73105b8SAntonio Quartulli 		}
1476a73105b8SAntonio Quartulli 		rcu_read_unlock();
1477a73105b8SAntonio Quartulli 	}
1478a73105b8SAntonio Quartulli 
1479a73105b8SAntonio Quartulli 	return total;
1480a73105b8SAntonio Quartulli }
1481a73105b8SAntonio Quartulli 
148256303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
1483a73105b8SAntonio Quartulli {
148456303d34SSven Eckelmann 	struct batadv_tt_req_node *node, *safe;
1485a73105b8SAntonio Quartulli 
1486807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
1487a73105b8SAntonio Quartulli 
1488807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
1489a73105b8SAntonio Quartulli 		list_del(&node->list);
1490a73105b8SAntonio Quartulli 		kfree(node);
1491a73105b8SAntonio Quartulli 	}
1492a73105b8SAntonio Quartulli 
1493807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
1494a73105b8SAntonio Quartulli }
1495a73105b8SAntonio Quartulli 
149656303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv,
149756303d34SSven Eckelmann 				       struct batadv_orig_node *orig_node,
1498de7aae65SSven Eckelmann 				       const unsigned char *tt_buff,
1499e1bf0c14SMarek Lindner 				       uint16_t tt_num_changes)
1500a73105b8SAntonio Quartulli {
150108c36d3eSSven Eckelmann 	uint16_t tt_buff_len = batadv_tt_len(tt_num_changes);
1502a73105b8SAntonio Quartulli 
1503a73105b8SAntonio Quartulli 	/* Replace the old buffer only if I received something in the
15049cfc7bd6SSven Eckelmann 	 * last OGM (the OGM could carry no changes)
15059cfc7bd6SSven Eckelmann 	 */
1506a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
1507a73105b8SAntonio Quartulli 	if (tt_buff_len > 0) {
1508a73105b8SAntonio Quartulli 		kfree(orig_node->tt_buff);
1509a73105b8SAntonio Quartulli 		orig_node->tt_buff_len = 0;
1510a73105b8SAntonio Quartulli 		orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
1511a73105b8SAntonio Quartulli 		if (orig_node->tt_buff) {
1512a73105b8SAntonio Quartulli 			memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
1513a73105b8SAntonio Quartulli 			orig_node->tt_buff_len = tt_buff_len;
1514a73105b8SAntonio Quartulli 		}
1515a73105b8SAntonio Quartulli 	}
1516a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
1517a73105b8SAntonio Quartulli }
1518a73105b8SAntonio Quartulli 
151956303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv)
1520a73105b8SAntonio Quartulli {
152156303d34SSven Eckelmann 	struct batadv_tt_req_node *node, *safe;
1522a73105b8SAntonio Quartulli 
1523807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
1524807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
152542d0b044SSven Eckelmann 		if (batadv_has_timed_out(node->issued_at,
152642d0b044SSven Eckelmann 					 BATADV_TT_REQUEST_TIMEOUT)) {
1527a73105b8SAntonio Quartulli 			list_del(&node->list);
1528a73105b8SAntonio Quartulli 			kfree(node);
1529a73105b8SAntonio Quartulli 		}
1530a73105b8SAntonio Quartulli 	}
1531807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
1532a73105b8SAntonio Quartulli }
1533a73105b8SAntonio Quartulli 
1534a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request
15359cfc7bd6SSven Eckelmann  * has already been issued for this orig_node, NULL otherwise
15369cfc7bd6SSven Eckelmann  */
153756303d34SSven Eckelmann static struct batadv_tt_req_node *
153856303d34SSven Eckelmann batadv_new_tt_req_node(struct batadv_priv *bat_priv,
153956303d34SSven Eckelmann 		       struct batadv_orig_node *orig_node)
1540a73105b8SAntonio Quartulli {
154156303d34SSven Eckelmann 	struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
1542a73105b8SAntonio Quartulli 
1543807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
1544807736f6SSven Eckelmann 	list_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) {
15451eda58bfSSven Eckelmann 		if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
15461eda58bfSSven Eckelmann 		    !batadv_has_timed_out(tt_req_node_tmp->issued_at,
154742d0b044SSven Eckelmann 					  BATADV_TT_REQUEST_TIMEOUT))
1548a73105b8SAntonio Quartulli 			goto unlock;
1549a73105b8SAntonio Quartulli 	}
1550a73105b8SAntonio Quartulli 
1551a73105b8SAntonio Quartulli 	tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
1552a73105b8SAntonio Quartulli 	if (!tt_req_node)
1553a73105b8SAntonio Quartulli 		goto unlock;
1554a73105b8SAntonio Quartulli 
1555a73105b8SAntonio Quartulli 	memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
1556a73105b8SAntonio Quartulli 	tt_req_node->issued_at = jiffies;
1557a73105b8SAntonio Quartulli 
1558807736f6SSven Eckelmann 	list_add(&tt_req_node->list, &bat_priv->tt.req_list);
1559a73105b8SAntonio Quartulli unlock:
1560807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
1561a73105b8SAntonio Quartulli 	return tt_req_node;
1562a73105b8SAntonio Quartulli }
1563a73105b8SAntonio Quartulli 
1564335fbe0fSMarek Lindner /**
1565335fbe0fSMarek Lindner  * batadv_tt_local_valid - verify that given tt entry is a valid one
1566335fbe0fSMarek Lindner  * @entry_ptr: to be checked local tt entry
1567335fbe0fSMarek Lindner  * @data_ptr: not used but definition required to satisfy the callback prototype
1568335fbe0fSMarek Lindner  *
1569335fbe0fSMarek Lindner  * Returns 1 if the entry is a valid, 0 otherwise.
1570335fbe0fSMarek Lindner  */
1571335fbe0fSMarek Lindner static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr)
1572058d0e26SAntonio Quartulli {
157356303d34SSven Eckelmann 	const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
1574058d0e26SAntonio Quartulli 
1575acd34afaSSven Eckelmann 	if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
1576058d0e26SAntonio Quartulli 		return 0;
1577058d0e26SAntonio Quartulli 	return 1;
1578058d0e26SAntonio Quartulli }
1579058d0e26SAntonio Quartulli 
1580a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr,
1581a513088dSSven Eckelmann 				  const void *data_ptr)
1582a73105b8SAntonio Quartulli {
158356303d34SSven Eckelmann 	const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
158456303d34SSven Eckelmann 	const struct batadv_tt_global_entry *tt_global_entry;
158556303d34SSven Eckelmann 	const struct batadv_orig_node *orig_node = data_ptr;
1586a73105b8SAntonio Quartulli 
158730cfd02bSAntonio Quartulli 	if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
158830cfd02bSAntonio Quartulli 	    tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
1589cc47f66eSAntonio Quartulli 		return 0;
1590cc47f66eSAntonio Quartulli 
159156303d34SSven Eckelmann 	tt_global_entry = container_of(tt_common_entry,
159256303d34SSven Eckelmann 				       struct batadv_tt_global_entry,
159348100bacSAntonio Quartulli 				       common);
159448100bacSAntonio Quartulli 
1595a513088dSSven Eckelmann 	return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node);
1596a73105b8SAntonio Quartulli }
1597a73105b8SAntonio Quartulli 
1598335fbe0fSMarek Lindner /**
1599335fbe0fSMarek Lindner  * batadv_tt_tvlv_generate - creates tvlv tt data buffer to fill it with the
1600335fbe0fSMarek Lindner  *  tt entries from the specified tt hash
1601335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
1602335fbe0fSMarek Lindner  * @hash: hash table containing the tt entries
1603335fbe0fSMarek Lindner  * @tt_len: expected tvlv tt data buffer length in number of bytes
1604335fbe0fSMarek Lindner  * @valid_cb: function to filter tt change entries
1605335fbe0fSMarek Lindner  * @cb_data: data passed to the filter function as argument
1606335fbe0fSMarek Lindner  *
1607335fbe0fSMarek Lindner  * Returns pointer to allocated tvlv tt data buffer if operation was
1608335fbe0fSMarek Lindner  * successful or NULL otherwise.
1609335fbe0fSMarek Lindner  */
1610335fbe0fSMarek Lindner static struct batadv_tvlv_tt_data *
1611335fbe0fSMarek Lindner batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
1612335fbe0fSMarek Lindner 			struct batadv_hashtable *hash, uint16_t tt_len,
1613a513088dSSven Eckelmann 			int (*valid_cb)(const void *, const void *),
1614a73105b8SAntonio Quartulli 			void *cb_data)
1615a73105b8SAntonio Quartulli {
161656303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
1617335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
1618335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
1619a73105b8SAntonio Quartulli 	struct hlist_head *head;
1620335fbe0fSMarek Lindner 	uint16_t tt_tot, tt_num_entries = 0;
1621335fbe0fSMarek Lindner 	ssize_t tvlv_tt_size = sizeof(struct batadv_tvlv_tt_data);
1622c90681b8SAntonio Quartulli 	uint32_t i;
1623a73105b8SAntonio Quartulli 
1624335fbe0fSMarek Lindner 	if (tvlv_tt_size + tt_len > bat_priv->soft_iface->mtu) {
1625335fbe0fSMarek Lindner 		tt_len = bat_priv->soft_iface->mtu - tvlv_tt_size;
1626335fbe0fSMarek Lindner 		tt_len -= tt_len % sizeof(struct batadv_tvlv_tt_change);
1627a73105b8SAntonio Quartulli 	}
1628a73105b8SAntonio Quartulli 
1629335fbe0fSMarek Lindner 	tt_tot = tt_len / sizeof(struct batadv_tvlv_tt_change);
1630335fbe0fSMarek Lindner 
1631335fbe0fSMarek Lindner 	tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
1632335fbe0fSMarek Lindner 			       GFP_ATOMIC);
1633335fbe0fSMarek Lindner 	if (!tvlv_tt_data)
1634a73105b8SAntonio Quartulli 		goto out;
1635a73105b8SAntonio Quartulli 
1636335fbe0fSMarek Lindner 	tt_change = (struct batadv_tvlv_tt_change *)(tvlv_tt_data + 1);
1637a73105b8SAntonio Quartulli 
1638a73105b8SAntonio Quartulli 	rcu_read_lock();
1639a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1640a73105b8SAntonio Quartulli 		head = &hash->table[i];
1641a73105b8SAntonio Quartulli 
1642b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
1643a73105b8SAntonio Quartulli 					 head, hash_entry) {
1644335fbe0fSMarek Lindner 			if (tt_tot == tt_num_entries)
1645a73105b8SAntonio Quartulli 				break;
1646a73105b8SAntonio Quartulli 
164748100bacSAntonio Quartulli 			if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
1648a73105b8SAntonio Quartulli 				continue;
1649a73105b8SAntonio Quartulli 
165048100bacSAntonio Quartulli 			memcpy(tt_change->addr, tt_common_entry->addr,
165148100bacSAntonio Quartulli 			       ETH_ALEN);
165227b37ebfSAntonio Quartulli 			tt_change->flags = tt_common_entry->flags;
1653335fbe0fSMarek Lindner 			tt_change->reserved = 0;
1654a73105b8SAntonio Quartulli 
1655335fbe0fSMarek Lindner 			tt_num_entries++;
1656a73105b8SAntonio Quartulli 			tt_change++;
1657a73105b8SAntonio Quartulli 		}
1658a73105b8SAntonio Quartulli 	}
1659a73105b8SAntonio Quartulli 	rcu_read_unlock();
1660a73105b8SAntonio Quartulli 
1661a73105b8SAntonio Quartulli out:
1662335fbe0fSMarek Lindner 	return tvlv_tt_data;
1663a73105b8SAntonio Quartulli }
1664a73105b8SAntonio Quartulli 
166556303d34SSven Eckelmann static int batadv_send_tt_request(struct batadv_priv *bat_priv,
166656303d34SSven Eckelmann 				  struct batadv_orig_node *dst_orig_node,
1667a513088dSSven Eckelmann 				  uint8_t ttvn, uint16_t tt_crc,
1668a513088dSSven Eckelmann 				  bool full_table)
1669a73105b8SAntonio Quartulli {
1670335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
167156303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if;
167256303d34SSven Eckelmann 	struct batadv_tt_req_node *tt_req_node = NULL;
1673335fbe0fSMarek Lindner 	bool ret = false;
1674a73105b8SAntonio Quartulli 
1675e5d89254SSven Eckelmann 	primary_if = batadv_primary_if_get_selected(bat_priv);
1676a73105b8SAntonio Quartulli 	if (!primary_if)
1677a73105b8SAntonio Quartulli 		goto out;
1678a73105b8SAntonio Quartulli 
1679a73105b8SAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
16809cfc7bd6SSven Eckelmann 	 * reply from the same orig_node yet
16819cfc7bd6SSven Eckelmann 	 */
1682a513088dSSven Eckelmann 	tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node);
1683a73105b8SAntonio Quartulli 	if (!tt_req_node)
1684a73105b8SAntonio Quartulli 		goto out;
1685a73105b8SAntonio Quartulli 
1686335fbe0fSMarek Lindner 	tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data), GFP_ATOMIC);
1687335fbe0fSMarek Lindner 	if (!tvlv_tt_data)
1688a73105b8SAntonio Quartulli 		goto out;
1689a73105b8SAntonio Quartulli 
1690335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_REQUEST;
1691335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = ttvn;
1692335fbe0fSMarek Lindner 	tvlv_tt_data->crc = htons(tt_crc);
1693a73105b8SAntonio Quartulli 
1694a73105b8SAntonio Quartulli 	if (full_table)
1695335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
1696a73105b8SAntonio Quartulli 
1697bb351ba0SMartin Hundebøll 	batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n",
1698335fbe0fSMarek Lindner 		   dst_orig_node->orig, full_table ? 'F' : '.');
1699a73105b8SAntonio Quartulli 
1700d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX);
1701335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
1702335fbe0fSMarek Lindner 				 dst_orig_node->orig, BATADV_TVLV_TT, 1,
1703335fbe0fSMarek Lindner 				 tvlv_tt_data, sizeof(*tvlv_tt_data));
1704335fbe0fSMarek Lindner 	ret = true;
1705a73105b8SAntonio Quartulli 
1706a73105b8SAntonio Quartulli out:
1707a73105b8SAntonio Quartulli 	if (primary_if)
1708e5d89254SSven Eckelmann 		batadv_hardif_free_ref(primary_if);
1709a73105b8SAntonio Quartulli 	if (ret && tt_req_node) {
1710807736f6SSven Eckelmann 		spin_lock_bh(&bat_priv->tt.req_list_lock);
1711a73105b8SAntonio Quartulli 		list_del(&tt_req_node->list);
1712807736f6SSven Eckelmann 		spin_unlock_bh(&bat_priv->tt.req_list_lock);
1713a73105b8SAntonio Quartulli 		kfree(tt_req_node);
1714a73105b8SAntonio Quartulli 	}
1715335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
1716a73105b8SAntonio Quartulli 	return ret;
1717a73105b8SAntonio Quartulli }
1718a73105b8SAntonio Quartulli 
1719335fbe0fSMarek Lindner /**
1720335fbe0fSMarek Lindner  * batadv_send_other_tt_response - send reply to tt request concerning another
1721335fbe0fSMarek Lindner  *  node's translation table
1722335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
1723335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
1724335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
1725335fbe0fSMarek Lindner  * @req_dst: mac address of tt request recipient
1726335fbe0fSMarek Lindner  *
1727335fbe0fSMarek Lindner  * Returns true if tt request reply was sent, false otherwise.
1728335fbe0fSMarek Lindner  */
1729335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
1730335fbe0fSMarek Lindner 					  struct batadv_tvlv_tt_data *tt_data,
1731335fbe0fSMarek Lindner 					  uint8_t *req_src, uint8_t *req_dst)
1732a73105b8SAntonio Quartulli {
1733170173bfSSven Eckelmann 	struct batadv_orig_node *req_dst_orig_node;
173456303d34SSven Eckelmann 	struct batadv_orig_node *res_dst_orig_node = NULL;
1735335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
1736335fbe0fSMarek Lindner 	uint8_t orig_ttvn, req_ttvn;
1737335fbe0fSMarek Lindner 	uint16_t tt_len;
1738335fbe0fSMarek Lindner 	bool ret = false, full_table;
1739a73105b8SAntonio Quartulli 
174039c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
174186ceb360SSven Eckelmann 		   "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
1742335fbe0fSMarek Lindner 		   req_src, tt_data->ttvn, req_dst,
1743335fbe0fSMarek Lindner 		   (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
1744a73105b8SAntonio Quartulli 
1745a73105b8SAntonio Quartulli 	/* Let's get the orig node of the REAL destination */
1746335fbe0fSMarek Lindner 	req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst);
1747a73105b8SAntonio Quartulli 	if (!req_dst_orig_node)
1748a73105b8SAntonio Quartulli 		goto out;
1749a73105b8SAntonio Quartulli 
1750335fbe0fSMarek Lindner 	res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src);
1751a73105b8SAntonio Quartulli 	if (!res_dst_orig_node)
1752a73105b8SAntonio Quartulli 		goto out;
1753a73105b8SAntonio Quartulli 
1754a73105b8SAntonio Quartulli 	orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1755335fbe0fSMarek Lindner 	req_ttvn = tt_data->ttvn;
1756a73105b8SAntonio Quartulli 
1757335fbe0fSMarek Lindner 	/* this node doesn't have the requested data */
1758a73105b8SAntonio Quartulli 	if (orig_ttvn != req_ttvn ||
1759335fbe0fSMarek Lindner 	    tt_data->crc != htons(req_dst_orig_node->tt_crc))
1760a73105b8SAntonio Quartulli 		goto out;
1761a73105b8SAntonio Quartulli 
1762015758d0SAntonio Quartulli 	/* If the full table has been explicitly requested */
1763335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE ||
1764a73105b8SAntonio Quartulli 	    !req_dst_orig_node->tt_buff)
1765a73105b8SAntonio Quartulli 		full_table = true;
1766a73105b8SAntonio Quartulli 	else
1767a73105b8SAntonio Quartulli 		full_table = false;
1768a73105b8SAntonio Quartulli 
1769335fbe0fSMarek Lindner 	/* TT fragmentation hasn't been implemented yet, so send as many
1770335fbe0fSMarek Lindner 	 * TT entries fit a single packet as possible only
17719cfc7bd6SSven Eckelmann 	 */
1772a73105b8SAntonio Quartulli 	if (!full_table) {
1773a73105b8SAntonio Quartulli 		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1774a73105b8SAntonio Quartulli 		tt_len = req_dst_orig_node->tt_buff_len;
1775a73105b8SAntonio Quartulli 
1776335fbe0fSMarek Lindner 		tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
1777335fbe0fSMarek Lindner 				       GFP_ATOMIC);
1778335fbe0fSMarek Lindner 		if (!tvlv_tt_data)
1779a73105b8SAntonio Quartulli 			goto unlock;
1780a73105b8SAntonio Quartulli 
1781a73105b8SAntonio Quartulli 		/* Copy the last orig_node's OGM buffer */
1782335fbe0fSMarek Lindner 		memcpy(tvlv_tt_data + 1, req_dst_orig_node->tt_buff,
1783a73105b8SAntonio Quartulli 		       req_dst_orig_node->tt_buff_len);
1784a73105b8SAntonio Quartulli 		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1785a73105b8SAntonio Quartulli 	} else {
178696412690SSven Eckelmann 		tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size);
1787335fbe0fSMarek Lindner 		tt_len = batadv_tt_len(tt_len);
1788a73105b8SAntonio Quartulli 
1789335fbe0fSMarek Lindner 		tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv,
1790807736f6SSven Eckelmann 						       bat_priv->tt.global_hash,
1791335fbe0fSMarek Lindner 						       tt_len,
1792a513088dSSven Eckelmann 						       batadv_tt_global_valid,
1793a73105b8SAntonio Quartulli 						       req_dst_orig_node);
1794335fbe0fSMarek Lindner 		if (!tvlv_tt_data)
1795a73105b8SAntonio Quartulli 			goto out;
1796a73105b8SAntonio Quartulli 	}
1797a73105b8SAntonio Quartulli 
1798335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
1799335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = req_ttvn;
1800a73105b8SAntonio Quartulli 
1801a73105b8SAntonio Quartulli 	if (full_table)
1802335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
1803a73105b8SAntonio Quartulli 
180439c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
1805335fbe0fSMarek Lindner 		   "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n",
1806335fbe0fSMarek Lindner 		   res_dst_orig_node->orig, req_dst_orig_node->orig,
1807335fbe0fSMarek Lindner 		   full_table ? 'F' : '.', req_ttvn);
1808a73105b8SAntonio Quartulli 
1809d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
1810f8214865SMartin Hundebøll 
1811335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig,
1812335fbe0fSMarek Lindner 				 req_src, BATADV_TVLV_TT, 1,
1813335fbe0fSMarek Lindner 				 tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len);
1814e91ecfc6SMartin Hundebøll 
1815335fbe0fSMarek Lindner 	ret = true;
1816a73105b8SAntonio Quartulli 	goto out;
1817a73105b8SAntonio Quartulli 
1818a73105b8SAntonio Quartulli unlock:
1819a73105b8SAntonio Quartulli 	spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1820a73105b8SAntonio Quartulli 
1821a73105b8SAntonio Quartulli out:
1822a73105b8SAntonio Quartulli 	if (res_dst_orig_node)
18237d211efcSSven Eckelmann 		batadv_orig_node_free_ref(res_dst_orig_node);
1824a73105b8SAntonio Quartulli 	if (req_dst_orig_node)
18257d211efcSSven Eckelmann 		batadv_orig_node_free_ref(req_dst_orig_node);
1826335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
1827a73105b8SAntonio Quartulli 	return ret;
1828a73105b8SAntonio Quartulli }
182996412690SSven Eckelmann 
1830335fbe0fSMarek Lindner /**
1831335fbe0fSMarek Lindner  * batadv_send_my_tt_response - send reply to tt request concerning this node's
1832335fbe0fSMarek Lindner  *  translation table
1833335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
1834335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
1835335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
1836335fbe0fSMarek Lindner  *
1837335fbe0fSMarek Lindner  * Returns true if tt request reply was sent, false otherwise.
1838335fbe0fSMarek Lindner  */
1839335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
1840335fbe0fSMarek Lindner 				       struct batadv_tvlv_tt_data *tt_data,
1841335fbe0fSMarek Lindner 				       uint8_t *req_src)
1842a73105b8SAntonio Quartulli {
1843335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
1844170173bfSSven Eckelmann 	struct batadv_orig_node *orig_node;
184556303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if = NULL;
1846335fbe0fSMarek Lindner 	uint8_t my_ttvn, req_ttvn;
1847a73105b8SAntonio Quartulli 	bool full_table;
1848335fbe0fSMarek Lindner 	uint16_t tt_len;
1849a73105b8SAntonio Quartulli 
185039c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
185186ceb360SSven Eckelmann 		   "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
1852335fbe0fSMarek Lindner 		   req_src, tt_data->ttvn,
1853335fbe0fSMarek Lindner 		   (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
1854a73105b8SAntonio Quartulli 
1855a73105b8SAntonio Quartulli 
1856807736f6SSven Eckelmann 	my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
1857335fbe0fSMarek Lindner 	req_ttvn = tt_data->ttvn;
1858a73105b8SAntonio Quartulli 
1859335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, req_src);
1860a73105b8SAntonio Quartulli 	if (!orig_node)
1861a73105b8SAntonio Quartulli 		goto out;
1862a73105b8SAntonio Quartulli 
1863e5d89254SSven Eckelmann 	primary_if = batadv_primary_if_get_selected(bat_priv);
1864a73105b8SAntonio Quartulli 	if (!primary_if)
1865a73105b8SAntonio Quartulli 		goto out;
1866a73105b8SAntonio Quartulli 
1867a73105b8SAntonio Quartulli 	/* If the full table has been explicitly requested or the gap
18689cfc7bd6SSven Eckelmann 	 * is too big send the whole local translation table
18699cfc7bd6SSven Eckelmann 	 */
1870335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn ||
1871807736f6SSven Eckelmann 	    !bat_priv->tt.last_changeset)
1872a73105b8SAntonio Quartulli 		full_table = true;
1873a73105b8SAntonio Quartulli 	else
1874a73105b8SAntonio Quartulli 		full_table = false;
1875a73105b8SAntonio Quartulli 
1876335fbe0fSMarek Lindner 	/* TT fragmentation hasn't been implemented yet, so send as many
1877335fbe0fSMarek Lindner 	 * TT entries fit a single packet as possible only
18789cfc7bd6SSven Eckelmann 	 */
1879a73105b8SAntonio Quartulli 	if (!full_table) {
1880807736f6SSven Eckelmann 		spin_lock_bh(&bat_priv->tt.last_changeset_lock);
1881807736f6SSven Eckelmann 		tt_len = bat_priv->tt.last_changeset_len;
1882a73105b8SAntonio Quartulli 
1883335fbe0fSMarek Lindner 		tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
1884335fbe0fSMarek Lindner 				       GFP_ATOMIC);
1885335fbe0fSMarek Lindner 		if (!tvlv_tt_data)
1886a73105b8SAntonio Quartulli 			goto unlock;
1887a73105b8SAntonio Quartulli 
1888335fbe0fSMarek Lindner 		/* Copy the last orig_node's OGM buffer */
1889335fbe0fSMarek Lindner 		memcpy(tvlv_tt_data + 1, bat_priv->tt.last_changeset,
1890807736f6SSven Eckelmann 		       bat_priv->tt.last_changeset_len);
1891807736f6SSven Eckelmann 		spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
1892a73105b8SAntonio Quartulli 	} else {
1893807736f6SSven Eckelmann 		tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num);
1894335fbe0fSMarek Lindner 		tt_len = batadv_tt_len(tt_len);
1895335fbe0fSMarek Lindner 		req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
1896a73105b8SAntonio Quartulli 
1897335fbe0fSMarek Lindner 		tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv,
1898807736f6SSven Eckelmann 						       bat_priv->tt.local_hash,
1899335fbe0fSMarek Lindner 						       tt_len,
1900335fbe0fSMarek Lindner 						       batadv_tt_local_valid,
1901058d0e26SAntonio Quartulli 						       NULL);
1902335fbe0fSMarek Lindner 		if (!tvlv_tt_data)
1903a73105b8SAntonio Quartulli 			goto out;
1904a73105b8SAntonio Quartulli 	}
1905a73105b8SAntonio Quartulli 
1906335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
1907335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = req_ttvn;
1908a73105b8SAntonio Quartulli 
1909a73105b8SAntonio Quartulli 	if (full_table)
1910335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
1911a73105b8SAntonio Quartulli 
191239c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
1913335fbe0fSMarek Lindner 		   "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n",
1914335fbe0fSMarek Lindner 		   orig_node->orig, full_table ? 'F' : '.', req_ttvn);
1915a73105b8SAntonio Quartulli 
1916d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
1917f8214865SMartin Hundebøll 
1918335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
1919335fbe0fSMarek Lindner 				 req_src, BATADV_TVLV_TT, 1,
1920335fbe0fSMarek Lindner 				 tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len);
1921335fbe0fSMarek Lindner 
1922a73105b8SAntonio Quartulli 	goto out;
1923a73105b8SAntonio Quartulli 
1924a73105b8SAntonio Quartulli unlock:
1925807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
1926a73105b8SAntonio Quartulli out:
1927a73105b8SAntonio Quartulli 	if (orig_node)
19287d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
1929a73105b8SAntonio Quartulli 	if (primary_if)
1930e5d89254SSven Eckelmann 		batadv_hardif_free_ref(primary_if);
1931335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
1932335fbe0fSMarek Lindner 	/* The packet was for this host, so it doesn't need to be re-routed */
1933a73105b8SAntonio Quartulli 	return true;
1934a73105b8SAntonio Quartulli }
1935a73105b8SAntonio Quartulli 
1936335fbe0fSMarek Lindner /**
1937335fbe0fSMarek Lindner  * batadv_send_tt_response - send reply to tt request
1938335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
1939335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
1940335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
1941335fbe0fSMarek Lindner  * @req_dst: mac address of tt request recipient
1942335fbe0fSMarek Lindner  *
1943335fbe0fSMarek Lindner  * Returns true if tt request reply was sent, false otherwise.
1944335fbe0fSMarek Lindner  */
1945335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv,
1946335fbe0fSMarek Lindner 				    struct batadv_tvlv_tt_data *tt_data,
1947335fbe0fSMarek Lindner 				    uint8_t *req_src, uint8_t *req_dst)
1948a73105b8SAntonio Quartulli {
1949335fbe0fSMarek Lindner 	if (batadv_is_my_mac(bat_priv, req_dst)) {
195020ff9d59SSimon Wunderlich 		/* don't answer backbone gws! */
1951335fbe0fSMarek Lindner 		if (batadv_bla_is_backbone_gw_orig(bat_priv, req_src))
195220ff9d59SSimon Wunderlich 			return true;
195320ff9d59SSimon Wunderlich 
1954335fbe0fSMarek Lindner 		return batadv_send_my_tt_response(bat_priv, tt_data, req_src);
195520ff9d59SSimon Wunderlich 	} else {
1956335fbe0fSMarek Lindner 		return batadv_send_other_tt_response(bat_priv, tt_data,
1957335fbe0fSMarek Lindner 						     req_src, req_dst);
1958a73105b8SAntonio Quartulli 	}
195920ff9d59SSimon Wunderlich }
1960a73105b8SAntonio Quartulli 
196156303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
196256303d34SSven Eckelmann 				      struct batadv_orig_node *orig_node,
1963335fbe0fSMarek Lindner 				      struct batadv_tvlv_tt_change *tt_change,
1964a73105b8SAntonio Quartulli 				      uint16_t tt_num_changes, uint8_t ttvn)
1965a73105b8SAntonio Quartulli {
1966a73105b8SAntonio Quartulli 	int i;
1967a513088dSSven Eckelmann 	int roams;
1968a73105b8SAntonio Quartulli 
1969a73105b8SAntonio Quartulli 	for (i = 0; i < tt_num_changes; i++) {
1970acd34afaSSven Eckelmann 		if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
1971acd34afaSSven Eckelmann 			roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
1972a513088dSSven Eckelmann 			batadv_tt_global_del(bat_priv, orig_node,
1973a73105b8SAntonio Quartulli 					     (tt_change + i)->addr,
1974cc47f66eSAntonio Quartulli 					     "tt removed by changes",
1975a513088dSSven Eckelmann 					     roams);
197608c36d3eSSven Eckelmann 		} else {
197708c36d3eSSven Eckelmann 			if (!batadv_tt_global_add(bat_priv, orig_node,
1978d4f44692SAntonio Quartulli 						  (tt_change + i)->addr,
1979d4f44692SAntonio Quartulli 						  (tt_change + i)->flags, ttvn))
1980a73105b8SAntonio Quartulli 				/* In case of problem while storing a
1981a73105b8SAntonio Quartulli 				 * global_entry, we stop the updating
1982a73105b8SAntonio Quartulli 				 * procedure without committing the
1983a73105b8SAntonio Quartulli 				 * ttvn change. This will avoid to send
1984a73105b8SAntonio Quartulli 				 * corrupted data on tt_request
1985a73105b8SAntonio Quartulli 				 */
1986a73105b8SAntonio Quartulli 				return;
1987a73105b8SAntonio Quartulli 		}
198808c36d3eSSven Eckelmann 	}
198917071578SAntonio Quartulli 	orig_node->tt_initialised = true;
1990a73105b8SAntonio Quartulli }
1991a73105b8SAntonio Quartulli 
199256303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
1993335fbe0fSMarek Lindner 				  struct batadv_tvlv_tt_data *tt_data,
1994335fbe0fSMarek Lindner 				  uint8_t *resp_src, uint16_t num_entries)
1995a73105b8SAntonio Quartulli {
1996170173bfSSven Eckelmann 	struct batadv_orig_node *orig_node;
1997a73105b8SAntonio Quartulli 
1998335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
1999a73105b8SAntonio Quartulli 	if (!orig_node)
2000a73105b8SAntonio Quartulli 		goto out;
2001a73105b8SAntonio Quartulli 
2002a73105b8SAntonio Quartulli 	/* Purge the old table first.. */
200308c36d3eSSven Eckelmann 	batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table");
2004a73105b8SAntonio Quartulli 
2005a513088dSSven Eckelmann 	_batadv_tt_update_changes(bat_priv, orig_node,
2006335fbe0fSMarek Lindner 				  (struct batadv_tvlv_tt_change *)(tt_data + 1),
2007335fbe0fSMarek Lindner 				  num_entries, tt_data->ttvn);
2008a73105b8SAntonio Quartulli 
2009a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
2010a73105b8SAntonio Quartulli 	kfree(orig_node->tt_buff);
2011a73105b8SAntonio Quartulli 	orig_node->tt_buff_len = 0;
2012a73105b8SAntonio Quartulli 	orig_node->tt_buff = NULL;
2013a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
2014a73105b8SAntonio Quartulli 
2015335fbe0fSMarek Lindner 	atomic_set(&orig_node->last_ttvn, tt_data->ttvn);
2016a73105b8SAntonio Quartulli 
2017a73105b8SAntonio Quartulli out:
2018a73105b8SAntonio Quartulli 	if (orig_node)
20197d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
2020a73105b8SAntonio Quartulli }
2021a73105b8SAntonio Quartulli 
202256303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
202356303d34SSven Eckelmann 				     struct batadv_orig_node *orig_node,
2024a73105b8SAntonio Quartulli 				     uint16_t tt_num_changes, uint8_t ttvn,
2025335fbe0fSMarek Lindner 				     struct batadv_tvlv_tt_change *tt_change)
2026a73105b8SAntonio Quartulli {
2027a513088dSSven Eckelmann 	_batadv_tt_update_changes(bat_priv, orig_node, tt_change,
2028a513088dSSven Eckelmann 				  tt_num_changes, ttvn);
2029a73105b8SAntonio Quartulli 
2030a513088dSSven Eckelmann 	batadv_tt_save_orig_buffer(bat_priv, orig_node,
2031a513088dSSven Eckelmann 				   (unsigned char *)tt_change, tt_num_changes);
2032a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, ttvn);
2033a73105b8SAntonio Quartulli }
2034a73105b8SAntonio Quartulli 
203556303d34SSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr)
2036a73105b8SAntonio Quartulli {
2037170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
20387683fdc1SAntonio Quartulli 	bool ret = false;
2039a73105b8SAntonio Quartulli 
2040a513088dSSven Eckelmann 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
20417683fdc1SAntonio Quartulli 	if (!tt_local_entry)
20427683fdc1SAntonio Quartulli 		goto out;
2043058d0e26SAntonio Quartulli 	/* Check if the client has been logically deleted (but is kept for
20449cfc7bd6SSven Eckelmann 	 * consistency purpose)
20459cfc7bd6SSven Eckelmann 	 */
20467c1fd91dSAntonio Quartulli 	if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
20477c1fd91dSAntonio Quartulli 	    (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
2048058d0e26SAntonio Quartulli 		goto out;
20497683fdc1SAntonio Quartulli 	ret = true;
20507683fdc1SAntonio Quartulli out:
2051a73105b8SAntonio Quartulli 	if (tt_local_entry)
2052a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(tt_local_entry);
20537683fdc1SAntonio Quartulli 	return ret;
2054a73105b8SAntonio Quartulli }
2055a73105b8SAntonio Quartulli 
2056335fbe0fSMarek Lindner /**
2057335fbe0fSMarek Lindner  * batadv_handle_tt_response - process incoming tt reply
2058335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2059335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
2060335fbe0fSMarek Lindner  * @resp_src: mac address of tt reply sender
2061335fbe0fSMarek Lindner  * @num_entries: number of tt change entries appended to the tt data
2062335fbe0fSMarek Lindner  */
2063335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
2064335fbe0fSMarek Lindner 				      struct batadv_tvlv_tt_data *tt_data,
2065335fbe0fSMarek Lindner 				      uint8_t *resp_src, uint16_t num_entries)
2066a73105b8SAntonio Quartulli {
206756303d34SSven Eckelmann 	struct batadv_tt_req_node *node, *safe;
206856303d34SSven Eckelmann 	struct batadv_orig_node *orig_node = NULL;
2069335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
2070a73105b8SAntonio Quartulli 
207139c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
207286ceb360SSven Eckelmann 		   "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
2073335fbe0fSMarek Lindner 		   resp_src, tt_data->ttvn, num_entries,
2074335fbe0fSMarek Lindner 		   (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
2075a73105b8SAntonio Quartulli 
207620ff9d59SSimon Wunderlich 	/* we should have never asked a backbone gw */
2077335fbe0fSMarek Lindner 	if (batadv_bla_is_backbone_gw_orig(bat_priv, resp_src))
207820ff9d59SSimon Wunderlich 		goto out;
207920ff9d59SSimon Wunderlich 
2080335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
2081a73105b8SAntonio Quartulli 	if (!orig_node)
2082a73105b8SAntonio Quartulli 		goto out;
2083a73105b8SAntonio Quartulli 
2084335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE) {
2085335fbe0fSMarek Lindner 		batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries);
208696412690SSven Eckelmann 	} else {
2087335fbe0fSMarek Lindner 		tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1);
2088335fbe0fSMarek Lindner 		batadv_tt_update_changes(bat_priv, orig_node, num_entries,
2089335fbe0fSMarek Lindner 					 tt_data->ttvn, tt_change);
209096412690SSven Eckelmann 	}
2091a73105b8SAntonio Quartulli 
2092a73105b8SAntonio Quartulli 	/* Delete the tt_req_node from pending tt_requests list */
2093807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
2094807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
2095335fbe0fSMarek Lindner 		if (!batadv_compare_eth(node->addr, resp_src))
2096a73105b8SAntonio Quartulli 			continue;
2097a73105b8SAntonio Quartulli 		list_del(&node->list);
2098a73105b8SAntonio Quartulli 		kfree(node);
2099a73105b8SAntonio Quartulli 	}
2100807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
2101a73105b8SAntonio Quartulli 
2102a73105b8SAntonio Quartulli 	/* Recalculate the CRC for this orig_node and store it */
2103a513088dSSven Eckelmann 	orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
2104a73105b8SAntonio Quartulli out:
2105a73105b8SAntonio Quartulli 	if (orig_node)
21067d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
2107a73105b8SAntonio Quartulli }
2108a73105b8SAntonio Quartulli 
210956303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv)
2110a73105b8SAntonio Quartulli {
211156303d34SSven Eckelmann 	struct batadv_tt_roam_node *node, *safe;
2112a73105b8SAntonio Quartulli 
2113807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
2114a73105b8SAntonio Quartulli 
2115807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
2116cc47f66eSAntonio Quartulli 		list_del(&node->list);
2117cc47f66eSAntonio Quartulli 		kfree(node);
2118cc47f66eSAntonio Quartulli 	}
2119cc47f66eSAntonio Quartulli 
2120807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
2121cc47f66eSAntonio Quartulli }
2122cc47f66eSAntonio Quartulli 
212356303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)
2124cc47f66eSAntonio Quartulli {
212556303d34SSven Eckelmann 	struct batadv_tt_roam_node *node, *safe;
2126cc47f66eSAntonio Quartulli 
2127807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
2128807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
212942d0b044SSven Eckelmann 		if (!batadv_has_timed_out(node->first_time,
213042d0b044SSven Eckelmann 					  BATADV_ROAMING_MAX_TIME))
2131cc47f66eSAntonio Quartulli 			continue;
2132cc47f66eSAntonio Quartulli 
2133cc47f66eSAntonio Quartulli 		list_del(&node->list);
2134cc47f66eSAntonio Quartulli 		kfree(node);
2135cc47f66eSAntonio Quartulli 	}
2136807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
2137cc47f66eSAntonio Quartulli }
2138cc47f66eSAntonio Quartulli 
2139cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the
2140cc47f66eSAntonio Quartulli  * maximum number of possible roaming phases. In this case the ROAMING_ADV
2141cc47f66eSAntonio Quartulli  * will not be sent.
2142cc47f66eSAntonio Quartulli  *
21439cfc7bd6SSven Eckelmann  * returns true if the ROAMING_ADV can be sent, false otherwise
21449cfc7bd6SSven Eckelmann  */
214556303d34SSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv,
2146cc47f66eSAntonio Quartulli 				       uint8_t *client)
2147cc47f66eSAntonio Quartulli {
214856303d34SSven Eckelmann 	struct batadv_tt_roam_node *tt_roam_node;
2149cc47f66eSAntonio Quartulli 	bool ret = false;
2150cc47f66eSAntonio Quartulli 
2151807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
2152cc47f66eSAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
21539cfc7bd6SSven Eckelmann 	 * reply from the same orig_node yet
21549cfc7bd6SSven Eckelmann 	 */
2155807736f6SSven Eckelmann 	list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) {
21561eda58bfSSven Eckelmann 		if (!batadv_compare_eth(tt_roam_node->addr, client))
2157cc47f66eSAntonio Quartulli 			continue;
2158cc47f66eSAntonio Quartulli 
21591eda58bfSSven Eckelmann 		if (batadv_has_timed_out(tt_roam_node->first_time,
216042d0b044SSven Eckelmann 					 BATADV_ROAMING_MAX_TIME))
2161cc47f66eSAntonio Quartulli 			continue;
2162cc47f66eSAntonio Quartulli 
21633e34819eSSven Eckelmann 		if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter))
2164cc47f66eSAntonio Quartulli 			/* Sorry, you roamed too many times! */
2165cc47f66eSAntonio Quartulli 			goto unlock;
2166cc47f66eSAntonio Quartulli 		ret = true;
2167cc47f66eSAntonio Quartulli 		break;
2168cc47f66eSAntonio Quartulli 	}
2169cc47f66eSAntonio Quartulli 
2170cc47f66eSAntonio Quartulli 	if (!ret) {
2171cc47f66eSAntonio Quartulli 		tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
2172cc47f66eSAntonio Quartulli 		if (!tt_roam_node)
2173cc47f66eSAntonio Quartulli 			goto unlock;
2174cc47f66eSAntonio Quartulli 
2175cc47f66eSAntonio Quartulli 		tt_roam_node->first_time = jiffies;
217642d0b044SSven Eckelmann 		atomic_set(&tt_roam_node->counter,
217742d0b044SSven Eckelmann 			   BATADV_ROAMING_MAX_COUNT - 1);
2178cc47f66eSAntonio Quartulli 		memcpy(tt_roam_node->addr, client, ETH_ALEN);
2179cc47f66eSAntonio Quartulli 
2180807736f6SSven Eckelmann 		list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
2181cc47f66eSAntonio Quartulli 		ret = true;
2182cc47f66eSAntonio Quartulli 	}
2183cc47f66eSAntonio Quartulli 
2184cc47f66eSAntonio Quartulli unlock:
2185807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
2186cc47f66eSAntonio Quartulli 	return ret;
2187cc47f66eSAntonio Quartulli }
2188cc47f66eSAntonio Quartulli 
218956303d34SSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
219056303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node)
2191cc47f66eSAntonio Quartulli {
219256303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if;
2193122edaa0SMarek Lindner 	struct batadv_tvlv_roam_adv tvlv_roam;
2194122edaa0SMarek Lindner 
2195122edaa0SMarek Lindner 	primary_if = batadv_primary_if_get_selected(bat_priv);
2196122edaa0SMarek Lindner 	if (!primary_if)
2197122edaa0SMarek Lindner 		goto out;
2198cc47f66eSAntonio Quartulli 
2199cc47f66eSAntonio Quartulli 	/* before going on we have to check whether the client has
22009cfc7bd6SSven Eckelmann 	 * already roamed to us too many times
22019cfc7bd6SSven Eckelmann 	 */
2202a513088dSSven Eckelmann 	if (!batadv_tt_check_roam_count(bat_priv, client))
2203cc47f66eSAntonio Quartulli 		goto out;
2204cc47f66eSAntonio Quartulli 
220539c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
2206bb351ba0SMartin Hundebøll 		   "Sending ROAMING_ADV to %pM (client %pM)\n",
2207bb351ba0SMartin Hundebøll 		   orig_node->orig, client);
2208cc47f66eSAntonio Quartulli 
2209d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
2210f8214865SMartin Hundebøll 
2211122edaa0SMarek Lindner 	memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client));
2212122edaa0SMarek Lindner 	tvlv_roam.reserved = 0;
2213122edaa0SMarek Lindner 
2214122edaa0SMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
2215122edaa0SMarek Lindner 				 orig_node->orig, BATADV_TVLV_ROAM, 1,
2216122edaa0SMarek Lindner 				 &tvlv_roam, sizeof(tvlv_roam));
2217cc47f66eSAntonio Quartulli 
2218cc47f66eSAntonio Quartulli out:
2219122edaa0SMarek Lindner 	if (primary_if)
2220122edaa0SMarek Lindner 		batadv_hardif_free_ref(primary_if);
2221a73105b8SAntonio Quartulli }
2222a73105b8SAntonio Quartulli 
2223a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work)
2224a73105b8SAntonio Quartulli {
222556303d34SSven Eckelmann 	struct delayed_work *delayed_work;
2226807736f6SSven Eckelmann 	struct batadv_priv_tt *priv_tt;
222756303d34SSven Eckelmann 	struct batadv_priv *bat_priv;
222856303d34SSven Eckelmann 
222956303d34SSven Eckelmann 	delayed_work = container_of(work, struct delayed_work, work);
2230807736f6SSven Eckelmann 	priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
2231807736f6SSven Eckelmann 	bat_priv = container_of(priv_tt, struct batadv_priv, tt);
2232a73105b8SAntonio Quartulli 
2233a513088dSSven Eckelmann 	batadv_tt_local_purge(bat_priv);
223430cfd02bSAntonio Quartulli 	batadv_tt_global_purge(bat_priv);
2235a513088dSSven Eckelmann 	batadv_tt_req_purge(bat_priv);
2236a513088dSSven Eckelmann 	batadv_tt_roam_purge(bat_priv);
2237a73105b8SAntonio Quartulli 
223872414442SAntonio Quartulli 	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
223972414442SAntonio Quartulli 			   msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
2240a73105b8SAntonio Quartulli }
2241cc47f66eSAntonio Quartulli 
224256303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv)
2243cc47f66eSAntonio Quartulli {
2244e1bf0c14SMarek Lindner 	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1);
2245e1bf0c14SMarek Lindner 	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1);
2246e1bf0c14SMarek Lindner 
2247807736f6SSven Eckelmann 	cancel_delayed_work_sync(&bat_priv->tt.work);
2248cc47f66eSAntonio Quartulli 
2249a513088dSSven Eckelmann 	batadv_tt_local_table_free(bat_priv);
2250a513088dSSven Eckelmann 	batadv_tt_global_table_free(bat_priv);
2251a513088dSSven Eckelmann 	batadv_tt_req_list_free(bat_priv);
2252a513088dSSven Eckelmann 	batadv_tt_changes_list_free(bat_priv);
2253a513088dSSven Eckelmann 	batadv_tt_roam_list_free(bat_priv);
2254cc47f66eSAntonio Quartulli 
2255807736f6SSven Eckelmann 	kfree(bat_priv->tt.last_changeset);
2256cc47f66eSAntonio Quartulli }
2257058d0e26SAntonio Quartulli 
2258697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries
22599cfc7bd6SSven Eckelmann  * in the given hash table and returns the number of modified entries
22609cfc7bd6SSven Eckelmann  */
22615bf74e9cSSven Eckelmann static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash,
22625bf74e9cSSven Eckelmann 				    uint16_t flags, bool enable)
2263058d0e26SAntonio Quartulli {
2264c90681b8SAntonio Quartulli 	uint32_t i;
2265697f2531SAntonio Quartulli 	uint16_t changed_num = 0;
2266058d0e26SAntonio Quartulli 	struct hlist_head *head;
226756303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
2268058d0e26SAntonio Quartulli 
2269058d0e26SAntonio Quartulli 	if (!hash)
2270697f2531SAntonio Quartulli 		goto out;
2271058d0e26SAntonio Quartulli 
2272058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2273058d0e26SAntonio Quartulli 		head = &hash->table[i];
2274058d0e26SAntonio Quartulli 
2275058d0e26SAntonio Quartulli 		rcu_read_lock();
2276b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
2277058d0e26SAntonio Quartulli 					 head, hash_entry) {
2278697f2531SAntonio Quartulli 			if (enable) {
2279697f2531SAntonio Quartulli 				if ((tt_common_entry->flags & flags) == flags)
2280697f2531SAntonio Quartulli 					continue;
2281697f2531SAntonio Quartulli 				tt_common_entry->flags |= flags;
2282697f2531SAntonio Quartulli 			} else {
228348100bacSAntonio Quartulli 				if (!(tt_common_entry->flags & flags))
228431901264SAntonio Quartulli 					continue;
228548100bacSAntonio Quartulli 				tt_common_entry->flags &= ~flags;
2286697f2531SAntonio Quartulli 			}
2287697f2531SAntonio Quartulli 			changed_num++;
2288058d0e26SAntonio Quartulli 		}
2289058d0e26SAntonio Quartulli 		rcu_read_unlock();
2290058d0e26SAntonio Quartulli 	}
2291697f2531SAntonio Quartulli out:
2292697f2531SAntonio Quartulli 	return changed_num;
2293058d0e26SAntonio Quartulli }
2294058d0e26SAntonio Quartulli 
2295acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */
229656303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
2297058d0e26SAntonio Quartulli {
2298807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
229956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
230056303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
2301b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
2302058d0e26SAntonio Quartulli 	struct hlist_head *head;
2303058d0e26SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
2304c90681b8SAntonio Quartulli 	uint32_t i;
2305058d0e26SAntonio Quartulli 
2306058d0e26SAntonio Quartulli 	if (!hash)
2307058d0e26SAntonio Quartulli 		return;
2308058d0e26SAntonio Quartulli 
2309058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2310058d0e26SAntonio Quartulli 		head = &hash->table[i];
2311058d0e26SAntonio Quartulli 		list_lock = &hash->list_locks[i];
2312058d0e26SAntonio Quartulli 
2313058d0e26SAntonio Quartulli 		spin_lock_bh(list_lock);
2314b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common, node_tmp, head,
2315acd34afaSSven Eckelmann 					  hash_entry) {
2316acd34afaSSven Eckelmann 			if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
2317058d0e26SAntonio Quartulli 				continue;
2318058d0e26SAntonio Quartulli 
231939c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
232086ceb360SSven Eckelmann 				   "Deleting local tt entry (%pM): pending\n",
2321acd34afaSSven Eckelmann 				   tt_common->addr);
2322058d0e26SAntonio Quartulli 
2323807736f6SSven Eckelmann 			atomic_dec(&bat_priv->tt.local_entry_num);
2324b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common->hash_entry);
232556303d34SSven Eckelmann 			tt_local = container_of(tt_common,
232656303d34SSven Eckelmann 						struct batadv_tt_local_entry,
232748100bacSAntonio Quartulli 						common);
232856303d34SSven Eckelmann 			batadv_tt_local_entry_free_ref(tt_local);
2329058d0e26SAntonio Quartulli 		}
2330058d0e26SAntonio Quartulli 		spin_unlock_bh(list_lock);
2331058d0e26SAntonio Quartulli 	}
2332058d0e26SAntonio Quartulli }
2333058d0e26SAntonio Quartulli 
2334e1bf0c14SMarek Lindner /**
2335e1bf0c14SMarek Lindner  * batadv_tt_local_commit_changes - commit all pending local tt changes which
2336e1bf0c14SMarek Lindner  *  have been queued in the time since the last commit
2337e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2338e1bf0c14SMarek Lindner  */
2339e1bf0c14SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
2340058d0e26SAntonio Quartulli {
2341be9aa4c1SMarek Lindner 	uint16_t changed_num = 0;
2342be9aa4c1SMarek Lindner 
2343e1bf0c14SMarek Lindner 	if (atomic_read(&bat_priv->tt.local_changes) < 1) {
2344e1bf0c14SMarek Lindner 		if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
2345e1bf0c14SMarek Lindner 			batadv_tt_tvlv_container_update(bat_priv);
2346e1bf0c14SMarek Lindner 		return;
2347e1bf0c14SMarek Lindner 	}
2348be9aa4c1SMarek Lindner 
2349807736f6SSven Eckelmann 	changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash,
2350acd34afaSSven Eckelmann 					  BATADV_TT_CLIENT_NEW, false);
2351be9aa4c1SMarek Lindner 
2352be9aa4c1SMarek Lindner 	/* all reset entries have to be counted as local entries */
2353807736f6SSven Eckelmann 	atomic_add(changed_num, &bat_priv->tt.local_entry_num);
2354a513088dSSven Eckelmann 	batadv_tt_local_purge_pending_clients(bat_priv);
2355807736f6SSven Eckelmann 	bat_priv->tt.local_crc = batadv_tt_local_crc(bat_priv);
2356058d0e26SAntonio Quartulli 
2357058d0e26SAntonio Quartulli 	/* Increment the TTVN only once per OGM interval */
2358807736f6SSven Eckelmann 	atomic_inc(&bat_priv->tt.vn);
235939c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
23601eda58bfSSven Eckelmann 		   "Local changes committed, updating to ttvn %u\n",
2361807736f6SSven Eckelmann 		   (uint8_t)atomic_read(&bat_priv->tt.vn));
2362be9aa4c1SMarek Lindner 
2363be9aa4c1SMarek Lindner 	/* reset the sending counter */
2364807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
2365e1bf0c14SMarek Lindner 	batadv_tt_tvlv_container_update(bat_priv);
2366058d0e26SAntonio Quartulli }
236759b699cdSAntonio Quartulli 
236856303d34SSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
236908c36d3eSSven Eckelmann 			   uint8_t *dst)
237059b699cdSAntonio Quartulli {
237156303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry = NULL;
237256303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry = NULL;
23735870adc6SMarek Lindner 	bool ret = false;
237459b699cdSAntonio Quartulli 
237559b699cdSAntonio Quartulli 	if (!atomic_read(&bat_priv->ap_isolation))
23765870adc6SMarek Lindner 		goto out;
237759b699cdSAntonio Quartulli 
2378a513088dSSven Eckelmann 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst);
237959b699cdSAntonio Quartulli 	if (!tt_local_entry)
238059b699cdSAntonio Quartulli 		goto out;
238159b699cdSAntonio Quartulli 
2382a513088dSSven Eckelmann 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src);
238359b699cdSAntonio Quartulli 	if (!tt_global_entry)
238459b699cdSAntonio Quartulli 		goto out;
238559b699cdSAntonio Quartulli 
23861f129fefSAntonio Quartulli 	if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
238759b699cdSAntonio Quartulli 		goto out;
238859b699cdSAntonio Quartulli 
23895870adc6SMarek Lindner 	ret = true;
239059b699cdSAntonio Quartulli 
239159b699cdSAntonio Quartulli out:
239259b699cdSAntonio Quartulli 	if (tt_global_entry)
2393a513088dSSven Eckelmann 		batadv_tt_global_entry_free_ref(tt_global_entry);
239459b699cdSAntonio Quartulli 	if (tt_local_entry)
2395a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(tt_local_entry);
239659b699cdSAntonio Quartulli 	return ret;
239759b699cdSAntonio Quartulli }
2398a943cac1SMarek Lindner 
2399e1bf0c14SMarek Lindner /**
2400e1bf0c14SMarek Lindner  * batadv_tt_update_orig - update global translation table with new tt
2401e1bf0c14SMarek Lindner  *  information received via ogms
2402e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2403e1bf0c14SMarek Lindner  * @orig: the orig_node of the ogm
2404e1bf0c14SMarek Lindner  * @tt_buff: buffer holding the tt information
2405e1bf0c14SMarek Lindner  * @tt_num_changes: number of tt changes inside the tt buffer
2406e1bf0c14SMarek Lindner  * @ttvn: translation table version number of this changeset
2407e1bf0c14SMarek Lindner  * @tt_crc: crc16 checksum of orig node's translation table
2408e1bf0c14SMarek Lindner  */
2409e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
241056303d34SSven Eckelmann 				  struct batadv_orig_node *orig_node,
2411e1bf0c14SMarek Lindner 				  const unsigned char *tt_buff,
2412e1bf0c14SMarek Lindner 				  uint16_t tt_num_changes, uint8_t ttvn,
2413e1bf0c14SMarek Lindner 				  uint16_t tt_crc)
2414a943cac1SMarek Lindner {
2415a943cac1SMarek Lindner 	uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
2416a943cac1SMarek Lindner 	bool full_table = true;
2417335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
2418a943cac1SMarek Lindner 
241920ff9d59SSimon Wunderlich 	/* don't care about a backbone gateways updates. */
242008adf151SSven Eckelmann 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
242120ff9d59SSimon Wunderlich 		return;
242220ff9d59SSimon Wunderlich 
242317071578SAntonio Quartulli 	/* orig table not initialised AND first diff is in the OGM OR the ttvn
24249cfc7bd6SSven Eckelmann 	 * increased by one -> we can apply the attached changes
24259cfc7bd6SSven Eckelmann 	 */
242617071578SAntonio Quartulli 	if ((!orig_node->tt_initialised && ttvn == 1) ||
242717071578SAntonio Quartulli 	    ttvn - orig_ttvn == 1) {
2428a943cac1SMarek Lindner 		/* the OGM could not contain the changes due to their size or
242942d0b044SSven Eckelmann 		 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
243042d0b044SSven Eckelmann 		 * times.
24319cfc7bd6SSven Eckelmann 		 * In this case send a tt request
24329cfc7bd6SSven Eckelmann 		 */
2433a943cac1SMarek Lindner 		if (!tt_num_changes) {
2434a943cac1SMarek Lindner 			full_table = false;
2435a943cac1SMarek Lindner 			goto request_table;
2436a943cac1SMarek Lindner 		}
2437a943cac1SMarek Lindner 
2438335fbe0fSMarek Lindner 		tt_change = (struct batadv_tvlv_tt_change *)tt_buff;
2439a513088dSSven Eckelmann 		batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
244096412690SSven Eckelmann 					 ttvn, tt_change);
2441a943cac1SMarek Lindner 
2442a943cac1SMarek Lindner 		/* Even if we received the precomputed crc with the OGM, we
2443a943cac1SMarek Lindner 		 * prefer to recompute it to spot any possible inconsistency
24449cfc7bd6SSven Eckelmann 		 * in the global table
24459cfc7bd6SSven Eckelmann 		 */
2446a513088dSSven Eckelmann 		orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
2447a943cac1SMarek Lindner 
2448a943cac1SMarek Lindner 		/* The ttvn alone is not enough to guarantee consistency
2449a943cac1SMarek Lindner 		 * because a single value could represent different states
2450a943cac1SMarek Lindner 		 * (due to the wrap around). Thus a node has to check whether
2451a943cac1SMarek Lindner 		 * the resulting table (after applying the changes) is still
2452a943cac1SMarek Lindner 		 * consistent or not. E.g. a node could disconnect while its
2453a943cac1SMarek Lindner 		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
2454a943cac1SMarek Lindner 		 * checking the CRC value is mandatory to detect the
24559cfc7bd6SSven Eckelmann 		 * inconsistency
24569cfc7bd6SSven Eckelmann 		 */
2457a943cac1SMarek Lindner 		if (orig_node->tt_crc != tt_crc)
2458a943cac1SMarek Lindner 			goto request_table;
2459a943cac1SMarek Lindner 	} else {
2460a943cac1SMarek Lindner 		/* if we missed more than one change or our tables are not
24619cfc7bd6SSven Eckelmann 		 * in sync anymore -> request fresh tt data
24629cfc7bd6SSven Eckelmann 		 */
246317071578SAntonio Quartulli 		if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
246417071578SAntonio Quartulli 		    orig_node->tt_crc != tt_crc) {
2465a943cac1SMarek Lindner request_table:
246639c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
246739a32991SAntonio Quartulli 				   "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %#.4x last_crc: %#.4x num_changes: %u)\n",
246886ceb360SSven Eckelmann 				   orig_node->orig, ttvn, orig_ttvn, tt_crc,
246986ceb360SSven Eckelmann 				   orig_node->tt_crc, tt_num_changes);
2470a513088dSSven Eckelmann 			batadv_send_tt_request(bat_priv, orig_node, ttvn,
2471a513088dSSven Eckelmann 					       tt_crc, full_table);
2472a943cac1SMarek Lindner 			return;
2473a943cac1SMarek Lindner 		}
2474a943cac1SMarek Lindner 	}
2475a943cac1SMarek Lindner }
24763275e7ccSAntonio Quartulli 
24773275e7ccSAntonio Quartulli /* returns true whether we know that the client has moved from its old
24783275e7ccSAntonio Quartulli  * originator to another one. This entry is kept is still kept for consistency
24793275e7ccSAntonio Quartulli  * purposes
24803275e7ccSAntonio Quartulli  */
248156303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
248208c36d3eSSven Eckelmann 					uint8_t *addr)
24833275e7ccSAntonio Quartulli {
248456303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
24853275e7ccSAntonio Quartulli 	bool ret = false;
24863275e7ccSAntonio Quartulli 
2487a513088dSSven Eckelmann 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
24883275e7ccSAntonio Quartulli 	if (!tt_global_entry)
24893275e7ccSAntonio Quartulli 		goto out;
24903275e7ccSAntonio Quartulli 
2491c1d07431SAntonio Quartulli 	ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
2492a513088dSSven Eckelmann 	batadv_tt_global_entry_free_ref(tt_global_entry);
24933275e7ccSAntonio Quartulli out:
24943275e7ccSAntonio Quartulli 	return ret;
24953275e7ccSAntonio Quartulli }
249630cfd02bSAntonio Quartulli 
24977c1fd91dSAntonio Quartulli /**
24987c1fd91dSAntonio Quartulli  * batadv_tt_local_client_is_roaming - tells whether the client is roaming
24997c1fd91dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
25007c1fd91dSAntonio Quartulli  * @addr: the MAC address of the local client to query
25017c1fd91dSAntonio Quartulli  *
25027c1fd91dSAntonio Quartulli  * Returns true if the local client is known to be roaming (it is not served by
25037c1fd91dSAntonio Quartulli  * this node anymore) or not. If yes, the client is still present in the table
25047c1fd91dSAntonio Quartulli  * to keep the latter consistent with the node TTVN
25057c1fd91dSAntonio Quartulli  */
25067c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
25077c1fd91dSAntonio Quartulli 				       uint8_t *addr)
25087c1fd91dSAntonio Quartulli {
25097c1fd91dSAntonio Quartulli 	struct batadv_tt_local_entry *tt_local_entry;
25107c1fd91dSAntonio Quartulli 	bool ret = false;
25117c1fd91dSAntonio Quartulli 
25127c1fd91dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
25137c1fd91dSAntonio Quartulli 	if (!tt_local_entry)
25147c1fd91dSAntonio Quartulli 		goto out;
25157c1fd91dSAntonio Quartulli 
25167c1fd91dSAntonio Quartulli 	ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
25177c1fd91dSAntonio Quartulli 	batadv_tt_local_entry_free_ref(tt_local_entry);
25187c1fd91dSAntonio Quartulli out:
25197c1fd91dSAntonio Quartulli 	return ret;
25207c1fd91dSAntonio Quartulli }
25217c1fd91dSAntonio Quartulli 
252230cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
252330cfd02bSAntonio Quartulli 					  struct batadv_orig_node *orig_node,
252430cfd02bSAntonio Quartulli 					  const unsigned char *addr)
252530cfd02bSAntonio Quartulli {
252630cfd02bSAntonio Quartulli 	bool ret = false;
252730cfd02bSAntonio Quartulli 
25281f36aebcSAntonio Quartulli 	/* if the originator is a backbone node (meaning it belongs to the same
25291f36aebcSAntonio Quartulli 	 * LAN of this node) the temporary client must not be added because to
25301f36aebcSAntonio Quartulli 	 * reach such destination the node must use the LAN instead of the mesh
25311f36aebcSAntonio Quartulli 	 */
25321f36aebcSAntonio Quartulli 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
25331f36aebcSAntonio Quartulli 		goto out;
25341f36aebcSAntonio Quartulli 
253530cfd02bSAntonio Quartulli 	if (!batadv_tt_global_add(bat_priv, orig_node, addr,
253630cfd02bSAntonio Quartulli 				  BATADV_TT_CLIENT_TEMP,
253730cfd02bSAntonio Quartulli 				  atomic_read(&orig_node->last_ttvn)))
253830cfd02bSAntonio Quartulli 		goto out;
253930cfd02bSAntonio Quartulli 
254030cfd02bSAntonio Quartulli 	batadv_dbg(BATADV_DBG_TT, bat_priv,
254130cfd02bSAntonio Quartulli 		   "Added temporary global client (addr: %pM orig: %pM)\n",
254230cfd02bSAntonio Quartulli 		   addr, orig_node->orig);
254330cfd02bSAntonio Quartulli 	ret = true;
254430cfd02bSAntonio Quartulli out:
254530cfd02bSAntonio Quartulli 	return ret;
254630cfd02bSAntonio Quartulli }
2547e1bf0c14SMarek Lindner 
2548e1bf0c14SMarek Lindner /**
2549e1bf0c14SMarek Lindner  * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
2550e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2551e1bf0c14SMarek Lindner  * @orig: the orig_node of the ogm
2552e1bf0c14SMarek Lindner  * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
2553e1bf0c14SMarek Lindner  * @tvlv_value: tvlv buffer containing the gateway data
2554e1bf0c14SMarek Lindner  * @tvlv_value_len: tvlv buffer length
2555e1bf0c14SMarek Lindner  */
2556e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
2557e1bf0c14SMarek Lindner 					  struct batadv_orig_node *orig,
2558e1bf0c14SMarek Lindner 					  uint8_t flags,
2559e1bf0c14SMarek Lindner 					  void *tvlv_value,
2560e1bf0c14SMarek Lindner 					  uint16_t tvlv_value_len)
2561e1bf0c14SMarek Lindner {
2562e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
2563e1bf0c14SMarek Lindner 	uint16_t num_entries;
2564e1bf0c14SMarek Lindner 
2565e1bf0c14SMarek Lindner 	if (tvlv_value_len < sizeof(*tt_data))
2566e1bf0c14SMarek Lindner 		return;
2567e1bf0c14SMarek Lindner 
2568e1bf0c14SMarek Lindner 	tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
2569e1bf0c14SMarek Lindner 	tvlv_value_len -= sizeof(*tt_data);
2570e1bf0c14SMarek Lindner 
2571e1bf0c14SMarek Lindner 	num_entries = tvlv_value_len / batadv_tt_len(1);
2572e1bf0c14SMarek Lindner 
2573e1bf0c14SMarek Lindner 	batadv_tt_update_orig(bat_priv, orig,
2574e1bf0c14SMarek Lindner 			      (unsigned char *)(tt_data + 1),
2575e1bf0c14SMarek Lindner 			      num_entries, tt_data->ttvn, ntohs(tt_data->crc));
2576e1bf0c14SMarek Lindner }
2577e1bf0c14SMarek Lindner 
2578e1bf0c14SMarek Lindner /**
2579335fbe0fSMarek Lindner  * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv
2580335fbe0fSMarek Lindner  *  container
2581335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2582335fbe0fSMarek Lindner  * @src: mac address of tt tvlv sender
2583335fbe0fSMarek Lindner  * @dst: mac address of tt tvlv recipient
2584335fbe0fSMarek Lindner  * @tvlv_value: tvlv buffer containing the tt data
2585335fbe0fSMarek Lindner  * @tvlv_value_len: tvlv buffer length
2586335fbe0fSMarek Lindner  *
2587335fbe0fSMarek Lindner  * Returns NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS
2588335fbe0fSMarek Lindner  * otherwise.
2589335fbe0fSMarek Lindner  */
2590335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
2591335fbe0fSMarek Lindner 					     uint8_t *src, uint8_t *dst,
2592335fbe0fSMarek Lindner 					     void *tvlv_value,
2593335fbe0fSMarek Lindner 					     uint16_t tvlv_value_len)
2594335fbe0fSMarek Lindner {
2595335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
2596335fbe0fSMarek Lindner 	uint16_t num_entries;
2597335fbe0fSMarek Lindner 	char tt_flag;
2598335fbe0fSMarek Lindner 	bool ret;
2599335fbe0fSMarek Lindner 
2600335fbe0fSMarek Lindner 	if (tvlv_value_len < sizeof(*tt_data))
2601335fbe0fSMarek Lindner 		return NET_RX_SUCCESS;
2602335fbe0fSMarek Lindner 
2603335fbe0fSMarek Lindner 	tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
2604335fbe0fSMarek Lindner 	tvlv_value_len -= sizeof(*tt_data);
2605335fbe0fSMarek Lindner 
2606335fbe0fSMarek Lindner 	num_entries = tvlv_value_len / batadv_tt_len(1);
2607335fbe0fSMarek Lindner 
2608335fbe0fSMarek Lindner 	switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
2609335fbe0fSMarek Lindner 	case BATADV_TT_REQUEST:
2610335fbe0fSMarek Lindner 		batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX);
2611335fbe0fSMarek Lindner 
2612335fbe0fSMarek Lindner 		/* If this node cannot provide a TT response the tt_request is
2613335fbe0fSMarek Lindner 		 * forwarded
2614335fbe0fSMarek Lindner 		 */
2615335fbe0fSMarek Lindner 		ret = batadv_send_tt_response(bat_priv, tt_data, src, dst);
2616335fbe0fSMarek Lindner 		if (!ret) {
2617335fbe0fSMarek Lindner 			if (tt_data->flags & BATADV_TT_FULL_TABLE)
2618335fbe0fSMarek Lindner 				tt_flag = 'F';
2619335fbe0fSMarek Lindner 			else
2620335fbe0fSMarek Lindner 				tt_flag = '.';
2621335fbe0fSMarek Lindner 
2622335fbe0fSMarek Lindner 			batadv_dbg(BATADV_DBG_TT, bat_priv,
2623335fbe0fSMarek Lindner 				   "Routing TT_REQUEST to %pM [%c]\n",
2624335fbe0fSMarek Lindner 				   dst, tt_flag);
2625335fbe0fSMarek Lindner 			/* tvlv API will re-route the packet */
2626335fbe0fSMarek Lindner 			return NET_RX_DROP;
2627335fbe0fSMarek Lindner 		}
2628335fbe0fSMarek Lindner 		break;
2629335fbe0fSMarek Lindner 	case BATADV_TT_RESPONSE:
2630335fbe0fSMarek Lindner 		batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
2631335fbe0fSMarek Lindner 
2632335fbe0fSMarek Lindner 		if (batadv_is_my_mac(bat_priv, dst)) {
2633335fbe0fSMarek Lindner 			batadv_handle_tt_response(bat_priv, tt_data,
2634335fbe0fSMarek Lindner 						  src, num_entries);
2635335fbe0fSMarek Lindner 			return NET_RX_SUCCESS;
2636335fbe0fSMarek Lindner 		}
2637335fbe0fSMarek Lindner 
2638335fbe0fSMarek Lindner 		if (tt_data->flags & BATADV_TT_FULL_TABLE)
2639335fbe0fSMarek Lindner 			tt_flag =  'F';
2640335fbe0fSMarek Lindner 		else
2641335fbe0fSMarek Lindner 			tt_flag = '.';
2642335fbe0fSMarek Lindner 
2643335fbe0fSMarek Lindner 		batadv_dbg(BATADV_DBG_TT, bat_priv,
2644335fbe0fSMarek Lindner 			   "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag);
2645335fbe0fSMarek Lindner 
2646335fbe0fSMarek Lindner 		/* tvlv API will re-route the packet */
2647335fbe0fSMarek Lindner 		return NET_RX_DROP;
2648335fbe0fSMarek Lindner 	}
2649335fbe0fSMarek Lindner 
2650335fbe0fSMarek Lindner 	return NET_RX_SUCCESS;
2651335fbe0fSMarek Lindner }
2652335fbe0fSMarek Lindner 
2653335fbe0fSMarek Lindner /**
2654122edaa0SMarek Lindner  * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container
2655122edaa0SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2656122edaa0SMarek Lindner  * @src: mac address of tt tvlv sender
2657122edaa0SMarek Lindner  * @dst: mac address of tt tvlv recipient
2658122edaa0SMarek Lindner  * @tvlv_value: tvlv buffer containing the tt data
2659122edaa0SMarek Lindner  * @tvlv_value_len: tvlv buffer length
2660122edaa0SMarek Lindner  *
2661122edaa0SMarek Lindner  * Returns NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS
2662122edaa0SMarek Lindner  * otherwise.
2663122edaa0SMarek Lindner  */
2664122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
2665122edaa0SMarek Lindner 					       uint8_t *src, uint8_t *dst,
2666122edaa0SMarek Lindner 					       void *tvlv_value,
2667122edaa0SMarek Lindner 					       uint16_t tvlv_value_len)
2668122edaa0SMarek Lindner {
2669122edaa0SMarek Lindner 	struct batadv_tvlv_roam_adv *roaming_adv;
2670122edaa0SMarek Lindner 	struct batadv_orig_node *orig_node = NULL;
2671122edaa0SMarek Lindner 
2672122edaa0SMarek Lindner 	/* If this node is not the intended recipient of the
2673122edaa0SMarek Lindner 	 * roaming advertisement the packet is forwarded
2674122edaa0SMarek Lindner 	 * (the tvlv API will re-route the packet).
2675122edaa0SMarek Lindner 	 */
2676122edaa0SMarek Lindner 	if (!batadv_is_my_mac(bat_priv, dst))
2677122edaa0SMarek Lindner 		return NET_RX_DROP;
2678122edaa0SMarek Lindner 
2679122edaa0SMarek Lindner 	/* check if it is a backbone gateway. we don't accept
2680122edaa0SMarek Lindner 	 * roaming advertisement from it, as it has the same
2681122edaa0SMarek Lindner 	 * entries as we have.
2682122edaa0SMarek Lindner 	 */
2683122edaa0SMarek Lindner 	if (batadv_bla_is_backbone_gw_orig(bat_priv, src))
2684122edaa0SMarek Lindner 		goto out;
2685122edaa0SMarek Lindner 
2686122edaa0SMarek Lindner 	if (tvlv_value_len < sizeof(*roaming_adv))
2687122edaa0SMarek Lindner 		goto out;
2688122edaa0SMarek Lindner 
2689122edaa0SMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, src);
2690122edaa0SMarek Lindner 	if (!orig_node)
2691122edaa0SMarek Lindner 		goto out;
2692122edaa0SMarek Lindner 
2693122edaa0SMarek Lindner 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
2694122edaa0SMarek Lindner 	roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value;
2695122edaa0SMarek Lindner 
2696122edaa0SMarek Lindner 	batadv_dbg(BATADV_DBG_TT, bat_priv,
2697122edaa0SMarek Lindner 		   "Received ROAMING_ADV from %pM (client %pM)\n",
2698122edaa0SMarek Lindner 		   src, roaming_adv->client);
2699122edaa0SMarek Lindner 
2700122edaa0SMarek Lindner 	batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client,
2701122edaa0SMarek Lindner 			     BATADV_TT_CLIENT_ROAM,
2702122edaa0SMarek Lindner 			     atomic_read(&orig_node->last_ttvn) + 1);
2703122edaa0SMarek Lindner 
2704122edaa0SMarek Lindner out:
2705122edaa0SMarek Lindner 	if (orig_node)
2706122edaa0SMarek Lindner 		batadv_orig_node_free_ref(orig_node);
2707122edaa0SMarek Lindner 	return NET_RX_SUCCESS;
2708122edaa0SMarek Lindner }
2709122edaa0SMarek Lindner 
2710122edaa0SMarek Lindner /**
2711e1bf0c14SMarek Lindner  * batadv_tt_init - initialise the translation table internals
2712e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2713e1bf0c14SMarek Lindner  *
2714e1bf0c14SMarek Lindner  * Return 0 on success or negative error number in case of failure.
2715e1bf0c14SMarek Lindner  */
2716e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv)
2717e1bf0c14SMarek Lindner {
2718e1bf0c14SMarek Lindner 	int ret;
2719e1bf0c14SMarek Lindner 
2720e1bf0c14SMarek Lindner 	ret = batadv_tt_local_init(bat_priv);
2721e1bf0c14SMarek Lindner 	if (ret < 0)
2722e1bf0c14SMarek Lindner 		return ret;
2723e1bf0c14SMarek Lindner 
2724e1bf0c14SMarek Lindner 	ret = batadv_tt_global_init(bat_priv);
2725e1bf0c14SMarek Lindner 	if (ret < 0)
2726e1bf0c14SMarek Lindner 		return ret;
2727e1bf0c14SMarek Lindner 
2728e1bf0c14SMarek Lindner 	batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1,
2729335fbe0fSMarek Lindner 				     batadv_tt_tvlv_unicast_handler_v1,
2730335fbe0fSMarek Lindner 				     BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
2731e1bf0c14SMarek Lindner 
2732122edaa0SMarek Lindner 	batadv_tvlv_handler_register(bat_priv, NULL,
2733122edaa0SMarek Lindner 				     batadv_roam_tvlv_unicast_handler_v1,
2734122edaa0SMarek Lindner 				     BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS);
2735122edaa0SMarek Lindner 
2736e1bf0c14SMarek Lindner 	INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
2737e1bf0c14SMarek Lindner 	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
2738e1bf0c14SMarek Lindner 			   msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
2739e1bf0c14SMarek Lindner 
2740e1bf0c14SMarek Lindner 	return 1;
2741e1bf0c14SMarek Lindner }
2742