19f6446c7SSven Eckelmann /* Copyright (C) 2007-2015 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
15ebf38fb7SAntonio Quartulli  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16c6c8fea2SSven Eckelmann  */
17c6c8fea2SSven Eckelmann 
18c6c8fea2SSven Eckelmann #include "translation-table.h"
191e2c2a4fSSven Eckelmann #include "main.h"
20c6c8fea2SSven Eckelmann 
211e2c2a4fSSven Eckelmann #include <linux/atomic.h>
22ac4eebd4SLinus Lüssing #include <linux/bitops.h>
231e2c2a4fSSven Eckelmann #include <linux/bug.h>
241e2c2a4fSSven Eckelmann #include <linux/byteorder/generic.h>
251e2c2a4fSSven Eckelmann #include <linux/compiler.h>
26ced72933SAntonio Quartulli #include <linux/crc32c.h>
271e2c2a4fSSven Eckelmann #include <linux/errno.h>
281e2c2a4fSSven Eckelmann #include <linux/etherdevice.h>
291e2c2a4fSSven Eckelmann #include <linux/fs.h>
301e2c2a4fSSven Eckelmann #include <linux/if_ether.h>
311e2c2a4fSSven Eckelmann #include <linux/jhash.h>
321e2c2a4fSSven Eckelmann #include <linux/jiffies.h>
331e2c2a4fSSven Eckelmann #include <linux/kernel.h>
341e2c2a4fSSven Eckelmann #include <linux/list.h>
351e2c2a4fSSven Eckelmann #include <linux/lockdep.h>
361e2c2a4fSSven Eckelmann #include <linux/netdevice.h>
371e2c2a4fSSven Eckelmann #include <linux/rculist.h>
381e2c2a4fSSven Eckelmann #include <linux/rcupdate.h>
391e2c2a4fSSven Eckelmann #include <linux/seq_file.h>
401e2c2a4fSSven Eckelmann #include <linux/slab.h>
411e2c2a4fSSven Eckelmann #include <linux/spinlock.h>
421e2c2a4fSSven Eckelmann #include <linux/stddef.h>
431e2c2a4fSSven Eckelmann #include <linux/string.h>
441e2c2a4fSSven Eckelmann #include <linux/workqueue.h>
451e2c2a4fSSven Eckelmann #include <net/net_namespace.h>
461e2c2a4fSSven Eckelmann 
471e2c2a4fSSven Eckelmann #include "bridge_loop_avoidance.h"
481e2c2a4fSSven Eckelmann #include "hard-interface.h"
491e2c2a4fSSven Eckelmann #include "hash.h"
501e2c2a4fSSven Eckelmann #include "multicast.h"
511e2c2a4fSSven Eckelmann #include "originator.h"
521e2c2a4fSSven Eckelmann #include "packet.h"
531e2c2a4fSSven Eckelmann #include "soft-interface.h"
54a73105b8SAntonio Quartulli 
55dec05074SAntonio Quartulli /* hash class keys */
56dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_local_hash_lock_class_key;
57dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_global_hash_lock_class_key;
58dec05074SAntonio Quartulli 
596b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
60c018ad3dSAntonio Quartulli 				 unsigned short vid,
6156303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node);
62a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work);
63a513088dSSven Eckelmann static void
6456303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
6530cfd02bSAntonio Quartulli static void batadv_tt_global_del(struct batadv_priv *bat_priv,
6630cfd02bSAntonio Quartulli 				 struct batadv_orig_node *orig_node,
6730cfd02bSAntonio Quartulli 				 const unsigned char *addr,
68c018ad3dSAntonio Quartulli 				 unsigned short vid, const char *message,
69c018ad3dSAntonio Quartulli 				 bool roaming);
70c6c8fea2SSven Eckelmann 
7162fe710fSSven Eckelmann /**
7262fe710fSSven Eckelmann  * batadv_compare_tt
7362fe710fSSven Eckelmann  *
7462fe710fSSven Eckelmann  * Return: 1 if they are the same mac addr and vid
7562fe710fSSven Eckelmann  */
76a513088dSSven Eckelmann static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
777aadf889SMarek Lindner {
7856303d34SSven Eckelmann 	const void *data1 = container_of(node, struct batadv_tt_common_entry,
79747e4221SSven Eckelmann 					 hash_entry);
804c718958SMarek Lindner 	const struct batadv_tt_common_entry *tt1 = data1;
814c718958SMarek Lindner 	const struct batadv_tt_common_entry *tt2 = data2;
827aadf889SMarek Lindner 
834c718958SMarek Lindner 	return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
847aadf889SMarek Lindner }
857aadf889SMarek Lindner 
86c018ad3dSAntonio Quartulli /**
87c018ad3dSAntonio Quartulli  * batadv_choose_tt - return the index of the tt entry in the hash table
88c018ad3dSAntonio Quartulli  * @data: pointer to the tt_common_entry object to map
89c018ad3dSAntonio Quartulli  * @size: the size of the hash table
90c018ad3dSAntonio Quartulli  *
9162fe710fSSven Eckelmann  * Return: the hash index where the object represented by 'data' should be
92c018ad3dSAntonio Quartulli  * stored at.
93c018ad3dSAntonio Quartulli  */
946b5e971aSSven Eckelmann static inline u32 batadv_choose_tt(const void *data, u32 size)
95c018ad3dSAntonio Quartulli {
96c018ad3dSAntonio Quartulli 	struct batadv_tt_common_entry *tt;
976b5e971aSSven Eckelmann 	u32 hash = 0;
98c018ad3dSAntonio Quartulli 
99c018ad3dSAntonio Quartulli 	tt = (struct batadv_tt_common_entry *)data;
10036fd61cbSSven Eckelmann 	hash = jhash(&tt->addr, ETH_ALEN, hash);
10136fd61cbSSven Eckelmann 	hash = jhash(&tt->vid, sizeof(tt->vid), hash);
102c018ad3dSAntonio Quartulli 
103c018ad3dSAntonio Quartulli 	return hash % size;
104c018ad3dSAntonio Quartulli }
105c018ad3dSAntonio Quartulli 
106c018ad3dSAntonio Quartulli /**
107c018ad3dSAntonio Quartulli  * batadv_tt_hash_find - look for a client in the given hash table
108c018ad3dSAntonio Quartulli  * @hash: the hash table to search
109c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to look for
110c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
111c018ad3dSAntonio Quartulli  *
11262fe710fSSven Eckelmann  * Return: a pointer to the tt_common struct belonging to the searched client if
113c018ad3dSAntonio Quartulli  * found, NULL otherwise.
114c018ad3dSAntonio Quartulli  */
11556303d34SSven Eckelmann static struct batadv_tt_common_entry *
1166b5e971aSSven Eckelmann batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr,
117c018ad3dSAntonio Quartulli 		    unsigned short vid)
1187aadf889SMarek Lindner {
1197aadf889SMarek Lindner 	struct hlist_head *head;
120c018ad3dSAntonio Quartulli 	struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL;
1216b5e971aSSven Eckelmann 	u32 index;
1227aadf889SMarek Lindner 
1237aadf889SMarek Lindner 	if (!hash)
1247aadf889SMarek Lindner 		return NULL;
1257aadf889SMarek Lindner 
1268fdd0153SAntonio Quartulli 	ether_addr_copy(to_search.addr, addr);
127c018ad3dSAntonio Quartulli 	to_search.vid = vid;
128c018ad3dSAntonio Quartulli 
129c018ad3dSAntonio Quartulli 	index = batadv_choose_tt(&to_search, hash->size);
1307aadf889SMarek Lindner 	head = &hash->table[index];
1317aadf889SMarek Lindner 
1327aadf889SMarek Lindner 	rcu_read_lock();
133c018ad3dSAntonio Quartulli 	hlist_for_each_entry_rcu(tt, head, hash_entry) {
134c018ad3dSAntonio Quartulli 		if (!batadv_compare_eth(tt, addr))
1357aadf889SMarek Lindner 			continue;
1367aadf889SMarek Lindner 
137c018ad3dSAntonio Quartulli 		if (tt->vid != vid)
1387683fdc1SAntonio Quartulli 			continue;
1397683fdc1SAntonio Quartulli 
140c018ad3dSAntonio Quartulli 		if (!atomic_inc_not_zero(&tt->refcount))
141c018ad3dSAntonio Quartulli 			continue;
142c018ad3dSAntonio Quartulli 
143c018ad3dSAntonio Quartulli 		tt_tmp = tt;
1447aadf889SMarek Lindner 		break;
1457aadf889SMarek Lindner 	}
1467aadf889SMarek Lindner 	rcu_read_unlock();
1477aadf889SMarek Lindner 
148c018ad3dSAntonio Quartulli 	return tt_tmp;
14948100bacSAntonio Quartulli }
15048100bacSAntonio Quartulli 
151c018ad3dSAntonio Quartulli /**
152c018ad3dSAntonio Quartulli  * batadv_tt_local_hash_find - search the local table for a given client
153c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
154c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to look for
155c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
156c018ad3dSAntonio Quartulli  *
15762fe710fSSven Eckelmann  * Return: a pointer to the corresponding tt_local_entry struct if the client is
158c018ad3dSAntonio Quartulli  * found, NULL otherwise.
159c018ad3dSAntonio Quartulli  */
16056303d34SSven Eckelmann static struct batadv_tt_local_entry *
1616b5e971aSSven Eckelmann batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
162c018ad3dSAntonio Quartulli 			  unsigned short vid)
16348100bacSAntonio Quartulli {
16456303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
16556303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry = NULL;
16648100bacSAntonio Quartulli 
167c018ad3dSAntonio Quartulli 	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr,
168c018ad3dSAntonio Quartulli 					      vid);
16948100bacSAntonio Quartulli 	if (tt_common_entry)
17048100bacSAntonio Quartulli 		tt_local_entry = container_of(tt_common_entry,
17156303d34SSven Eckelmann 					      struct batadv_tt_local_entry,
17256303d34SSven Eckelmann 					      common);
17348100bacSAntonio Quartulli 	return tt_local_entry;
1747aadf889SMarek Lindner }
1757aadf889SMarek Lindner 
176c018ad3dSAntonio Quartulli /**
177c018ad3dSAntonio Quartulli  * batadv_tt_global_hash_find - search the global table for a given client
178c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
179c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to look for
180c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
181c018ad3dSAntonio Quartulli  *
18262fe710fSSven Eckelmann  * Return: a pointer to the corresponding tt_global_entry struct if the client
183c018ad3dSAntonio Quartulli  * is found, NULL otherwise.
184c018ad3dSAntonio Quartulli  */
18556303d34SSven Eckelmann static struct batadv_tt_global_entry *
1866b5e971aSSven Eckelmann batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
187c018ad3dSAntonio Quartulli 			   unsigned short vid)
1887aadf889SMarek Lindner {
18956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
19056303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry = NULL;
1917aadf889SMarek Lindner 
192c018ad3dSAntonio Quartulli 	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr,
193c018ad3dSAntonio Quartulli 					      vid);
19448100bacSAntonio Quartulli 	if (tt_common_entry)
19548100bacSAntonio Quartulli 		tt_global_entry = container_of(tt_common_entry,
19656303d34SSven Eckelmann 					       struct batadv_tt_global_entry,
19756303d34SSven Eckelmann 					       common);
19848100bacSAntonio Quartulli 	return tt_global_entry;
1997aadf889SMarek Lindner }
2007aadf889SMarek Lindner 
201a513088dSSven Eckelmann static void
20256303d34SSven Eckelmann batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry)
2037683fdc1SAntonio Quartulli {
20448100bacSAntonio Quartulli 	if (atomic_dec_and_test(&tt_local_entry->common.refcount))
20548100bacSAntonio Quartulli 		kfree_rcu(tt_local_entry, common.rcu);
2067683fdc1SAntonio Quartulli }
2077683fdc1SAntonio Quartulli 
20821026059SAntonio Quartulli /**
20921026059SAntonio Quartulli  * batadv_tt_global_entry_free_ref - decrement the refcounter for a
21021026059SAntonio Quartulli  *  tt_global_entry and possibly free it
21121026059SAntonio Quartulli  * @tt_global_entry: the object to free
21221026059SAntonio Quartulli  */
213a513088dSSven Eckelmann static void
21456303d34SSven Eckelmann batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry)
2157683fdc1SAntonio Quartulli {
216db08e6e5SSimon Wunderlich 	if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
217a513088dSSven Eckelmann 		batadv_tt_global_del_orig_list(tt_global_entry);
21821026059SAntonio Quartulli 		kfree_rcu(tt_global_entry, common.rcu);
2197683fdc1SAntonio Quartulli 	}
220db08e6e5SSimon Wunderlich }
221db08e6e5SSimon Wunderlich 
2221d8ab8d3SLinus Lüssing /**
2231d8ab8d3SLinus Lüssing  * batadv_tt_global_hash_count - count the number of orig entries
2241d8ab8d3SLinus Lüssing  * @addr: the mac address of the client to count entries for
2251d8ab8d3SLinus Lüssing  * @vid: VLAN identifier
2261d8ab8d3SLinus Lüssing  *
22762fe710fSSven Eckelmann  * Return: the number of originators advertising the given address/data
2281d8ab8d3SLinus Lüssing  * (excluding ourself).
2291d8ab8d3SLinus Lüssing  */
2301d8ab8d3SLinus Lüssing int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
2316b5e971aSSven Eckelmann 				const u8 *addr, unsigned short vid)
2321d8ab8d3SLinus Lüssing {
2331d8ab8d3SLinus Lüssing 	struct batadv_tt_global_entry *tt_global_entry;
2341d8ab8d3SLinus Lüssing 	int count;
2351d8ab8d3SLinus Lüssing 
2361d8ab8d3SLinus Lüssing 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
2371d8ab8d3SLinus Lüssing 	if (!tt_global_entry)
2381d8ab8d3SLinus Lüssing 		return 0;
2391d8ab8d3SLinus Lüssing 
2401d8ab8d3SLinus Lüssing 	count = atomic_read(&tt_global_entry->orig_list_count);
2411d8ab8d3SLinus Lüssing 	batadv_tt_global_entry_free_ref(tt_global_entry);
2421d8ab8d3SLinus Lüssing 
2431d8ab8d3SLinus Lüssing 	return count;
2441d8ab8d3SLinus Lüssing }
2451d8ab8d3SLinus Lüssing 
2467ea7b4a1SAntonio Quartulli /**
2477ea7b4a1SAntonio Quartulli  * batadv_tt_local_size_mod - change the size by v of the local table identified
2487ea7b4a1SAntonio Quartulli  *  by vid
2497ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2507ea7b4a1SAntonio Quartulli  * @vid: the VLAN identifier of the sub-table to change
2517ea7b4a1SAntonio Quartulli  * @v: the amount to sum to the local table size
2527ea7b4a1SAntonio Quartulli  */
2537ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
2547ea7b4a1SAntonio Quartulli 				     unsigned short vid, int v)
2557ea7b4a1SAntonio Quartulli {
2567ea7b4a1SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
2577ea7b4a1SAntonio Quartulli 
2587ea7b4a1SAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
2597ea7b4a1SAntonio Quartulli 	if (!vlan)
2607ea7b4a1SAntonio Quartulli 		return;
2617ea7b4a1SAntonio Quartulli 
2627ea7b4a1SAntonio Quartulli 	atomic_add(v, &vlan->tt.num_entries);
2637ea7b4a1SAntonio Quartulli 
2647ea7b4a1SAntonio Quartulli 	batadv_softif_vlan_free_ref(vlan);
2657ea7b4a1SAntonio Quartulli }
2667ea7b4a1SAntonio Quartulli 
2677ea7b4a1SAntonio Quartulli /**
2687ea7b4a1SAntonio Quartulli  * batadv_tt_local_size_inc - increase by one the local table size for the given
2697ea7b4a1SAntonio Quartulli  *  vid
2707ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2717ea7b4a1SAntonio Quartulli  * @vid: the VLAN identifier
2727ea7b4a1SAntonio Quartulli  */
2737ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
2747ea7b4a1SAntonio Quartulli 				     unsigned short vid)
2757ea7b4a1SAntonio Quartulli {
2767ea7b4a1SAntonio Quartulli 	batadv_tt_local_size_mod(bat_priv, vid, 1);
2777ea7b4a1SAntonio Quartulli }
2787ea7b4a1SAntonio Quartulli 
2797ea7b4a1SAntonio Quartulli /**
2807ea7b4a1SAntonio Quartulli  * batadv_tt_local_size_dec - decrease by one the local table size for the given
2817ea7b4a1SAntonio Quartulli  *  vid
2827ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2837ea7b4a1SAntonio Quartulli  * @vid: the VLAN identifier
2847ea7b4a1SAntonio Quartulli  */
2857ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
2867ea7b4a1SAntonio Quartulli 				     unsigned short vid)
2877ea7b4a1SAntonio Quartulli {
2887ea7b4a1SAntonio Quartulli 	batadv_tt_local_size_mod(bat_priv, vid, -1);
2897ea7b4a1SAntonio Quartulli }
2907ea7b4a1SAntonio Quartulli 
2917ea7b4a1SAntonio Quartulli /**
2927ea7b4a1SAntonio Quartulli  * batadv_tt_global_size_mod - change the size by v of the local table
2937ea7b4a1SAntonio Quartulli  *  identified by vid
2947ea7b4a1SAntonio Quartulli  * @vid: the VLAN identifier
2957ea7b4a1SAntonio Quartulli  * @v: the amount to sum to the global table size
2967ea7b4a1SAntonio Quartulli  */
2977ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node,
2987ea7b4a1SAntonio Quartulli 				      unsigned short vid, int v)
2997ea7b4a1SAntonio Quartulli {
3007ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
3017ea7b4a1SAntonio Quartulli 
3027ea7b4a1SAntonio Quartulli 	vlan = batadv_orig_node_vlan_new(orig_node, vid);
3037ea7b4a1SAntonio Quartulli 	if (!vlan)
3047ea7b4a1SAntonio Quartulli 		return;
3057ea7b4a1SAntonio Quartulli 
3067ea7b4a1SAntonio Quartulli 	if (atomic_add_return(v, &vlan->tt.num_entries) == 0) {
3077ea7b4a1SAntonio Quartulli 		spin_lock_bh(&orig_node->vlan_list_lock);
308a121048aSMarek Lindner 		hlist_del_init_rcu(&vlan->list);
3097ea7b4a1SAntonio Quartulli 		spin_unlock_bh(&orig_node->vlan_list_lock);
3107ea7b4a1SAntonio Quartulli 		batadv_orig_node_vlan_free_ref(vlan);
3117ea7b4a1SAntonio Quartulli 	}
3127ea7b4a1SAntonio Quartulli 
3137ea7b4a1SAntonio Quartulli 	batadv_orig_node_vlan_free_ref(vlan);
3147ea7b4a1SAntonio Quartulli }
3157ea7b4a1SAntonio Quartulli 
3167ea7b4a1SAntonio Quartulli /**
3177ea7b4a1SAntonio Quartulli  * batadv_tt_global_size_inc - increase by one the global table size for the
3187ea7b4a1SAntonio Quartulli  *  given vid
3197ea7b4a1SAntonio Quartulli  * @orig_node: the originator which global table size has to be decreased
3207ea7b4a1SAntonio Quartulli  * @vid: the vlan identifier
3217ea7b4a1SAntonio Quartulli  */
3227ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node,
3237ea7b4a1SAntonio Quartulli 				      unsigned short vid)
3247ea7b4a1SAntonio Quartulli {
3257ea7b4a1SAntonio Quartulli 	batadv_tt_global_size_mod(orig_node, vid, 1);
3267ea7b4a1SAntonio Quartulli }
3277ea7b4a1SAntonio Quartulli 
3287ea7b4a1SAntonio Quartulli /**
3297ea7b4a1SAntonio Quartulli  * batadv_tt_global_size_dec - decrease by one the global table size for the
3307ea7b4a1SAntonio Quartulli  *  given vid
3317ea7b4a1SAntonio Quartulli  * @orig_node: the originator which global table size has to be decreased
3327ea7b4a1SAntonio Quartulli  * @vid: the vlan identifier
3337ea7b4a1SAntonio Quartulli  */
3347ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node,
3357ea7b4a1SAntonio Quartulli 				      unsigned short vid)
3367ea7b4a1SAntonio Quartulli {
3377ea7b4a1SAntonio Quartulli 	batadv_tt_global_size_mod(orig_node, vid, -1);
3387ea7b4a1SAntonio Quartulli }
3397ea7b4a1SAntonio Quartulli 
34042eff6a6SSven Eckelmann /**
34142eff6a6SSven Eckelmann  * batadv_tt_orig_list_entry_release - release tt orig entry from lists and
34242eff6a6SSven Eckelmann  *  queue for free after rcu grace period
34342eff6a6SSven Eckelmann  * @orig_entry: tt orig entry to be free'd
34442eff6a6SSven Eckelmann  */
34542eff6a6SSven Eckelmann static void
34642eff6a6SSven Eckelmann batadv_tt_orig_list_entry_release(struct batadv_tt_orig_list_entry *orig_entry)
34742eff6a6SSven Eckelmann {
34842eff6a6SSven Eckelmann 	batadv_orig_node_free_ref(orig_entry->orig_node);
34942eff6a6SSven Eckelmann 	kfree_rcu(orig_entry, rcu);
35042eff6a6SSven Eckelmann }
35142eff6a6SSven Eckelmann 
352a513088dSSven Eckelmann static void
35356303d34SSven Eckelmann batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
354db08e6e5SSimon Wunderlich {
355d657e621SAntonio Quartulli 	if (!atomic_dec_and_test(&orig_entry->refcount))
356d657e621SAntonio Quartulli 		return;
3577ea7b4a1SAntonio Quartulli 
35842eff6a6SSven Eckelmann 	batadv_tt_orig_list_entry_release(orig_entry);
359db08e6e5SSimon Wunderlich }
3607683fdc1SAntonio Quartulli 
3613abe4adbSAntonio Quartulli /**
3623abe4adbSAntonio Quartulli  * batadv_tt_local_event - store a local TT event (ADD/DEL)
3633abe4adbSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3643abe4adbSAntonio Quartulli  * @tt_local_entry: the TT entry involved in the event
3653abe4adbSAntonio Quartulli  * @event_flags: flags to store in the event structure
3663abe4adbSAntonio Quartulli  */
36756303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv,
3683abe4adbSAntonio Quartulli 				  struct batadv_tt_local_entry *tt_local_entry,
3696b5e971aSSven Eckelmann 				  u8 event_flags)
370a73105b8SAntonio Quartulli {
37156303d34SSven Eckelmann 	struct batadv_tt_change_node *tt_change_node, *entry, *safe;
3723abe4adbSAntonio Quartulli 	struct batadv_tt_common_entry *common = &tt_local_entry->common;
3736b5e971aSSven Eckelmann 	u8 flags = common->flags | event_flags;
3743b643de5SAntonio Quartulli 	bool event_removed = false;
3753b643de5SAntonio Quartulli 	bool del_op_requested, del_op_entry;
376a73105b8SAntonio Quartulli 
377a73105b8SAntonio Quartulli 	tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
378a73105b8SAntonio Quartulli 	if (!tt_change_node)
379a73105b8SAntonio Quartulli 		return;
380a73105b8SAntonio Quartulli 
381ff66c975SAntonio Quartulli 	tt_change_node->change.flags = flags;
382ca663046SAntonio Quartulli 	memset(tt_change_node->change.reserved, 0,
383ca663046SAntonio Quartulli 	       sizeof(tt_change_node->change.reserved));
3848fdd0153SAntonio Quartulli 	ether_addr_copy(tt_change_node->change.addr, common->addr);
385c018ad3dSAntonio Quartulli 	tt_change_node->change.vid = htons(common->vid);
386a73105b8SAntonio Quartulli 
387acd34afaSSven Eckelmann 	del_op_requested = flags & BATADV_TT_CLIENT_DEL;
3883b643de5SAntonio Quartulli 
3893b643de5SAntonio Quartulli 	/* check for ADD+DEL or DEL+ADD events */
390807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
391807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
3923b643de5SAntonio Quartulli 				 list) {
3933abe4adbSAntonio Quartulli 		if (!batadv_compare_eth(entry->change.addr, common->addr))
3943b643de5SAntonio Quartulli 			continue;
3953b643de5SAntonio Quartulli 
3963b643de5SAntonio Quartulli 		/* DEL+ADD in the same orig interval have no effect and can be
3973b643de5SAntonio Quartulli 		 * removed to avoid silly behaviour on the receiver side. The
3983b643de5SAntonio Quartulli 		 * other way around (ADD+DEL) can happen in case of roaming of
3993b643de5SAntonio Quartulli 		 * a client still in the NEW state. Roaming of NEW clients is
4003b643de5SAntonio Quartulli 		 * now possible due to automatically recognition of "temporary"
4013b643de5SAntonio Quartulli 		 * clients
4023b643de5SAntonio Quartulli 		 */
403acd34afaSSven Eckelmann 		del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
4043b643de5SAntonio Quartulli 		if (!del_op_requested && del_op_entry)
4053b643de5SAntonio Quartulli 			goto del;
4063b643de5SAntonio Quartulli 		if (del_op_requested && !del_op_entry)
4073b643de5SAntonio Quartulli 			goto del;
4083c4f7ab6SAntonio Quartulli 
4093c4f7ab6SAntonio Quartulli 		/* this is a second add in the same originator interval. It
4103c4f7ab6SAntonio Quartulli 		 * means that flags have been changed: update them!
4113c4f7ab6SAntonio Quartulli 		 */
4123c4f7ab6SAntonio Quartulli 		if (!del_op_requested && !del_op_entry)
4133c4f7ab6SAntonio Quartulli 			entry->change.flags = flags;
4143c4f7ab6SAntonio Quartulli 
4153b643de5SAntonio Quartulli 		continue;
4163b643de5SAntonio Quartulli del:
4173b643de5SAntonio Quartulli 		list_del(&entry->list);
4183b643de5SAntonio Quartulli 		kfree(entry);
419155e4e12SJesper Juhl 		kfree(tt_change_node);
4203b643de5SAntonio Quartulli 		event_removed = true;
4213b643de5SAntonio Quartulli 		goto unlock;
4223b643de5SAntonio Quartulli 	}
4233b643de5SAntonio Quartulli 
424a73105b8SAntonio Quartulli 	/* track the change in the OGMinterval list */
425807736f6SSven Eckelmann 	list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list);
4263b643de5SAntonio Quartulli 
4273b643de5SAntonio Quartulli unlock:
428807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
429a73105b8SAntonio Quartulli 
4303b643de5SAntonio Quartulli 	if (event_removed)
431807736f6SSven Eckelmann 		atomic_dec(&bat_priv->tt.local_changes);
4323b643de5SAntonio Quartulli 	else
433807736f6SSven Eckelmann 		atomic_inc(&bat_priv->tt.local_changes);
434a73105b8SAntonio Quartulli }
435a73105b8SAntonio Quartulli 
436335fbe0fSMarek Lindner /**
437335fbe0fSMarek Lindner  * batadv_tt_len - compute length in bytes of given number of tt changes
438335fbe0fSMarek Lindner  * @changes_num: number of tt changes
439335fbe0fSMarek Lindner  *
44062fe710fSSven Eckelmann  * Return: computed length in bytes.
441335fbe0fSMarek Lindner  */
442335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num)
443a73105b8SAntonio Quartulli {
444335fbe0fSMarek Lindner 	return changes_num * sizeof(struct batadv_tvlv_tt_change);
445a73105b8SAntonio Quartulli }
446a73105b8SAntonio Quartulli 
447298e6e68SAntonio Quartulli /**
448298e6e68SAntonio Quartulli  * batadv_tt_entries - compute the number of entries fitting in tt_len bytes
449298e6e68SAntonio Quartulli  * @tt_len: available space
450298e6e68SAntonio Quartulli  *
45162fe710fSSven Eckelmann  * Return: the number of entries.
452298e6e68SAntonio Quartulli  */
4536b5e971aSSven Eckelmann static u16 batadv_tt_entries(u16 tt_len)
454298e6e68SAntonio Quartulli {
455298e6e68SAntonio Quartulli 	return tt_len / batadv_tt_len(1);
456298e6e68SAntonio Quartulli }
457298e6e68SAntonio Quartulli 
458a19d3d85SMarek Lindner /**
459a19d3d85SMarek Lindner  * batadv_tt_local_table_transmit_size - calculates the local translation table
460a19d3d85SMarek Lindner  *  size when transmitted over the air
461a19d3d85SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
462a19d3d85SMarek Lindner  *
46362fe710fSSven Eckelmann  * Return: local translation table size in bytes.
464a19d3d85SMarek Lindner  */
465a19d3d85SMarek Lindner static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
466a19d3d85SMarek Lindner {
4674f248cffSSven Eckelmann 	u16 num_vlan = 0;
4684f248cffSSven Eckelmann 	u16 tt_local_entries = 0;
469a19d3d85SMarek Lindner 	struct batadv_softif_vlan *vlan;
470a19d3d85SMarek Lindner 	int hdr_size;
471a19d3d85SMarek Lindner 
472a19d3d85SMarek Lindner 	rcu_read_lock();
473a19d3d85SMarek Lindner 	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
474a19d3d85SMarek Lindner 		num_vlan++;
475a19d3d85SMarek Lindner 		tt_local_entries += atomic_read(&vlan->tt.num_entries);
476a19d3d85SMarek Lindner 	}
477a19d3d85SMarek Lindner 	rcu_read_unlock();
478a19d3d85SMarek Lindner 
479a19d3d85SMarek Lindner 	/* header size of tvlv encapsulated tt response payload */
480a19d3d85SMarek Lindner 	hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
481a19d3d85SMarek Lindner 	hdr_size += sizeof(struct batadv_tvlv_hdr);
482a19d3d85SMarek Lindner 	hdr_size += sizeof(struct batadv_tvlv_tt_data);
483a19d3d85SMarek Lindner 	hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
484a19d3d85SMarek Lindner 
485a19d3d85SMarek Lindner 	return hdr_size + batadv_tt_len(tt_local_entries);
486a19d3d85SMarek Lindner }
487a19d3d85SMarek Lindner 
48856303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv)
489c6c8fea2SSven Eckelmann {
490807736f6SSven Eckelmann 	if (bat_priv->tt.local_hash)
4915346c35eSSven Eckelmann 		return 0;
492c6c8fea2SSven Eckelmann 
493807736f6SSven Eckelmann 	bat_priv->tt.local_hash = batadv_hash_new(1024);
494c6c8fea2SSven Eckelmann 
495807736f6SSven Eckelmann 	if (!bat_priv->tt.local_hash)
4965346c35eSSven Eckelmann 		return -ENOMEM;
497c6c8fea2SSven Eckelmann 
498dec05074SAntonio Quartulli 	batadv_hash_set_lock_class(bat_priv->tt.local_hash,
499dec05074SAntonio Quartulli 				   &batadv_tt_local_hash_lock_class_key);
500dec05074SAntonio Quartulli 
5015346c35eSSven Eckelmann 	return 0;
502c6c8fea2SSven Eckelmann }
503c6c8fea2SSven Eckelmann 
504068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv,
505068ee6e2SAntonio Quartulli 				  struct batadv_tt_global_entry *tt_global,
506068ee6e2SAntonio Quartulli 				  const char *message)
507068ee6e2SAntonio Quartulli {
508068ee6e2SAntonio Quartulli 	batadv_dbg(BATADV_DBG_TT, bat_priv,
50916052789SAntonio Quartulli 		   "Deleting global tt entry %pM (vid: %d): %s\n",
51016052789SAntonio Quartulli 		   tt_global->common.addr,
51116052789SAntonio Quartulli 		   BATADV_PRINT_VID(tt_global->common.vid), message);
512068ee6e2SAntonio Quartulli 
513068ee6e2SAntonio Quartulli 	batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
514c018ad3dSAntonio Quartulli 			   batadv_choose_tt, &tt_global->common);
515068ee6e2SAntonio Quartulli 	batadv_tt_global_entry_free_ref(tt_global);
516068ee6e2SAntonio Quartulli }
517068ee6e2SAntonio Quartulli 
518c018ad3dSAntonio Quartulli /**
519c018ad3dSAntonio Quartulli  * batadv_tt_local_add - add a new client to the local table or update an
520c018ad3dSAntonio Quartulli  *  existing client
521c018ad3dSAntonio Quartulli  * @soft_iface: netdev struct of the mesh interface
522c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to add
523c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
524c018ad3dSAntonio Quartulli  * @ifindex: index of the interface where the client is connected to (useful to
525c018ad3dSAntonio Quartulli  *  identify wireless clients)
5269464d071SAntonio Quartulli  * @mark: the value contained in the skb->mark field of the received packet (if
5279464d071SAntonio Quartulli  *  any)
528a19d3d85SMarek Lindner  *
52962fe710fSSven Eckelmann  * Return: true if the client was successfully added, false otherwise.
530c018ad3dSAntonio Quartulli  */
5316b5e971aSSven Eckelmann bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
5326b5e971aSSven Eckelmann 			 unsigned short vid, int ifindex, u32 mark)
533c6c8fea2SSven Eckelmann {
53456303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
535170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
536c5caf4efSLinus Lüssing 	struct batadv_tt_global_entry *tt_global = NULL;
53735df3b29SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
5380c69aeccSAntonio Quartulli 	struct net_device *in_dev = NULL;
539db08e6e5SSimon Wunderlich 	struct hlist_head *head;
54056303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
541a19d3d85SMarek Lindner 	int hash_added, table_size, packet_size_max;
5424f248cffSSven Eckelmann 	bool ret = false;
5434f248cffSSven Eckelmann 	bool roamed_back = false;
5446b5e971aSSven Eckelmann 	u8 remote_flags;
5456b5e971aSSven Eckelmann 	u32 match_mark;
546c6c8fea2SSven Eckelmann 
5470c69aeccSAntonio Quartulli 	if (ifindex != BATADV_NULL_IFINDEX)
5480c69aeccSAntonio Quartulli 		in_dev = dev_get_by_index(&init_net, ifindex);
5490c69aeccSAntonio Quartulli 
550c018ad3dSAntonio Quartulli 	tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
551c5caf4efSLinus Lüssing 
552c5caf4efSLinus Lüssing 	if (!is_multicast_ether_addr(addr))
553c018ad3dSAntonio Quartulli 		tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
554c6c8fea2SSven Eckelmann 
55547c94655SAntonio Quartulli 	if (tt_local) {
55647c94655SAntonio Quartulli 		tt_local->last_seen = jiffies;
557068ee6e2SAntonio Quartulli 		if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
558068ee6e2SAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
55916052789SAntonio Quartulli 				   "Re-adding pending client %pM (vid: %d)\n",
56016052789SAntonio Quartulli 				   addr, BATADV_PRINT_VID(vid));
561068ee6e2SAntonio Quartulli 			/* whatever the reason why the PENDING flag was set,
562068ee6e2SAntonio Quartulli 			 * this is a client which was enqueued to be removed in
563068ee6e2SAntonio Quartulli 			 * this orig_interval. Since it popped up again, the
564068ee6e2SAntonio Quartulli 			 * flag can be reset like it was never enqueued
565068ee6e2SAntonio Quartulli 			 */
56647c94655SAntonio Quartulli 			tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
567068ee6e2SAntonio Quartulli 			goto add_event;
568068ee6e2SAntonio Quartulli 		}
569068ee6e2SAntonio Quartulli 
570068ee6e2SAntonio Quartulli 		if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
571068ee6e2SAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
57216052789SAntonio Quartulli 				   "Roaming client %pM (vid: %d) came back to its original location\n",
57316052789SAntonio Quartulli 				   addr, BATADV_PRINT_VID(vid));
574068ee6e2SAntonio Quartulli 			/* the ROAM flag is set because this client roamed away
575068ee6e2SAntonio Quartulli 			 * and the node got a roaming_advertisement message. Now
576068ee6e2SAntonio Quartulli 			 * that the client popped up again at its original
577068ee6e2SAntonio Quartulli 			 * location such flag can be unset
578068ee6e2SAntonio Quartulli 			 */
579068ee6e2SAntonio Quartulli 			tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
580068ee6e2SAntonio Quartulli 			roamed_back = true;
581068ee6e2SAntonio Quartulli 		}
582068ee6e2SAntonio Quartulli 		goto check_roaming;
583c6c8fea2SSven Eckelmann 	}
584c6c8fea2SSven Eckelmann 
585a19d3d85SMarek Lindner 	/* Ignore the client if we cannot send it in a full table response. */
586a19d3d85SMarek Lindner 	table_size = batadv_tt_local_table_transmit_size(bat_priv);
587a19d3d85SMarek Lindner 	table_size += batadv_tt_len(1);
588a19d3d85SMarek Lindner 	packet_size_max = atomic_read(&bat_priv->packet_size_max);
589a19d3d85SMarek Lindner 	if (table_size > packet_size_max) {
590a19d3d85SMarek Lindner 		net_ratelimited_function(batadv_info, soft_iface,
591a19d3d85SMarek Lindner 					 "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
592a19d3d85SMarek Lindner 					 table_size, packet_size_max, addr);
593a19d3d85SMarek Lindner 		goto out;
594a19d3d85SMarek Lindner 	}
595a19d3d85SMarek Lindner 
59647c94655SAntonio Quartulli 	tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
59747c94655SAntonio Quartulli 	if (!tt_local)
5987683fdc1SAntonio Quartulli 		goto out;
599a73105b8SAntonio Quartulli 
60035df3b29SAntonio Quartulli 	/* increase the refcounter of the related vlan */
60135df3b29SAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
602354136bcSMarek Lindner 	if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d",
603fd7dec25SSven Eckelmann 		 addr, BATADV_PRINT_VID(vid))) {
604fd7dec25SSven Eckelmann 		kfree(tt_local);
605fd7dec25SSven Eckelmann 		tt_local = NULL;
606354136bcSMarek Lindner 		goto out;
607fd7dec25SSven Eckelmann 	}
60835df3b29SAntonio Quartulli 
60939c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
61016052789SAntonio Quartulli 		   "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
61116052789SAntonio Quartulli 		   addr, BATADV_PRINT_VID(vid),
6126b5e971aSSven Eckelmann 		   (u8)atomic_read(&bat_priv->tt.vn));
613c6c8fea2SSven Eckelmann 
6148fdd0153SAntonio Quartulli 	ether_addr_copy(tt_local->common.addr, addr);
6158425ec6aSAntonio Quartulli 	/* The local entry has to be marked as NEW to avoid to send it in
6168425ec6aSAntonio Quartulli 	 * a full table response going out before the next ttvn increment
6178425ec6aSAntonio Quartulli 	 * (consistency check)
6188425ec6aSAntonio Quartulli 	 */
6198425ec6aSAntonio Quartulli 	tt_local->common.flags = BATADV_TT_CLIENT_NEW;
620c018ad3dSAntonio Quartulli 	tt_local->common.vid = vid;
6210c69aeccSAntonio Quartulli 	if (batadv_is_wifi_netdev(in_dev))
62247c94655SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
62347c94655SAntonio Quartulli 	atomic_set(&tt_local->common.refcount, 2);
62447c94655SAntonio Quartulli 	tt_local->last_seen = jiffies;
62547c94655SAntonio Quartulli 	tt_local->common.added_at = tt_local->last_seen;
626c6c8fea2SSven Eckelmann 
627c5caf4efSLinus Lüssing 	/* the batman interface mac and multicast addresses should never be
628c5caf4efSLinus Lüssing 	 * purged
629c5caf4efSLinus Lüssing 	 */
630c5caf4efSLinus Lüssing 	if (batadv_compare_eth(addr, soft_iface->dev_addr) ||
631c5caf4efSLinus Lüssing 	    is_multicast_ether_addr(addr))
63247c94655SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
633c6c8fea2SSven Eckelmann 
634807736f6SSven Eckelmann 	hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
635c018ad3dSAntonio Quartulli 				     batadv_choose_tt, &tt_local->common,
63647c94655SAntonio Quartulli 				     &tt_local->common.hash_entry);
63780b3f58cSSimon Wunderlich 
63880b3f58cSSimon Wunderlich 	if (unlikely(hash_added != 0)) {
63980b3f58cSSimon Wunderlich 		/* remove the reference for the hash */
64047c94655SAntonio Quartulli 		batadv_tt_local_entry_free_ref(tt_local);
64135df3b29SAntonio Quartulli 		batadv_softif_vlan_free_ref(vlan);
64280b3f58cSSimon Wunderlich 		goto out;
64380b3f58cSSimon Wunderlich 	}
64480b3f58cSSimon Wunderlich 
645068ee6e2SAntonio Quartulli add_event:
6463abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
647ff66c975SAntonio Quartulli 
648068ee6e2SAntonio Quartulli check_roaming:
649068ee6e2SAntonio Quartulli 	/* Check whether it is a roaming, but don't do anything if the roaming
650068ee6e2SAntonio Quartulli 	 * process has already been handled
651068ee6e2SAntonio Quartulli 	 */
652068ee6e2SAntonio Quartulli 	if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
653db08e6e5SSimon Wunderlich 		/* These node are probably going to update their tt table */
65447c94655SAntonio Quartulli 		head = &tt_global->orig_list;
655db08e6e5SSimon Wunderlich 		rcu_read_lock();
656b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(orig_entry, head, list) {
65747c94655SAntonio Quartulli 			batadv_send_roam_adv(bat_priv, tt_global->common.addr,
658c018ad3dSAntonio Quartulli 					     tt_global->common.vid,
659db08e6e5SSimon Wunderlich 					     orig_entry->orig_node);
660db08e6e5SSimon Wunderlich 		}
661db08e6e5SSimon Wunderlich 		rcu_read_unlock();
662068ee6e2SAntonio Quartulli 		if (roamed_back) {
663068ee6e2SAntonio Quartulli 			batadv_tt_global_free(bat_priv, tt_global,
664068ee6e2SAntonio Quartulli 					      "Roaming canceled");
665068ee6e2SAntonio Quartulli 			tt_global = NULL;
666068ee6e2SAntonio Quartulli 		} else {
667db08e6e5SSimon Wunderlich 			/* The global entry has to be marked as ROAMING and
668db08e6e5SSimon Wunderlich 			 * has to be kept for consistency purpose
669db08e6e5SSimon Wunderlich 			 */
67047c94655SAntonio Quartulli 			tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
67147c94655SAntonio Quartulli 			tt_global->roam_at = jiffies;
6727683fdc1SAntonio Quartulli 		}
673068ee6e2SAntonio Quartulli 	}
674068ee6e2SAntonio Quartulli 
6753c4f7ab6SAntonio Quartulli 	/* store the current remote flags before altering them. This helps
6763c4f7ab6SAntonio Quartulli 	 * understanding is flags are changing or not
6773c4f7ab6SAntonio Quartulli 	 */
6783c4f7ab6SAntonio Quartulli 	remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
679a19d3d85SMarek Lindner 
6803c4f7ab6SAntonio Quartulli 	if (batadv_is_wifi_netdev(in_dev))
6813c4f7ab6SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
6823c4f7ab6SAntonio Quartulli 	else
6833c4f7ab6SAntonio Quartulli 		tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
6843c4f7ab6SAntonio Quartulli 
6859464d071SAntonio Quartulli 	/* check the mark in the skb: if it's equal to the configured
6869464d071SAntonio Quartulli 	 * isolation_mark, it means the packet is coming from an isolated
6879464d071SAntonio Quartulli 	 * non-mesh client
6889464d071SAntonio Quartulli 	 */
6899464d071SAntonio Quartulli 	match_mark = (mark & bat_priv->isolation_mark_mask);
6909464d071SAntonio Quartulli 	if (bat_priv->isolation_mark_mask &&
6919464d071SAntonio Quartulli 	    match_mark == bat_priv->isolation_mark)
6929464d071SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
6939464d071SAntonio Quartulli 	else
6949464d071SAntonio Quartulli 		tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
6959464d071SAntonio Quartulli 
6963c4f7ab6SAntonio Quartulli 	/* if any "dynamic" flag has been modified, resend an ADD event for this
6973c4f7ab6SAntonio Quartulli 	 * entry so that all the nodes can get the new flags
6983c4f7ab6SAntonio Quartulli 	 */
6993c4f7ab6SAntonio Quartulli 	if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
7003c4f7ab6SAntonio Quartulli 		batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
7013c4f7ab6SAntonio Quartulli 
7023c4f7ab6SAntonio Quartulli 	ret = true;
7037683fdc1SAntonio Quartulli out:
7040c69aeccSAntonio Quartulli 	if (in_dev)
7050c69aeccSAntonio Quartulli 		dev_put(in_dev);
70647c94655SAntonio Quartulli 	if (tt_local)
70747c94655SAntonio Quartulli 		batadv_tt_local_entry_free_ref(tt_local);
70847c94655SAntonio Quartulli 	if (tt_global)
70947c94655SAntonio Quartulli 		batadv_tt_global_entry_free_ref(tt_global);
710a19d3d85SMarek Lindner 	return ret;
711c6c8fea2SSven Eckelmann }
712c6c8fea2SSven Eckelmann 
713e1bf0c14SMarek Lindner /**
7147ea7b4a1SAntonio Quartulli  * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send
7157ea7b4a1SAntonio Quartulli  *  within a TT Response directed to another node
7167ea7b4a1SAntonio Quartulli  * @orig_node: originator for which the TT data has to be prepared
7177ea7b4a1SAntonio Quartulli  * @tt_data: uninitialised pointer to the address of the TVLV buffer
7187ea7b4a1SAntonio Quartulli  * @tt_change: uninitialised pointer to the address of the area where the TT
7197ea7b4a1SAntonio Quartulli  *  changed can be stored
7207ea7b4a1SAntonio Quartulli  * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
7217ea7b4a1SAntonio Quartulli  *  function reserves the amount of space needed to send the entire global TT
7227ea7b4a1SAntonio Quartulli  *  table. In case of success the value is updated with the real amount of
7237ea7b4a1SAntonio Quartulli  *  reserved bytes
7247ea7b4a1SAntonio Quartulli 
7257ea7b4a1SAntonio Quartulli  * Allocate the needed amount of memory for the entire TT TVLV and write its
7267ea7b4a1SAntonio Quartulli  * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
7277ea7b4a1SAntonio Quartulli  * objects, one per active VLAN served by the originator node.
7287ea7b4a1SAntonio Quartulli  *
72962fe710fSSven Eckelmann  * Return: the size of the allocated buffer or 0 in case of failure.
7307ea7b4a1SAntonio Quartulli  */
7316b5e971aSSven Eckelmann static u16
7327ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
7337ea7b4a1SAntonio Quartulli 				   struct batadv_tvlv_tt_data **tt_data,
7347ea7b4a1SAntonio Quartulli 				   struct batadv_tvlv_tt_change **tt_change,
7356b5e971aSSven Eckelmann 				   s32 *tt_len)
7367ea7b4a1SAntonio Quartulli {
7374f248cffSSven Eckelmann 	u16 num_vlan = 0;
7384f248cffSSven Eckelmann 	u16 num_entries = 0;
7394f248cffSSven Eckelmann 	u16 change_offset;
7404f248cffSSven Eckelmann 	u16 tvlv_len;
7417ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
7427ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
7436b5e971aSSven Eckelmann 	u8 *tt_change_ptr;
7447ea7b4a1SAntonio Quartulli 
7457ea7b4a1SAntonio Quartulli 	rcu_read_lock();
746d0fa4f3fSMarek Lindner 	hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
7477ea7b4a1SAntonio Quartulli 		num_vlan++;
7487ea7b4a1SAntonio Quartulli 		num_entries += atomic_read(&vlan->tt.num_entries);
7497ea7b4a1SAntonio Quartulli 	}
7507ea7b4a1SAntonio Quartulli 
7517ea7b4a1SAntonio Quartulli 	change_offset = sizeof(**tt_data);
7527ea7b4a1SAntonio Quartulli 	change_offset += num_vlan * sizeof(*tt_vlan);
7537ea7b4a1SAntonio Quartulli 
7547ea7b4a1SAntonio Quartulli 	/* if tt_len is negative, allocate the space needed by the full table */
7557ea7b4a1SAntonio Quartulli 	if (*tt_len < 0)
7567ea7b4a1SAntonio Quartulli 		*tt_len = batadv_tt_len(num_entries);
7577ea7b4a1SAntonio Quartulli 
7587ea7b4a1SAntonio Quartulli 	tvlv_len = *tt_len;
7597ea7b4a1SAntonio Quartulli 	tvlv_len += change_offset;
7607ea7b4a1SAntonio Quartulli 
7617ea7b4a1SAntonio Quartulli 	*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
7627ea7b4a1SAntonio Quartulli 	if (!*tt_data) {
7637ea7b4a1SAntonio Quartulli 		*tt_len = 0;
7647ea7b4a1SAntonio Quartulli 		goto out;
7657ea7b4a1SAntonio Quartulli 	}
7667ea7b4a1SAntonio Quartulli 
7677ea7b4a1SAntonio Quartulli 	(*tt_data)->flags = BATADV_NO_FLAGS;
7687ea7b4a1SAntonio Quartulli 	(*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn);
7697ea7b4a1SAntonio Quartulli 	(*tt_data)->num_vlan = htons(num_vlan);
7707ea7b4a1SAntonio Quartulli 
7717ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
772d0fa4f3fSMarek Lindner 	hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
7737ea7b4a1SAntonio Quartulli 		tt_vlan->vid = htons(vlan->vid);
7747ea7b4a1SAntonio Quartulli 		tt_vlan->crc = htonl(vlan->tt.crc);
7757ea7b4a1SAntonio Quartulli 
7767ea7b4a1SAntonio Quartulli 		tt_vlan++;
7777ea7b4a1SAntonio Quartulli 	}
7787ea7b4a1SAntonio Quartulli 
7796b5e971aSSven Eckelmann 	tt_change_ptr = (u8 *)*tt_data + change_offset;
7807ea7b4a1SAntonio Quartulli 	*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
7817ea7b4a1SAntonio Quartulli 
7827ea7b4a1SAntonio Quartulli out:
7837ea7b4a1SAntonio Quartulli 	rcu_read_unlock();
7847ea7b4a1SAntonio Quartulli 	return tvlv_len;
7857ea7b4a1SAntonio Quartulli }
7867ea7b4a1SAntonio Quartulli 
7877ea7b4a1SAntonio Quartulli /**
7887ea7b4a1SAntonio Quartulli  * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this
7897ea7b4a1SAntonio Quartulli  *  node
7907ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
7917ea7b4a1SAntonio Quartulli  * @tt_data: uninitialised pointer to the address of the TVLV buffer
7927ea7b4a1SAntonio Quartulli  * @tt_change: uninitialised pointer to the address of the area where the TT
7937ea7b4a1SAntonio Quartulli  *  changes can be stored
7947ea7b4a1SAntonio Quartulli  * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
7957ea7b4a1SAntonio Quartulli  *  function reserves the amount of space needed to send the entire local TT
7967ea7b4a1SAntonio Quartulli  *  table. In case of success the value is updated with the real amount of
7977ea7b4a1SAntonio Quartulli  *  reserved bytes
7987ea7b4a1SAntonio Quartulli  *
7997ea7b4a1SAntonio Quartulli  * Allocate the needed amount of memory for the entire TT TVLV and write its
8007ea7b4a1SAntonio Quartulli  * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
8017ea7b4a1SAntonio Quartulli  * objects, one per active VLAN.
8027ea7b4a1SAntonio Quartulli  *
80362fe710fSSven Eckelmann  * Return: the size of the allocated buffer or 0 in case of failure.
8047ea7b4a1SAntonio Quartulli  */
8056b5e971aSSven Eckelmann static u16
8067ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
8077ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_data **tt_data,
8087ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_change **tt_change,
8096b5e971aSSven Eckelmann 				  s32 *tt_len)
8107ea7b4a1SAntonio Quartulli {
8117ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
8127ea7b4a1SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
8134f248cffSSven Eckelmann 	u16 num_vlan = 0;
8144f248cffSSven Eckelmann 	u16 num_entries = 0;
8154f248cffSSven Eckelmann 	u16 tvlv_len;
8166b5e971aSSven Eckelmann 	u8 *tt_change_ptr;
8177ea7b4a1SAntonio Quartulli 	int change_offset;
8187ea7b4a1SAntonio Quartulli 
8197ea7b4a1SAntonio Quartulli 	rcu_read_lock();
8207ea7b4a1SAntonio Quartulli 	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
8217ea7b4a1SAntonio Quartulli 		num_vlan++;
8227ea7b4a1SAntonio Quartulli 		num_entries += atomic_read(&vlan->tt.num_entries);
8237ea7b4a1SAntonio Quartulli 	}
8247ea7b4a1SAntonio Quartulli 
8257ea7b4a1SAntonio Quartulli 	change_offset = sizeof(**tt_data);
8267ea7b4a1SAntonio Quartulli 	change_offset += num_vlan * sizeof(*tt_vlan);
8277ea7b4a1SAntonio Quartulli 
8287ea7b4a1SAntonio Quartulli 	/* if tt_len is negative, allocate the space needed by the full table */
8297ea7b4a1SAntonio Quartulli 	if (*tt_len < 0)
8307ea7b4a1SAntonio Quartulli 		*tt_len = batadv_tt_len(num_entries);
8317ea7b4a1SAntonio Quartulli 
8327ea7b4a1SAntonio Quartulli 	tvlv_len = *tt_len;
8337ea7b4a1SAntonio Quartulli 	tvlv_len += change_offset;
8347ea7b4a1SAntonio Quartulli 
8357ea7b4a1SAntonio Quartulli 	*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
8367ea7b4a1SAntonio Quartulli 	if (!*tt_data) {
8377ea7b4a1SAntonio Quartulli 		tvlv_len = 0;
8387ea7b4a1SAntonio Quartulli 		goto out;
8397ea7b4a1SAntonio Quartulli 	}
8407ea7b4a1SAntonio Quartulli 
8417ea7b4a1SAntonio Quartulli 	(*tt_data)->flags = BATADV_NO_FLAGS;
8427ea7b4a1SAntonio Quartulli 	(*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn);
8437ea7b4a1SAntonio Quartulli 	(*tt_data)->num_vlan = htons(num_vlan);
8447ea7b4a1SAntonio Quartulli 
8457ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
8467ea7b4a1SAntonio Quartulli 	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
8477ea7b4a1SAntonio Quartulli 		tt_vlan->vid = htons(vlan->vid);
8487ea7b4a1SAntonio Quartulli 		tt_vlan->crc = htonl(vlan->tt.crc);
8497ea7b4a1SAntonio Quartulli 
8507ea7b4a1SAntonio Quartulli 		tt_vlan++;
8517ea7b4a1SAntonio Quartulli 	}
8527ea7b4a1SAntonio Quartulli 
8536b5e971aSSven Eckelmann 	tt_change_ptr = (u8 *)*tt_data + change_offset;
8547ea7b4a1SAntonio Quartulli 	*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
8557ea7b4a1SAntonio Quartulli 
8567ea7b4a1SAntonio Quartulli out:
8577ea7b4a1SAntonio Quartulli 	rcu_read_unlock();
8587ea7b4a1SAntonio Quartulli 	return tvlv_len;
8597ea7b4a1SAntonio Quartulli }
8607ea7b4a1SAntonio Quartulli 
8617ea7b4a1SAntonio Quartulli /**
862e1bf0c14SMarek Lindner  * batadv_tt_tvlv_container_update - update the translation table tvlv container
863e1bf0c14SMarek Lindner  *  after local tt changes have been committed
864e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
865e1bf0c14SMarek Lindner  */
866e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
867c6c8fea2SSven Eckelmann {
868e1bf0c14SMarek Lindner 	struct batadv_tt_change_node *entry, *safe;
869e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
870e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
8717ea7b4a1SAntonio Quartulli 	int tt_diff_len, tt_change_len = 0;
8724f248cffSSven Eckelmann 	int tt_diff_entries_num = 0;
8734f248cffSSven Eckelmann 	int tt_diff_entries_count = 0;
8746b5e971aSSven Eckelmann 	u16 tvlv_len;
875c6c8fea2SSven Eckelmann 
8767ea7b4a1SAntonio Quartulli 	tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes);
8777ea7b4a1SAntonio Quartulli 	tt_diff_len = batadv_tt_len(tt_diff_entries_num);
878be9aa4c1SMarek Lindner 
879be9aa4c1SMarek Lindner 	/* if we have too many changes for one packet don't send any
880be9aa4c1SMarek Lindner 	 * and wait for the tt table request which will be fragmented
881be9aa4c1SMarek Lindner 	 */
882e1bf0c14SMarek Lindner 	if (tt_diff_len > bat_priv->soft_iface->mtu)
883e1bf0c14SMarek Lindner 		tt_diff_len = 0;
884be9aa4c1SMarek Lindner 
8857ea7b4a1SAntonio Quartulli 	tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
8867ea7b4a1SAntonio Quartulli 						     &tt_change, &tt_diff_len);
8877ea7b4a1SAntonio Quartulli 	if (!tvlv_len)
888e1bf0c14SMarek Lindner 		return;
889be9aa4c1SMarek Lindner 
890e1bf0c14SMarek Lindner 	tt_data->flags = BATADV_TT_OGM_DIFF;
891be9aa4c1SMarek Lindner 
892e1bf0c14SMarek Lindner 	if (tt_diff_len == 0)
893e1bf0c14SMarek Lindner 		goto container_register;
894be9aa4c1SMarek Lindner 
895807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
896807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.local_changes, 0);
897c6c8fea2SSven Eckelmann 
898807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
899a73105b8SAntonio Quartulli 				 list) {
900e1bf0c14SMarek Lindner 		if (tt_diff_entries_count < tt_diff_entries_num) {
901e1bf0c14SMarek Lindner 			memcpy(tt_change + tt_diff_entries_count,
902e1bf0c14SMarek Lindner 			       &entry->change,
903e1bf0c14SMarek Lindner 			       sizeof(struct batadv_tvlv_tt_change));
904e1bf0c14SMarek Lindner 			tt_diff_entries_count++;
905c6c8fea2SSven Eckelmann 		}
906a73105b8SAntonio Quartulli 		list_del(&entry->list);
907a73105b8SAntonio Quartulli 		kfree(entry);
908c6c8fea2SSven Eckelmann 	}
909807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
910c6c8fea2SSven Eckelmann 
911a73105b8SAntonio Quartulli 	/* Keep the buffer for possible tt_request */
912807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.last_changeset_lock);
913807736f6SSven Eckelmann 	kfree(bat_priv->tt.last_changeset);
914807736f6SSven Eckelmann 	bat_priv->tt.last_changeset_len = 0;
915807736f6SSven Eckelmann 	bat_priv->tt.last_changeset = NULL;
916e1bf0c14SMarek Lindner 	tt_change_len = batadv_tt_len(tt_diff_entries_count);
917be9aa4c1SMarek Lindner 	/* check whether this new OGM has no changes due to size problems */
918e1bf0c14SMarek Lindner 	if (tt_diff_entries_count > 0) {
919be9aa4c1SMarek Lindner 		/* if kmalloc() fails we will reply with the full table
920a73105b8SAntonio Quartulli 		 * instead of providing the diff
921a73105b8SAntonio Quartulli 		 */
922e1bf0c14SMarek Lindner 		bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC);
923807736f6SSven Eckelmann 		if (bat_priv->tt.last_changeset) {
924e1bf0c14SMarek Lindner 			memcpy(bat_priv->tt.last_changeset,
925e1bf0c14SMarek Lindner 			       tt_change, tt_change_len);
926e1bf0c14SMarek Lindner 			bat_priv->tt.last_changeset_len = tt_diff_len;
927a73105b8SAntonio Quartulli 		}
928a73105b8SAntonio Quartulli 	}
929807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
930c6c8fea2SSven Eckelmann 
931e1bf0c14SMarek Lindner container_register:
932e1bf0c14SMarek Lindner 	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
9337ea7b4a1SAntonio Quartulli 				       tvlv_len);
934e1bf0c14SMarek Lindner 	kfree(tt_data);
935c6c8fea2SSven Eckelmann }
936c6c8fea2SSven Eckelmann 
93708c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
938c6c8fea2SSven Eckelmann {
939c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
94056303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(net_dev);
941807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
94256303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
94385766a82SAntonio Quartulli 	struct batadv_tt_local_entry *tt_local;
94456303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if;
9457ea7b4a1SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
946c6c8fea2SSven Eckelmann 	struct hlist_head *head;
9477ea7b4a1SAntonio Quartulli 	unsigned short vid;
9486b5e971aSSven Eckelmann 	u32 i;
94985766a82SAntonio Quartulli 	int last_seen_secs;
95085766a82SAntonio Quartulli 	int last_seen_msecs;
95185766a82SAntonio Quartulli 	unsigned long last_seen_jiffies;
95285766a82SAntonio Quartulli 	bool no_purge;
9536b5e971aSSven Eckelmann 	u16 np_flag = BATADV_TT_CLIENT_NOPURGE;
954c6c8fea2SSven Eckelmann 
95530da63a6SMarek Lindner 	primary_if = batadv_seq_print_text_primary_if_get(seq);
95630da63a6SMarek Lindner 	if (!primary_if)
95732ae9b22SMarek Lindner 		goto out;
958c6c8fea2SSven Eckelmann 
95986ceb360SSven Eckelmann 	seq_printf(seq,
9607ea7b4a1SAntonio Quartulli 		   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
9616b5e971aSSven Eckelmann 		   net_dev->name, (u8)atomic_read(&bat_priv->tt.vn));
962dd24ddb2SAntonio Quartulli 	seq_printf(seq, "       %-13s  %s %-8s %-9s (%-10s)\n", "Client", "VID",
9637ea7b4a1SAntonio Quartulli 		   "Flags", "Last seen", "CRC");
964c6c8fea2SSven Eckelmann 
965c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
966c6c8fea2SSven Eckelmann 		head = &hash->table[i];
967c6c8fea2SSven Eckelmann 
9687aadf889SMarek Lindner 		rcu_read_lock();
969b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
9707aadf889SMarek Lindner 					 head, hash_entry) {
97185766a82SAntonio Quartulli 			tt_local = container_of(tt_common_entry,
97285766a82SAntonio Quartulli 						struct batadv_tt_local_entry,
97385766a82SAntonio Quartulli 						common);
9747ea7b4a1SAntonio Quartulli 			vid = tt_common_entry->vid;
97585766a82SAntonio Quartulli 			last_seen_jiffies = jiffies - tt_local->last_seen;
97685766a82SAntonio Quartulli 			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
97785766a82SAntonio Quartulli 			last_seen_secs = last_seen_msecs / 1000;
97885766a82SAntonio Quartulli 			last_seen_msecs = last_seen_msecs % 1000;
97985766a82SAntonio Quartulli 
98085766a82SAntonio Quartulli 			no_purge = tt_common_entry->flags & np_flag;
98185766a82SAntonio Quartulli 
9827ea7b4a1SAntonio Quartulli 			vlan = batadv_softif_vlan_get(bat_priv, vid);
9837ea7b4a1SAntonio Quartulli 			if (!vlan) {
9847ea7b4a1SAntonio Quartulli 				seq_printf(seq, "Cannot retrieve VLAN %d\n",
9857ea7b4a1SAntonio Quartulli 					   BATADV_PRINT_VID(vid));
9867ea7b4a1SAntonio Quartulli 				continue;
9877ea7b4a1SAntonio Quartulli 			}
9887ea7b4a1SAntonio Quartulli 
9897ea7b4a1SAntonio Quartulli 			seq_printf(seq,
990dd24ddb2SAntonio Quartulli 				   " * %pM %4i [%c%c%c%c%c%c] %3u.%03u   (%#.8x)\n",
99148100bacSAntonio Quartulli 				   tt_common_entry->addr,
99216052789SAntonio Quartulli 				   BATADV_PRINT_VID(tt_common_entry->vid),
993a2f2b6cdSSven Eckelmann 				   ((tt_common_entry->flags &
994a2f2b6cdSSven Eckelmann 				     BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
99585766a82SAntonio Quartulli 				   no_purge ? 'P' : '.',
996a2f2b6cdSSven Eckelmann 				   ((tt_common_entry->flags &
997a2f2b6cdSSven Eckelmann 				     BATADV_TT_CLIENT_NEW) ? 'N' : '.'),
998a2f2b6cdSSven Eckelmann 				   ((tt_common_entry->flags &
999a2f2b6cdSSven Eckelmann 				     BATADV_TT_CLIENT_PENDING) ? 'X' : '.'),
1000a2f2b6cdSSven Eckelmann 				   ((tt_common_entry->flags &
1001a2f2b6cdSSven Eckelmann 				     BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
1002a2f2b6cdSSven Eckelmann 				   ((tt_common_entry->flags &
1003a2f2b6cdSSven Eckelmann 				     BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
1004a7966d90SAntonio Quartulli 				   no_purge ? 0 : last_seen_secs,
10057ea7b4a1SAntonio Quartulli 				   no_purge ? 0 : last_seen_msecs,
10067ea7b4a1SAntonio Quartulli 				   vlan->tt.crc);
10077ea7b4a1SAntonio Quartulli 
10087ea7b4a1SAntonio Quartulli 			batadv_softif_vlan_free_ref(vlan);
1009c6c8fea2SSven Eckelmann 		}
10107aadf889SMarek Lindner 		rcu_read_unlock();
1011c6c8fea2SSven Eckelmann 	}
101232ae9b22SMarek Lindner out:
101332ae9b22SMarek Lindner 	if (primary_if)
1014e5d89254SSven Eckelmann 		batadv_hardif_free_ref(primary_if);
101530da63a6SMarek Lindner 	return 0;
1016c6c8fea2SSven Eckelmann }
1017c6c8fea2SSven Eckelmann 
101856303d34SSven Eckelmann static void
101956303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
102056303d34SSven Eckelmann 			    struct batadv_tt_local_entry *tt_local_entry,
10216b5e971aSSven Eckelmann 			    u16 flags, const char *message)
1022c6c8fea2SSven Eckelmann {
10233abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local_entry, flags);
1024c6c8fea2SSven Eckelmann 
1025015758d0SAntonio Quartulli 	/* The local client has to be marked as "pending to be removed" but has
1026015758d0SAntonio Quartulli 	 * to be kept in the table in order to send it in a full table
10279cfc7bd6SSven Eckelmann 	 * response issued before the net ttvn increment (consistency check)
10289cfc7bd6SSven Eckelmann 	 */
1029acd34afaSSven Eckelmann 	tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
1030c566dbbeSAntonio Quartulli 
103139c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
103216052789SAntonio Quartulli 		   "Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
103316052789SAntonio Quartulli 		   tt_local_entry->common.addr,
103416052789SAntonio Quartulli 		   BATADV_PRINT_VID(tt_local_entry->common.vid), message);
1035c6c8fea2SSven Eckelmann }
1036c6c8fea2SSven Eckelmann 
10377f91d06cSAntonio Quartulli /**
10387f91d06cSAntonio Quartulli  * batadv_tt_local_remove - logically remove an entry from the local table
10397f91d06cSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
10407f91d06cSAntonio Quartulli  * @addr: the MAC address of the client to remove
1041c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
10427f91d06cSAntonio Quartulli  * @message: message to append to the log on deletion
10437f91d06cSAntonio Quartulli  * @roaming: true if the deletion is due to a roaming event
10447f91d06cSAntonio Quartulli  *
104562fe710fSSven Eckelmann  * Return: the flags assigned to the local entry before being deleted
10467f91d06cSAntonio Quartulli  */
10476b5e971aSSven Eckelmann u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
10486b5e971aSSven Eckelmann 			   unsigned short vid, const char *message,
10496b5e971aSSven Eckelmann 			   bool roaming)
1050c6c8fea2SSven Eckelmann {
1051170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
10526b5e971aSSven Eckelmann 	u16 flags, curr_flags = BATADV_NO_FLAGS;
105335df3b29SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
1054ef72706aSMarek Lindner 	void *tt_entry_exists;
1055c6c8fea2SSven Eckelmann 
1056c018ad3dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
10577683fdc1SAntonio Quartulli 	if (!tt_local_entry)
10587683fdc1SAntonio Quartulli 		goto out;
10597683fdc1SAntonio Quartulli 
10607f91d06cSAntonio Quartulli 	curr_flags = tt_local_entry->common.flags;
10617f91d06cSAntonio Quartulli 
1062acd34afaSSven Eckelmann 	flags = BATADV_TT_CLIENT_DEL;
1063068ee6e2SAntonio Quartulli 	/* if this global entry addition is due to a roaming, the node has to
1064068ee6e2SAntonio Quartulli 	 * mark the local entry as "roamed" in order to correctly reroute
1065068ee6e2SAntonio Quartulli 	 * packets later
1066068ee6e2SAntonio Quartulli 	 */
10677c1fd91dSAntonio Quartulli 	if (roaming) {
1068acd34afaSSven Eckelmann 		flags |= BATADV_TT_CLIENT_ROAM;
10697c1fd91dSAntonio Quartulli 		/* mark the local client as ROAMed */
10707c1fd91dSAntonio Quartulli 		tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
10717c1fd91dSAntonio Quartulli 	}
107242d0b044SSven Eckelmann 
1073068ee6e2SAntonio Quartulli 	if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
1074068ee6e2SAntonio Quartulli 		batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
1075068ee6e2SAntonio Quartulli 					    message);
1076068ee6e2SAntonio Quartulli 		goto out;
1077068ee6e2SAntonio Quartulli 	}
1078068ee6e2SAntonio Quartulli 	/* if this client has been added right now, it is possible to
1079068ee6e2SAntonio Quartulli 	 * immediately purge it
1080068ee6e2SAntonio Quartulli 	 */
10813abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
1082ef72706aSMarek Lindner 
1083ef72706aSMarek Lindner 	tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash,
1084ef72706aSMarek Lindner 					     batadv_compare_tt,
1085ef72706aSMarek Lindner 					     batadv_choose_tt,
1086ef72706aSMarek Lindner 					     &tt_local_entry->common);
1087ef72706aSMarek Lindner 	if (!tt_entry_exists)
1088ef72706aSMarek Lindner 		goto out;
1089ef72706aSMarek Lindner 
1090ef72706aSMarek Lindner 	/* extra call to free the local tt entry */
1091068ee6e2SAntonio Quartulli 	batadv_tt_local_entry_free_ref(tt_local_entry);
10927f91d06cSAntonio Quartulli 
109335df3b29SAntonio Quartulli 	/* decrease the reference held for this vlan */
109435df3b29SAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
1095354136bcSMarek Lindner 	if (!vlan)
1096354136bcSMarek Lindner 		goto out;
1097354136bcSMarek Lindner 
109835df3b29SAntonio Quartulli 	batadv_softif_vlan_free_ref(vlan);
109935df3b29SAntonio Quartulli 	batadv_softif_vlan_free_ref(vlan);
110035df3b29SAntonio Quartulli 
11017683fdc1SAntonio Quartulli out:
11027683fdc1SAntonio Quartulli 	if (tt_local_entry)
1103a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(tt_local_entry);
11047f91d06cSAntonio Quartulli 
11057f91d06cSAntonio Quartulli 	return curr_flags;
1106c6c8fea2SSven Eckelmann }
1107c6c8fea2SSven Eckelmann 
1108a19d3d85SMarek Lindner /**
1109a19d3d85SMarek Lindner  * batadv_tt_local_purge_list - purge inactive tt local entries
1110a19d3d85SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
1111a19d3d85SMarek Lindner  * @head: pointer to the list containing the local tt entries
1112a19d3d85SMarek Lindner  * @timeout: parameter deciding whether a given tt local entry is considered
1113a19d3d85SMarek Lindner  *  inactive or not
1114a19d3d85SMarek Lindner  */
111556303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
1116a19d3d85SMarek Lindner 				       struct hlist_head *head,
1117a19d3d85SMarek Lindner 				       int timeout)
1118c6c8fea2SSven Eckelmann {
111956303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
112056303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
1121b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
1122acd34afaSSven Eckelmann 
1123b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
1124acd34afaSSven Eckelmann 				  hash_entry) {
1125acd34afaSSven Eckelmann 		tt_local_entry = container_of(tt_common_entry,
112656303d34SSven Eckelmann 					      struct batadv_tt_local_entry,
112756303d34SSven Eckelmann 					      common);
1128acd34afaSSven Eckelmann 		if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
1129acd34afaSSven Eckelmann 			continue;
1130acd34afaSSven Eckelmann 
1131acd34afaSSven Eckelmann 		/* entry already marked for deletion */
1132acd34afaSSven Eckelmann 		if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
1133acd34afaSSven Eckelmann 			continue;
1134acd34afaSSven Eckelmann 
1135a19d3d85SMarek Lindner 		if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
1136acd34afaSSven Eckelmann 			continue;
1137acd34afaSSven Eckelmann 
1138acd34afaSSven Eckelmann 		batadv_tt_local_set_pending(bat_priv, tt_local_entry,
1139acd34afaSSven Eckelmann 					    BATADV_TT_CLIENT_DEL, "timed out");
1140acd34afaSSven Eckelmann 	}
1141acd34afaSSven Eckelmann }
1142acd34afaSSven Eckelmann 
1143a19d3d85SMarek Lindner /**
1144a19d3d85SMarek Lindner  * batadv_tt_local_purge - purge inactive tt local entries
1145a19d3d85SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
1146a19d3d85SMarek Lindner  * @timeout: parameter deciding whether a given tt local entry is considered
1147a19d3d85SMarek Lindner  *  inactive or not
1148a19d3d85SMarek Lindner  */
1149a19d3d85SMarek Lindner static void batadv_tt_local_purge(struct batadv_priv *bat_priv,
1150a19d3d85SMarek Lindner 				  int timeout)
1151acd34afaSSven Eckelmann {
1152807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
1153c6c8fea2SSven Eckelmann 	struct hlist_head *head;
11547683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
11556b5e971aSSven Eckelmann 	u32 i;
1156c6c8fea2SSven Eckelmann 
1157c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
1158c6c8fea2SSven Eckelmann 		head = &hash->table[i];
11597683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
1160c6c8fea2SSven Eckelmann 
11617683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
1162a19d3d85SMarek Lindner 		batadv_tt_local_purge_list(bat_priv, head, timeout);
11637683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
1164c6c8fea2SSven Eckelmann 	}
1165c6c8fea2SSven Eckelmann }
1166c6c8fea2SSven Eckelmann 
116756303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
1168c6c8fea2SSven Eckelmann {
11695bf74e9cSSven Eckelmann 	struct batadv_hashtable *hash;
1170a73105b8SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
117156303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
117256303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
117335df3b29SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
1174b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
11757683fdc1SAntonio Quartulli 	struct hlist_head *head;
11766b5e971aSSven Eckelmann 	u32 i;
1177a73105b8SAntonio Quartulli 
1178807736f6SSven Eckelmann 	if (!bat_priv->tt.local_hash)
1179c6c8fea2SSven Eckelmann 		return;
1180c6c8fea2SSven Eckelmann 
1181807736f6SSven Eckelmann 	hash = bat_priv->tt.local_hash;
1182a73105b8SAntonio Quartulli 
1183a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1184a73105b8SAntonio Quartulli 		head = &hash->table[i];
1185a73105b8SAntonio Quartulli 		list_lock = &hash->list_locks[i];
1186a73105b8SAntonio Quartulli 
1187a73105b8SAntonio Quartulli 		spin_lock_bh(list_lock);
1188b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, node_tmp,
1189a73105b8SAntonio Quartulli 					  head, hash_entry) {
1190b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common_entry->hash_entry);
119156303d34SSven Eckelmann 			tt_local = container_of(tt_common_entry,
119256303d34SSven Eckelmann 						struct batadv_tt_local_entry,
119348100bacSAntonio Quartulli 						common);
119435df3b29SAntonio Quartulli 
119535df3b29SAntonio Quartulli 			/* decrease the reference held for this vlan */
119635df3b29SAntonio Quartulli 			vlan = batadv_softif_vlan_get(bat_priv,
119735df3b29SAntonio Quartulli 						      tt_common_entry->vid);
1198354136bcSMarek Lindner 			if (vlan) {
119935df3b29SAntonio Quartulli 				batadv_softif_vlan_free_ref(vlan);
120035df3b29SAntonio Quartulli 				batadv_softif_vlan_free_ref(vlan);
1201354136bcSMarek Lindner 			}
120235df3b29SAntonio Quartulli 
120356303d34SSven Eckelmann 			batadv_tt_local_entry_free_ref(tt_local);
1204a73105b8SAntonio Quartulli 		}
1205a73105b8SAntonio Quartulli 		spin_unlock_bh(list_lock);
1206a73105b8SAntonio Quartulli 	}
1207a73105b8SAntonio Quartulli 
12081a8eaf07SSven Eckelmann 	batadv_hash_destroy(hash);
1209a73105b8SAntonio Quartulli 
1210807736f6SSven Eckelmann 	bat_priv->tt.local_hash = NULL;
1211c6c8fea2SSven Eckelmann }
1212c6c8fea2SSven Eckelmann 
121356303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv)
1214c6c8fea2SSven Eckelmann {
1215807736f6SSven Eckelmann 	if (bat_priv->tt.global_hash)
12165346c35eSSven Eckelmann 		return 0;
1217c6c8fea2SSven Eckelmann 
1218807736f6SSven Eckelmann 	bat_priv->tt.global_hash = batadv_hash_new(1024);
1219c6c8fea2SSven Eckelmann 
1220807736f6SSven Eckelmann 	if (!bat_priv->tt.global_hash)
12215346c35eSSven Eckelmann 		return -ENOMEM;
1222c6c8fea2SSven Eckelmann 
1223dec05074SAntonio Quartulli 	batadv_hash_set_lock_class(bat_priv->tt.global_hash,
1224dec05074SAntonio Quartulli 				   &batadv_tt_global_hash_lock_class_key);
1225dec05074SAntonio Quartulli 
12265346c35eSSven Eckelmann 	return 0;
1227c6c8fea2SSven Eckelmann }
1228c6c8fea2SSven Eckelmann 
122956303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
1230a73105b8SAntonio Quartulli {
123156303d34SSven Eckelmann 	struct batadv_tt_change_node *entry, *safe;
1232a73105b8SAntonio Quartulli 
1233807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
1234a73105b8SAntonio Quartulli 
1235807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
1236a73105b8SAntonio Quartulli 				 list) {
1237a73105b8SAntonio Quartulli 		list_del(&entry->list);
1238a73105b8SAntonio Quartulli 		kfree(entry);
1239a73105b8SAntonio Quartulli 	}
1240a73105b8SAntonio Quartulli 
1241807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.local_changes, 0);
1242807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
1243a73105b8SAntonio Quartulli }
1244a73105b8SAntonio Quartulli 
124562fe710fSSven Eckelmann /**
124662fe710fSSven Eckelmann  * batadv_tt_global_orig_entry_find
124762fe710fSSven Eckelmann  *
124862fe710fSSven Eckelmann  * retrieves the orig_tt_list_entry belonging to orig_node from the
1249d657e621SAntonio Quartulli  * batadv_tt_global_entry list
1250d657e621SAntonio Quartulli  *
125162fe710fSSven Eckelmann  * Return: it with an increased refcounter, NULL if not found
1252d657e621SAntonio Quartulli  */
1253d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry *
1254d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
1255d657e621SAntonio Quartulli 				 const struct batadv_orig_node *orig_node)
1256d657e621SAntonio Quartulli {
1257d657e621SAntonio Quartulli 	struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
1258d657e621SAntonio Quartulli 	const struct hlist_head *head;
1259d657e621SAntonio Quartulli 
1260d657e621SAntonio Quartulli 	rcu_read_lock();
1261d657e621SAntonio Quartulli 	head = &entry->orig_list;
1262b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(tmp_orig_entry, head, list) {
1263d657e621SAntonio Quartulli 		if (tmp_orig_entry->orig_node != orig_node)
1264d657e621SAntonio Quartulli 			continue;
1265d657e621SAntonio Quartulli 		if (!atomic_inc_not_zero(&tmp_orig_entry->refcount))
1266d657e621SAntonio Quartulli 			continue;
1267d657e621SAntonio Quartulli 
1268d657e621SAntonio Quartulli 		orig_entry = tmp_orig_entry;
1269d657e621SAntonio Quartulli 		break;
1270d657e621SAntonio Quartulli 	}
1271d657e621SAntonio Quartulli 	rcu_read_unlock();
1272d657e621SAntonio Quartulli 
1273d657e621SAntonio Quartulli 	return orig_entry;
1274d657e621SAntonio Quartulli }
1275d657e621SAntonio Quartulli 
127662fe710fSSven Eckelmann /**
127762fe710fSSven Eckelmann  * batadv_tt_global_entry_has_orig
127862fe710fSSven Eckelmann  *
127962fe710fSSven Eckelmann  * find out if an orig_node is already in the list of a tt_global_entry.
128062fe710fSSven Eckelmann  *
128162fe710fSSven Eckelmann  * Return: true if found, false otherwise
1282db08e6e5SSimon Wunderlich  */
128356303d34SSven Eckelmann static bool
128456303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
128556303d34SSven Eckelmann 				const struct batadv_orig_node *orig_node)
1286db08e6e5SSimon Wunderlich {
1287d657e621SAntonio Quartulli 	struct batadv_tt_orig_list_entry *orig_entry;
1288db08e6e5SSimon Wunderlich 	bool found = false;
1289db08e6e5SSimon Wunderlich 
1290d657e621SAntonio Quartulli 	orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
1291d657e621SAntonio Quartulli 	if (orig_entry) {
1292db08e6e5SSimon Wunderlich 		found = true;
1293d657e621SAntonio Quartulli 		batadv_tt_orig_list_entry_free_ref(orig_entry);
1294db08e6e5SSimon Wunderlich 	}
1295d657e621SAntonio Quartulli 
1296db08e6e5SSimon Wunderlich 	return found;
1297db08e6e5SSimon Wunderlich }
1298db08e6e5SSimon Wunderlich 
1299a513088dSSven Eckelmann static void
1300d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
130156303d34SSven Eckelmann 				struct batadv_orig_node *orig_node, int ttvn)
1302db08e6e5SSimon Wunderlich {
130356303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
1304db08e6e5SSimon Wunderlich 
1305d657e621SAntonio Quartulli 	orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
130630cfd02bSAntonio Quartulli 	if (orig_entry) {
130730cfd02bSAntonio Quartulli 		/* refresh the ttvn: the current value could be a bogus one that
130830cfd02bSAntonio Quartulli 		 * was added during a "temporary client detection"
130930cfd02bSAntonio Quartulli 		 */
131030cfd02bSAntonio Quartulli 		orig_entry->ttvn = ttvn;
1311d657e621SAntonio Quartulli 		goto out;
131230cfd02bSAntonio Quartulli 	}
1313d657e621SAntonio Quartulli 
1314db08e6e5SSimon Wunderlich 	orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
1315db08e6e5SSimon Wunderlich 	if (!orig_entry)
1316d657e621SAntonio Quartulli 		goto out;
1317db08e6e5SSimon Wunderlich 
1318db08e6e5SSimon Wunderlich 	INIT_HLIST_NODE(&orig_entry->list);
1319db08e6e5SSimon Wunderlich 	atomic_inc(&orig_node->refcount);
13207ea7b4a1SAntonio Quartulli 	batadv_tt_global_size_inc(orig_node, tt_global->common.vid);
1321db08e6e5SSimon Wunderlich 	orig_entry->orig_node = orig_node;
1322db08e6e5SSimon Wunderlich 	orig_entry->ttvn = ttvn;
1323d657e621SAntonio Quartulli 	atomic_set(&orig_entry->refcount, 2);
1324db08e6e5SSimon Wunderlich 
1325d657e621SAntonio Quartulli 	spin_lock_bh(&tt_global->list_lock);
1326db08e6e5SSimon Wunderlich 	hlist_add_head_rcu(&orig_entry->list,
1327d657e621SAntonio Quartulli 			   &tt_global->orig_list);
1328d657e621SAntonio Quartulli 	spin_unlock_bh(&tt_global->list_lock);
13291d8ab8d3SLinus Lüssing 	atomic_inc(&tt_global->orig_list_count);
13301d8ab8d3SLinus Lüssing 
1331d657e621SAntonio Quartulli out:
1332d657e621SAntonio Quartulli 	if (orig_entry)
1333d657e621SAntonio Quartulli 		batadv_tt_orig_list_entry_free_ref(orig_entry);
1334db08e6e5SSimon Wunderlich }
1335db08e6e5SSimon Wunderlich 
1336d4ff40f6SAntonio Quartulli /**
1337d4ff40f6SAntonio Quartulli  * batadv_tt_global_add - add a new TT global entry or update an existing one
1338d4ff40f6SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
1339d4ff40f6SAntonio Quartulli  * @orig_node: the originator announcing the client
1340d4ff40f6SAntonio Quartulli  * @tt_addr: the mac address of the non-mesh client
1341c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
1342d4ff40f6SAntonio Quartulli  * @flags: TT flags that have to be set for this non-mesh client
1343d4ff40f6SAntonio Quartulli  * @ttvn: the tt version number ever announcing this non-mesh client
1344d4ff40f6SAntonio Quartulli  *
1345d4ff40f6SAntonio Quartulli  * Add a new TT global entry for the given originator. If the entry already
1346d4ff40f6SAntonio Quartulli  * exists add a new reference to the given originator (a global entry can have
1347d4ff40f6SAntonio Quartulli  * references to multiple originators) and adjust the flags attribute to reflect
1348d4ff40f6SAntonio Quartulli  * the function argument.
1349d4ff40f6SAntonio Quartulli  * If a TT local entry exists for this non-mesh client remove it.
1350d4ff40f6SAntonio Quartulli  *
1351d4ff40f6SAntonio Quartulli  * The caller must hold orig_node refcount.
13521e5d49fcSAntonio Quartulli  *
135362fe710fSSven Eckelmann  * Return: true if the new entry has been added, false otherwise
1354d4ff40f6SAntonio Quartulli  */
13551e5d49fcSAntonio Quartulli static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
135656303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node,
1357c018ad3dSAntonio Quartulli 				 const unsigned char *tt_addr,
13586b5e971aSSven Eckelmann 				 unsigned short vid, u16 flags, u8 ttvn)
1359c6c8fea2SSven Eckelmann {
1360170173bfSSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
1361170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
13621e5d49fcSAntonio Quartulli 	bool ret = false;
136380b3f58cSSimon Wunderlich 	int hash_added;
136456303d34SSven Eckelmann 	struct batadv_tt_common_entry *common;
13656b5e971aSSven Eckelmann 	u16 local_flags;
1366c6c8fea2SSven Eckelmann 
1367cfd4f757SAntonio Quartulli 	/* ignore global entries from backbone nodes */
1368cfd4f757SAntonio Quartulli 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
1369cfd4f757SAntonio Quartulli 		return true;
1370cfd4f757SAntonio Quartulli 
1371c018ad3dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid);
1372c018ad3dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid);
1373068ee6e2SAntonio Quartulli 
1374068ee6e2SAntonio Quartulli 	/* if the node already has a local client for this entry, it has to wait
1375068ee6e2SAntonio Quartulli 	 * for a roaming advertisement instead of manually messing up the global
1376068ee6e2SAntonio Quartulli 	 * table
1377068ee6e2SAntonio Quartulli 	 */
1378068ee6e2SAntonio Quartulli 	if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
1379068ee6e2SAntonio Quartulli 	    !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
1380068ee6e2SAntonio Quartulli 		goto out;
1381c6c8fea2SSven Eckelmann 
13822dafb49dSAntonio Quartulli 	if (!tt_global_entry) {
1383d4f44692SAntonio Quartulli 		tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC);
13842dafb49dSAntonio Quartulli 		if (!tt_global_entry)
13857683fdc1SAntonio Quartulli 			goto out;
13867683fdc1SAntonio Quartulli 
1387c0a55929SSven Eckelmann 		common = &tt_global_entry->common;
13888fdd0153SAntonio Quartulli 		ether_addr_copy(common->addr, tt_addr);
1389c018ad3dSAntonio Quartulli 		common->vid = vid;
1390db08e6e5SSimon Wunderlich 
1391d4f44692SAntonio Quartulli 		common->flags = flags;
1392cc47f66eSAntonio Quartulli 		tt_global_entry->roam_at = 0;
1393fdf79320SAntonio Quartulli 		/* node must store current time in case of roaming. This is
1394fdf79320SAntonio Quartulli 		 * needed to purge this entry out on timeout (if nobody claims
1395fdf79320SAntonio Quartulli 		 * it)
1396fdf79320SAntonio Quartulli 		 */
1397fdf79320SAntonio Quartulli 		if (flags & BATADV_TT_CLIENT_ROAM)
1398fdf79320SAntonio Quartulli 			tt_global_entry->roam_at = jiffies;
1399c0a55929SSven Eckelmann 		atomic_set(&common->refcount, 2);
140030cfd02bSAntonio Quartulli 		common->added_at = jiffies;
1401db08e6e5SSimon Wunderlich 
1402db08e6e5SSimon Wunderlich 		INIT_HLIST_HEAD(&tt_global_entry->orig_list);
14031d8ab8d3SLinus Lüssing 		atomic_set(&tt_global_entry->orig_list_count, 0);
1404db08e6e5SSimon Wunderlich 		spin_lock_init(&tt_global_entry->list_lock);
14057683fdc1SAntonio Quartulli 
1406807736f6SSven Eckelmann 		hash_added = batadv_hash_add(bat_priv->tt.global_hash,
1407a513088dSSven Eckelmann 					     batadv_compare_tt,
1408c018ad3dSAntonio Quartulli 					     batadv_choose_tt, common,
1409a513088dSSven Eckelmann 					     &common->hash_entry);
141080b3f58cSSimon Wunderlich 
141180b3f58cSSimon Wunderlich 		if (unlikely(hash_added != 0)) {
141280b3f58cSSimon Wunderlich 			/* remove the reference for the hash */
1413a513088dSSven Eckelmann 			batadv_tt_global_entry_free_ref(tt_global_entry);
141480b3f58cSSimon Wunderlich 			goto out_remove;
141580b3f58cSSimon Wunderlich 		}
1416a73105b8SAntonio Quartulli 	} else {
1417068ee6e2SAntonio Quartulli 		common = &tt_global_entry->common;
141830cfd02bSAntonio Quartulli 		/* If there is already a global entry, we can use this one for
141930cfd02bSAntonio Quartulli 		 * our processing.
1420068ee6e2SAntonio Quartulli 		 * But if we are trying to add a temporary client then here are
1421068ee6e2SAntonio Quartulli 		 * two options at this point:
1422068ee6e2SAntonio Quartulli 		 * 1) the global client is not a temporary client: the global
1423068ee6e2SAntonio Quartulli 		 *    client has to be left as it is, temporary information
1424068ee6e2SAntonio Quartulli 		 *    should never override any already known client state
1425068ee6e2SAntonio Quartulli 		 * 2) the global client is a temporary client: purge the
1426068ee6e2SAntonio Quartulli 		 *    originator list and add the new one orig_entry
142730cfd02bSAntonio Quartulli 		 */
1428068ee6e2SAntonio Quartulli 		if (flags & BATADV_TT_CLIENT_TEMP) {
1429068ee6e2SAntonio Quartulli 			if (!(common->flags & BATADV_TT_CLIENT_TEMP))
143030cfd02bSAntonio Quartulli 				goto out;
1431068ee6e2SAntonio Quartulli 			if (batadv_tt_global_entry_has_orig(tt_global_entry,
1432068ee6e2SAntonio Quartulli 							    orig_node))
1433068ee6e2SAntonio Quartulli 				goto out_remove;
1434068ee6e2SAntonio Quartulli 			batadv_tt_global_del_orig_list(tt_global_entry);
1435068ee6e2SAntonio Quartulli 			goto add_orig_entry;
1436068ee6e2SAntonio Quartulli 		}
143730cfd02bSAntonio Quartulli 
143830cfd02bSAntonio Quartulli 		/* if the client was temporary added before receiving the first
1439a6cb3909SSimon Wunderlich 		 * OGM announcing it, we have to clear the TEMP flag. Also,
1440a6cb3909SSimon Wunderlich 		 * remove the previous temporary orig node and re-add it
1441a6cb3909SSimon Wunderlich 		 * if required. If the orig entry changed, the new one which
1442a6cb3909SSimon Wunderlich 		 * is a non-temporary entry is preferred.
144330cfd02bSAntonio Quartulli 		 */
1444a6cb3909SSimon Wunderlich 		if (common->flags & BATADV_TT_CLIENT_TEMP) {
1445a6cb3909SSimon Wunderlich 			batadv_tt_global_del_orig_list(tt_global_entry);
1446068ee6e2SAntonio Quartulli 			common->flags &= ~BATADV_TT_CLIENT_TEMP;
1447a6cb3909SSimon Wunderlich 		}
1448db08e6e5SSimon Wunderlich 
1449e9c00136SAntonio Quartulli 		/* the change can carry possible "attribute" flags like the
1450e9c00136SAntonio Quartulli 		 * TT_CLIENT_WIFI, therefore they have to be copied in the
1451e9c00136SAntonio Quartulli 		 * client entry
1452e9c00136SAntonio Quartulli 		 */
1453ad7e2c46SSimon Wunderlich 		common->flags |= flags;
1454e9c00136SAntonio Quartulli 
1455acd34afaSSven Eckelmann 		/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
1456acd34afaSSven Eckelmann 		 * one originator left in the list and we previously received a
1457db08e6e5SSimon Wunderlich 		 * delete + roaming change for this originator.
1458db08e6e5SSimon Wunderlich 		 *
1459db08e6e5SSimon Wunderlich 		 * We should first delete the old originator before adding the
1460db08e6e5SSimon Wunderlich 		 * new one.
1461db08e6e5SSimon Wunderlich 		 */
1462068ee6e2SAntonio Quartulli 		if (common->flags & BATADV_TT_CLIENT_ROAM) {
1463a513088dSSven Eckelmann 			batadv_tt_global_del_orig_list(tt_global_entry);
1464068ee6e2SAntonio Quartulli 			common->flags &= ~BATADV_TT_CLIENT_ROAM;
1465cc47f66eSAntonio Quartulli 			tt_global_entry->roam_at = 0;
1466c6c8fea2SSven Eckelmann 		}
1467db08e6e5SSimon Wunderlich 	}
1468068ee6e2SAntonio Quartulli add_orig_entry:
146930cfd02bSAntonio Quartulli 	/* add the new orig_entry (if needed) or update it */
1470d657e621SAntonio Quartulli 	batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
1471db08e6e5SSimon Wunderlich 
147239c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
147316052789SAntonio Quartulli 		   "Creating new global tt entry: %pM (vid: %d, via %pM)\n",
147416052789SAntonio Quartulli 		   common->addr, BATADV_PRINT_VID(common->vid),
147516052789SAntonio Quartulli 		   orig_node->orig);
14761e5d49fcSAntonio Quartulli 	ret = true;
1477a73105b8SAntonio Quartulli 
147880b3f58cSSimon Wunderlich out_remove:
1479c5caf4efSLinus Lüssing 	/* Do not remove multicast addresses from the local hash on
1480c5caf4efSLinus Lüssing 	 * global additions
1481c5caf4efSLinus Lüssing 	 */
1482c5caf4efSLinus Lüssing 	if (is_multicast_ether_addr(tt_addr))
1483c5caf4efSLinus Lüssing 		goto out;
14847f91d06cSAntonio Quartulli 
1485c6c8fea2SSven Eckelmann 	/* remove address from local hash if present */
1486c018ad3dSAntonio Quartulli 	local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
1487acd34afaSSven Eckelmann 					     "global tt received",
1488c1d07431SAntonio Quartulli 					     flags & BATADV_TT_CLIENT_ROAM);
14897f91d06cSAntonio Quartulli 	tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
14907f91d06cSAntonio Quartulli 
1491068ee6e2SAntonio Quartulli 	if (!(flags & BATADV_TT_CLIENT_ROAM))
1492068ee6e2SAntonio Quartulli 		/* this is a normal global add. Therefore the client is not in a
1493068ee6e2SAntonio Quartulli 		 * roaming state anymore.
1494068ee6e2SAntonio Quartulli 		 */
1495068ee6e2SAntonio Quartulli 		tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
1496068ee6e2SAntonio Quartulli 
14977683fdc1SAntonio Quartulli out:
14987683fdc1SAntonio Quartulli 	if (tt_global_entry)
1499a513088dSSven Eckelmann 		batadv_tt_global_entry_free_ref(tt_global_entry);
1500068ee6e2SAntonio Quartulli 	if (tt_local_entry)
1501068ee6e2SAntonio Quartulli 		batadv_tt_local_entry_free_ref(tt_local_entry);
15027683fdc1SAntonio Quartulli 	return ret;
1503c6c8fea2SSven Eckelmann }
1504c6c8fea2SSven Eckelmann 
15051b371d13SSimon Wunderlich /**
15061b371d13SSimon Wunderlich  * batadv_transtable_best_orig - Get best originator list entry from tt entry
15074627456aSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
1508981d8900SSven Eckelmann  * @tt_global_entry: global translation table entry to be analyzed
1509981d8900SSven Eckelmann  *
1510981d8900SSven Eckelmann  * This functon assumes the caller holds rcu_read_lock().
151162fe710fSSven Eckelmann  * Return: best originator list entry or NULL on errors.
1512981d8900SSven Eckelmann  */
1513981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry *
15144627456aSAntonio Quartulli batadv_transtable_best_orig(struct batadv_priv *bat_priv,
15154627456aSAntonio Quartulli 			    struct batadv_tt_global_entry *tt_global_entry)
1516981d8900SSven Eckelmann {
15174627456aSAntonio Quartulli 	struct batadv_neigh_node *router, *best_router = NULL;
15184627456aSAntonio Quartulli 	struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
1519981d8900SSven Eckelmann 	struct hlist_head *head;
1520981d8900SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL;
1521981d8900SSven Eckelmann 
1522981d8900SSven Eckelmann 	head = &tt_global_entry->orig_list;
1523b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(orig_entry, head, list) {
15247351a482SSimon Wunderlich 		router = batadv_orig_router_get(orig_entry->orig_node,
15257351a482SSimon Wunderlich 						BATADV_IF_DEFAULT);
1526981d8900SSven Eckelmann 		if (!router)
1527981d8900SSven Eckelmann 			continue;
1528981d8900SSven Eckelmann 
15294627456aSAntonio Quartulli 		if (best_router &&
153089652331SSimon Wunderlich 		    bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT,
153189652331SSimon Wunderlich 				       best_router, BATADV_IF_DEFAULT) <= 0) {
15324627456aSAntonio Quartulli 			batadv_neigh_node_free_ref(router);
15334627456aSAntonio Quartulli 			continue;
1534981d8900SSven Eckelmann 		}
1535981d8900SSven Eckelmann 
15364627456aSAntonio Quartulli 		/* release the refcount for the "old" best */
15374627456aSAntonio Quartulli 		if (best_router)
15384627456aSAntonio Quartulli 			batadv_neigh_node_free_ref(best_router);
15394627456aSAntonio Quartulli 
15404627456aSAntonio Quartulli 		best_entry = orig_entry;
15414627456aSAntonio Quartulli 		best_router = router;
1542981d8900SSven Eckelmann 	}
1543981d8900SSven Eckelmann 
15444627456aSAntonio Quartulli 	if (best_router)
15454627456aSAntonio Quartulli 		batadv_neigh_node_free_ref(best_router);
15464627456aSAntonio Quartulli 
1547981d8900SSven Eckelmann 	return best_entry;
1548981d8900SSven Eckelmann }
1549981d8900SSven Eckelmann 
15501b371d13SSimon Wunderlich /**
15511b371d13SSimon Wunderlich  * batadv_tt_global_print_entry - print all orig nodes who announce the address
1552981d8900SSven Eckelmann  *  for this global entry
15534627456aSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
1554981d8900SSven Eckelmann  * @tt_global_entry: global translation table entry to be printed
1555981d8900SSven Eckelmann  * @seq: debugfs table seq_file struct
1556981d8900SSven Eckelmann  *
1557981d8900SSven Eckelmann  * This functon assumes the caller holds rcu_read_lock().
1558db08e6e5SSimon Wunderlich  */
1559a513088dSSven Eckelmann static void
15604627456aSAntonio Quartulli batadv_tt_global_print_entry(struct batadv_priv *bat_priv,
15614627456aSAntonio Quartulli 			     struct batadv_tt_global_entry *tt_global_entry,
1562db08e6e5SSimon Wunderlich 			     struct seq_file *seq)
1563db08e6e5SSimon Wunderlich {
1564981d8900SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
156556303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
15667ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
15677ea7b4a1SAntonio Quartulli 	struct hlist_head *head;
15686b5e971aSSven Eckelmann 	u8 last_ttvn;
15696b5e971aSSven Eckelmann 	u16 flags;
1570db08e6e5SSimon Wunderlich 
1571db08e6e5SSimon Wunderlich 	tt_common_entry = &tt_global_entry->common;
1572981d8900SSven Eckelmann 	flags = tt_common_entry->flags;
1573981d8900SSven Eckelmann 
15744627456aSAntonio Quartulli 	best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
1575981d8900SSven Eckelmann 	if (best_entry) {
15767ea7b4a1SAntonio Quartulli 		vlan = batadv_orig_node_vlan_get(best_entry->orig_node,
15777ea7b4a1SAntonio Quartulli 						 tt_common_entry->vid);
15787ea7b4a1SAntonio Quartulli 		if (!vlan) {
15797ea7b4a1SAntonio Quartulli 			seq_printf(seq,
15807ea7b4a1SAntonio Quartulli 				   " * Cannot retrieve VLAN %d for originator %pM\n",
15817ea7b4a1SAntonio Quartulli 				   BATADV_PRINT_VID(tt_common_entry->vid),
15827ea7b4a1SAntonio Quartulli 				   best_entry->orig_node->orig);
15837ea7b4a1SAntonio Quartulli 			goto print_list;
15847ea7b4a1SAntonio Quartulli 		}
15857ea7b4a1SAntonio Quartulli 
1586981d8900SSven Eckelmann 		last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
1587f9d8a537SAntonio Quartulli 		seq_printf(seq,
1588dd24ddb2SAntonio Quartulli 			   " %c %pM %4i   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c%c]\n",
1589981d8900SSven Eckelmann 			   '*', tt_global_entry->common.addr,
159016052789SAntonio Quartulli 			   BATADV_PRINT_VID(tt_global_entry->common.vid),
1591981d8900SSven Eckelmann 			   best_entry->ttvn, best_entry->orig_node->orig,
15927ea7b4a1SAntonio Quartulli 			   last_ttvn, vlan->tt.crc,
1593a2f2b6cdSSven Eckelmann 			   ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
1594a2f2b6cdSSven Eckelmann 			   ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
1595a2f2b6cdSSven Eckelmann 			   ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
1596a2f2b6cdSSven Eckelmann 			   ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
15977ea7b4a1SAntonio Quartulli 
15987ea7b4a1SAntonio Quartulli 		batadv_orig_node_vlan_free_ref(vlan);
1599981d8900SSven Eckelmann 	}
1600db08e6e5SSimon Wunderlich 
16017ea7b4a1SAntonio Quartulli print_list:
1602db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
1603db08e6e5SSimon Wunderlich 
1604b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(orig_entry, head, list) {
1605981d8900SSven Eckelmann 		if (best_entry == orig_entry)
1606981d8900SSven Eckelmann 			continue;
1607981d8900SSven Eckelmann 
16087ea7b4a1SAntonio Quartulli 		vlan = batadv_orig_node_vlan_get(orig_entry->orig_node,
16097ea7b4a1SAntonio Quartulli 						 tt_common_entry->vid);
16107ea7b4a1SAntonio Quartulli 		if (!vlan) {
16117ea7b4a1SAntonio Quartulli 			seq_printf(seq,
16127ea7b4a1SAntonio Quartulli 				   " + Cannot retrieve VLAN %d for originator %pM\n",
16137ea7b4a1SAntonio Quartulli 				   BATADV_PRINT_VID(tt_common_entry->vid),
16147ea7b4a1SAntonio Quartulli 				   orig_entry->orig_node->orig);
16157ea7b4a1SAntonio Quartulli 			continue;
16167ea7b4a1SAntonio Quartulli 		}
16177ea7b4a1SAntonio Quartulli 
1618db08e6e5SSimon Wunderlich 		last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
161916052789SAntonio Quartulli 		seq_printf(seq,
1620dd24ddb2SAntonio Quartulli 			   " %c %pM %4d   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c%c]\n",
1621981d8900SSven Eckelmann 			   '+', tt_global_entry->common.addr,
162216052789SAntonio Quartulli 			   BATADV_PRINT_VID(tt_global_entry->common.vid),
1623981d8900SSven Eckelmann 			   orig_entry->ttvn, orig_entry->orig_node->orig,
16247ea7b4a1SAntonio Quartulli 			   last_ttvn, vlan->tt.crc,
1625a2f2b6cdSSven Eckelmann 			   ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
1626a2f2b6cdSSven Eckelmann 			   ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
1627a2f2b6cdSSven Eckelmann 			   ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
1628a2f2b6cdSSven Eckelmann 			   ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
16297ea7b4a1SAntonio Quartulli 
16307ea7b4a1SAntonio Quartulli 		batadv_orig_node_vlan_free_ref(vlan);
1631db08e6e5SSimon Wunderlich 	}
1632db08e6e5SSimon Wunderlich }
1633db08e6e5SSimon Wunderlich 
163408c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
1635c6c8fea2SSven Eckelmann {
1636c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
163756303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(net_dev);
1638807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
163956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
164056303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
164156303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if;
1642c6c8fea2SSven Eckelmann 	struct hlist_head *head;
16436b5e971aSSven Eckelmann 	u32 i;
1644c6c8fea2SSven Eckelmann 
164530da63a6SMarek Lindner 	primary_if = batadv_seq_print_text_primary_if_get(seq);
164630da63a6SMarek Lindner 	if (!primary_if)
164732ae9b22SMarek Lindner 		goto out;
1648c6c8fea2SSven Eckelmann 
16492dafb49dSAntonio Quartulli 	seq_printf(seq,
16502dafb49dSAntonio Quartulli 		   "Globally announced TT entries received via the mesh %s\n",
1651c6c8fea2SSven Eckelmann 		   net_dev->name);
165216052789SAntonio Quartulli 	seq_printf(seq, "       %-13s  %s  %s       %-15s %s (%-10s) %s\n",
165316052789SAntonio Quartulli 		   "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)",
165416052789SAntonio Quartulli 		   "CRC", "Flags");
1655c6c8fea2SSven Eckelmann 
1656c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
1657c6c8fea2SSven Eckelmann 		head = &hash->table[i];
1658c6c8fea2SSven Eckelmann 
16597aadf889SMarek Lindner 		rcu_read_lock();
1660b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
16617aadf889SMarek Lindner 					 head, hash_entry) {
166256303d34SSven Eckelmann 			tt_global = container_of(tt_common_entry,
166356303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
166448100bacSAntonio Quartulli 						 common);
16654627456aSAntonio Quartulli 			batadv_tt_global_print_entry(bat_priv, tt_global, seq);
1666c6c8fea2SSven Eckelmann 		}
16677aadf889SMarek Lindner 		rcu_read_unlock();
1668c6c8fea2SSven Eckelmann 	}
166932ae9b22SMarek Lindner out:
167032ae9b22SMarek Lindner 	if (primary_if)
1671e5d89254SSven Eckelmann 		batadv_hardif_free_ref(primary_if);
167230da63a6SMarek Lindner 	return 0;
1673c6c8fea2SSven Eckelmann }
1674c6c8fea2SSven Eckelmann 
16751d8ab8d3SLinus Lüssing /**
1676433ff98fSMarek Lindner  * _batadv_tt_global_del_orig_entry - remove and free an orig_entry
16771d8ab8d3SLinus Lüssing  * @tt_global_entry: the global entry to remove the orig_entry from
16781d8ab8d3SLinus Lüssing  * @orig_entry: the orig entry to remove and free
16791d8ab8d3SLinus Lüssing  *
16801d8ab8d3SLinus Lüssing  * Remove an orig_entry from its list in the given tt_global_entry and
16811d8ab8d3SLinus Lüssing  * free this orig_entry afterwards.
1682433ff98fSMarek Lindner  *
1683433ff98fSMarek Lindner  * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is
1684433ff98fSMarek Lindner  * part of a list.
16851d8ab8d3SLinus Lüssing  */
16861d8ab8d3SLinus Lüssing static void
1687433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
16881d8ab8d3SLinus Lüssing 				 struct batadv_tt_orig_list_entry *orig_entry)
16891d8ab8d3SLinus Lüssing {
16902c72d655SSven Eckelmann 	lockdep_assert_held(&tt_global_entry->list_lock);
16912c72d655SSven Eckelmann 
16921d8ab8d3SLinus Lüssing 	batadv_tt_global_size_dec(orig_entry->orig_node,
16931d8ab8d3SLinus Lüssing 				  tt_global_entry->common.vid);
16941d8ab8d3SLinus Lüssing 	atomic_dec(&tt_global_entry->orig_list_count);
1695433ff98fSMarek Lindner 	/* requires holding tt_global_entry->list_lock and orig_entry->list
1696433ff98fSMarek Lindner 	 * being part of a list
1697433ff98fSMarek Lindner 	 */
16981d8ab8d3SLinus Lüssing 	hlist_del_rcu(&orig_entry->list);
16991d8ab8d3SLinus Lüssing 	batadv_tt_orig_list_entry_free_ref(orig_entry);
17001d8ab8d3SLinus Lüssing }
17011d8ab8d3SLinus Lüssing 
1702db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */
1703a513088dSSven Eckelmann static void
170456303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
1705db08e6e5SSimon Wunderlich {
1706db08e6e5SSimon Wunderlich 	struct hlist_head *head;
1707b67bfe0dSSasha Levin 	struct hlist_node *safe;
170856303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
1709db08e6e5SSimon Wunderlich 
1710db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
1711db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
17121d8ab8d3SLinus Lüssing 	hlist_for_each_entry_safe(orig_entry, safe, head, list)
1713433ff98fSMarek Lindner 		_batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry);
1714db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
1715db08e6e5SSimon Wunderlich }
1716db08e6e5SSimon Wunderlich 
17171d8ab8d3SLinus Lüssing /**
17181d8ab8d3SLinus Lüssing  * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry
17191d8ab8d3SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
17201d8ab8d3SLinus Lüssing  * @tt_global_entry: the global entry to remove the orig_node from
17211d8ab8d3SLinus Lüssing  * @orig_node: the originator announcing the client
17221d8ab8d3SLinus Lüssing  * @message: message to append to the log on deletion
17231d8ab8d3SLinus Lüssing  *
17241d8ab8d3SLinus Lüssing  * Remove the given orig_node and its according orig_entry from the given
17251d8ab8d3SLinus Lüssing  * global tt entry.
17261d8ab8d3SLinus Lüssing  */
1727a513088dSSven Eckelmann static void
17281d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv,
172956303d34SSven Eckelmann 			       struct batadv_tt_global_entry *tt_global_entry,
173056303d34SSven Eckelmann 			       struct batadv_orig_node *orig_node,
1731db08e6e5SSimon Wunderlich 			       const char *message)
1732db08e6e5SSimon Wunderlich {
1733db08e6e5SSimon Wunderlich 	struct hlist_head *head;
1734b67bfe0dSSasha Levin 	struct hlist_node *safe;
173556303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
173616052789SAntonio Quartulli 	unsigned short vid;
1737db08e6e5SSimon Wunderlich 
1738db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
1739db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
1740b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(orig_entry, safe, head, list) {
1741db08e6e5SSimon Wunderlich 		if (orig_entry->orig_node == orig_node) {
174216052789SAntonio Quartulli 			vid = tt_global_entry->common.vid;
174339c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
174416052789SAntonio Quartulli 				   "Deleting %pM from global tt entry %pM (vid: %d): %s\n",
17451eda58bfSSven Eckelmann 				   orig_node->orig,
174616052789SAntonio Quartulli 				   tt_global_entry->common.addr,
174716052789SAntonio Quartulli 				   BATADV_PRINT_VID(vid), message);
1748433ff98fSMarek Lindner 			_batadv_tt_global_del_orig_entry(tt_global_entry,
17491d8ab8d3SLinus Lüssing 							 orig_entry);
1750db08e6e5SSimon Wunderlich 		}
1751db08e6e5SSimon Wunderlich 	}
1752db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
1753db08e6e5SSimon Wunderlich }
1754db08e6e5SSimon Wunderlich 
1755db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry
1756acd34afaSSven Eckelmann  * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
1757acd34afaSSven Eckelmann  * timer, otherwise we simply remove the originator scheduled for deletion.
1758db08e6e5SSimon Wunderlich  */
1759a513088dSSven Eckelmann static void
176056303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
176156303d34SSven Eckelmann 			     struct batadv_tt_global_entry *tt_global_entry,
176256303d34SSven Eckelmann 			     struct batadv_orig_node *orig_node,
176356303d34SSven Eckelmann 			     const char *message)
1764db08e6e5SSimon Wunderlich {
1765db08e6e5SSimon Wunderlich 	bool last_entry = true;
1766db08e6e5SSimon Wunderlich 	struct hlist_head *head;
176756303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
1768db08e6e5SSimon Wunderlich 
1769db08e6e5SSimon Wunderlich 	/* no local entry exists, case 1:
1770db08e6e5SSimon Wunderlich 	 * Check if this is the last one or if other entries exist.
1771db08e6e5SSimon Wunderlich 	 */
1772db08e6e5SSimon Wunderlich 
1773db08e6e5SSimon Wunderlich 	rcu_read_lock();
1774db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
1775b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(orig_entry, head, list) {
1776db08e6e5SSimon Wunderlich 		if (orig_entry->orig_node != orig_node) {
1777db08e6e5SSimon Wunderlich 			last_entry = false;
1778db08e6e5SSimon Wunderlich 			break;
1779db08e6e5SSimon Wunderlich 		}
1780db08e6e5SSimon Wunderlich 	}
1781db08e6e5SSimon Wunderlich 	rcu_read_unlock();
1782db08e6e5SSimon Wunderlich 
1783db08e6e5SSimon Wunderlich 	if (last_entry) {
1784db08e6e5SSimon Wunderlich 		/* its the last one, mark for roaming. */
1785acd34afaSSven Eckelmann 		tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
1786db08e6e5SSimon Wunderlich 		tt_global_entry->roam_at = jiffies;
1787db08e6e5SSimon Wunderlich 	} else
1788db08e6e5SSimon Wunderlich 		/* there is another entry, we can simply delete this
1789db08e6e5SSimon Wunderlich 		 * one and can still use the other one.
1790db08e6e5SSimon Wunderlich 		 */
17911d8ab8d3SLinus Lüssing 		batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
1792db08e6e5SSimon Wunderlich 					       orig_node, message);
1793db08e6e5SSimon Wunderlich }
1794db08e6e5SSimon Wunderlich 
1795c018ad3dSAntonio Quartulli /**
1796c018ad3dSAntonio Quartulli  * batadv_tt_global_del - remove a client from the global table
1797c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
1798c018ad3dSAntonio Quartulli  * @orig_node: an originator serving this client
1799c018ad3dSAntonio Quartulli  * @addr: the mac address of the client
1800c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
1801c018ad3dSAntonio Quartulli  * @message: a message explaining the reason for deleting the client to print
1802c018ad3dSAntonio Quartulli  *  for debugging purpose
1803c018ad3dSAntonio Quartulli  * @roaming: true if the deletion has been triggered by a roaming event
1804c018ad3dSAntonio Quartulli  */
180556303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv,
180656303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node,
1807c018ad3dSAntonio Quartulli 				 const unsigned char *addr, unsigned short vid,
1808cc47f66eSAntonio Quartulli 				 const char *message, bool roaming)
1809a73105b8SAntonio Quartulli {
1810170173bfSSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
181156303d34SSven Eckelmann 	struct batadv_tt_local_entry *local_entry = NULL;
1812a73105b8SAntonio Quartulli 
1813c018ad3dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
1814db08e6e5SSimon Wunderlich 	if (!tt_global_entry)
18157683fdc1SAntonio Quartulli 		goto out;
1816a73105b8SAntonio Quartulli 
1817db08e6e5SSimon Wunderlich 	if (!roaming) {
18181d8ab8d3SLinus Lüssing 		batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
1819a513088dSSven Eckelmann 					       orig_node, message);
182092f90f56SSven Eckelmann 
1821db08e6e5SSimon Wunderlich 		if (hlist_empty(&tt_global_entry->orig_list))
1822be73b488SAntonio Quartulli 			batadv_tt_global_free(bat_priv, tt_global_entry,
1823db08e6e5SSimon Wunderlich 					      message);
1824db08e6e5SSimon Wunderlich 
1825cc47f66eSAntonio Quartulli 		goto out;
1826cc47f66eSAntonio Quartulli 	}
182792f90f56SSven Eckelmann 
1828db08e6e5SSimon Wunderlich 	/* if we are deleting a global entry due to a roam
1829db08e6e5SSimon Wunderlich 	 * event, there are two possibilities:
1830db08e6e5SSimon Wunderlich 	 * 1) the client roamed from node A to node B => if there
1831db08e6e5SSimon Wunderlich 	 *    is only one originator left for this client, we mark
1832acd34afaSSven Eckelmann 	 *    it with BATADV_TT_CLIENT_ROAM, we start a timer and we
1833db08e6e5SSimon Wunderlich 	 *    wait for node B to claim it. In case of timeout
1834db08e6e5SSimon Wunderlich 	 *    the entry is purged.
1835db08e6e5SSimon Wunderlich 	 *
1836db08e6e5SSimon Wunderlich 	 *    If there are other originators left, we directly delete
1837db08e6e5SSimon Wunderlich 	 *    the originator.
1838db08e6e5SSimon Wunderlich 	 * 2) the client roamed to us => we can directly delete
18399cfc7bd6SSven Eckelmann 	 *    the global entry, since it is useless now.
18409cfc7bd6SSven Eckelmann 	 */
1841a513088dSSven Eckelmann 	local_entry = batadv_tt_local_hash_find(bat_priv,
1842c018ad3dSAntonio Quartulli 						tt_global_entry->common.addr,
1843c018ad3dSAntonio Quartulli 						vid);
1844a513088dSSven Eckelmann 	if (local_entry) {
1845db08e6e5SSimon Wunderlich 		/* local entry exists, case 2: client roamed to us. */
1846a513088dSSven Eckelmann 		batadv_tt_global_del_orig_list(tt_global_entry);
1847be73b488SAntonio Quartulli 		batadv_tt_global_free(bat_priv, tt_global_entry, message);
1848db08e6e5SSimon Wunderlich 	} else
1849db08e6e5SSimon Wunderlich 		/* no local entry exists, case 1: check for roaming */
1850a513088dSSven Eckelmann 		batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
1851a513088dSSven Eckelmann 					     orig_node, message);
1852db08e6e5SSimon Wunderlich 
1853cc47f66eSAntonio Quartulli out:
18547683fdc1SAntonio Quartulli 	if (tt_global_entry)
1855a513088dSSven Eckelmann 		batadv_tt_global_entry_free_ref(tt_global_entry);
1856a513088dSSven Eckelmann 	if (local_entry)
1857a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(local_entry);
1858a73105b8SAntonio Quartulli }
1859a73105b8SAntonio Quartulli 
186095fb130dSAntonio Quartulli /**
186195fb130dSAntonio Quartulli  * batadv_tt_global_del_orig - remove all the TT global entries belonging to the
186295fb130dSAntonio Quartulli  *  given originator matching the provided vid
186395fb130dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
186495fb130dSAntonio Quartulli  * @orig_node: the originator owning the entries to remove
186595fb130dSAntonio Quartulli  * @match_vid: the VLAN identifier to match. If negative all the entries will be
186695fb130dSAntonio Quartulli  *  removed
186795fb130dSAntonio Quartulli  * @message: debug message to print as "reason"
186895fb130dSAntonio Quartulli  */
186956303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
187056303d34SSven Eckelmann 			       struct batadv_orig_node *orig_node,
18716b5e971aSSven Eckelmann 			       s32 match_vid,
187256303d34SSven Eckelmann 			       const char *message)
1873c6c8fea2SSven Eckelmann {
187456303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
187556303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
18766b5e971aSSven Eckelmann 	u32 i;
1877807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
1878b67bfe0dSSasha Levin 	struct hlist_node *safe;
1879a73105b8SAntonio Quartulli 	struct hlist_head *head;
18807683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
188116052789SAntonio Quartulli 	unsigned short vid;
1882c6c8fea2SSven Eckelmann 
18836e801494SSimon Wunderlich 	if (!hash)
18846e801494SSimon Wunderlich 		return;
18856e801494SSimon Wunderlich 
1886a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1887a73105b8SAntonio Quartulli 		head = &hash->table[i];
18887683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
1889c6c8fea2SSven Eckelmann 
18907683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
1891b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, safe,
1892a73105b8SAntonio Quartulli 					  head, hash_entry) {
189395fb130dSAntonio Quartulli 			/* remove only matching entries */
189495fb130dSAntonio Quartulli 			if (match_vid >= 0 && tt_common_entry->vid != match_vid)
189595fb130dSAntonio Quartulli 				continue;
189695fb130dSAntonio Quartulli 
189756303d34SSven Eckelmann 			tt_global = container_of(tt_common_entry,
189856303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
189948100bacSAntonio Quartulli 						 common);
1900db08e6e5SSimon Wunderlich 
19011d8ab8d3SLinus Lüssing 			batadv_tt_global_del_orig_node(bat_priv, tt_global,
1902db08e6e5SSimon Wunderlich 						       orig_node, message);
1903db08e6e5SSimon Wunderlich 
190456303d34SSven Eckelmann 			if (hlist_empty(&tt_global->orig_list)) {
190516052789SAntonio Quartulli 				vid = tt_global->common.vid;
190639c75a51SSven Eckelmann 				batadv_dbg(BATADV_DBG_TT, bat_priv,
190716052789SAntonio Quartulli 					   "Deleting global tt entry %pM (vid: %d): %s\n",
190816052789SAntonio Quartulli 					   tt_global->common.addr,
190916052789SAntonio Quartulli 					   BATADV_PRINT_VID(vid), message);
1910b67bfe0dSSasha Levin 				hlist_del_rcu(&tt_common_entry->hash_entry);
191156303d34SSven Eckelmann 				batadv_tt_global_entry_free_ref(tt_global);
1912c6c8fea2SSven Eckelmann 			}
1913a73105b8SAntonio Quartulli 		}
19147683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
19157683fdc1SAntonio Quartulli 	}
1916ac4eebd4SLinus Lüssing 	clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
1917c6c8fea2SSven Eckelmann }
1918c6c8fea2SSven Eckelmann 
191930cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
192030cfd02bSAntonio Quartulli 				      char **msg)
1921cc47f66eSAntonio Quartulli {
192230cfd02bSAntonio Quartulli 	bool purge = false;
192330cfd02bSAntonio Quartulli 	unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT;
192430cfd02bSAntonio Quartulli 	unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
1925cc47f66eSAntonio Quartulli 
192630cfd02bSAntonio Quartulli 	if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
192730cfd02bSAntonio Quartulli 	    batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
192830cfd02bSAntonio Quartulli 		purge = true;
192930cfd02bSAntonio Quartulli 		*msg = "Roaming timeout\n";
193042d0b044SSven Eckelmann 	}
193142d0b044SSven Eckelmann 
193230cfd02bSAntonio Quartulli 	if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
193330cfd02bSAntonio Quartulli 	    batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
193430cfd02bSAntonio Quartulli 		purge = true;
193530cfd02bSAntonio Quartulli 		*msg = "Temporary client timeout\n";
193630cfd02bSAntonio Quartulli 	}
193730cfd02bSAntonio Quartulli 
193830cfd02bSAntonio Quartulli 	return purge;
193930cfd02bSAntonio Quartulli }
194030cfd02bSAntonio Quartulli 
194130cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
194242d0b044SSven Eckelmann {
1943807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
194442d0b044SSven Eckelmann 	struct hlist_head *head;
1945b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
194642d0b044SSven Eckelmann 	spinlock_t *list_lock; /* protects write access to the hash lists */
19476b5e971aSSven Eckelmann 	u32 i;
194830cfd02bSAntonio Quartulli 	char *msg = NULL;
194930cfd02bSAntonio Quartulli 	struct batadv_tt_common_entry *tt_common;
195030cfd02bSAntonio Quartulli 	struct batadv_tt_global_entry *tt_global;
195142d0b044SSven Eckelmann 
195242d0b044SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
195342d0b044SSven Eckelmann 		head = &hash->table[i];
195442d0b044SSven Eckelmann 		list_lock = &hash->list_locks[i];
195542d0b044SSven Eckelmann 
195642d0b044SSven Eckelmann 		spin_lock_bh(list_lock);
1957b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common, node_tmp, head,
195830cfd02bSAntonio Quartulli 					  hash_entry) {
195930cfd02bSAntonio Quartulli 			tt_global = container_of(tt_common,
196030cfd02bSAntonio Quartulli 						 struct batadv_tt_global_entry,
196130cfd02bSAntonio Quartulli 						 common);
196230cfd02bSAntonio Quartulli 
196330cfd02bSAntonio Quartulli 			if (!batadv_tt_global_to_purge(tt_global, &msg))
196430cfd02bSAntonio Quartulli 				continue;
196530cfd02bSAntonio Quartulli 
196630cfd02bSAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
196716052789SAntonio Quartulli 				   "Deleting global tt entry %pM (vid: %d): %s\n",
196816052789SAntonio Quartulli 				   tt_global->common.addr,
196916052789SAntonio Quartulli 				   BATADV_PRINT_VID(tt_global->common.vid),
197016052789SAntonio Quartulli 				   msg);
197130cfd02bSAntonio Quartulli 
1972b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common->hash_entry);
197330cfd02bSAntonio Quartulli 
197430cfd02bSAntonio Quartulli 			batadv_tt_global_entry_free_ref(tt_global);
197530cfd02bSAntonio Quartulli 		}
19767683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
1977cc47f66eSAntonio Quartulli 	}
1978cc47f66eSAntonio Quartulli }
1979cc47f66eSAntonio Quartulli 
198056303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
1981c6c8fea2SSven Eckelmann {
19825bf74e9cSSven Eckelmann 	struct batadv_hashtable *hash;
19837683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
198456303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
198556303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
1986b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
19877683fdc1SAntonio Quartulli 	struct hlist_head *head;
19886b5e971aSSven Eckelmann 	u32 i;
19897683fdc1SAntonio Quartulli 
1990807736f6SSven Eckelmann 	if (!bat_priv->tt.global_hash)
1991c6c8fea2SSven Eckelmann 		return;
1992c6c8fea2SSven Eckelmann 
1993807736f6SSven Eckelmann 	hash = bat_priv->tt.global_hash;
19947683fdc1SAntonio Quartulli 
19957683fdc1SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
19967683fdc1SAntonio Quartulli 		head = &hash->table[i];
19977683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
19987683fdc1SAntonio Quartulli 
19997683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
2000b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, node_tmp,
20017683fdc1SAntonio Quartulli 					  head, hash_entry) {
2002b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common_entry->hash_entry);
200356303d34SSven Eckelmann 			tt_global = container_of(tt_common_entry,
200456303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
200548100bacSAntonio Quartulli 						 common);
200656303d34SSven Eckelmann 			batadv_tt_global_entry_free_ref(tt_global);
20077683fdc1SAntonio Quartulli 		}
20087683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
20097683fdc1SAntonio Quartulli 	}
20107683fdc1SAntonio Quartulli 
20111a8eaf07SSven Eckelmann 	batadv_hash_destroy(hash);
20127683fdc1SAntonio Quartulli 
2013807736f6SSven Eckelmann 	bat_priv->tt.global_hash = NULL;
2014c6c8fea2SSven Eckelmann }
2015c6c8fea2SSven Eckelmann 
201656303d34SSven Eckelmann static bool
201756303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
201856303d34SSven Eckelmann 		       struct batadv_tt_global_entry *tt_global_entry)
201959b699cdSAntonio Quartulli {
202059b699cdSAntonio Quartulli 	bool ret = false;
202159b699cdSAntonio Quartulli 
2022acd34afaSSven Eckelmann 	if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
2023acd34afaSSven Eckelmann 	    tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
202459b699cdSAntonio Quartulli 		ret = true;
202559b699cdSAntonio Quartulli 
20262d2fcc2aSAntonio Quartulli 	/* check if the two clients are marked as isolated */
20272d2fcc2aSAntonio Quartulli 	if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
20282d2fcc2aSAntonio Quartulli 	    tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
20292d2fcc2aSAntonio Quartulli 		ret = true;
20302d2fcc2aSAntonio Quartulli 
203159b699cdSAntonio Quartulli 	return ret;
203259b699cdSAntonio Quartulli }
203359b699cdSAntonio Quartulli 
2034c018ad3dSAntonio Quartulli /**
2035c018ad3dSAntonio Quartulli  * batadv_transtable_search - get the mesh destination for a given client
2036c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2037c018ad3dSAntonio Quartulli  * @src: mac address of the source client
2038c018ad3dSAntonio Quartulli  * @addr: mac address of the destination client
2039c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
2040c018ad3dSAntonio Quartulli  *
204162fe710fSSven Eckelmann  * Return: a pointer to the originator that was selected as destination in the
2042c018ad3dSAntonio Quartulli  * mesh for contacting the client 'addr', NULL otherwise.
2043c018ad3dSAntonio Quartulli  * In case of multiple originators serving the same client, the function returns
2044c018ad3dSAntonio Quartulli  * the best one (best in terms of metric towards the destination node).
2045c018ad3dSAntonio Quartulli  *
2046c018ad3dSAntonio Quartulli  * If the two clients are AP isolated the function returns NULL.
2047c018ad3dSAntonio Quartulli  */
204856303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
20496b5e971aSSven Eckelmann 						  const u8 *src,
20506b5e971aSSven Eckelmann 						  const u8 *addr,
2051c018ad3dSAntonio Quartulli 						  unsigned short vid)
2052c6c8fea2SSven Eckelmann {
205356303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry = NULL;
205456303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry = NULL;
205556303d34SSven Eckelmann 	struct batadv_orig_node *orig_node = NULL;
2056981d8900SSven Eckelmann 	struct batadv_tt_orig_list_entry *best_entry;
2057c6c8fea2SSven Eckelmann 
2058eceb22aeSAntonio Quartulli 	if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
2059c018ad3dSAntonio Quartulli 		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
2060068ee6e2SAntonio Quartulli 		if (!tt_local_entry ||
2061068ee6e2SAntonio Quartulli 		    (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
20623d393e47SAntonio Quartulli 			goto out;
20633d393e47SAntonio Quartulli 	}
20647aadf889SMarek Lindner 
2065c018ad3dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
20662dafb49dSAntonio Quartulli 	if (!tt_global_entry)
20677b36e8eeSMarek Lindner 		goto out;
2068c6c8fea2SSven Eckelmann 
20693d393e47SAntonio Quartulli 	/* check whether the clients should not communicate due to AP
20709cfc7bd6SSven Eckelmann 	 * isolation
20719cfc7bd6SSven Eckelmann 	 */
2072a513088dSSven Eckelmann 	if (tt_local_entry &&
2073a513088dSSven Eckelmann 	    _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
20743d393e47SAntonio Quartulli 		goto out;
20753d393e47SAntonio Quartulli 
2076db08e6e5SSimon Wunderlich 	rcu_read_lock();
20774627456aSAntonio Quartulli 	best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
2078db08e6e5SSimon Wunderlich 	/* found anything? */
2079981d8900SSven Eckelmann 	if (best_entry)
2080981d8900SSven Eckelmann 		orig_node = best_entry->orig_node;
2081db08e6e5SSimon Wunderlich 	if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
2082db08e6e5SSimon Wunderlich 		orig_node = NULL;
2083db08e6e5SSimon Wunderlich 	rcu_read_unlock();
2084981d8900SSven Eckelmann 
20857b36e8eeSMarek Lindner out:
20863d393e47SAntonio Quartulli 	if (tt_global_entry)
2087a513088dSSven Eckelmann 		batadv_tt_global_entry_free_ref(tt_global_entry);
20883d393e47SAntonio Quartulli 	if (tt_local_entry)
2089a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(tt_local_entry);
20903d393e47SAntonio Quartulli 
20917b36e8eeSMarek Lindner 	return orig_node;
2092c6c8fea2SSven Eckelmann }
2093a73105b8SAntonio Quartulli 
2094ced72933SAntonio Quartulli /**
2095ced72933SAntonio Quartulli  * batadv_tt_global_crc - calculates the checksum of the local table belonging
2096ced72933SAntonio Quartulli  *  to the given orig_node
2097ced72933SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
20980ffa9e8dSAntonio Quartulli  * @orig_node: originator for which the CRC should be computed
20997ea7b4a1SAntonio Quartulli  * @vid: VLAN identifier for which the CRC32 has to be computed
21000ffa9e8dSAntonio Quartulli  *
21010ffa9e8dSAntonio Quartulli  * This function computes the checksum for the global table corresponding to a
21020ffa9e8dSAntonio Quartulli  * specific originator. In particular, the checksum is computed as follows: For
21030ffa9e8dSAntonio Quartulli  * each client connected to the originator the CRC32C of the MAC address and the
21040ffa9e8dSAntonio Quartulli  * VID is computed and then all the CRC32Cs of the various clients are xor'ed
21050ffa9e8dSAntonio Quartulli  * together.
21060ffa9e8dSAntonio Quartulli  *
21070ffa9e8dSAntonio Quartulli  * The idea behind is that CRC32C should be used as much as possible in order to
21080ffa9e8dSAntonio Quartulli  * produce a unique hash of the table, but since the order which is used to feed
21090ffa9e8dSAntonio Quartulli  * the CRC32C function affects the result and since every node in the network
21100ffa9e8dSAntonio Quartulli  * probably sorts the clients differently, the hash function cannot be directly
21110ffa9e8dSAntonio Quartulli  * computed over the entire table. Hence the CRC32C is used only on
21120ffa9e8dSAntonio Quartulli  * the single client entry, while all the results are then xor'ed together
21130ffa9e8dSAntonio Quartulli  * because the XOR operation can combine them all while trying to reduce the
21140ffa9e8dSAntonio Quartulli  * noise as much as possible.
21150ffa9e8dSAntonio Quartulli  *
211662fe710fSSven Eckelmann  * Return: the checksum of the global table of a given originator.
2117ced72933SAntonio Quartulli  */
21186b5e971aSSven Eckelmann static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
21197ea7b4a1SAntonio Quartulli 				struct batadv_orig_node *orig_node,
21207ea7b4a1SAntonio Quartulli 				unsigned short vid)
2121a73105b8SAntonio Quartulli {
2122807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
212356303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
212456303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
2125a73105b8SAntonio Quartulli 	struct hlist_head *head;
21266b5e971aSSven Eckelmann 	u32 i, crc_tmp, crc = 0;
21276b5e971aSSven Eckelmann 	u8 flags;
2128a30e22caSAntonio Quartulli 	__be16 tmp_vid;
2129a73105b8SAntonio Quartulli 
2130a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2131a73105b8SAntonio Quartulli 		head = &hash->table[i];
2132a73105b8SAntonio Quartulli 
2133a73105b8SAntonio Quartulli 		rcu_read_lock();
2134b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
213556303d34SSven Eckelmann 			tt_global = container_of(tt_common,
213656303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
213748100bacSAntonio Quartulli 						 common);
21387ea7b4a1SAntonio Quartulli 			/* compute the CRC only for entries belonging to the
21397ea7b4a1SAntonio Quartulli 			 * VLAN identified by the vid passed as parameter
21407ea7b4a1SAntonio Quartulli 			 */
21417ea7b4a1SAntonio Quartulli 			if (tt_common->vid != vid)
21427ea7b4a1SAntonio Quartulli 				continue;
21437ea7b4a1SAntonio Quartulli 
2144cc47f66eSAntonio Quartulli 			/* Roaming clients are in the global table for
2145cc47f66eSAntonio Quartulli 			 * consistency only. They don't have to be
2146cc47f66eSAntonio Quartulli 			 * taken into account while computing the
2147db08e6e5SSimon Wunderlich 			 * global crc
2148db08e6e5SSimon Wunderlich 			 */
2149acd34afaSSven Eckelmann 			if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
2150cc47f66eSAntonio Quartulli 				continue;
215130cfd02bSAntonio Quartulli 			/* Temporary clients have not been announced yet, so
215230cfd02bSAntonio Quartulli 			 * they have to be skipped while computing the global
215330cfd02bSAntonio Quartulli 			 * crc
215430cfd02bSAntonio Quartulli 			 */
215530cfd02bSAntonio Quartulli 			if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
215630cfd02bSAntonio Quartulli 				continue;
2157db08e6e5SSimon Wunderlich 
2158db08e6e5SSimon Wunderlich 			/* find out if this global entry is announced by this
2159db08e6e5SSimon Wunderlich 			 * originator
2160db08e6e5SSimon Wunderlich 			 */
216156303d34SSven Eckelmann 			if (!batadv_tt_global_entry_has_orig(tt_global,
2162db08e6e5SSimon Wunderlich 							     orig_node))
2163db08e6e5SSimon Wunderlich 				continue;
2164db08e6e5SSimon Wunderlich 
2165a30e22caSAntonio Quartulli 			/* use network order to read the VID: this ensures that
2166a30e22caSAntonio Quartulli 			 * every node reads the bytes in the same order.
2167a30e22caSAntonio Quartulli 			 */
2168a30e22caSAntonio Quartulli 			tmp_vid = htons(tt_common->vid);
2169a30e22caSAntonio Quartulli 			crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
21700eb01568SAntonio Quartulli 
21710eb01568SAntonio Quartulli 			/* compute the CRC on flags that have to be kept in sync
21720eb01568SAntonio Quartulli 			 * among nodes
21730eb01568SAntonio Quartulli 			 */
21740eb01568SAntonio Quartulli 			flags = tt_common->flags & BATADV_TT_SYNC_MASK;
21750eb01568SAntonio Quartulli 			crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
21760eb01568SAntonio Quartulli 
21770ffa9e8dSAntonio Quartulli 			crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
2178a73105b8SAntonio Quartulli 		}
2179a73105b8SAntonio Quartulli 		rcu_read_unlock();
2180a73105b8SAntonio Quartulli 	}
2181a73105b8SAntonio Quartulli 
2182ced72933SAntonio Quartulli 	return crc;
2183a73105b8SAntonio Quartulli }
2184a73105b8SAntonio Quartulli 
2185ced72933SAntonio Quartulli /**
2186ced72933SAntonio Quartulli  * batadv_tt_local_crc - calculates the checksum of the local table
2187ced72933SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
21887ea7b4a1SAntonio Quartulli  * @vid: VLAN identifier for which the CRC32 has to be computed
21890ffa9e8dSAntonio Quartulli  *
21900ffa9e8dSAntonio Quartulli  * For details about the computation, please refer to the documentation for
21910ffa9e8dSAntonio Quartulli  * batadv_tt_global_crc().
21920ffa9e8dSAntonio Quartulli  *
219362fe710fSSven Eckelmann  * Return: the checksum of the local table
2194ced72933SAntonio Quartulli  */
21956b5e971aSSven Eckelmann static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
21967ea7b4a1SAntonio Quartulli 			       unsigned short vid)
2197a73105b8SAntonio Quartulli {
2198807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
219956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
2200a73105b8SAntonio Quartulli 	struct hlist_head *head;
22016b5e971aSSven Eckelmann 	u32 i, crc_tmp, crc = 0;
22026b5e971aSSven Eckelmann 	u8 flags;
2203a30e22caSAntonio Quartulli 	__be16 tmp_vid;
2204a73105b8SAntonio Quartulli 
2205a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2206a73105b8SAntonio Quartulli 		head = &hash->table[i];
2207a73105b8SAntonio Quartulli 
2208a73105b8SAntonio Quartulli 		rcu_read_lock();
2209b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
22107ea7b4a1SAntonio Quartulli 			/* compute the CRC only for entries belonging to the
22117ea7b4a1SAntonio Quartulli 			 * VLAN identified by vid
22127ea7b4a1SAntonio Quartulli 			 */
22137ea7b4a1SAntonio Quartulli 			if (tt_common->vid != vid)
22147ea7b4a1SAntonio Quartulli 				continue;
22157ea7b4a1SAntonio Quartulli 
2216058d0e26SAntonio Quartulli 			/* not yet committed clients have not to be taken into
22179cfc7bd6SSven Eckelmann 			 * account while computing the CRC
22189cfc7bd6SSven Eckelmann 			 */
2219acd34afaSSven Eckelmann 			if (tt_common->flags & BATADV_TT_CLIENT_NEW)
2220058d0e26SAntonio Quartulli 				continue;
2221ced72933SAntonio Quartulli 
2222a30e22caSAntonio Quartulli 			/* use network order to read the VID: this ensures that
2223a30e22caSAntonio Quartulli 			 * every node reads the bytes in the same order.
2224a30e22caSAntonio Quartulli 			 */
2225a30e22caSAntonio Quartulli 			tmp_vid = htons(tt_common->vid);
2226a30e22caSAntonio Quartulli 			crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
22270eb01568SAntonio Quartulli 
22280eb01568SAntonio Quartulli 			/* compute the CRC on flags that have to be kept in sync
22290eb01568SAntonio Quartulli 			 * among nodes
22300eb01568SAntonio Quartulli 			 */
22310eb01568SAntonio Quartulli 			flags = tt_common->flags & BATADV_TT_SYNC_MASK;
22320eb01568SAntonio Quartulli 			crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
22330eb01568SAntonio Quartulli 
22340ffa9e8dSAntonio Quartulli 			crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
2235a73105b8SAntonio Quartulli 		}
2236a73105b8SAntonio Quartulli 		rcu_read_unlock();
2237a73105b8SAntonio Quartulli 	}
2238a73105b8SAntonio Quartulli 
2239ced72933SAntonio Quartulli 	return crc;
2240a73105b8SAntonio Quartulli }
2241a73105b8SAntonio Quartulli 
224256303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
2243a73105b8SAntonio Quartulli {
22447c26a53bSMarek Lindner 	struct batadv_tt_req_node *node;
22457c26a53bSMarek Lindner 	struct hlist_node *safe;
2246a73105b8SAntonio Quartulli 
2247807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
2248a73105b8SAntonio Quartulli 
22497c26a53bSMarek Lindner 	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
22507c26a53bSMarek Lindner 		hlist_del_init(&node->list);
2251a73105b8SAntonio Quartulli 		kfree(node);
2252a73105b8SAntonio Quartulli 	}
2253a73105b8SAntonio Quartulli 
2254807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
2255a73105b8SAntonio Quartulli }
2256a73105b8SAntonio Quartulli 
225756303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv,
225856303d34SSven Eckelmann 				       struct batadv_orig_node *orig_node,
2259e8cf234aSAntonio Quartulli 				       const void *tt_buff,
22606b5e971aSSven Eckelmann 				       u16 tt_buff_len)
2261a73105b8SAntonio Quartulli {
2262a73105b8SAntonio Quartulli 	/* Replace the old buffer only if I received something in the
22639cfc7bd6SSven Eckelmann 	 * last OGM (the OGM could carry no changes)
22649cfc7bd6SSven Eckelmann 	 */
2265a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
2266a73105b8SAntonio Quartulli 	if (tt_buff_len > 0) {
2267a73105b8SAntonio Quartulli 		kfree(orig_node->tt_buff);
2268a73105b8SAntonio Quartulli 		orig_node->tt_buff_len = 0;
2269a73105b8SAntonio Quartulli 		orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
2270a73105b8SAntonio Quartulli 		if (orig_node->tt_buff) {
2271a73105b8SAntonio Quartulli 			memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
2272a73105b8SAntonio Quartulli 			orig_node->tt_buff_len = tt_buff_len;
2273a73105b8SAntonio Quartulli 		}
2274a73105b8SAntonio Quartulli 	}
2275a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
2276a73105b8SAntonio Quartulli }
2277a73105b8SAntonio Quartulli 
227856303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv)
2279a73105b8SAntonio Quartulli {
22807c26a53bSMarek Lindner 	struct batadv_tt_req_node *node;
22817c26a53bSMarek Lindner 	struct hlist_node *safe;
2282a73105b8SAntonio Quartulli 
2283807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
22847c26a53bSMarek Lindner 	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
228542d0b044SSven Eckelmann 		if (batadv_has_timed_out(node->issued_at,
228642d0b044SSven Eckelmann 					 BATADV_TT_REQUEST_TIMEOUT)) {
22877c26a53bSMarek Lindner 			hlist_del_init(&node->list);
2288a73105b8SAntonio Quartulli 			kfree(node);
2289a73105b8SAntonio Quartulli 		}
2290a73105b8SAntonio Quartulli 	}
2291807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
2292a73105b8SAntonio Quartulli }
2293a73105b8SAntonio Quartulli 
2294383b8636SMarek Lindner /**
2295383b8636SMarek Lindner  * batadv_tt_req_node_new - search and possibly create a tt_req_node object
2296383b8636SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2297383b8636SMarek Lindner  * @orig_node: orig node this request is being issued for
2298383b8636SMarek Lindner  *
229962fe710fSSven Eckelmann  * Return: the pointer to the new tt_req_node struct if no request
2300383b8636SMarek Lindner  * has already been issued for this orig_node, NULL otherwise.
23019cfc7bd6SSven Eckelmann  */
230256303d34SSven Eckelmann static struct batadv_tt_req_node *
2303383b8636SMarek Lindner batadv_tt_req_node_new(struct batadv_priv *bat_priv,
230456303d34SSven Eckelmann 		       struct batadv_orig_node *orig_node)
2305a73105b8SAntonio Quartulli {
230656303d34SSven Eckelmann 	struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
2307a73105b8SAntonio Quartulli 
2308807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
23097c26a53bSMarek Lindner 	hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) {
23101eda58bfSSven Eckelmann 		if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
23111eda58bfSSven Eckelmann 		    !batadv_has_timed_out(tt_req_node_tmp->issued_at,
231242d0b044SSven Eckelmann 					  BATADV_TT_REQUEST_TIMEOUT))
2313a73105b8SAntonio Quartulli 			goto unlock;
2314a73105b8SAntonio Quartulli 	}
2315a73105b8SAntonio Quartulli 
2316a73105b8SAntonio Quartulli 	tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
2317a73105b8SAntonio Quartulli 	if (!tt_req_node)
2318a73105b8SAntonio Quartulli 		goto unlock;
2319a73105b8SAntonio Quartulli 
23208fdd0153SAntonio Quartulli 	ether_addr_copy(tt_req_node->addr, orig_node->orig);
2321a73105b8SAntonio Quartulli 	tt_req_node->issued_at = jiffies;
2322a73105b8SAntonio Quartulli 
23237c26a53bSMarek Lindner 	hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list);
2324a73105b8SAntonio Quartulli unlock:
2325807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
2326a73105b8SAntonio Quartulli 	return tt_req_node;
2327a73105b8SAntonio Quartulli }
2328a73105b8SAntonio Quartulli 
2329335fbe0fSMarek Lindner /**
2330335fbe0fSMarek Lindner  * batadv_tt_local_valid - verify that given tt entry is a valid one
2331335fbe0fSMarek Lindner  * @entry_ptr: to be checked local tt entry
2332335fbe0fSMarek Lindner  * @data_ptr: not used but definition required to satisfy the callback prototype
2333335fbe0fSMarek Lindner  *
233462fe710fSSven Eckelmann  * Return: 1 if the entry is a valid, 0 otherwise.
2335335fbe0fSMarek Lindner  */
2336335fbe0fSMarek Lindner static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr)
2337058d0e26SAntonio Quartulli {
233856303d34SSven Eckelmann 	const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
2339058d0e26SAntonio Quartulli 
2340acd34afaSSven Eckelmann 	if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
2341058d0e26SAntonio Quartulli 		return 0;
2342058d0e26SAntonio Quartulli 	return 1;
2343058d0e26SAntonio Quartulli }
2344058d0e26SAntonio Quartulli 
2345a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr,
2346a513088dSSven Eckelmann 				  const void *data_ptr)
2347a73105b8SAntonio Quartulli {
234856303d34SSven Eckelmann 	const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
234956303d34SSven Eckelmann 	const struct batadv_tt_global_entry *tt_global_entry;
235056303d34SSven Eckelmann 	const struct batadv_orig_node *orig_node = data_ptr;
2351a73105b8SAntonio Quartulli 
235230cfd02bSAntonio Quartulli 	if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
235330cfd02bSAntonio Quartulli 	    tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
2354cc47f66eSAntonio Quartulli 		return 0;
2355cc47f66eSAntonio Quartulli 
235656303d34SSven Eckelmann 	tt_global_entry = container_of(tt_common_entry,
235756303d34SSven Eckelmann 				       struct batadv_tt_global_entry,
235848100bacSAntonio Quartulli 				       common);
235948100bacSAntonio Quartulli 
2360a513088dSSven Eckelmann 	return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node);
2361a73105b8SAntonio Quartulli }
2362a73105b8SAntonio Quartulli 
2363335fbe0fSMarek Lindner /**
23647ea7b4a1SAntonio Quartulli  * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the
23657ea7b4a1SAntonio Quartulli  *  specified tt hash
2366335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2367335fbe0fSMarek Lindner  * @hash: hash table containing the tt entries
2368335fbe0fSMarek Lindner  * @tt_len: expected tvlv tt data buffer length in number of bytes
23697ea7b4a1SAntonio Quartulli  * @tvlv_buff: pointer to the buffer to fill with the TT data
2370335fbe0fSMarek Lindner  * @valid_cb: function to filter tt change entries
2371335fbe0fSMarek Lindner  * @cb_data: data passed to the filter function as argument
2372335fbe0fSMarek Lindner  */
23737ea7b4a1SAntonio Quartulli static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
23747ea7b4a1SAntonio Quartulli 				    struct batadv_hashtable *hash,
23756b5e971aSSven Eckelmann 				    void *tvlv_buff, u16 tt_len,
2376a513088dSSven Eckelmann 				    int (*valid_cb)(const void *, const void *),
2377a73105b8SAntonio Quartulli 				    void *cb_data)
2378a73105b8SAntonio Quartulli {
237956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
2380335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
2381a73105b8SAntonio Quartulli 	struct hlist_head *head;
23826b5e971aSSven Eckelmann 	u16 tt_tot, tt_num_entries = 0;
23836b5e971aSSven Eckelmann 	u32 i;
2384a73105b8SAntonio Quartulli 
2385298e6e68SAntonio Quartulli 	tt_tot = batadv_tt_entries(tt_len);
23867ea7b4a1SAntonio Quartulli 	tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff;
2387a73105b8SAntonio Quartulli 
2388a73105b8SAntonio Quartulli 	rcu_read_lock();
2389a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2390a73105b8SAntonio Quartulli 		head = &hash->table[i];
2391a73105b8SAntonio Quartulli 
2392b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
2393a73105b8SAntonio Quartulli 					 head, hash_entry) {
2394335fbe0fSMarek Lindner 			if (tt_tot == tt_num_entries)
2395a73105b8SAntonio Quartulli 				break;
2396a73105b8SAntonio Quartulli 
239748100bacSAntonio Quartulli 			if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
2398a73105b8SAntonio Quartulli 				continue;
2399a73105b8SAntonio Quartulli 
24008fdd0153SAntonio Quartulli 			ether_addr_copy(tt_change->addr, tt_common_entry->addr);
240127b37ebfSAntonio Quartulli 			tt_change->flags = tt_common_entry->flags;
2402c018ad3dSAntonio Quartulli 			tt_change->vid = htons(tt_common_entry->vid);
2403ca663046SAntonio Quartulli 			memset(tt_change->reserved, 0,
2404ca663046SAntonio Quartulli 			       sizeof(tt_change->reserved));
2405a73105b8SAntonio Quartulli 
2406335fbe0fSMarek Lindner 			tt_num_entries++;
2407a73105b8SAntonio Quartulli 			tt_change++;
2408a73105b8SAntonio Quartulli 		}
2409a73105b8SAntonio Quartulli 	}
2410a73105b8SAntonio Quartulli 	rcu_read_unlock();
24117ea7b4a1SAntonio Quartulli }
2412a73105b8SAntonio Quartulli 
24137ea7b4a1SAntonio Quartulli /**
24147ea7b4a1SAntonio Quartulli  * batadv_tt_global_check_crc - check if all the CRCs are correct
24157ea7b4a1SAntonio Quartulli  * @orig_node: originator for which the CRCs have to be checked
24167ea7b4a1SAntonio Quartulli  * @tt_vlan: pointer to the first tvlv VLAN entry
24177ea7b4a1SAntonio Quartulli  * @num_vlan: number of tvlv VLAN entries
24187ea7b4a1SAntonio Quartulli  *
241962fe710fSSven Eckelmann  * Return: true if all the received CRCs match the locally stored ones, false
24207ea7b4a1SAntonio Quartulli  * otherwise
24217ea7b4a1SAntonio Quartulli  */
24227ea7b4a1SAntonio Quartulli static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
24237ea7b4a1SAntonio Quartulli 				       struct batadv_tvlv_tt_vlan_data *tt_vlan,
24246b5e971aSSven Eckelmann 				       u16 num_vlan)
24257ea7b4a1SAntonio Quartulli {
24267ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
24277ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
2428c169c59dSSimon Wunderlich 	int i, orig_num_vlan;
24296b5e971aSSven Eckelmann 	u32 crc;
24307ea7b4a1SAntonio Quartulli 
24317ea7b4a1SAntonio Quartulli 	/* check if each received CRC matches the locally stored one */
24327ea7b4a1SAntonio Quartulli 	for (i = 0; i < num_vlan; i++) {
24337ea7b4a1SAntonio Quartulli 		tt_vlan_tmp = tt_vlan + i;
24347ea7b4a1SAntonio Quartulli 
24357ea7b4a1SAntonio Quartulli 		/* if orig_node is a backbone node for this VLAN, don't check
24367ea7b4a1SAntonio Quartulli 		 * the CRC as we ignore all the global entries over it
24377ea7b4a1SAntonio Quartulli 		 */
24387ea7b4a1SAntonio Quartulli 		if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv,
2439cfd4f757SAntonio Quartulli 						   orig_node->orig,
2440cfd4f757SAntonio Quartulli 						   ntohs(tt_vlan_tmp->vid)))
24417ea7b4a1SAntonio Quartulli 			continue;
24427ea7b4a1SAntonio Quartulli 
24437ea7b4a1SAntonio Quartulli 		vlan = batadv_orig_node_vlan_get(orig_node,
24447ea7b4a1SAntonio Quartulli 						 ntohs(tt_vlan_tmp->vid));
24457ea7b4a1SAntonio Quartulli 		if (!vlan)
24467ea7b4a1SAntonio Quartulli 			return false;
24477ea7b4a1SAntonio Quartulli 
244891c2b1a9SAntonio Quartulli 		crc = vlan->tt.crc;
244991c2b1a9SAntonio Quartulli 		batadv_orig_node_vlan_free_ref(vlan);
245091c2b1a9SAntonio Quartulli 
245191c2b1a9SAntonio Quartulli 		if (crc != ntohl(tt_vlan_tmp->crc))
24527ea7b4a1SAntonio Quartulli 			return false;
24537ea7b4a1SAntonio Quartulli 	}
24547ea7b4a1SAntonio Quartulli 
2455c169c59dSSimon Wunderlich 	/* check if any excess VLANs exist locally for the originator
2456c169c59dSSimon Wunderlich 	 * which are not mentioned in the TVLV from the originator.
2457c169c59dSSimon Wunderlich 	 */
2458c169c59dSSimon Wunderlich 	rcu_read_lock();
2459c169c59dSSimon Wunderlich 	orig_num_vlan = 0;
2460c169c59dSSimon Wunderlich 	hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list)
2461c169c59dSSimon Wunderlich 		orig_num_vlan++;
2462c169c59dSSimon Wunderlich 	rcu_read_unlock();
2463c169c59dSSimon Wunderlich 
2464c169c59dSSimon Wunderlich 	if (orig_num_vlan > num_vlan)
2465c169c59dSSimon Wunderlich 		return false;
2466c169c59dSSimon Wunderlich 
24677ea7b4a1SAntonio Quartulli 	return true;
24687ea7b4a1SAntonio Quartulli }
24697ea7b4a1SAntonio Quartulli 
24707ea7b4a1SAntonio Quartulli /**
24717ea7b4a1SAntonio Quartulli  * batadv_tt_local_update_crc - update all the local CRCs
24727ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
24737ea7b4a1SAntonio Quartulli  */
24747ea7b4a1SAntonio Quartulli static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv)
24757ea7b4a1SAntonio Quartulli {
24767ea7b4a1SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
24777ea7b4a1SAntonio Quartulli 
24787ea7b4a1SAntonio Quartulli 	/* recompute the global CRC for each VLAN */
24797ea7b4a1SAntonio Quartulli 	rcu_read_lock();
24807ea7b4a1SAntonio Quartulli 	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
24817ea7b4a1SAntonio Quartulli 		vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid);
24827ea7b4a1SAntonio Quartulli 	}
24837ea7b4a1SAntonio Quartulli 	rcu_read_unlock();
24847ea7b4a1SAntonio Quartulli }
24857ea7b4a1SAntonio Quartulli 
24867ea7b4a1SAntonio Quartulli /**
24877ea7b4a1SAntonio Quartulli  * batadv_tt_global_update_crc - update all the global CRCs for this orig_node
24887ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
24897ea7b4a1SAntonio Quartulli  * @orig_node: the orig_node for which the CRCs have to be updated
24907ea7b4a1SAntonio Quartulli  */
24917ea7b4a1SAntonio Quartulli static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
24927ea7b4a1SAntonio Quartulli 					struct batadv_orig_node *orig_node)
24937ea7b4a1SAntonio Quartulli {
24947ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
24956b5e971aSSven Eckelmann 	u32 crc;
24967ea7b4a1SAntonio Quartulli 
24977ea7b4a1SAntonio Quartulli 	/* recompute the global CRC for each VLAN */
24987ea7b4a1SAntonio Quartulli 	rcu_read_lock();
2499d0fa4f3fSMarek Lindner 	hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
25007ea7b4a1SAntonio Quartulli 		/* if orig_node is a backbone node for this VLAN, don't compute
25017ea7b4a1SAntonio Quartulli 		 * the CRC as we ignore all the global entries over it
25027ea7b4a1SAntonio Quartulli 		 */
2503cfd4f757SAntonio Quartulli 		if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig,
2504cfd4f757SAntonio Quartulli 						   vlan->vid))
25057ea7b4a1SAntonio Quartulli 			continue;
25067ea7b4a1SAntonio Quartulli 
25077ea7b4a1SAntonio Quartulli 		crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid);
25087ea7b4a1SAntonio Quartulli 		vlan->tt.crc = crc;
25097ea7b4a1SAntonio Quartulli 	}
25107ea7b4a1SAntonio Quartulli 	rcu_read_unlock();
2511a73105b8SAntonio Quartulli }
2512a73105b8SAntonio Quartulli 
2513ced72933SAntonio Quartulli /**
2514ced72933SAntonio Quartulli  * batadv_send_tt_request - send a TT Request message to a given node
2515ced72933SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2516ced72933SAntonio Quartulli  * @dst_orig_node: the destination of the message
2517ced72933SAntonio Quartulli  * @ttvn: the version number that the source of the message is looking for
25187ea7b4a1SAntonio Quartulli  * @tt_vlan: pointer to the first tvlv VLAN object to request
25197ea7b4a1SAntonio Quartulli  * @num_vlan: number of tvlv VLAN entries
2520ced72933SAntonio Quartulli  * @full_table: ask for the entire translation table if true, while only for the
2521ced72933SAntonio Quartulli  *  last TT diff otherwise
2522ced72933SAntonio Quartulli  */
252356303d34SSven Eckelmann static int batadv_send_tt_request(struct batadv_priv *bat_priv,
252456303d34SSven Eckelmann 				  struct batadv_orig_node *dst_orig_node,
25256b5e971aSSven Eckelmann 				  u8 ttvn,
25267ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_vlan_data *tt_vlan,
25276b5e971aSSven Eckelmann 				  u16 num_vlan, bool full_table)
2528a73105b8SAntonio Quartulli {
2529335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
253056303d34SSven Eckelmann 	struct batadv_tt_req_node *tt_req_node = NULL;
25317ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan_req;
25327ea7b4a1SAntonio Quartulli 	struct batadv_hard_iface *primary_if;
2533335fbe0fSMarek Lindner 	bool ret = false;
25347ea7b4a1SAntonio Quartulli 	int i, size;
2535a73105b8SAntonio Quartulli 
2536e5d89254SSven Eckelmann 	primary_if = batadv_primary_if_get_selected(bat_priv);
2537a73105b8SAntonio Quartulli 	if (!primary_if)
2538a73105b8SAntonio Quartulli 		goto out;
2539a73105b8SAntonio Quartulli 
2540a73105b8SAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
25419cfc7bd6SSven Eckelmann 	 * reply from the same orig_node yet
25429cfc7bd6SSven Eckelmann 	 */
2543383b8636SMarek Lindner 	tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node);
2544a73105b8SAntonio Quartulli 	if (!tt_req_node)
2545a73105b8SAntonio Quartulli 		goto out;
2546a73105b8SAntonio Quartulli 
25477ea7b4a1SAntonio Quartulli 	size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan;
25487ea7b4a1SAntonio Quartulli 	tvlv_tt_data = kzalloc(size, GFP_ATOMIC);
2549335fbe0fSMarek Lindner 	if (!tvlv_tt_data)
2550a73105b8SAntonio Quartulli 		goto out;
2551a73105b8SAntonio Quartulli 
2552335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_REQUEST;
2553335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = ttvn;
25547ea7b4a1SAntonio Quartulli 	tvlv_tt_data->num_vlan = htons(num_vlan);
25557ea7b4a1SAntonio Quartulli 
25567ea7b4a1SAntonio Quartulli 	/* send all the CRCs within the request. This is needed by intermediate
25577ea7b4a1SAntonio Quartulli 	 * nodes to ensure they have the correct table before replying
25587ea7b4a1SAntonio Quartulli 	 */
25597ea7b4a1SAntonio Quartulli 	tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1);
25607ea7b4a1SAntonio Quartulli 	for (i = 0; i < num_vlan; i++) {
25617ea7b4a1SAntonio Quartulli 		tt_vlan_req->vid = tt_vlan->vid;
25627ea7b4a1SAntonio Quartulli 		tt_vlan_req->crc = tt_vlan->crc;
25637ea7b4a1SAntonio Quartulli 
25647ea7b4a1SAntonio Quartulli 		tt_vlan_req++;
25657ea7b4a1SAntonio Quartulli 		tt_vlan++;
25667ea7b4a1SAntonio Quartulli 	}
2567a73105b8SAntonio Quartulli 
2568a73105b8SAntonio Quartulli 	if (full_table)
2569335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
2570a73105b8SAntonio Quartulli 
2571bb351ba0SMartin Hundebøll 	batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n",
2572335fbe0fSMarek Lindner 		   dst_orig_node->orig, full_table ? 'F' : '.');
2573a73105b8SAntonio Quartulli 
2574d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX);
2575335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
2576335fbe0fSMarek Lindner 				 dst_orig_node->orig, BATADV_TVLV_TT, 1,
25777ea7b4a1SAntonio Quartulli 				 tvlv_tt_data, size);
2578335fbe0fSMarek Lindner 	ret = true;
2579a73105b8SAntonio Quartulli 
2580a73105b8SAntonio Quartulli out:
2581a73105b8SAntonio Quartulli 	if (primary_if)
2582e5d89254SSven Eckelmann 		batadv_hardif_free_ref(primary_if);
2583a73105b8SAntonio Quartulli 	if (ret && tt_req_node) {
2584807736f6SSven Eckelmann 		spin_lock_bh(&bat_priv->tt.req_list_lock);
25857c26a53bSMarek Lindner 		/* hlist_del_init() verifies tt_req_node still is in the list */
25867c26a53bSMarek Lindner 		hlist_del_init(&tt_req_node->list);
2587807736f6SSven Eckelmann 		spin_unlock_bh(&bat_priv->tt.req_list_lock);
2588a73105b8SAntonio Quartulli 		kfree(tt_req_node);
2589a73105b8SAntonio Quartulli 	}
2590335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
2591a73105b8SAntonio Quartulli 	return ret;
2592a73105b8SAntonio Quartulli }
2593a73105b8SAntonio Quartulli 
2594335fbe0fSMarek Lindner /**
2595335fbe0fSMarek Lindner  * batadv_send_other_tt_response - send reply to tt request concerning another
2596335fbe0fSMarek Lindner  *  node's translation table
2597335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2598335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
2599335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
2600335fbe0fSMarek Lindner  * @req_dst: mac address of tt request recipient
2601335fbe0fSMarek Lindner  *
260262fe710fSSven Eckelmann  * Return: true if tt request reply was sent, false otherwise.
2603335fbe0fSMarek Lindner  */
2604335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
2605335fbe0fSMarek Lindner 					  struct batadv_tvlv_tt_data *tt_data,
26066b5e971aSSven Eckelmann 					  u8 *req_src, u8 *req_dst)
2607a73105b8SAntonio Quartulli {
2608170173bfSSven Eckelmann 	struct batadv_orig_node *req_dst_orig_node;
260956303d34SSven Eckelmann 	struct batadv_orig_node *res_dst_orig_node = NULL;
26107ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_change *tt_change;
2611335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
26127ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
2613335fbe0fSMarek Lindner 	bool ret = false, full_table;
26146b5e971aSSven Eckelmann 	u8 orig_ttvn, req_ttvn;
26156b5e971aSSven Eckelmann 	u16 tvlv_len;
26166b5e971aSSven Eckelmann 	s32 tt_len;
2617a73105b8SAntonio Quartulli 
261839c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
261986ceb360SSven Eckelmann 		   "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
2620335fbe0fSMarek Lindner 		   req_src, tt_data->ttvn, req_dst,
2621a2f2b6cdSSven Eckelmann 		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
2622a73105b8SAntonio Quartulli 
2623a73105b8SAntonio Quartulli 	/* Let's get the orig node of the REAL destination */
2624335fbe0fSMarek Lindner 	req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst);
2625a73105b8SAntonio Quartulli 	if (!req_dst_orig_node)
2626a73105b8SAntonio Quartulli 		goto out;
2627a73105b8SAntonio Quartulli 
2628335fbe0fSMarek Lindner 	res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src);
2629a73105b8SAntonio Quartulli 	if (!res_dst_orig_node)
2630a73105b8SAntonio Quartulli 		goto out;
2631a73105b8SAntonio Quartulli 
26326b5e971aSSven Eckelmann 	orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn);
2633335fbe0fSMarek Lindner 	req_ttvn = tt_data->ttvn;
2634a73105b8SAntonio Quartulli 
26357ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
2636335fbe0fSMarek Lindner 	/* this node doesn't have the requested data */
2637a73105b8SAntonio Quartulli 	if (orig_ttvn != req_ttvn ||
26387ea7b4a1SAntonio Quartulli 	    !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan,
26397ea7b4a1SAntonio Quartulli 					ntohs(tt_data->num_vlan)))
2640a73105b8SAntonio Quartulli 		goto out;
2641a73105b8SAntonio Quartulli 
2642015758d0SAntonio Quartulli 	/* If the full table has been explicitly requested */
2643335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE ||
2644a73105b8SAntonio Quartulli 	    !req_dst_orig_node->tt_buff)
2645a73105b8SAntonio Quartulli 		full_table = true;
2646a73105b8SAntonio Quartulli 	else
2647a73105b8SAntonio Quartulli 		full_table = false;
2648a73105b8SAntonio Quartulli 
2649335fbe0fSMarek Lindner 	/* TT fragmentation hasn't been implemented yet, so send as many
2650335fbe0fSMarek Lindner 	 * TT entries fit a single packet as possible only
26519cfc7bd6SSven Eckelmann 	 */
2652a73105b8SAntonio Quartulli 	if (!full_table) {
2653a73105b8SAntonio Quartulli 		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
2654a73105b8SAntonio Quartulli 		tt_len = req_dst_orig_node->tt_buff_len;
2655a73105b8SAntonio Quartulli 
26567ea7b4a1SAntonio Quartulli 		tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
26577ea7b4a1SAntonio Quartulli 							      &tvlv_tt_data,
26587ea7b4a1SAntonio Quartulli 							      &tt_change,
26597ea7b4a1SAntonio Quartulli 							      &tt_len);
26607ea7b4a1SAntonio Quartulli 		if (!tt_len)
2661a73105b8SAntonio Quartulli 			goto unlock;
2662a73105b8SAntonio Quartulli 
2663a73105b8SAntonio Quartulli 		/* Copy the last orig_node's OGM buffer */
26647ea7b4a1SAntonio Quartulli 		memcpy(tt_change, req_dst_orig_node->tt_buff,
2665a73105b8SAntonio Quartulli 		       req_dst_orig_node->tt_buff_len);
2666a73105b8SAntonio Quartulli 		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
2667a73105b8SAntonio Quartulli 	} else {
26687ea7b4a1SAntonio Quartulli 		/* allocate the tvlv, put the tt_data and all the tt_vlan_data
26697ea7b4a1SAntonio Quartulli 		 * in the initial part
26707ea7b4a1SAntonio Quartulli 		 */
26717ea7b4a1SAntonio Quartulli 		tt_len = -1;
26727ea7b4a1SAntonio Quartulli 		tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
26737ea7b4a1SAntonio Quartulli 							      &tvlv_tt_data,
26747ea7b4a1SAntonio Quartulli 							      &tt_change,
26757ea7b4a1SAntonio Quartulli 							      &tt_len);
26767ea7b4a1SAntonio Quartulli 		if (!tt_len)
26777ea7b4a1SAntonio Quartulli 			goto out;
2678a73105b8SAntonio Quartulli 
26797ea7b4a1SAntonio Quartulli 		/* fill the rest of the tvlv with the real TT entries */
26807ea7b4a1SAntonio Quartulli 		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash,
26817ea7b4a1SAntonio Quartulli 					tt_change, tt_len,
2682a513088dSSven Eckelmann 					batadv_tt_global_valid,
2683a73105b8SAntonio Quartulli 					req_dst_orig_node);
2684a73105b8SAntonio Quartulli 	}
2685a73105b8SAntonio Quartulli 
2686a19d3d85SMarek Lindner 	/* Don't send the response, if larger than fragmented packet. */
2687a19d3d85SMarek Lindner 	tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
2688a19d3d85SMarek Lindner 	if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
2689a19d3d85SMarek Lindner 		net_ratelimited_function(batadv_info, bat_priv->soft_iface,
2690a19d3d85SMarek Lindner 					 "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
2691a19d3d85SMarek Lindner 					 res_dst_orig_node->orig);
2692a19d3d85SMarek Lindner 		goto out;
2693a19d3d85SMarek Lindner 	}
2694a19d3d85SMarek Lindner 
2695335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
2696335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = req_ttvn;
2697a73105b8SAntonio Quartulli 
2698a73105b8SAntonio Quartulli 	if (full_table)
2699335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
2700a73105b8SAntonio Quartulli 
270139c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
2702335fbe0fSMarek Lindner 		   "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n",
2703335fbe0fSMarek Lindner 		   res_dst_orig_node->orig, req_dst_orig_node->orig,
2704335fbe0fSMarek Lindner 		   full_table ? 'F' : '.', req_ttvn);
2705a73105b8SAntonio Quartulli 
2706d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
2707f8214865SMartin Hundebøll 
2708335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig,
27097ea7b4a1SAntonio Quartulli 				 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
27107ea7b4a1SAntonio Quartulli 				 tvlv_len);
2711e91ecfc6SMartin Hundebøll 
2712335fbe0fSMarek Lindner 	ret = true;
2713a73105b8SAntonio Quartulli 	goto out;
2714a73105b8SAntonio Quartulli 
2715a73105b8SAntonio Quartulli unlock:
2716a73105b8SAntonio Quartulli 	spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
2717a73105b8SAntonio Quartulli 
2718a73105b8SAntonio Quartulli out:
2719a73105b8SAntonio Quartulli 	if (res_dst_orig_node)
27207d211efcSSven Eckelmann 		batadv_orig_node_free_ref(res_dst_orig_node);
2721a73105b8SAntonio Quartulli 	if (req_dst_orig_node)
27227d211efcSSven Eckelmann 		batadv_orig_node_free_ref(req_dst_orig_node);
2723335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
2724a73105b8SAntonio Quartulli 	return ret;
2725a73105b8SAntonio Quartulli }
272696412690SSven Eckelmann 
2727335fbe0fSMarek Lindner /**
2728335fbe0fSMarek Lindner  * batadv_send_my_tt_response - send reply to tt request concerning this node's
2729335fbe0fSMarek Lindner  *  translation table
2730335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2731335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
2732335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
2733335fbe0fSMarek Lindner  *
273462fe710fSSven Eckelmann  * Return: true if tt request reply was sent, false otherwise.
2735335fbe0fSMarek Lindner  */
2736335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
2737335fbe0fSMarek Lindner 				       struct batadv_tvlv_tt_data *tt_data,
27386b5e971aSSven Eckelmann 				       u8 *req_src)
2739a73105b8SAntonio Quartulli {
2740335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
274156303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if = NULL;
27427ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_change *tt_change;
27437ea7b4a1SAntonio Quartulli 	struct batadv_orig_node *orig_node;
27446b5e971aSSven Eckelmann 	u8 my_ttvn, req_ttvn;
27456b5e971aSSven Eckelmann 	u16 tvlv_len;
2746a73105b8SAntonio Quartulli 	bool full_table;
27476b5e971aSSven Eckelmann 	s32 tt_len;
2748a73105b8SAntonio Quartulli 
274939c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
275086ceb360SSven Eckelmann 		   "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
2751335fbe0fSMarek Lindner 		   req_src, tt_data->ttvn,
2752a2f2b6cdSSven Eckelmann 		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
2753a73105b8SAntonio Quartulli 
2754a70a9aa9SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt.commit_lock);
2755a73105b8SAntonio Quartulli 
27566b5e971aSSven Eckelmann 	my_ttvn = (u8)atomic_read(&bat_priv->tt.vn);
2757335fbe0fSMarek Lindner 	req_ttvn = tt_data->ttvn;
2758a73105b8SAntonio Quartulli 
2759335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, req_src);
2760a73105b8SAntonio Quartulli 	if (!orig_node)
2761a73105b8SAntonio Quartulli 		goto out;
2762a73105b8SAntonio Quartulli 
2763e5d89254SSven Eckelmann 	primary_if = batadv_primary_if_get_selected(bat_priv);
2764a73105b8SAntonio Quartulli 	if (!primary_if)
2765a73105b8SAntonio Quartulli 		goto out;
2766a73105b8SAntonio Quartulli 
2767a73105b8SAntonio Quartulli 	/* If the full table has been explicitly requested or the gap
27689cfc7bd6SSven Eckelmann 	 * is too big send the whole local translation table
27699cfc7bd6SSven Eckelmann 	 */
2770335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn ||
2771807736f6SSven Eckelmann 	    !bat_priv->tt.last_changeset)
2772a73105b8SAntonio Quartulli 		full_table = true;
2773a73105b8SAntonio Quartulli 	else
2774a73105b8SAntonio Quartulli 		full_table = false;
2775a73105b8SAntonio Quartulli 
2776335fbe0fSMarek Lindner 	/* TT fragmentation hasn't been implemented yet, so send as many
2777335fbe0fSMarek Lindner 	 * TT entries fit a single packet as possible only
27789cfc7bd6SSven Eckelmann 	 */
2779a73105b8SAntonio Quartulli 	if (!full_table) {
2780807736f6SSven Eckelmann 		spin_lock_bh(&bat_priv->tt.last_changeset_lock);
2781a73105b8SAntonio Quartulli 
27827ea7b4a1SAntonio Quartulli 		tt_len = bat_priv->tt.last_changeset_len;
27837ea7b4a1SAntonio Quartulli 		tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
27847ea7b4a1SAntonio Quartulli 							     &tvlv_tt_data,
27857ea7b4a1SAntonio Quartulli 							     &tt_change,
27867ea7b4a1SAntonio Quartulli 							     &tt_len);
27877ea7b4a1SAntonio Quartulli 		if (!tt_len)
2788a73105b8SAntonio Quartulli 			goto unlock;
2789a73105b8SAntonio Quartulli 
2790335fbe0fSMarek Lindner 		/* Copy the last orig_node's OGM buffer */
27917ea7b4a1SAntonio Quartulli 		memcpy(tt_change, bat_priv->tt.last_changeset,
2792807736f6SSven Eckelmann 		       bat_priv->tt.last_changeset_len);
2793807736f6SSven Eckelmann 		spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
2794a73105b8SAntonio Quartulli 	} else {
27956b5e971aSSven Eckelmann 		req_ttvn = (u8)atomic_read(&bat_priv->tt.vn);
2796a73105b8SAntonio Quartulli 
27977ea7b4a1SAntonio Quartulli 		/* allocate the tvlv, put the tt_data and all the tt_vlan_data
27987ea7b4a1SAntonio Quartulli 		 * in the initial part
27997ea7b4a1SAntonio Quartulli 		 */
28007ea7b4a1SAntonio Quartulli 		tt_len = -1;
28017ea7b4a1SAntonio Quartulli 		tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
28027ea7b4a1SAntonio Quartulli 							     &tvlv_tt_data,
28037ea7b4a1SAntonio Quartulli 							     &tt_change,
28047ea7b4a1SAntonio Quartulli 							     &tt_len);
28057ea7b4a1SAntonio Quartulli 		if (!tt_len)
2806a73105b8SAntonio Quartulli 			goto out;
28077ea7b4a1SAntonio Quartulli 
28087ea7b4a1SAntonio Quartulli 		/* fill the rest of the tvlv with the real TT entries */
28097ea7b4a1SAntonio Quartulli 		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash,
28107ea7b4a1SAntonio Quartulli 					tt_change, tt_len,
28117ea7b4a1SAntonio Quartulli 					batadv_tt_local_valid, NULL);
2812a73105b8SAntonio Quartulli 	}
2813a73105b8SAntonio Quartulli 
2814335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
2815335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = req_ttvn;
2816a73105b8SAntonio Quartulli 
2817a73105b8SAntonio Quartulli 	if (full_table)
2818335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
2819a73105b8SAntonio Quartulli 
282039c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
2821335fbe0fSMarek Lindner 		   "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n",
2822335fbe0fSMarek Lindner 		   orig_node->orig, full_table ? 'F' : '.', req_ttvn);
2823a73105b8SAntonio Quartulli 
2824d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
2825f8214865SMartin Hundebøll 
2826335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
28277ea7b4a1SAntonio Quartulli 				 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
28287ea7b4a1SAntonio Quartulli 				 tvlv_len);
2829335fbe0fSMarek Lindner 
2830a73105b8SAntonio Quartulli 	goto out;
2831a73105b8SAntonio Quartulli 
2832a73105b8SAntonio Quartulli unlock:
2833807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
2834a73105b8SAntonio Quartulli out:
2835a70a9aa9SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt.commit_lock);
2836a73105b8SAntonio Quartulli 	if (orig_node)
28377d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
2838a73105b8SAntonio Quartulli 	if (primary_if)
2839e5d89254SSven Eckelmann 		batadv_hardif_free_ref(primary_if);
2840335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
2841335fbe0fSMarek Lindner 	/* The packet was for this host, so it doesn't need to be re-routed */
2842a73105b8SAntonio Quartulli 	return true;
2843a73105b8SAntonio Quartulli }
2844a73105b8SAntonio Quartulli 
2845335fbe0fSMarek Lindner /**
2846335fbe0fSMarek Lindner  * batadv_send_tt_response - send reply to tt request
2847335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2848335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
2849335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
2850335fbe0fSMarek Lindner  * @req_dst: mac address of tt request recipient
2851335fbe0fSMarek Lindner  *
285262fe710fSSven Eckelmann  * Return: true if tt request reply was sent, false otherwise.
2853335fbe0fSMarek Lindner  */
2854335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv,
2855335fbe0fSMarek Lindner 				    struct batadv_tvlv_tt_data *tt_data,
28566b5e971aSSven Eckelmann 				    u8 *req_src, u8 *req_dst)
2857a73105b8SAntonio Quartulli {
2858cfd4f757SAntonio Quartulli 	if (batadv_is_my_mac(bat_priv, req_dst))
2859335fbe0fSMarek Lindner 		return batadv_send_my_tt_response(bat_priv, tt_data, req_src);
286024820df1SAntonio Quartulli 	return batadv_send_other_tt_response(bat_priv, tt_data, req_src,
286124820df1SAntonio Quartulli 					     req_dst);
2862a73105b8SAntonio Quartulli }
2863a73105b8SAntonio Quartulli 
286456303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
286556303d34SSven Eckelmann 				      struct batadv_orig_node *orig_node,
2866335fbe0fSMarek Lindner 				      struct batadv_tvlv_tt_change *tt_change,
28676b5e971aSSven Eckelmann 				      u16 tt_num_changes, u8 ttvn)
2868a73105b8SAntonio Quartulli {
2869a73105b8SAntonio Quartulli 	int i;
2870a513088dSSven Eckelmann 	int roams;
2871a73105b8SAntonio Quartulli 
2872a73105b8SAntonio Quartulli 	for (i = 0; i < tt_num_changes; i++) {
2873acd34afaSSven Eckelmann 		if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
2874acd34afaSSven Eckelmann 			roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
2875a513088dSSven Eckelmann 			batadv_tt_global_del(bat_priv, orig_node,
2876a73105b8SAntonio Quartulli 					     (tt_change + i)->addr,
2877c018ad3dSAntonio Quartulli 					     ntohs((tt_change + i)->vid),
2878cc47f66eSAntonio Quartulli 					     "tt removed by changes",
2879a513088dSSven Eckelmann 					     roams);
288008c36d3eSSven Eckelmann 		} else {
288108c36d3eSSven Eckelmann 			if (!batadv_tt_global_add(bat_priv, orig_node,
2882d4f44692SAntonio Quartulli 						  (tt_change + i)->addr,
2883c018ad3dSAntonio Quartulli 						  ntohs((tt_change + i)->vid),
2884d4f44692SAntonio Quartulli 						  (tt_change + i)->flags, ttvn))
2885a73105b8SAntonio Quartulli 				/* In case of problem while storing a
2886a73105b8SAntonio Quartulli 				 * global_entry, we stop the updating
2887a73105b8SAntonio Quartulli 				 * procedure without committing the
2888a73105b8SAntonio Quartulli 				 * ttvn change. This will avoid to send
2889a73105b8SAntonio Quartulli 				 * corrupted data on tt_request
2890a73105b8SAntonio Quartulli 				 */
2891a73105b8SAntonio Quartulli 				return;
2892a73105b8SAntonio Quartulli 		}
289308c36d3eSSven Eckelmann 	}
2894ac4eebd4SLinus Lüssing 	set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
2895a73105b8SAntonio Quartulli }
2896a73105b8SAntonio Quartulli 
289756303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
28987ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_change *tt_change,
28996b5e971aSSven Eckelmann 				  u8 ttvn, u8 *resp_src,
29006b5e971aSSven Eckelmann 				  u16 num_entries)
2901a73105b8SAntonio Quartulli {
2902170173bfSSven Eckelmann 	struct batadv_orig_node *orig_node;
2903a73105b8SAntonio Quartulli 
2904335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
2905a73105b8SAntonio Quartulli 	if (!orig_node)
2906a73105b8SAntonio Quartulli 		goto out;
2907a73105b8SAntonio Quartulli 
2908a73105b8SAntonio Quartulli 	/* Purge the old table first.. */
290995fb130dSAntonio Quartulli 	batadv_tt_global_del_orig(bat_priv, orig_node, -1,
291095fb130dSAntonio Quartulli 				  "Received full table");
2911a73105b8SAntonio Quartulli 
29127ea7b4a1SAntonio Quartulli 	_batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries,
29137ea7b4a1SAntonio Quartulli 				  ttvn);
2914a73105b8SAntonio Quartulli 
2915a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
2916a73105b8SAntonio Quartulli 	kfree(orig_node->tt_buff);
2917a73105b8SAntonio Quartulli 	orig_node->tt_buff_len = 0;
2918a73105b8SAntonio Quartulli 	orig_node->tt_buff = NULL;
2919a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
2920a73105b8SAntonio Quartulli 
29217ea7b4a1SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, ttvn);
2922a73105b8SAntonio Quartulli 
2923a73105b8SAntonio Quartulli out:
2924a73105b8SAntonio Quartulli 	if (orig_node)
29257d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
2926a73105b8SAntonio Quartulli }
2927a73105b8SAntonio Quartulli 
292856303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
292956303d34SSven Eckelmann 				     struct batadv_orig_node *orig_node,
29306b5e971aSSven Eckelmann 				     u16 tt_num_changes, u8 ttvn,
2931335fbe0fSMarek Lindner 				     struct batadv_tvlv_tt_change *tt_change)
2932a73105b8SAntonio Quartulli {
2933a513088dSSven Eckelmann 	_batadv_tt_update_changes(bat_priv, orig_node, tt_change,
2934a513088dSSven Eckelmann 				  tt_num_changes, ttvn);
2935a73105b8SAntonio Quartulli 
2936e8cf234aSAntonio Quartulli 	batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change,
2937e8cf234aSAntonio Quartulli 				   batadv_tt_len(tt_num_changes));
2938a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, ttvn);
2939a73105b8SAntonio Quartulli }
2940a73105b8SAntonio Quartulli 
2941c018ad3dSAntonio Quartulli /**
2942c018ad3dSAntonio Quartulli  * batadv_is_my_client - check if a client is served by the local node
2943c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
29443f68785eSAntonio Quartulli  * @addr: the mac address of the client to check
2945c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
2946c018ad3dSAntonio Quartulli  *
294762fe710fSSven Eckelmann  * Return: true if the client is served by this node, false otherwise.
2948c018ad3dSAntonio Quartulli  */
29496b5e971aSSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
2950c018ad3dSAntonio Quartulli 			 unsigned short vid)
2951a73105b8SAntonio Quartulli {
2952170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
29537683fdc1SAntonio Quartulli 	bool ret = false;
2954a73105b8SAntonio Quartulli 
2955c018ad3dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
29567683fdc1SAntonio Quartulli 	if (!tt_local_entry)
29577683fdc1SAntonio Quartulli 		goto out;
2958058d0e26SAntonio Quartulli 	/* Check if the client has been logically deleted (but is kept for
29599cfc7bd6SSven Eckelmann 	 * consistency purpose)
29609cfc7bd6SSven Eckelmann 	 */
29617c1fd91dSAntonio Quartulli 	if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
29627c1fd91dSAntonio Quartulli 	    (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
2963058d0e26SAntonio Quartulli 		goto out;
29647683fdc1SAntonio Quartulli 	ret = true;
29657683fdc1SAntonio Quartulli out:
2966a73105b8SAntonio Quartulli 	if (tt_local_entry)
2967a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(tt_local_entry);
29687683fdc1SAntonio Quartulli 	return ret;
2969a73105b8SAntonio Quartulli }
2970a73105b8SAntonio Quartulli 
2971335fbe0fSMarek Lindner /**
2972335fbe0fSMarek Lindner  * batadv_handle_tt_response - process incoming tt reply
2973335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2974335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
2975335fbe0fSMarek Lindner  * @resp_src: mac address of tt reply sender
2976335fbe0fSMarek Lindner  * @num_entries: number of tt change entries appended to the tt data
2977335fbe0fSMarek Lindner  */
2978335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
2979335fbe0fSMarek Lindner 				      struct batadv_tvlv_tt_data *tt_data,
29806b5e971aSSven Eckelmann 				      u8 *resp_src, u16 num_entries)
2981a73105b8SAntonio Quartulli {
29827c26a53bSMarek Lindner 	struct batadv_tt_req_node *node;
29837c26a53bSMarek Lindner 	struct hlist_node *safe;
298456303d34SSven Eckelmann 	struct batadv_orig_node *orig_node = NULL;
2985335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
29866b5e971aSSven Eckelmann 	u8 *tvlv_ptr = (u8 *)tt_data;
29876b5e971aSSven Eckelmann 	u16 change_offset;
2988a73105b8SAntonio Quartulli 
298939c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
299086ceb360SSven Eckelmann 		   "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
2991335fbe0fSMarek Lindner 		   resp_src, tt_data->ttvn, num_entries,
2992a2f2b6cdSSven Eckelmann 		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
2993a73105b8SAntonio Quartulli 
2994335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
2995a73105b8SAntonio Quartulli 	if (!orig_node)
2996a73105b8SAntonio Quartulli 		goto out;
2997a73105b8SAntonio Quartulli 
2998a70a9aa9SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_lock);
2999a70a9aa9SAntonio Quartulli 
30007ea7b4a1SAntonio Quartulli 	change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
30017ea7b4a1SAntonio Quartulli 	change_offset *= ntohs(tt_data->num_vlan);
30027ea7b4a1SAntonio Quartulli 	change_offset += sizeof(*tt_data);
30037ea7b4a1SAntonio Quartulli 	tvlv_ptr += change_offset;
30047ea7b4a1SAntonio Quartulli 
30057ea7b4a1SAntonio Quartulli 	tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
3006335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE) {
30077ea7b4a1SAntonio Quartulli 		batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn,
30087ea7b4a1SAntonio Quartulli 				      resp_src, num_entries);
300996412690SSven Eckelmann 	} else {
3010335fbe0fSMarek Lindner 		batadv_tt_update_changes(bat_priv, orig_node, num_entries,
3011335fbe0fSMarek Lindner 					 tt_data->ttvn, tt_change);
301296412690SSven Eckelmann 	}
3013a73105b8SAntonio Quartulli 
3014a70a9aa9SAntonio Quartulli 	/* Recalculate the CRC for this orig_node and store it */
30157ea7b4a1SAntonio Quartulli 	batadv_tt_global_update_crc(bat_priv, orig_node);
3016a70a9aa9SAntonio Quartulli 
3017a70a9aa9SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_lock);
3018a70a9aa9SAntonio Quartulli 
3019a73105b8SAntonio Quartulli 	/* Delete the tt_req_node from pending tt_requests list */
3020807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
30217c26a53bSMarek Lindner 	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
3022335fbe0fSMarek Lindner 		if (!batadv_compare_eth(node->addr, resp_src))
3023a73105b8SAntonio Quartulli 			continue;
30247c26a53bSMarek Lindner 		hlist_del_init(&node->list);
3025a73105b8SAntonio Quartulli 		kfree(node);
3026a73105b8SAntonio Quartulli 	}
30277ea7b4a1SAntonio Quartulli 
3028807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
3029a73105b8SAntonio Quartulli out:
3030a73105b8SAntonio Quartulli 	if (orig_node)
30317d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
3032a73105b8SAntonio Quartulli }
3033a73105b8SAntonio Quartulli 
303456303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv)
3035a73105b8SAntonio Quartulli {
303656303d34SSven Eckelmann 	struct batadv_tt_roam_node *node, *safe;
3037a73105b8SAntonio Quartulli 
3038807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
3039a73105b8SAntonio Quartulli 
3040807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
3041cc47f66eSAntonio Quartulli 		list_del(&node->list);
3042cc47f66eSAntonio Quartulli 		kfree(node);
3043cc47f66eSAntonio Quartulli 	}
3044cc47f66eSAntonio Quartulli 
3045807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
3046cc47f66eSAntonio Quartulli }
3047cc47f66eSAntonio Quartulli 
304856303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)
3049cc47f66eSAntonio Quartulli {
305056303d34SSven Eckelmann 	struct batadv_tt_roam_node *node, *safe;
3051cc47f66eSAntonio Quartulli 
3052807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
3053807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
305442d0b044SSven Eckelmann 		if (!batadv_has_timed_out(node->first_time,
305542d0b044SSven Eckelmann 					  BATADV_ROAMING_MAX_TIME))
3056cc47f66eSAntonio Quartulli 			continue;
3057cc47f66eSAntonio Quartulli 
3058cc47f66eSAntonio Quartulli 		list_del(&node->list);
3059cc47f66eSAntonio Quartulli 		kfree(node);
3060cc47f66eSAntonio Quartulli 	}
3061807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
3062cc47f66eSAntonio Quartulli }
3063cc47f66eSAntonio Quartulli 
306462fe710fSSven Eckelmann /**
306562fe710fSSven Eckelmann  * batadv_tt_check_roam_count
306662fe710fSSven Eckelmann  *
306762fe710fSSven Eckelmann  * This function checks whether the client already reached the
3068cc47f66eSAntonio Quartulli  * maximum number of possible roaming phases. In this case the ROAMING_ADV
3069cc47f66eSAntonio Quartulli  * will not be sent.
3070cc47f66eSAntonio Quartulli  *
307162fe710fSSven Eckelmann  * Return: true if the ROAMING_ADV can be sent, false otherwise
30729cfc7bd6SSven Eckelmann  */
30736b5e971aSSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client)
3074cc47f66eSAntonio Quartulli {
307556303d34SSven Eckelmann 	struct batadv_tt_roam_node *tt_roam_node;
3076cc47f66eSAntonio Quartulli 	bool ret = false;
3077cc47f66eSAntonio Quartulli 
3078807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
3079cc47f66eSAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
30809cfc7bd6SSven Eckelmann 	 * reply from the same orig_node yet
30819cfc7bd6SSven Eckelmann 	 */
3082807736f6SSven Eckelmann 	list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) {
30831eda58bfSSven Eckelmann 		if (!batadv_compare_eth(tt_roam_node->addr, client))
3084cc47f66eSAntonio Quartulli 			continue;
3085cc47f66eSAntonio Quartulli 
30861eda58bfSSven Eckelmann 		if (batadv_has_timed_out(tt_roam_node->first_time,
308742d0b044SSven Eckelmann 					 BATADV_ROAMING_MAX_TIME))
3088cc47f66eSAntonio Quartulli 			continue;
3089cc47f66eSAntonio Quartulli 
30903e34819eSSven Eckelmann 		if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter))
3091cc47f66eSAntonio Quartulli 			/* Sorry, you roamed too many times! */
3092cc47f66eSAntonio Quartulli 			goto unlock;
3093cc47f66eSAntonio Quartulli 		ret = true;
3094cc47f66eSAntonio Quartulli 		break;
3095cc47f66eSAntonio Quartulli 	}
3096cc47f66eSAntonio Quartulli 
3097cc47f66eSAntonio Quartulli 	if (!ret) {
3098cc47f66eSAntonio Quartulli 		tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
3099cc47f66eSAntonio Quartulli 		if (!tt_roam_node)
3100cc47f66eSAntonio Quartulli 			goto unlock;
3101cc47f66eSAntonio Quartulli 
3102cc47f66eSAntonio Quartulli 		tt_roam_node->first_time = jiffies;
310342d0b044SSven Eckelmann 		atomic_set(&tt_roam_node->counter,
310442d0b044SSven Eckelmann 			   BATADV_ROAMING_MAX_COUNT - 1);
31058fdd0153SAntonio Quartulli 		ether_addr_copy(tt_roam_node->addr, client);
3106cc47f66eSAntonio Quartulli 
3107807736f6SSven Eckelmann 		list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
3108cc47f66eSAntonio Quartulli 		ret = true;
3109cc47f66eSAntonio Quartulli 	}
3110cc47f66eSAntonio Quartulli 
3111cc47f66eSAntonio Quartulli unlock:
3112807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
3113cc47f66eSAntonio Quartulli 	return ret;
3114cc47f66eSAntonio Quartulli }
3115cc47f66eSAntonio Quartulli 
3116c018ad3dSAntonio Quartulli /**
3117c018ad3dSAntonio Quartulli  * batadv_send_roam_adv - send a roaming advertisement message
3118c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3119c018ad3dSAntonio Quartulli  * @client: mac address of the roaming client
3120c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
3121c018ad3dSAntonio Quartulli  * @orig_node: message destination
3122c018ad3dSAntonio Quartulli  *
3123c018ad3dSAntonio Quartulli  * Send a ROAMING_ADV message to the node which was previously serving this
3124c018ad3dSAntonio Quartulli  * client. This is done to inform the node that from now on all traffic destined
3125c018ad3dSAntonio Quartulli  * for this particular roamed client has to be forwarded to the sender of the
3126c018ad3dSAntonio Quartulli  * roaming message.
3127c018ad3dSAntonio Quartulli  */
31286b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
3129c018ad3dSAntonio Quartulli 				 unsigned short vid,
313056303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node)
3131cc47f66eSAntonio Quartulli {
313256303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if;
3133122edaa0SMarek Lindner 	struct batadv_tvlv_roam_adv tvlv_roam;
3134122edaa0SMarek Lindner 
3135122edaa0SMarek Lindner 	primary_if = batadv_primary_if_get_selected(bat_priv);
3136122edaa0SMarek Lindner 	if (!primary_if)
3137122edaa0SMarek Lindner 		goto out;
3138cc47f66eSAntonio Quartulli 
3139cc47f66eSAntonio Quartulli 	/* before going on we have to check whether the client has
31409cfc7bd6SSven Eckelmann 	 * already roamed to us too many times
31419cfc7bd6SSven Eckelmann 	 */
3142a513088dSSven Eckelmann 	if (!batadv_tt_check_roam_count(bat_priv, client))
3143cc47f66eSAntonio Quartulli 		goto out;
3144cc47f66eSAntonio Quartulli 
314539c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
314616052789SAntonio Quartulli 		   "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n",
314716052789SAntonio Quartulli 		   orig_node->orig, client, BATADV_PRINT_VID(vid));
3148cc47f66eSAntonio Quartulli 
3149d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
3150f8214865SMartin Hundebøll 
3151122edaa0SMarek Lindner 	memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client));
3152c018ad3dSAntonio Quartulli 	tvlv_roam.vid = htons(vid);
3153122edaa0SMarek Lindner 
3154122edaa0SMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
3155122edaa0SMarek Lindner 				 orig_node->orig, BATADV_TVLV_ROAM, 1,
3156122edaa0SMarek Lindner 				 &tvlv_roam, sizeof(tvlv_roam));
3157cc47f66eSAntonio Quartulli 
3158cc47f66eSAntonio Quartulli out:
3159122edaa0SMarek Lindner 	if (primary_if)
3160122edaa0SMarek Lindner 		batadv_hardif_free_ref(primary_if);
3161a73105b8SAntonio Quartulli }
3162a73105b8SAntonio Quartulli 
3163a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work)
3164a73105b8SAntonio Quartulli {
316556303d34SSven Eckelmann 	struct delayed_work *delayed_work;
3166807736f6SSven Eckelmann 	struct batadv_priv_tt *priv_tt;
316756303d34SSven Eckelmann 	struct batadv_priv *bat_priv;
316856303d34SSven Eckelmann 
316956303d34SSven Eckelmann 	delayed_work = container_of(work, struct delayed_work, work);
3170807736f6SSven Eckelmann 	priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
3171807736f6SSven Eckelmann 	bat_priv = container_of(priv_tt, struct batadv_priv, tt);
3172a73105b8SAntonio Quartulli 
3173a19d3d85SMarek Lindner 	batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
317430cfd02bSAntonio Quartulli 	batadv_tt_global_purge(bat_priv);
3175a513088dSSven Eckelmann 	batadv_tt_req_purge(bat_priv);
3176a513088dSSven Eckelmann 	batadv_tt_roam_purge(bat_priv);
3177a73105b8SAntonio Quartulli 
317872414442SAntonio Quartulli 	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
317972414442SAntonio Quartulli 			   msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
3180a73105b8SAntonio Quartulli }
3181cc47f66eSAntonio Quartulli 
318256303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv)
3183cc47f66eSAntonio Quartulli {
3184e1bf0c14SMarek Lindner 	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1);
3185e1bf0c14SMarek Lindner 	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1);
3186e1bf0c14SMarek Lindner 
3187807736f6SSven Eckelmann 	cancel_delayed_work_sync(&bat_priv->tt.work);
3188cc47f66eSAntonio Quartulli 
3189a513088dSSven Eckelmann 	batadv_tt_local_table_free(bat_priv);
3190a513088dSSven Eckelmann 	batadv_tt_global_table_free(bat_priv);
3191a513088dSSven Eckelmann 	batadv_tt_req_list_free(bat_priv);
3192a513088dSSven Eckelmann 	batadv_tt_changes_list_free(bat_priv);
3193a513088dSSven Eckelmann 	batadv_tt_roam_list_free(bat_priv);
3194cc47f66eSAntonio Quartulli 
3195807736f6SSven Eckelmann 	kfree(bat_priv->tt.last_changeset);
3196cc47f66eSAntonio Quartulli }
3197058d0e26SAntonio Quartulli 
31987ea7b4a1SAntonio Quartulli /**
31997ea7b4a1SAntonio Quartulli  * batadv_tt_local_set_flags - set or unset the specified flags on the local
32007ea7b4a1SAntonio Quartulli  *  table and possibly count them in the TT size
32017ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
32027ea7b4a1SAntonio Quartulli  * @flags: the flag to switch
32037ea7b4a1SAntonio Quartulli  * @enable: whether to set or unset the flag
32047ea7b4a1SAntonio Quartulli  * @count: whether to increase the TT size by the number of changed entries
32059cfc7bd6SSven Eckelmann  */
32066b5e971aSSven Eckelmann static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
32076b5e971aSSven Eckelmann 				      bool enable, bool count)
3208058d0e26SAntonio Quartulli {
32097ea7b4a1SAntonio Quartulli 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
32107ea7b4a1SAntonio Quartulli 	struct batadv_tt_common_entry *tt_common_entry;
32116b5e971aSSven Eckelmann 	u16 changed_num = 0;
3212058d0e26SAntonio Quartulli 	struct hlist_head *head;
32136b5e971aSSven Eckelmann 	u32 i;
3214058d0e26SAntonio Quartulli 
3215058d0e26SAntonio Quartulli 	if (!hash)
32167ea7b4a1SAntonio Quartulli 		return;
3217058d0e26SAntonio Quartulli 
3218058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
3219058d0e26SAntonio Quartulli 		head = &hash->table[i];
3220058d0e26SAntonio Quartulli 
3221058d0e26SAntonio Quartulli 		rcu_read_lock();
3222b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
3223058d0e26SAntonio Quartulli 					 head, hash_entry) {
3224697f2531SAntonio Quartulli 			if (enable) {
3225697f2531SAntonio Quartulli 				if ((tt_common_entry->flags & flags) == flags)
3226697f2531SAntonio Quartulli 					continue;
3227697f2531SAntonio Quartulli 				tt_common_entry->flags |= flags;
3228697f2531SAntonio Quartulli 			} else {
322948100bacSAntonio Quartulli 				if (!(tt_common_entry->flags & flags))
323031901264SAntonio Quartulli 					continue;
323148100bacSAntonio Quartulli 				tt_common_entry->flags &= ~flags;
3232697f2531SAntonio Quartulli 			}
3233697f2531SAntonio Quartulli 			changed_num++;
32347ea7b4a1SAntonio Quartulli 
32357ea7b4a1SAntonio Quartulli 			if (!count)
32367ea7b4a1SAntonio Quartulli 				continue;
32377ea7b4a1SAntonio Quartulli 
32387ea7b4a1SAntonio Quartulli 			batadv_tt_local_size_inc(bat_priv,
32397ea7b4a1SAntonio Quartulli 						 tt_common_entry->vid);
3240058d0e26SAntonio Quartulli 		}
3241058d0e26SAntonio Quartulli 		rcu_read_unlock();
3242058d0e26SAntonio Quartulli 	}
3243058d0e26SAntonio Quartulli }
3244058d0e26SAntonio Quartulli 
3245acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */
324656303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
3247058d0e26SAntonio Quartulli {
3248807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
324956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
325056303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
325135df3b29SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
3252b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
3253058d0e26SAntonio Quartulli 	struct hlist_head *head;
3254058d0e26SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
32556b5e971aSSven Eckelmann 	u32 i;
3256058d0e26SAntonio Quartulli 
3257058d0e26SAntonio Quartulli 	if (!hash)
3258058d0e26SAntonio Quartulli 		return;
3259058d0e26SAntonio Quartulli 
3260058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
3261058d0e26SAntonio Quartulli 		head = &hash->table[i];
3262058d0e26SAntonio Quartulli 		list_lock = &hash->list_locks[i];
3263058d0e26SAntonio Quartulli 
3264058d0e26SAntonio Quartulli 		spin_lock_bh(list_lock);
3265b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common, node_tmp, head,
3266acd34afaSSven Eckelmann 					  hash_entry) {
3267acd34afaSSven Eckelmann 			if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
3268058d0e26SAntonio Quartulli 				continue;
3269058d0e26SAntonio Quartulli 
327039c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
327116052789SAntonio Quartulli 				   "Deleting local tt entry (%pM, vid: %d): pending\n",
327216052789SAntonio Quartulli 				   tt_common->addr,
327316052789SAntonio Quartulli 				   BATADV_PRINT_VID(tt_common->vid));
3274058d0e26SAntonio Quartulli 
32757ea7b4a1SAntonio Quartulli 			batadv_tt_local_size_dec(bat_priv, tt_common->vid);
3276b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common->hash_entry);
327756303d34SSven Eckelmann 			tt_local = container_of(tt_common,
327856303d34SSven Eckelmann 						struct batadv_tt_local_entry,
327948100bacSAntonio Quartulli 						common);
328035df3b29SAntonio Quartulli 
328135df3b29SAntonio Quartulli 			/* decrease the reference held for this vlan */
328235df3b29SAntonio Quartulli 			vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
3283354136bcSMarek Lindner 			if (vlan) {
328435df3b29SAntonio Quartulli 				batadv_softif_vlan_free_ref(vlan);
328535df3b29SAntonio Quartulli 				batadv_softif_vlan_free_ref(vlan);
3286354136bcSMarek Lindner 			}
328735df3b29SAntonio Quartulli 
328856303d34SSven Eckelmann 			batadv_tt_local_entry_free_ref(tt_local);
3289058d0e26SAntonio Quartulli 		}
3290058d0e26SAntonio Quartulli 		spin_unlock_bh(list_lock);
3291058d0e26SAntonio Quartulli 	}
3292058d0e26SAntonio Quartulli }
3293058d0e26SAntonio Quartulli 
3294e1bf0c14SMarek Lindner /**
3295a19d3d85SMarek Lindner  * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes
3296a19d3d85SMarek Lindner  *  which have been queued in the time since the last commit
3297e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3298a19d3d85SMarek Lindner  *
3299a19d3d85SMarek Lindner  * Caller must hold tt->commit_lock.
3300e1bf0c14SMarek Lindner  */
3301a19d3d85SMarek Lindner static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
3302058d0e26SAntonio Quartulli {
33035274cd68SSven Eckelmann 	lockdep_assert_held(&bat_priv->tt.commit_lock);
33045274cd68SSven Eckelmann 
3305c5caf4efSLinus Lüssing 	/* Update multicast addresses in local translation table */
3306c5caf4efSLinus Lüssing 	batadv_mcast_mla_update(bat_priv);
3307c5caf4efSLinus Lüssing 
3308e1bf0c14SMarek Lindner 	if (atomic_read(&bat_priv->tt.local_changes) < 1) {
3309e1bf0c14SMarek Lindner 		if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
3310e1bf0c14SMarek Lindner 			batadv_tt_tvlv_container_update(bat_priv);
3311a19d3d85SMarek Lindner 		return;
3312e1bf0c14SMarek Lindner 	}
3313be9aa4c1SMarek Lindner 
33147ea7b4a1SAntonio Quartulli 	batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
3315be9aa4c1SMarek Lindner 
3316a513088dSSven Eckelmann 	batadv_tt_local_purge_pending_clients(bat_priv);
33177ea7b4a1SAntonio Quartulli 	batadv_tt_local_update_crc(bat_priv);
3318058d0e26SAntonio Quartulli 
3319058d0e26SAntonio Quartulli 	/* Increment the TTVN only once per OGM interval */
3320807736f6SSven Eckelmann 	atomic_inc(&bat_priv->tt.vn);
332139c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
33221eda58bfSSven Eckelmann 		   "Local changes committed, updating to ttvn %u\n",
33236b5e971aSSven Eckelmann 		   (u8)atomic_read(&bat_priv->tt.vn));
3324be9aa4c1SMarek Lindner 
3325be9aa4c1SMarek Lindner 	/* reset the sending counter */
3326807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
3327e1bf0c14SMarek Lindner 	batadv_tt_tvlv_container_update(bat_priv);
3328a19d3d85SMarek Lindner }
3329a70a9aa9SAntonio Quartulli 
3330a19d3d85SMarek Lindner /**
3331a19d3d85SMarek Lindner  * batadv_tt_local_commit_changes - commit all pending local tt changes which
3332a19d3d85SMarek Lindner  *  have been queued in the time since the last commit
3333a19d3d85SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3334a19d3d85SMarek Lindner  */
3335a19d3d85SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
3336a19d3d85SMarek Lindner {
3337a19d3d85SMarek Lindner 	spin_lock_bh(&bat_priv->tt.commit_lock);
3338a19d3d85SMarek Lindner 	batadv_tt_local_commit_changes_nolock(bat_priv);
3339a70a9aa9SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt.commit_lock);
3340058d0e26SAntonio Quartulli }
334159b699cdSAntonio Quartulli 
33426b5e971aSSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst,
33436b5e971aSSven Eckelmann 			   unsigned short vid)
334459b699cdSAntonio Quartulli {
334556303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry = NULL;
334656303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry = NULL;
3347b8cbd81dSAntonio Quartulli 	struct batadv_softif_vlan *vlan;
33485870adc6SMarek Lindner 	bool ret = false;
334959b699cdSAntonio Quartulli 
3350b8cbd81dSAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
3351e087f34fSMarkus Elfring 	if (!vlan)
3352e087f34fSMarkus Elfring 		return false;
3353e087f34fSMarkus Elfring 
3354e087f34fSMarkus Elfring 	if (!atomic_read(&vlan->ap_isolation))
33555870adc6SMarek Lindner 		goto out;
335659b699cdSAntonio Quartulli 
3357b8cbd81dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid);
335859b699cdSAntonio Quartulli 	if (!tt_local_entry)
335959b699cdSAntonio Quartulli 		goto out;
336059b699cdSAntonio Quartulli 
3361b8cbd81dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid);
336259b699cdSAntonio Quartulli 	if (!tt_global_entry)
336359b699cdSAntonio Quartulli 		goto out;
336459b699cdSAntonio Quartulli 
33651f129fefSAntonio Quartulli 	if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
336659b699cdSAntonio Quartulli 		goto out;
336759b699cdSAntonio Quartulli 
33685870adc6SMarek Lindner 	ret = true;
336959b699cdSAntonio Quartulli 
337059b699cdSAntonio Quartulli out:
3371b8cbd81dSAntonio Quartulli 	batadv_softif_vlan_free_ref(vlan);
337259b699cdSAntonio Quartulli 	if (tt_global_entry)
3373a513088dSSven Eckelmann 		batadv_tt_global_entry_free_ref(tt_global_entry);
337459b699cdSAntonio Quartulli 	if (tt_local_entry)
3375a513088dSSven Eckelmann 		batadv_tt_local_entry_free_ref(tt_local_entry);
337659b699cdSAntonio Quartulli 	return ret;
337759b699cdSAntonio Quartulli }
3378a943cac1SMarek Lindner 
3379e1bf0c14SMarek Lindner /**
3380e1bf0c14SMarek Lindner  * batadv_tt_update_orig - update global translation table with new tt
3381e1bf0c14SMarek Lindner  *  information received via ogms
3382e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3383e51f0397SSven Eckelmann  * @orig_node: the orig_node of the ogm
3384e51f0397SSven Eckelmann  * @tt_buff: pointer to the first tvlv VLAN entry
33857ea7b4a1SAntonio Quartulli  * @tt_num_vlan: number of tvlv VLAN entries
33867ea7b4a1SAntonio Quartulli  * @tt_change: pointer to the first entry in the TT buffer
3387e1bf0c14SMarek Lindner  * @tt_num_changes: number of tt changes inside the tt buffer
3388e1bf0c14SMarek Lindner  * @ttvn: translation table version number of this changeset
3389e1bf0c14SMarek Lindner  */
3390e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
339156303d34SSven Eckelmann 				  struct batadv_orig_node *orig_node,
33926b5e971aSSven Eckelmann 				  const void *tt_buff, u16 tt_num_vlan,
33937ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_change *tt_change,
33946b5e971aSSven Eckelmann 				  u16 tt_num_changes, u8 ttvn)
3395a943cac1SMarek Lindner {
33966b5e971aSSven Eckelmann 	u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn);
33977ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
3398a943cac1SMarek Lindner 	bool full_table = true;
3399e17931d1SLinus Lüssing 	bool has_tt_init;
3400a943cac1SMarek Lindner 
34017ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
3402ac4eebd4SLinus Lüssing 	has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT,
3403ac4eebd4SLinus Lüssing 			       &orig_node->capa_initialized);
3404e17931d1SLinus Lüssing 
340517071578SAntonio Quartulli 	/* orig table not initialised AND first diff is in the OGM OR the ttvn
34069cfc7bd6SSven Eckelmann 	 * increased by one -> we can apply the attached changes
34079cfc7bd6SSven Eckelmann 	 */
3408e17931d1SLinus Lüssing 	if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) {
3409a943cac1SMarek Lindner 		/* the OGM could not contain the changes due to their size or
341042d0b044SSven Eckelmann 		 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
341142d0b044SSven Eckelmann 		 * times.
34129cfc7bd6SSven Eckelmann 		 * In this case send a tt request
34139cfc7bd6SSven Eckelmann 		 */
3414a943cac1SMarek Lindner 		if (!tt_num_changes) {
3415a943cac1SMarek Lindner 			full_table = false;
3416a943cac1SMarek Lindner 			goto request_table;
3417a943cac1SMarek Lindner 		}
3418a943cac1SMarek Lindner 
3419a70a9aa9SAntonio Quartulli 		spin_lock_bh(&orig_node->tt_lock);
3420a70a9aa9SAntonio Quartulli 
3421a513088dSSven Eckelmann 		batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
342296412690SSven Eckelmann 					 ttvn, tt_change);
3423a943cac1SMarek Lindner 
3424a943cac1SMarek Lindner 		/* Even if we received the precomputed crc with the OGM, we
3425a943cac1SMarek Lindner 		 * prefer to recompute it to spot any possible inconsistency
34269cfc7bd6SSven Eckelmann 		 * in the global table
34279cfc7bd6SSven Eckelmann 		 */
34287ea7b4a1SAntonio Quartulli 		batadv_tt_global_update_crc(bat_priv, orig_node);
3429a943cac1SMarek Lindner 
3430a70a9aa9SAntonio Quartulli 		spin_unlock_bh(&orig_node->tt_lock);
3431a70a9aa9SAntonio Quartulli 
3432a943cac1SMarek Lindner 		/* The ttvn alone is not enough to guarantee consistency
3433a943cac1SMarek Lindner 		 * because a single value could represent different states
3434a943cac1SMarek Lindner 		 * (due to the wrap around). Thus a node has to check whether
3435a943cac1SMarek Lindner 		 * the resulting table (after applying the changes) is still
3436a943cac1SMarek Lindner 		 * consistent or not. E.g. a node could disconnect while its
3437a943cac1SMarek Lindner 		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
3438a943cac1SMarek Lindner 		 * checking the CRC value is mandatory to detect the
34399cfc7bd6SSven Eckelmann 		 * inconsistency
34409cfc7bd6SSven Eckelmann 		 */
34417ea7b4a1SAntonio Quartulli 		if (!batadv_tt_global_check_crc(orig_node, tt_vlan,
34427ea7b4a1SAntonio Quartulli 						tt_num_vlan))
3443a943cac1SMarek Lindner 			goto request_table;
3444a943cac1SMarek Lindner 	} else {
3445a943cac1SMarek Lindner 		/* if we missed more than one change or our tables are not
34469cfc7bd6SSven Eckelmann 		 * in sync anymore -> request fresh tt data
34479cfc7bd6SSven Eckelmann 		 */
3448e17931d1SLinus Lüssing 		if (!has_tt_init || ttvn != orig_ttvn ||
34497ea7b4a1SAntonio Quartulli 		    !batadv_tt_global_check_crc(orig_node, tt_vlan,
34507ea7b4a1SAntonio Quartulli 						tt_num_vlan)) {
3451a943cac1SMarek Lindner request_table:
345239c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
34537ea7b4a1SAntonio Quartulli 				   "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n",
34547ea7b4a1SAntonio Quartulli 				   orig_node->orig, ttvn, orig_ttvn,
34557ea7b4a1SAntonio Quartulli 				   tt_num_changes);
3456a513088dSSven Eckelmann 			batadv_send_tt_request(bat_priv, orig_node, ttvn,
34577ea7b4a1SAntonio Quartulli 					       tt_vlan, tt_num_vlan,
34587ea7b4a1SAntonio Quartulli 					       full_table);
3459a943cac1SMarek Lindner 			return;
3460a943cac1SMarek Lindner 		}
3461a943cac1SMarek Lindner 	}
3462a943cac1SMarek Lindner }
34633275e7ccSAntonio Quartulli 
3464c018ad3dSAntonio Quartulli /**
3465c018ad3dSAntonio Quartulli  * batadv_tt_global_client_is_roaming - check if a client is marked as roaming
3466c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3467c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to check
3468c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
3469c018ad3dSAntonio Quartulli  *
347062fe710fSSven Eckelmann  * Return: true if we know that the client has moved from its old originator
3471c018ad3dSAntonio Quartulli  * to another one. This entry is still kept for consistency purposes and will be
3472c018ad3dSAntonio Quartulli  * deleted later by a DEL or because of timeout
34733275e7ccSAntonio Quartulli  */
347456303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
34756b5e971aSSven Eckelmann 					u8 *addr, unsigned short vid)
34763275e7ccSAntonio Quartulli {
347756303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
34783275e7ccSAntonio Quartulli 	bool ret = false;
34793275e7ccSAntonio Quartulli 
3480c018ad3dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
34813275e7ccSAntonio Quartulli 	if (!tt_global_entry)
34823275e7ccSAntonio Quartulli 		goto out;
34833275e7ccSAntonio Quartulli 
3484c1d07431SAntonio Quartulli 	ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
3485a513088dSSven Eckelmann 	batadv_tt_global_entry_free_ref(tt_global_entry);
34863275e7ccSAntonio Quartulli out:
34873275e7ccSAntonio Quartulli 	return ret;
34883275e7ccSAntonio Quartulli }
348930cfd02bSAntonio Quartulli 
34907c1fd91dSAntonio Quartulli /**
34917c1fd91dSAntonio Quartulli  * batadv_tt_local_client_is_roaming - tells whether the client is roaming
34927c1fd91dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3493c018ad3dSAntonio Quartulli  * @addr: the mac address of the local client to query
3494c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
34957c1fd91dSAntonio Quartulli  *
349662fe710fSSven Eckelmann  * Return: true if the local client is known to be roaming (it is not served by
34977c1fd91dSAntonio Quartulli  * this node anymore) or not. If yes, the client is still present in the table
34987c1fd91dSAntonio Quartulli  * to keep the latter consistent with the node TTVN
34997c1fd91dSAntonio Quartulli  */
35007c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
35016b5e971aSSven Eckelmann 				       u8 *addr, unsigned short vid)
35027c1fd91dSAntonio Quartulli {
35037c1fd91dSAntonio Quartulli 	struct batadv_tt_local_entry *tt_local_entry;
35047c1fd91dSAntonio Quartulli 	bool ret = false;
35057c1fd91dSAntonio Quartulli 
3506c018ad3dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
35077c1fd91dSAntonio Quartulli 	if (!tt_local_entry)
35087c1fd91dSAntonio Quartulli 		goto out;
35097c1fd91dSAntonio Quartulli 
35107c1fd91dSAntonio Quartulli 	ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
35117c1fd91dSAntonio Quartulli 	batadv_tt_local_entry_free_ref(tt_local_entry);
35127c1fd91dSAntonio Quartulli out:
35137c1fd91dSAntonio Quartulli 	return ret;
35147c1fd91dSAntonio Quartulli }
35157c1fd91dSAntonio Quartulli 
351630cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
351730cfd02bSAntonio Quartulli 					  struct batadv_orig_node *orig_node,
3518c018ad3dSAntonio Quartulli 					  const unsigned char *addr,
351916052789SAntonio Quartulli 					  unsigned short vid)
352030cfd02bSAntonio Quartulli {
352130cfd02bSAntonio Quartulli 	bool ret = false;
352230cfd02bSAntonio Quartulli 
352316052789SAntonio Quartulli 	if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid,
352430cfd02bSAntonio Quartulli 				  BATADV_TT_CLIENT_TEMP,
352530cfd02bSAntonio Quartulli 				  atomic_read(&orig_node->last_ttvn)))
352630cfd02bSAntonio Quartulli 		goto out;
352730cfd02bSAntonio Quartulli 
352830cfd02bSAntonio Quartulli 	batadv_dbg(BATADV_DBG_TT, bat_priv,
352916052789SAntonio Quartulli 		   "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n",
353016052789SAntonio Quartulli 		   addr, BATADV_PRINT_VID(vid), orig_node->orig);
353130cfd02bSAntonio Quartulli 	ret = true;
353230cfd02bSAntonio Quartulli out:
353330cfd02bSAntonio Quartulli 	return ret;
353430cfd02bSAntonio Quartulli }
3535e1bf0c14SMarek Lindner 
3536e1bf0c14SMarek Lindner /**
3537a19d3d85SMarek Lindner  * batadv_tt_local_resize_to_mtu - resize the local translation table fit the
3538a19d3d85SMarek Lindner  *  maximum packet size that can be transported through the mesh
3539a19d3d85SMarek Lindner  * @soft_iface: netdev struct of the mesh interface
3540a19d3d85SMarek Lindner  *
3541a19d3d85SMarek Lindner  * Remove entries older than 'timeout' and half timeout if more entries need
3542a19d3d85SMarek Lindner  * to be removed.
3543a19d3d85SMarek Lindner  */
3544a19d3d85SMarek Lindner void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
3545a19d3d85SMarek Lindner {
3546a19d3d85SMarek Lindner 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
3547a19d3d85SMarek Lindner 	int packet_size_max = atomic_read(&bat_priv->packet_size_max);
3548a19d3d85SMarek Lindner 	int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
3549a19d3d85SMarek Lindner 	bool reduced = false;
3550a19d3d85SMarek Lindner 
3551a19d3d85SMarek Lindner 	spin_lock_bh(&bat_priv->tt.commit_lock);
3552a19d3d85SMarek Lindner 
3553a19d3d85SMarek Lindner 	while (true) {
3554a19d3d85SMarek Lindner 		table_size = batadv_tt_local_table_transmit_size(bat_priv);
3555a19d3d85SMarek Lindner 		if (packet_size_max >= table_size)
3556a19d3d85SMarek Lindner 			break;
3557a19d3d85SMarek Lindner 
3558a19d3d85SMarek Lindner 		batadv_tt_local_purge(bat_priv, timeout);
3559a19d3d85SMarek Lindner 		batadv_tt_local_purge_pending_clients(bat_priv);
3560a19d3d85SMarek Lindner 
3561a19d3d85SMarek Lindner 		timeout /= 2;
3562a19d3d85SMarek Lindner 		reduced = true;
3563a19d3d85SMarek Lindner 		net_ratelimited_function(batadv_info, soft_iface,
3564a19d3d85SMarek Lindner 					 "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
3565a19d3d85SMarek Lindner 					 packet_size_max);
3566a19d3d85SMarek Lindner 	}
3567a19d3d85SMarek Lindner 
3568a19d3d85SMarek Lindner 	/* commit these changes immediately, to avoid synchronization problem
3569a19d3d85SMarek Lindner 	 * with the TTVN
3570a19d3d85SMarek Lindner 	 */
3571a19d3d85SMarek Lindner 	if (reduced)
3572a19d3d85SMarek Lindner 		batadv_tt_local_commit_changes_nolock(bat_priv);
3573a19d3d85SMarek Lindner 
3574a19d3d85SMarek Lindner 	spin_unlock_bh(&bat_priv->tt.commit_lock);
3575a19d3d85SMarek Lindner }
3576a19d3d85SMarek Lindner 
3577a19d3d85SMarek Lindner /**
3578e1bf0c14SMarek Lindner  * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
3579e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3580e1bf0c14SMarek Lindner  * @orig: the orig_node of the ogm
3581e1bf0c14SMarek Lindner  * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
3582e1bf0c14SMarek Lindner  * @tvlv_value: tvlv buffer containing the gateway data
3583e1bf0c14SMarek Lindner  * @tvlv_value_len: tvlv buffer length
3584e1bf0c14SMarek Lindner  */
3585e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
3586e1bf0c14SMarek Lindner 					  struct batadv_orig_node *orig,
35876b5e971aSSven Eckelmann 					  u8 flags, void *tvlv_value,
35886b5e971aSSven Eckelmann 					  u16 tvlv_value_len)
3589e1bf0c14SMarek Lindner {
35907ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
35917ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_change *tt_change;
3592e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
35936b5e971aSSven Eckelmann 	u16 num_entries, num_vlan;
3594e1bf0c14SMarek Lindner 
3595e1bf0c14SMarek Lindner 	if (tvlv_value_len < sizeof(*tt_data))
3596e1bf0c14SMarek Lindner 		return;
3597e1bf0c14SMarek Lindner 
3598e1bf0c14SMarek Lindner 	tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
3599e1bf0c14SMarek Lindner 	tvlv_value_len -= sizeof(*tt_data);
3600e1bf0c14SMarek Lindner 
36017ea7b4a1SAntonio Quartulli 	num_vlan = ntohs(tt_data->num_vlan);
36027ea7b4a1SAntonio Quartulli 
36037ea7b4a1SAntonio Quartulli 	if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan)
36047ea7b4a1SAntonio Quartulli 		return;
36057ea7b4a1SAntonio Quartulli 
36067ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
36077ea7b4a1SAntonio Quartulli 	tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan);
36087ea7b4a1SAntonio Quartulli 	tvlv_value_len -= sizeof(*tt_vlan) * num_vlan;
36097ea7b4a1SAntonio Quartulli 
3610298e6e68SAntonio Quartulli 	num_entries = batadv_tt_entries(tvlv_value_len);
3611e1bf0c14SMarek Lindner 
36127ea7b4a1SAntonio Quartulli 	batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change,
36137ea7b4a1SAntonio Quartulli 			      num_entries, tt_data->ttvn);
3614e1bf0c14SMarek Lindner }
3615e1bf0c14SMarek Lindner 
3616e1bf0c14SMarek Lindner /**
3617335fbe0fSMarek Lindner  * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv
3618335fbe0fSMarek Lindner  *  container
3619335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3620335fbe0fSMarek Lindner  * @src: mac address of tt tvlv sender
3621335fbe0fSMarek Lindner  * @dst: mac address of tt tvlv recipient
3622335fbe0fSMarek Lindner  * @tvlv_value: tvlv buffer containing the tt data
3623335fbe0fSMarek Lindner  * @tvlv_value_len: tvlv buffer length
3624335fbe0fSMarek Lindner  *
362562fe710fSSven Eckelmann  * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS
3626335fbe0fSMarek Lindner  * otherwise.
3627335fbe0fSMarek Lindner  */
3628335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
36296b5e971aSSven Eckelmann 					     u8 *src, u8 *dst,
3630335fbe0fSMarek Lindner 					     void *tvlv_value,
36316b5e971aSSven Eckelmann 					     u16 tvlv_value_len)
3632335fbe0fSMarek Lindner {
3633335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
36346b5e971aSSven Eckelmann 	u16 tt_vlan_len, tt_num_entries;
3635335fbe0fSMarek Lindner 	char tt_flag;
3636335fbe0fSMarek Lindner 	bool ret;
3637335fbe0fSMarek Lindner 
3638335fbe0fSMarek Lindner 	if (tvlv_value_len < sizeof(*tt_data))
3639335fbe0fSMarek Lindner 		return NET_RX_SUCCESS;
3640335fbe0fSMarek Lindner 
3641335fbe0fSMarek Lindner 	tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
3642335fbe0fSMarek Lindner 	tvlv_value_len -= sizeof(*tt_data);
3643335fbe0fSMarek Lindner 
36447ea7b4a1SAntonio Quartulli 	tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data);
36457ea7b4a1SAntonio Quartulli 	tt_vlan_len *= ntohs(tt_data->num_vlan);
36467ea7b4a1SAntonio Quartulli 
36477ea7b4a1SAntonio Quartulli 	if (tvlv_value_len < tt_vlan_len)
36487ea7b4a1SAntonio Quartulli 		return NET_RX_SUCCESS;
36497ea7b4a1SAntonio Quartulli 
36507ea7b4a1SAntonio Quartulli 	tvlv_value_len -= tt_vlan_len;
36517ea7b4a1SAntonio Quartulli 	tt_num_entries = batadv_tt_entries(tvlv_value_len);
3652335fbe0fSMarek Lindner 
3653335fbe0fSMarek Lindner 	switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
3654335fbe0fSMarek Lindner 	case BATADV_TT_REQUEST:
3655335fbe0fSMarek Lindner 		batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX);
3656335fbe0fSMarek Lindner 
3657335fbe0fSMarek Lindner 		/* If this node cannot provide a TT response the tt_request is
3658335fbe0fSMarek Lindner 		 * forwarded
3659335fbe0fSMarek Lindner 		 */
3660335fbe0fSMarek Lindner 		ret = batadv_send_tt_response(bat_priv, tt_data, src, dst);
3661335fbe0fSMarek Lindner 		if (!ret) {
3662335fbe0fSMarek Lindner 			if (tt_data->flags & BATADV_TT_FULL_TABLE)
3663335fbe0fSMarek Lindner 				tt_flag = 'F';
3664335fbe0fSMarek Lindner 			else
3665335fbe0fSMarek Lindner 				tt_flag = '.';
3666335fbe0fSMarek Lindner 
3667335fbe0fSMarek Lindner 			batadv_dbg(BATADV_DBG_TT, bat_priv,
3668335fbe0fSMarek Lindner 				   "Routing TT_REQUEST to %pM [%c]\n",
3669335fbe0fSMarek Lindner 				   dst, tt_flag);
3670335fbe0fSMarek Lindner 			/* tvlv API will re-route the packet */
3671335fbe0fSMarek Lindner 			return NET_RX_DROP;
3672335fbe0fSMarek Lindner 		}
3673335fbe0fSMarek Lindner 		break;
3674335fbe0fSMarek Lindner 	case BATADV_TT_RESPONSE:
3675335fbe0fSMarek Lindner 		batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
3676335fbe0fSMarek Lindner 
3677335fbe0fSMarek Lindner 		if (batadv_is_my_mac(bat_priv, dst)) {
3678335fbe0fSMarek Lindner 			batadv_handle_tt_response(bat_priv, tt_data,
36797ea7b4a1SAntonio Quartulli 						  src, tt_num_entries);
3680335fbe0fSMarek Lindner 			return NET_RX_SUCCESS;
3681335fbe0fSMarek Lindner 		}
3682335fbe0fSMarek Lindner 
3683335fbe0fSMarek Lindner 		if (tt_data->flags & BATADV_TT_FULL_TABLE)
3684335fbe0fSMarek Lindner 			tt_flag =  'F';
3685335fbe0fSMarek Lindner 		else
3686335fbe0fSMarek Lindner 			tt_flag = '.';
3687335fbe0fSMarek Lindner 
3688335fbe0fSMarek Lindner 		batadv_dbg(BATADV_DBG_TT, bat_priv,
3689335fbe0fSMarek Lindner 			   "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag);
3690335fbe0fSMarek Lindner 
3691335fbe0fSMarek Lindner 		/* tvlv API will re-route the packet */
3692335fbe0fSMarek Lindner 		return NET_RX_DROP;
3693335fbe0fSMarek Lindner 	}
3694335fbe0fSMarek Lindner 
3695335fbe0fSMarek Lindner 	return NET_RX_SUCCESS;
3696335fbe0fSMarek Lindner }
3697335fbe0fSMarek Lindner 
3698335fbe0fSMarek Lindner /**
3699122edaa0SMarek Lindner  * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container
3700122edaa0SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3701122edaa0SMarek Lindner  * @src: mac address of tt tvlv sender
3702122edaa0SMarek Lindner  * @dst: mac address of tt tvlv recipient
3703122edaa0SMarek Lindner  * @tvlv_value: tvlv buffer containing the tt data
3704122edaa0SMarek Lindner  * @tvlv_value_len: tvlv buffer length
3705122edaa0SMarek Lindner  *
370662fe710fSSven Eckelmann  * Return: NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS
3707122edaa0SMarek Lindner  * otherwise.
3708122edaa0SMarek Lindner  */
3709122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
37106b5e971aSSven Eckelmann 					       u8 *src, u8 *dst,
3711122edaa0SMarek Lindner 					       void *tvlv_value,
37126b5e971aSSven Eckelmann 					       u16 tvlv_value_len)
3713122edaa0SMarek Lindner {
3714122edaa0SMarek Lindner 	struct batadv_tvlv_roam_adv *roaming_adv;
3715122edaa0SMarek Lindner 	struct batadv_orig_node *orig_node = NULL;
3716122edaa0SMarek Lindner 
3717122edaa0SMarek Lindner 	/* If this node is not the intended recipient of the
3718122edaa0SMarek Lindner 	 * roaming advertisement the packet is forwarded
3719122edaa0SMarek Lindner 	 * (the tvlv API will re-route the packet).
3720122edaa0SMarek Lindner 	 */
3721122edaa0SMarek Lindner 	if (!batadv_is_my_mac(bat_priv, dst))
3722122edaa0SMarek Lindner 		return NET_RX_DROP;
3723122edaa0SMarek Lindner 
3724122edaa0SMarek Lindner 	if (tvlv_value_len < sizeof(*roaming_adv))
3725122edaa0SMarek Lindner 		goto out;
3726122edaa0SMarek Lindner 
3727122edaa0SMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, src);
3728122edaa0SMarek Lindner 	if (!orig_node)
3729122edaa0SMarek Lindner 		goto out;
3730122edaa0SMarek Lindner 
3731122edaa0SMarek Lindner 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
3732122edaa0SMarek Lindner 	roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value;
3733122edaa0SMarek Lindner 
3734122edaa0SMarek Lindner 	batadv_dbg(BATADV_DBG_TT, bat_priv,
3735122edaa0SMarek Lindner 		   "Received ROAMING_ADV from %pM (client %pM)\n",
3736122edaa0SMarek Lindner 		   src, roaming_adv->client);
3737122edaa0SMarek Lindner 
3738122edaa0SMarek Lindner 	batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client,
3739c018ad3dSAntonio Quartulli 			     ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM,
3740122edaa0SMarek Lindner 			     atomic_read(&orig_node->last_ttvn) + 1);
3741122edaa0SMarek Lindner 
3742122edaa0SMarek Lindner out:
3743122edaa0SMarek Lindner 	if (orig_node)
3744122edaa0SMarek Lindner 		batadv_orig_node_free_ref(orig_node);
3745122edaa0SMarek Lindner 	return NET_RX_SUCCESS;
3746122edaa0SMarek Lindner }
3747122edaa0SMarek Lindner 
3748122edaa0SMarek Lindner /**
3749e1bf0c14SMarek Lindner  * batadv_tt_init - initialise the translation table internals
3750e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3751e1bf0c14SMarek Lindner  *
375262fe710fSSven Eckelmann  * Return: 0 on success or negative error number in case of failure.
3753e1bf0c14SMarek Lindner  */
3754e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv)
3755e1bf0c14SMarek Lindner {
3756e1bf0c14SMarek Lindner 	int ret;
3757e1bf0c14SMarek Lindner 
37580eb01568SAntonio Quartulli 	/* synchronized flags must be remote */
37590eb01568SAntonio Quartulli 	BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK));
37600eb01568SAntonio Quartulli 
3761e1bf0c14SMarek Lindner 	ret = batadv_tt_local_init(bat_priv);
3762e1bf0c14SMarek Lindner 	if (ret < 0)
3763e1bf0c14SMarek Lindner 		return ret;
3764e1bf0c14SMarek Lindner 
3765e1bf0c14SMarek Lindner 	ret = batadv_tt_global_init(bat_priv);
3766e1bf0c14SMarek Lindner 	if (ret < 0)
3767e1bf0c14SMarek Lindner 		return ret;
3768e1bf0c14SMarek Lindner 
3769e1bf0c14SMarek Lindner 	batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1,
3770335fbe0fSMarek Lindner 				     batadv_tt_tvlv_unicast_handler_v1,
3771335fbe0fSMarek Lindner 				     BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
3772e1bf0c14SMarek Lindner 
3773122edaa0SMarek Lindner 	batadv_tvlv_handler_register(bat_priv, NULL,
3774122edaa0SMarek Lindner 				     batadv_roam_tvlv_unicast_handler_v1,
3775122edaa0SMarek Lindner 				     BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS);
3776122edaa0SMarek Lindner 
3777e1bf0c14SMarek Lindner 	INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
3778e1bf0c14SMarek Lindner 	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
3779e1bf0c14SMarek Lindner 			   msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
3780e1bf0c14SMarek Lindner 
3781e1bf0c14SMarek Lindner 	return 1;
3782e1bf0c14SMarek Lindner }
378342cb0befSAntonio Quartulli 
378442cb0befSAntonio Quartulli /**
378542cb0befSAntonio Quartulli  * batadv_tt_global_is_isolated - check if a client is marked as isolated
378642cb0befSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
378742cb0befSAntonio Quartulli  * @addr: the mac address of the client
378842cb0befSAntonio Quartulli  * @vid: the identifier of the VLAN where this client is connected
378942cb0befSAntonio Quartulli  *
379062fe710fSSven Eckelmann  * Return: true if the client is marked with the TT_CLIENT_ISOLA flag, false
379142cb0befSAntonio Quartulli  * otherwise
379242cb0befSAntonio Quartulli  */
379342cb0befSAntonio Quartulli bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
37946b5e971aSSven Eckelmann 				  const u8 *addr, unsigned short vid)
379542cb0befSAntonio Quartulli {
379642cb0befSAntonio Quartulli 	struct batadv_tt_global_entry *tt;
379742cb0befSAntonio Quartulli 	bool ret;
379842cb0befSAntonio Quartulli 
379942cb0befSAntonio Quartulli 	tt = batadv_tt_global_hash_find(bat_priv, addr, vid);
380042cb0befSAntonio Quartulli 	if (!tt)
380142cb0befSAntonio Quartulli 		return false;
380242cb0befSAntonio Quartulli 
380342cb0befSAntonio Quartulli 	ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
380442cb0befSAntonio Quartulli 
380542cb0befSAntonio Quartulli 	batadv_tt_global_entry_free_ref(tt);
380642cb0befSAntonio Quartulli 
380742cb0befSAntonio Quartulli 	return ret;
380842cb0befSAntonio Quartulli }
3809