17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2cfa55c6dSSven Eckelmann /* Copyright (C) B.A.T.M.A.N. contributors:
3c6c8fea2SSven Eckelmann  *
435c133a0SAntonio Quartulli  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
5c6c8fea2SSven Eckelmann  */
6c6c8fea2SSven Eckelmann 
7c6c8fea2SSven Eckelmann #include "translation-table.h"
81e2c2a4fSSven Eckelmann #include "main.h"
9c6c8fea2SSven Eckelmann 
101e2c2a4fSSven Eckelmann #include <linux/atomic.h>
11ac4eebd4SLinus Lüssing #include <linux/bitops.h>
12ecc36f5eSSven Eckelmann #include <linux/build_bug.h>
131e2c2a4fSSven Eckelmann #include <linux/byteorder/generic.h>
1486452f81SSven Eckelmann #include <linux/cache.h>
151e2c2a4fSSven Eckelmann #include <linux/compiler.h>
16eb7da4f1SSven Eckelmann #include <linux/container_of.h>
17ced72933SAntonio Quartulli #include <linux/crc32c.h>
181e2c2a4fSSven Eckelmann #include <linux/errno.h>
191e2c2a4fSSven Eckelmann #include <linux/etherdevice.h>
20b92b94acSSven Eckelmann #include <linux/gfp.h>
211e2c2a4fSSven Eckelmann #include <linux/if_ether.h>
2286452f81SSven Eckelmann #include <linux/init.h>
231e2c2a4fSSven Eckelmann #include <linux/jhash.h>
241e2c2a4fSSven Eckelmann #include <linux/jiffies.h>
256e8ef69dSSven Eckelmann #include <linux/kref.h>
261e2c2a4fSSven Eckelmann #include <linux/list.h>
271e2c2a4fSSven Eckelmann #include <linux/lockdep.h>
283a64469eSSven Eckelmann #include <linux/net.h>
291e2c2a4fSSven Eckelmann #include <linux/netdevice.h>
30d34f0550SMatthias Schiffer #include <linux/netlink.h>
311e2c2a4fSSven Eckelmann #include <linux/rculist.h>
321e2c2a4fSSven Eckelmann #include <linux/rcupdate.h>
33d34f0550SMatthias Schiffer #include <linux/skbuff.h>
341e2c2a4fSSven Eckelmann #include <linux/slab.h>
351e2c2a4fSSven Eckelmann #include <linux/spinlock.h>
361e2c2a4fSSven Eckelmann #include <linux/stddef.h>
371e2c2a4fSSven Eckelmann #include <linux/string.h>
381e2c2a4fSSven Eckelmann #include <linux/workqueue.h>
39d34f0550SMatthias Schiffer #include <net/genetlink.h>
40d34f0550SMatthias Schiffer #include <net/netlink.h>
41d34f0550SMatthias Schiffer #include <net/sock.h>
42fec149f5SSven Eckelmann #include <uapi/linux/batadv_packet.h>
43d34f0550SMatthias Schiffer #include <uapi/linux/batman_adv.h>
441e2c2a4fSSven Eckelmann 
451e2c2a4fSSven Eckelmann #include "bridge_loop_avoidance.h"
461e2c2a4fSSven Eckelmann #include "hard-interface.h"
471e2c2a4fSSven Eckelmann #include "hash.h"
48ba412080SSven Eckelmann #include "log.h"
49d34f0550SMatthias Schiffer #include "netlink.h"
501e2c2a4fSSven Eckelmann #include "originator.h"
511e2c2a4fSSven Eckelmann #include "soft-interface.h"
521f8dce49SMarkus Pargmann #include "tvlv.h"
53a73105b8SAntonio Quartulli 
5486452f81SSven Eckelmann static struct kmem_cache *batadv_tl_cache __read_mostly;
5586452f81SSven Eckelmann static struct kmem_cache *batadv_tg_cache __read_mostly;
5686452f81SSven Eckelmann static struct kmem_cache *batadv_tt_orig_cache __read_mostly;
5786452f81SSven Eckelmann static struct kmem_cache *batadv_tt_change_cache __read_mostly;
5886452f81SSven Eckelmann static struct kmem_cache *batadv_tt_req_cache __read_mostly;
5986452f81SSven Eckelmann static struct kmem_cache *batadv_tt_roam_cache __read_mostly;
6086452f81SSven Eckelmann 
61dec05074SAntonio Quartulli /* hash class keys */
62dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_local_hash_lock_class_key;
63dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_global_hash_lock_class_key;
64dec05074SAntonio Quartulli 
656b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
66c018ad3dSAntonio Quartulli 				 unsigned short vid,
6756303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node);
68a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work);
69a513088dSSven Eckelmann static void
7056303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
7130cfd02bSAntonio Quartulli static void batadv_tt_global_del(struct batadv_priv *bat_priv,
7230cfd02bSAntonio Quartulli 				 struct batadv_orig_node *orig_node,
7330cfd02bSAntonio Quartulli 				 const unsigned char *addr,
74c018ad3dSAntonio Quartulli 				 unsigned short vid, const char *message,
75c018ad3dSAntonio Quartulli 				 bool roaming);
76c6c8fea2SSven Eckelmann 
7762fe710fSSven Eckelmann /**
787e9a8c2cSSven Eckelmann  * batadv_compare_tt() - check if two TT entries are the same
79d15cd622SAntonio Quartulli  * @node: the list element pointer of the first TT entry
80d15cd622SAntonio Quartulli  * @data2: pointer to the tt_common_entry of the second TT entry
8162fe710fSSven Eckelmann  *
82d15cd622SAntonio Quartulli  * Compare the MAC address and the VLAN ID of the two TT entries and check if
83d15cd622SAntonio Quartulli  * they are the same TT client.
844b426b10SSven Eckelmann  * Return: true if the two TT clients are the same, false otherwise
8562fe710fSSven Eckelmann  */
batadv_compare_tt(const struct hlist_node * node,const void * data2)864b426b10SSven Eckelmann static bool batadv_compare_tt(const struct hlist_node *node, const void *data2)
877aadf889SMarek Lindner {
8856303d34SSven Eckelmann 	const void *data1 = container_of(node, struct batadv_tt_common_entry,
89747e4221SSven Eckelmann 					 hash_entry);
904c718958SMarek Lindner 	const struct batadv_tt_common_entry *tt1 = data1;
914c718958SMarek Lindner 	const struct batadv_tt_common_entry *tt2 = data2;
927aadf889SMarek Lindner 
934c718958SMarek Lindner 	return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
947aadf889SMarek Lindner }
957aadf889SMarek Lindner 
96c018ad3dSAntonio Quartulli /**
977e9a8c2cSSven Eckelmann  * batadv_choose_tt() - return the index of the tt entry in the hash table
98c018ad3dSAntonio Quartulli  * @data: pointer to the tt_common_entry object to map
99c018ad3dSAntonio Quartulli  * @size: the size of the hash table
100c018ad3dSAntonio Quartulli  *
10162fe710fSSven Eckelmann  * Return: the hash index where the object represented by 'data' should be
102c018ad3dSAntonio Quartulli  * stored at.
103c018ad3dSAntonio Quartulli  */
batadv_choose_tt(const void * data,u32 size)1046b5e971aSSven Eckelmann static inline u32 batadv_choose_tt(const void *data, u32 size)
105c018ad3dSAntonio Quartulli {
1068864d2fcSYu Zhe 	const struct batadv_tt_common_entry *tt;
1076b5e971aSSven Eckelmann 	u32 hash = 0;
108c018ad3dSAntonio Quartulli 
1098864d2fcSYu Zhe 	tt = data;
11036fd61cbSSven Eckelmann 	hash = jhash(&tt->addr, ETH_ALEN, hash);
11136fd61cbSSven Eckelmann 	hash = jhash(&tt->vid, sizeof(tt->vid), hash);
112c018ad3dSAntonio Quartulli 
113c018ad3dSAntonio Quartulli 	return hash % size;
114c018ad3dSAntonio Quartulli }
115c018ad3dSAntonio Quartulli 
116c018ad3dSAntonio Quartulli /**
1177e9a8c2cSSven Eckelmann  * batadv_tt_hash_find() - look for a client in the given hash table
118c018ad3dSAntonio Quartulli  * @hash: the hash table to search
119c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to look for
120c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
121c018ad3dSAntonio Quartulli  *
12262fe710fSSven Eckelmann  * Return: a pointer to the tt_common struct belonging to the searched client if
123c018ad3dSAntonio Quartulli  * found, NULL otherwise.
124c018ad3dSAntonio Quartulli  */
12556303d34SSven Eckelmann static struct batadv_tt_common_entry *
batadv_tt_hash_find(struct batadv_hashtable * hash,const u8 * addr,unsigned short vid)1266b5e971aSSven Eckelmann batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr,
127c018ad3dSAntonio Quartulli 		    unsigned short vid)
1287aadf889SMarek Lindner {
1297aadf889SMarek Lindner 	struct hlist_head *head;
130c018ad3dSAntonio Quartulli 	struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL;
1316b5e971aSSven Eckelmann 	u32 index;
1327aadf889SMarek Lindner 
1337aadf889SMarek Lindner 	if (!hash)
1347aadf889SMarek Lindner 		return NULL;
1357aadf889SMarek Lindner 
1368fdd0153SAntonio Quartulli 	ether_addr_copy(to_search.addr, addr);
137c018ad3dSAntonio Quartulli 	to_search.vid = vid;
138c018ad3dSAntonio Quartulli 
139c018ad3dSAntonio Quartulli 	index = batadv_choose_tt(&to_search, hash->size);
1407aadf889SMarek Lindner 	head = &hash->table[index];
1417aadf889SMarek Lindner 
1427aadf889SMarek Lindner 	rcu_read_lock();
143c018ad3dSAntonio Quartulli 	hlist_for_each_entry_rcu(tt, head, hash_entry) {
144c018ad3dSAntonio Quartulli 		if (!batadv_compare_eth(tt, addr))
1457aadf889SMarek Lindner 			continue;
1467aadf889SMarek Lindner 
147c018ad3dSAntonio Quartulli 		if (tt->vid != vid)
1487683fdc1SAntonio Quartulli 			continue;
1497683fdc1SAntonio Quartulli 
15092dcdf09SSven Eckelmann 		if (!kref_get_unless_zero(&tt->refcount))
151c018ad3dSAntonio Quartulli 			continue;
152c018ad3dSAntonio Quartulli 
153c018ad3dSAntonio Quartulli 		tt_tmp = tt;
1547aadf889SMarek Lindner 		break;
1557aadf889SMarek Lindner 	}
1567aadf889SMarek Lindner 	rcu_read_unlock();
1577aadf889SMarek Lindner 
158c018ad3dSAntonio Quartulli 	return tt_tmp;
15948100bacSAntonio Quartulli }
16048100bacSAntonio Quartulli 
161c018ad3dSAntonio Quartulli /**
1627e9a8c2cSSven Eckelmann  * batadv_tt_local_hash_find() - search the local table for a given client
163c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
164c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to look for
165c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
166c018ad3dSAntonio Quartulli  *
16762fe710fSSven Eckelmann  * Return: a pointer to the corresponding tt_local_entry struct if the client is
168c018ad3dSAntonio Quartulli  * found, NULL otherwise.
169c018ad3dSAntonio Quartulli  */
17056303d34SSven Eckelmann static struct batadv_tt_local_entry *
batadv_tt_local_hash_find(struct batadv_priv * bat_priv,const u8 * addr,unsigned short vid)1716b5e971aSSven Eckelmann batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
172c018ad3dSAntonio Quartulli 			  unsigned short vid)
17348100bacSAntonio Quartulli {
17456303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
17556303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry = NULL;
17648100bacSAntonio Quartulli 
177c018ad3dSAntonio Quartulli 	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr,
178c018ad3dSAntonio Quartulli 					      vid);
17948100bacSAntonio Quartulli 	if (tt_common_entry)
18048100bacSAntonio Quartulli 		tt_local_entry = container_of(tt_common_entry,
18156303d34SSven Eckelmann 					      struct batadv_tt_local_entry,
18256303d34SSven Eckelmann 					      common);
18348100bacSAntonio Quartulli 	return tt_local_entry;
1847aadf889SMarek Lindner }
1857aadf889SMarek Lindner 
186c018ad3dSAntonio Quartulli /**
1877e9a8c2cSSven Eckelmann  * batadv_tt_global_hash_find() - search the global table for a given client
188c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
189c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to look for
190c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
191c018ad3dSAntonio Quartulli  *
19262fe710fSSven Eckelmann  * Return: a pointer to the corresponding tt_global_entry struct if the client
193c018ad3dSAntonio Quartulli  * is found, NULL otherwise.
194c018ad3dSAntonio Quartulli  */
19532e72744SLinus Lüssing struct batadv_tt_global_entry *
batadv_tt_global_hash_find(struct batadv_priv * bat_priv,const u8 * addr,unsigned short vid)1966b5e971aSSven Eckelmann batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
197c018ad3dSAntonio Quartulli 			   unsigned short vid)
1987aadf889SMarek Lindner {
19956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
20056303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry = NULL;
2017aadf889SMarek Lindner 
202c018ad3dSAntonio Quartulli 	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr,
203c018ad3dSAntonio Quartulli 					      vid);
20448100bacSAntonio Quartulli 	if (tt_common_entry)
20548100bacSAntonio Quartulli 		tt_global_entry = container_of(tt_common_entry,
20656303d34SSven Eckelmann 					       struct batadv_tt_global_entry,
20756303d34SSven Eckelmann 					       common);
20848100bacSAntonio Quartulli 	return tt_global_entry;
2097aadf889SMarek Lindner }
2107aadf889SMarek Lindner 
21192dcdf09SSven Eckelmann /**
2127e9a8c2cSSven Eckelmann  * batadv_tt_local_entry_free_rcu() - free the tt_local_entry
21386452f81SSven Eckelmann  * @rcu: rcu pointer of the tt_local_entry
21486452f81SSven Eckelmann  */
batadv_tt_local_entry_free_rcu(struct rcu_head * rcu)21586452f81SSven Eckelmann static void batadv_tt_local_entry_free_rcu(struct rcu_head *rcu)
21686452f81SSven Eckelmann {
21786452f81SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
21886452f81SSven Eckelmann 
21986452f81SSven Eckelmann 	tt_local_entry = container_of(rcu, struct batadv_tt_local_entry,
22086452f81SSven Eckelmann 				      common.rcu);
22186452f81SSven Eckelmann 
22286452f81SSven Eckelmann 	kmem_cache_free(batadv_tl_cache, tt_local_entry);
22386452f81SSven Eckelmann }
22486452f81SSven Eckelmann 
22586452f81SSven Eckelmann /**
2267e9a8c2cSSven Eckelmann  * batadv_tt_local_entry_release() - release tt_local_entry from lists and queue
22792dcdf09SSven Eckelmann  *  for free after rcu grace period
22892dcdf09SSven Eckelmann  * @ref: kref pointer of the nc_node
22992dcdf09SSven Eckelmann  */
batadv_tt_local_entry_release(struct kref * ref)23092dcdf09SSven Eckelmann static void batadv_tt_local_entry_release(struct kref *ref)
2317683fdc1SAntonio Quartulli {
23292dcdf09SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
23392dcdf09SSven Eckelmann 
23492dcdf09SSven Eckelmann 	tt_local_entry = container_of(ref, struct batadv_tt_local_entry,
23592dcdf09SSven Eckelmann 				      common.refcount);
23692dcdf09SSven Eckelmann 
237a33d970dSSven Eckelmann 	batadv_softif_vlan_put(tt_local_entry->vlan);
238a33d970dSSven Eckelmann 
23986452f81SSven Eckelmann 	call_rcu(&tt_local_entry->common.rcu, batadv_tt_local_entry_free_rcu);
2407683fdc1SAntonio Quartulli }
2417683fdc1SAntonio Quartulli 
24221026059SAntonio Quartulli /**
2437e9a8c2cSSven Eckelmann  * batadv_tt_local_entry_put() - decrement the tt_local_entry refcounter and
24492dcdf09SSven Eckelmann  *  possibly release it
24592dcdf09SSven Eckelmann  * @tt_local_entry: tt_local_entry to be free'd
24692dcdf09SSven Eckelmann  */
24792dcdf09SSven Eckelmann static void
batadv_tt_local_entry_put(struct batadv_tt_local_entry * tt_local_entry)24895c0db90SSven Eckelmann batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry)
24992dcdf09SSven Eckelmann {
2506340dcbdSSven Eckelmann 	if (!tt_local_entry)
2516340dcbdSSven Eckelmann 		return;
2526340dcbdSSven Eckelmann 
25392dcdf09SSven Eckelmann 	kref_put(&tt_local_entry->common.refcount,
25492dcdf09SSven Eckelmann 		 batadv_tt_local_entry_release);
25592dcdf09SSven Eckelmann }
25692dcdf09SSven Eckelmann 
25792dcdf09SSven Eckelmann /**
2587e9a8c2cSSven Eckelmann  * batadv_tt_global_entry_free_rcu() - free the tt_global_entry
25986452f81SSven Eckelmann  * @rcu: rcu pointer of the tt_global_entry
26086452f81SSven Eckelmann  */
batadv_tt_global_entry_free_rcu(struct rcu_head * rcu)26186452f81SSven Eckelmann static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu)
26286452f81SSven Eckelmann {
26386452f81SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
26486452f81SSven Eckelmann 
26586452f81SSven Eckelmann 	tt_global_entry = container_of(rcu, struct batadv_tt_global_entry,
26686452f81SSven Eckelmann 				       common.rcu);
26786452f81SSven Eckelmann 
26886452f81SSven Eckelmann 	kmem_cache_free(batadv_tg_cache, tt_global_entry);
26986452f81SSven Eckelmann }
27086452f81SSven Eckelmann 
27186452f81SSven Eckelmann /**
2727e9a8c2cSSven Eckelmann  * batadv_tt_global_entry_release() - release tt_global_entry from lists and
2737e9a8c2cSSven Eckelmann  *  queue for free after rcu grace period
27492dcdf09SSven Eckelmann  * @ref: kref pointer of the nc_node
27592dcdf09SSven Eckelmann  */
batadv_tt_global_entry_release(struct kref * ref)2766340dcbdSSven Eckelmann void batadv_tt_global_entry_release(struct kref *ref)
27792dcdf09SSven Eckelmann {
27892dcdf09SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
27992dcdf09SSven Eckelmann 
28092dcdf09SSven Eckelmann 	tt_global_entry = container_of(ref, struct batadv_tt_global_entry,
28192dcdf09SSven Eckelmann 				       common.refcount);
28292dcdf09SSven Eckelmann 
28392dcdf09SSven Eckelmann 	batadv_tt_global_del_orig_list(tt_global_entry);
28486452f81SSven Eckelmann 
28586452f81SSven Eckelmann 	call_rcu(&tt_global_entry->common.rcu, batadv_tt_global_entry_free_rcu);
28692dcdf09SSven Eckelmann }
28792dcdf09SSven Eckelmann 
28892dcdf09SSven Eckelmann /**
2897e9a8c2cSSven Eckelmann  * batadv_tt_global_hash_count() - count the number of orig entries
290d15cd622SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2911d8ab8d3SLinus Lüssing  * @addr: the mac address of the client to count entries for
2921d8ab8d3SLinus Lüssing  * @vid: VLAN identifier
2931d8ab8d3SLinus Lüssing  *
29462fe710fSSven Eckelmann  * Return: the number of originators advertising the given address/data
2951d8ab8d3SLinus Lüssing  * (excluding our self).
2961d8ab8d3SLinus Lüssing  */
batadv_tt_global_hash_count(struct batadv_priv * bat_priv,const u8 * addr,unsigned short vid)2971d8ab8d3SLinus Lüssing int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
2986b5e971aSSven Eckelmann 				const u8 *addr, unsigned short vid)
2991d8ab8d3SLinus Lüssing {
3001d8ab8d3SLinus Lüssing 	struct batadv_tt_global_entry *tt_global_entry;
3011d8ab8d3SLinus Lüssing 	int count;
3021d8ab8d3SLinus Lüssing 
3031d8ab8d3SLinus Lüssing 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
3041d8ab8d3SLinus Lüssing 	if (!tt_global_entry)
3051d8ab8d3SLinus Lüssing 		return 0;
3061d8ab8d3SLinus Lüssing 
3071d8ab8d3SLinus Lüssing 	count = atomic_read(&tt_global_entry->orig_list_count);
3085dafd8a6SSven Eckelmann 	batadv_tt_global_entry_put(tt_global_entry);
3091d8ab8d3SLinus Lüssing 
3101d8ab8d3SLinus Lüssing 	return count;
3111d8ab8d3SLinus Lüssing }
3121d8ab8d3SLinus Lüssing 
3137ea7b4a1SAntonio Quartulli /**
3147e9a8c2cSSven Eckelmann  * batadv_tt_local_size_mod() - change the size by v of the local table
3157e9a8c2cSSven Eckelmann  *  identified by vid
3167ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3177ea7b4a1SAntonio Quartulli  * @vid: the VLAN identifier of the sub-table to change
3187ea7b4a1SAntonio Quartulli  * @v: the amount to sum to the local table size
3197ea7b4a1SAntonio Quartulli  */
batadv_tt_local_size_mod(struct batadv_priv * bat_priv,unsigned short vid,int v)3207ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
3217ea7b4a1SAntonio Quartulli 				     unsigned short vid, int v)
3227ea7b4a1SAntonio Quartulli {
3237ea7b4a1SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
3247ea7b4a1SAntonio Quartulli 
3257ea7b4a1SAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
3267ea7b4a1SAntonio Quartulli 	if (!vlan)
3277ea7b4a1SAntonio Quartulli 		return;
3287ea7b4a1SAntonio Quartulli 
3297ea7b4a1SAntonio Quartulli 	atomic_add(v, &vlan->tt.num_entries);
3307ea7b4a1SAntonio Quartulli 
3319c3bf081SSven Eckelmann 	batadv_softif_vlan_put(vlan);
3327ea7b4a1SAntonio Quartulli }
3337ea7b4a1SAntonio Quartulli 
3347ea7b4a1SAntonio Quartulli /**
3357e9a8c2cSSven Eckelmann  * batadv_tt_local_size_inc() - increase by one the local table size for the
3367e9a8c2cSSven Eckelmann  *  given vid
3377ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3387ea7b4a1SAntonio Quartulli  * @vid: the VLAN identifier
3397ea7b4a1SAntonio Quartulli  */
batadv_tt_local_size_inc(struct batadv_priv * bat_priv,unsigned short vid)3407ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
3417ea7b4a1SAntonio Quartulli 				     unsigned short vid)
3427ea7b4a1SAntonio Quartulli {
3437ea7b4a1SAntonio Quartulli 	batadv_tt_local_size_mod(bat_priv, vid, 1);
3447ea7b4a1SAntonio Quartulli }
3457ea7b4a1SAntonio Quartulli 
3467ea7b4a1SAntonio Quartulli /**
3477e9a8c2cSSven Eckelmann  * batadv_tt_local_size_dec() - decrease by one the local table size for the
3487e9a8c2cSSven Eckelmann  *  given vid
3497ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3507ea7b4a1SAntonio Quartulli  * @vid: the VLAN identifier
3517ea7b4a1SAntonio Quartulli  */
batadv_tt_local_size_dec(struct batadv_priv * bat_priv,unsigned short vid)3527ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
3537ea7b4a1SAntonio Quartulli 				     unsigned short vid)
3547ea7b4a1SAntonio Quartulli {
3557ea7b4a1SAntonio Quartulli 	batadv_tt_local_size_mod(bat_priv, vid, -1);
3567ea7b4a1SAntonio Quartulli }
3577ea7b4a1SAntonio Quartulli 
3587ea7b4a1SAntonio Quartulli /**
3597e9a8c2cSSven Eckelmann  * batadv_tt_global_size_mod() - change the size by v of the global table
360d15cd622SAntonio Quartulli  *  for orig_node identified by vid
361d15cd622SAntonio Quartulli  * @orig_node: the originator for which the table has to be modified
3627ea7b4a1SAntonio Quartulli  * @vid: the VLAN identifier
3637ea7b4a1SAntonio Quartulli  * @v: the amount to sum to the global table size
3647ea7b4a1SAntonio Quartulli  */
batadv_tt_global_size_mod(struct batadv_orig_node * orig_node,unsigned short vid,int v)3657ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node,
3667ea7b4a1SAntonio Quartulli 				      unsigned short vid, int v)
3677ea7b4a1SAntonio Quartulli {
3687ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
3697ea7b4a1SAntonio Quartulli 
3707ea7b4a1SAntonio Quartulli 	vlan = batadv_orig_node_vlan_new(orig_node, vid);
3717ea7b4a1SAntonio Quartulli 	if (!vlan)
3727ea7b4a1SAntonio Quartulli 		return;
3737ea7b4a1SAntonio Quartulli 
3747ea7b4a1SAntonio Quartulli 	if (atomic_add_return(v, &vlan->tt.num_entries) == 0) {
3757ea7b4a1SAntonio Quartulli 		spin_lock_bh(&orig_node->vlan_list_lock);
3763db15209SSven Eckelmann 		if (!hlist_unhashed(&vlan->list)) {
377a121048aSMarek Lindner 			hlist_del_init_rcu(&vlan->list);
37821754e25SSven Eckelmann 			batadv_orig_node_vlan_put(vlan);
3797ea7b4a1SAntonio Quartulli 		}
3803db15209SSven Eckelmann 		spin_unlock_bh(&orig_node->vlan_list_lock);
3813db15209SSven Eckelmann 	}
3827ea7b4a1SAntonio Quartulli 
38321754e25SSven Eckelmann 	batadv_orig_node_vlan_put(vlan);
3847ea7b4a1SAntonio Quartulli }
3857ea7b4a1SAntonio Quartulli 
3867ea7b4a1SAntonio Quartulli /**
3877e9a8c2cSSven Eckelmann  * batadv_tt_global_size_inc() - increase by one the global table size for the
3887ea7b4a1SAntonio Quartulli  *  given vid
3897ea7b4a1SAntonio Quartulli  * @orig_node: the originator which global table size has to be decreased
3907ea7b4a1SAntonio Quartulli  * @vid: the vlan identifier
3917ea7b4a1SAntonio Quartulli  */
batadv_tt_global_size_inc(struct batadv_orig_node * orig_node,unsigned short vid)3927ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node,
3937ea7b4a1SAntonio Quartulli 				      unsigned short vid)
3947ea7b4a1SAntonio Quartulli {
3957ea7b4a1SAntonio Quartulli 	batadv_tt_global_size_mod(orig_node, vid, 1);
3967ea7b4a1SAntonio Quartulli }
3977ea7b4a1SAntonio Quartulli 
3987ea7b4a1SAntonio Quartulli /**
3997e9a8c2cSSven Eckelmann  * batadv_tt_global_size_dec() - decrease by one the global table size for the
4007ea7b4a1SAntonio Quartulli  *  given vid
4017ea7b4a1SAntonio Quartulli  * @orig_node: the originator which global table size has to be decreased
4027ea7b4a1SAntonio Quartulli  * @vid: the vlan identifier
4037ea7b4a1SAntonio Quartulli  */
batadv_tt_global_size_dec(struct batadv_orig_node * orig_node,unsigned short vid)4047ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node,
4057ea7b4a1SAntonio Quartulli 				      unsigned short vid)
4067ea7b4a1SAntonio Quartulli {
4077ea7b4a1SAntonio Quartulli 	batadv_tt_global_size_mod(orig_node, vid, -1);
4087ea7b4a1SAntonio Quartulli }
4097ea7b4a1SAntonio Quartulli 
41042eff6a6SSven Eckelmann /**
4117e9a8c2cSSven Eckelmann  * batadv_tt_orig_list_entry_free_rcu() - free the orig_entry
41286452f81SSven Eckelmann  * @rcu: rcu pointer of the orig_entry
41386452f81SSven Eckelmann  */
batadv_tt_orig_list_entry_free_rcu(struct rcu_head * rcu)41486452f81SSven Eckelmann static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
41586452f81SSven Eckelmann {
41686452f81SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
41786452f81SSven Eckelmann 
41886452f81SSven Eckelmann 	orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu);
41986452f81SSven Eckelmann 
42086452f81SSven Eckelmann 	kmem_cache_free(batadv_tt_orig_cache, orig_entry);
42186452f81SSven Eckelmann }
42286452f81SSven Eckelmann 
42386452f81SSven Eckelmann /**
4247e9a8c2cSSven Eckelmann  * batadv_tt_orig_list_entry_release() - release tt orig entry from lists and
42542eff6a6SSven Eckelmann  *  queue for free after rcu grace period
4266e8ef69dSSven Eckelmann  * @ref: kref pointer of the tt orig entry
42742eff6a6SSven Eckelmann  */
batadv_tt_orig_list_entry_release(struct kref * ref)4286e8ef69dSSven Eckelmann static void batadv_tt_orig_list_entry_release(struct kref *ref)
42942eff6a6SSven Eckelmann {
4306e8ef69dSSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
4316e8ef69dSSven Eckelmann 
4326e8ef69dSSven Eckelmann 	orig_entry = container_of(ref, struct batadv_tt_orig_list_entry,
4336e8ef69dSSven Eckelmann 				  refcount);
4346e8ef69dSSven Eckelmann 
4355d967310SSven Eckelmann 	batadv_orig_node_put(orig_entry->orig_node);
43686452f81SSven Eckelmann 	call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
43742eff6a6SSven Eckelmann }
43842eff6a6SSven Eckelmann 
4396e8ef69dSSven Eckelmann /**
4407e9a8c2cSSven Eckelmann  * batadv_tt_orig_list_entry_put() - decrement the tt orig entry refcounter and
4417e2366c6SSven Eckelmann  *  possibly release it
4426e8ef69dSSven Eckelmann  * @orig_entry: tt orig entry to be free'd
4436e8ef69dSSven Eckelmann  */
444a513088dSSven Eckelmann static void
batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry * orig_entry)4457e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry)
446db08e6e5SSimon Wunderlich {
4476340dcbdSSven Eckelmann 	if (!orig_entry)
4486340dcbdSSven Eckelmann 		return;
4496340dcbdSSven Eckelmann 
4506e8ef69dSSven Eckelmann 	kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release);
451db08e6e5SSimon Wunderlich }
4527683fdc1SAntonio Quartulli 
4533abe4adbSAntonio Quartulli /**
4547e9a8c2cSSven Eckelmann  * batadv_tt_local_event() - store a local TT event (ADD/DEL)
4553abe4adbSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
4563abe4adbSAntonio Quartulli  * @tt_local_entry: the TT entry involved in the event
4573abe4adbSAntonio Quartulli  * @event_flags: flags to store in the event structure
4583abe4adbSAntonio Quartulli  */
batadv_tt_local_event(struct batadv_priv * bat_priv,struct batadv_tt_local_entry * tt_local_entry,u8 event_flags)45956303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv,
4603abe4adbSAntonio Quartulli 				  struct batadv_tt_local_entry *tt_local_entry,
4616b5e971aSSven Eckelmann 				  u8 event_flags)
462a73105b8SAntonio Quartulli {
46356303d34SSven Eckelmann 	struct batadv_tt_change_node *tt_change_node, *entry, *safe;
4643abe4adbSAntonio Quartulli 	struct batadv_tt_common_entry *common = &tt_local_entry->common;
4656b5e971aSSven Eckelmann 	u8 flags = common->flags | event_flags;
4663b643de5SAntonio Quartulli 	bool event_removed = false;
4673b643de5SAntonio Quartulli 	bool del_op_requested, del_op_entry;
468a73105b8SAntonio Quartulli 
46986452f81SSven Eckelmann 	tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC);
470a73105b8SAntonio Quartulli 	if (!tt_change_node)
471a73105b8SAntonio Quartulli 		return;
472a73105b8SAntonio Quartulli 
473ff66c975SAntonio Quartulli 	tt_change_node->change.flags = flags;
474ca663046SAntonio Quartulli 	memset(tt_change_node->change.reserved, 0,
475ca663046SAntonio Quartulli 	       sizeof(tt_change_node->change.reserved));
4768fdd0153SAntonio Quartulli 	ether_addr_copy(tt_change_node->change.addr, common->addr);
477c018ad3dSAntonio Quartulli 	tt_change_node->change.vid = htons(common->vid);
478a73105b8SAntonio Quartulli 
479acd34afaSSven Eckelmann 	del_op_requested = flags & BATADV_TT_CLIENT_DEL;
4803b643de5SAntonio Quartulli 
4813b643de5SAntonio Quartulli 	/* check for ADD+DEL or DEL+ADD events */
482807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
483807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
4843b643de5SAntonio Quartulli 				 list) {
4853abe4adbSAntonio Quartulli 		if (!batadv_compare_eth(entry->change.addr, common->addr))
4863b643de5SAntonio Quartulli 			continue;
4873b643de5SAntonio Quartulli 
4883b643de5SAntonio Quartulli 		/* DEL+ADD in the same orig interval have no effect and can be
4893b643de5SAntonio Quartulli 		 * removed to avoid silly behaviour on the receiver side. The
4903b643de5SAntonio Quartulli 		 * other way around (ADD+DEL) can happen in case of roaming of
4913b643de5SAntonio Quartulli 		 * a client still in the NEW state. Roaming of NEW clients is
4923b643de5SAntonio Quartulli 		 * now possible due to automatically recognition of "temporary"
4933b643de5SAntonio Quartulli 		 * clients
4943b643de5SAntonio Quartulli 		 */
495acd34afaSSven Eckelmann 		del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
4963b643de5SAntonio Quartulli 		if (!del_op_requested && del_op_entry)
4973b643de5SAntonio Quartulli 			goto del;
4983b643de5SAntonio Quartulli 		if (del_op_requested && !del_op_entry)
4993b643de5SAntonio Quartulli 			goto del;
5003c4f7ab6SAntonio Quartulli 
5013c4f7ab6SAntonio Quartulli 		/* this is a second add in the same originator interval. It
5023c4f7ab6SAntonio Quartulli 		 * means that flags have been changed: update them!
5033c4f7ab6SAntonio Quartulli 		 */
5043c4f7ab6SAntonio Quartulli 		if (!del_op_requested && !del_op_entry)
5053c4f7ab6SAntonio Quartulli 			entry->change.flags = flags;
5063c4f7ab6SAntonio Quartulli 
5073b643de5SAntonio Quartulli 		continue;
5083b643de5SAntonio Quartulli del:
5093b643de5SAntonio Quartulli 		list_del(&entry->list);
51086452f81SSven Eckelmann 		kmem_cache_free(batadv_tt_change_cache, entry);
51186452f81SSven Eckelmann 		kmem_cache_free(batadv_tt_change_cache, tt_change_node);
5123b643de5SAntonio Quartulli 		event_removed = true;
5133b643de5SAntonio Quartulli 		goto unlock;
5143b643de5SAntonio Quartulli 	}
5153b643de5SAntonio Quartulli 
516a73105b8SAntonio Quartulli 	/* track the change in the OGMinterval list */
517807736f6SSven Eckelmann 	list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list);
5183b643de5SAntonio Quartulli 
5193b643de5SAntonio Quartulli unlock:
520807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
521a73105b8SAntonio Quartulli 
5223b643de5SAntonio Quartulli 	if (event_removed)
523807736f6SSven Eckelmann 		atomic_dec(&bat_priv->tt.local_changes);
5243b643de5SAntonio Quartulli 	else
525807736f6SSven Eckelmann 		atomic_inc(&bat_priv->tt.local_changes);
526a73105b8SAntonio Quartulli }
527a73105b8SAntonio Quartulli 
528335fbe0fSMarek Lindner /**
5297e9a8c2cSSven Eckelmann  * batadv_tt_len() - compute length in bytes of given number of tt changes
530335fbe0fSMarek Lindner  * @changes_num: number of tt changes
531335fbe0fSMarek Lindner  *
53262fe710fSSven Eckelmann  * Return: computed length in bytes.
533335fbe0fSMarek Lindner  */
batadv_tt_len(int changes_num)534335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num)
535a73105b8SAntonio Quartulli {
536335fbe0fSMarek Lindner 	return changes_num * sizeof(struct batadv_tvlv_tt_change);
537a73105b8SAntonio Quartulli }
538a73105b8SAntonio Quartulli 
539298e6e68SAntonio Quartulli /**
5407e9a8c2cSSven Eckelmann  * batadv_tt_entries() - compute the number of entries fitting in tt_len bytes
541298e6e68SAntonio Quartulli  * @tt_len: available space
542298e6e68SAntonio Quartulli  *
54362fe710fSSven Eckelmann  * Return: the number of entries.
544298e6e68SAntonio Quartulli  */
batadv_tt_entries(u16 tt_len)5456b5e971aSSven Eckelmann static u16 batadv_tt_entries(u16 tt_len)
546298e6e68SAntonio Quartulli {
547298e6e68SAntonio Quartulli 	return tt_len / batadv_tt_len(1);
548298e6e68SAntonio Quartulli }
549298e6e68SAntonio Quartulli 
550a19d3d85SMarek Lindner /**
5517e9a8c2cSSven Eckelmann  * batadv_tt_local_table_transmit_size() - calculates the local translation
5527e9a8c2cSSven Eckelmann  *  table size when transmitted over the air
553a19d3d85SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
554a19d3d85SMarek Lindner  *
55562fe710fSSven Eckelmann  * Return: local translation table size in bytes.
556a19d3d85SMarek Lindner  */
batadv_tt_local_table_transmit_size(struct batadv_priv * bat_priv)557a19d3d85SMarek Lindner static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
558a19d3d85SMarek Lindner {
5594f248cffSSven Eckelmann 	u16 num_vlan = 0;
5604f248cffSSven Eckelmann 	u16 tt_local_entries = 0;
561a19d3d85SMarek Lindner 	struct batadv_softif_vlan *vlan;
562a19d3d85SMarek Lindner 	int hdr_size;
563a19d3d85SMarek Lindner 
564a19d3d85SMarek Lindner 	rcu_read_lock();
565a19d3d85SMarek Lindner 	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
566a19d3d85SMarek Lindner 		num_vlan++;
567a19d3d85SMarek Lindner 		tt_local_entries += atomic_read(&vlan->tt.num_entries);
568a19d3d85SMarek Lindner 	}
569a19d3d85SMarek Lindner 	rcu_read_unlock();
570a19d3d85SMarek Lindner 
571a19d3d85SMarek Lindner 	/* header size of tvlv encapsulated tt response payload */
572a19d3d85SMarek Lindner 	hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
573a19d3d85SMarek Lindner 	hdr_size += sizeof(struct batadv_tvlv_hdr);
574a19d3d85SMarek Lindner 	hdr_size += sizeof(struct batadv_tvlv_tt_data);
575a19d3d85SMarek Lindner 	hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
576a19d3d85SMarek Lindner 
577a19d3d85SMarek Lindner 	return hdr_size + batadv_tt_len(tt_local_entries);
578a19d3d85SMarek Lindner }
579a19d3d85SMarek Lindner 
batadv_tt_local_init(struct batadv_priv * bat_priv)58056303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv)
581c6c8fea2SSven Eckelmann {
582807736f6SSven Eckelmann 	if (bat_priv->tt.local_hash)
5835346c35eSSven Eckelmann 		return 0;
584c6c8fea2SSven Eckelmann 
585807736f6SSven Eckelmann 	bat_priv->tt.local_hash = batadv_hash_new(1024);
586c6c8fea2SSven Eckelmann 
587807736f6SSven Eckelmann 	if (!bat_priv->tt.local_hash)
5885346c35eSSven Eckelmann 		return -ENOMEM;
589c6c8fea2SSven Eckelmann 
590dec05074SAntonio Quartulli 	batadv_hash_set_lock_class(bat_priv->tt.local_hash,
591dec05074SAntonio Quartulli 				   &batadv_tt_local_hash_lock_class_key);
592dec05074SAntonio Quartulli 
5935346c35eSSven Eckelmann 	return 0;
594c6c8fea2SSven Eckelmann }
595c6c8fea2SSven Eckelmann 
batadv_tt_global_free(struct batadv_priv * bat_priv,struct batadv_tt_global_entry * tt_global,const char * message)596068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv,
597068ee6e2SAntonio Quartulli 				  struct batadv_tt_global_entry *tt_global,
598068ee6e2SAntonio Quartulli 				  const char *message)
599068ee6e2SAntonio Quartulli {
600f131a568SSven Eckelmann 	struct batadv_tt_global_entry *tt_removed_entry;
601f131a568SSven Eckelmann 	struct hlist_node *tt_removed_node;
602f131a568SSven Eckelmann 
603068ee6e2SAntonio Quartulli 	batadv_dbg(BATADV_DBG_TT, bat_priv,
60416052789SAntonio Quartulli 		   "Deleting global tt entry %pM (vid: %d): %s\n",
60516052789SAntonio Quartulli 		   tt_global->common.addr,
606f7a2bd65SSven Eckelmann 		   batadv_print_vid(tt_global->common.vid), message);
607068ee6e2SAntonio Quartulli 
608f131a568SSven Eckelmann 	tt_removed_node = batadv_hash_remove(bat_priv->tt.global_hash,
609f131a568SSven Eckelmann 					     batadv_compare_tt,
610f131a568SSven Eckelmann 					     batadv_choose_tt,
611f131a568SSven Eckelmann 					     &tt_global->common);
612f131a568SSven Eckelmann 	if (!tt_removed_node)
613f131a568SSven Eckelmann 		return;
614f131a568SSven Eckelmann 
615f131a568SSven Eckelmann 	/* drop reference of remove hash entry */
616f131a568SSven Eckelmann 	tt_removed_entry = hlist_entry(tt_removed_node,
617f131a568SSven Eckelmann 				       struct batadv_tt_global_entry,
618f131a568SSven Eckelmann 				       common.hash_entry);
619f131a568SSven Eckelmann 	batadv_tt_global_entry_put(tt_removed_entry);
620068ee6e2SAntonio Quartulli }
621068ee6e2SAntonio Quartulli 
622c018ad3dSAntonio Quartulli /**
6237e9a8c2cSSven Eckelmann  * batadv_tt_local_add() - add a new client to the local table or update an
624c018ad3dSAntonio Quartulli  *  existing client
625c018ad3dSAntonio Quartulli  * @soft_iface: netdev struct of the mesh interface
626c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to add
627c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
628c018ad3dSAntonio Quartulli  * @ifindex: index of the interface where the client is connected to (useful to
629c018ad3dSAntonio Quartulli  *  identify wireless clients)
6309464d071SAntonio Quartulli  * @mark: the value contained in the skb->mark field of the received packet (if
6319464d071SAntonio Quartulli  *  any)
632a19d3d85SMarek Lindner  *
63362fe710fSSven Eckelmann  * Return: true if the client was successfully added, false otherwise.
634c018ad3dSAntonio Quartulli  */
batadv_tt_local_add(struct net_device * soft_iface,const u8 * addr,unsigned short vid,int ifindex,u32 mark)6356b5e971aSSven Eckelmann bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
6366b5e971aSSven Eckelmann 			 unsigned short vid, int ifindex, u32 mark)
637c6c8fea2SSven Eckelmann {
63856303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
639170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
640c5caf4efSLinus Lüssing 	struct batadv_tt_global_entry *tt_global = NULL;
6412cd45a06SAndrew Lunn 	struct net *net = dev_net(soft_iface);
64235df3b29SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
6430c69aeccSAntonio Quartulli 	struct net_device *in_dev = NULL;
64410b1bbb4SSven Eckelmann 	struct batadv_hard_iface *in_hardif = NULL;
645db08e6e5SSimon Wunderlich 	struct hlist_head *head;
64656303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
647a19d3d85SMarek Lindner 	int hash_added, table_size, packet_size_max;
6484f248cffSSven Eckelmann 	bool ret = false;
6494f248cffSSven Eckelmann 	bool roamed_back = false;
6506b5e971aSSven Eckelmann 	u8 remote_flags;
6516b5e971aSSven Eckelmann 	u32 match_mark;
652c6c8fea2SSven Eckelmann 
6530c69aeccSAntonio Quartulli 	if (ifindex != BATADV_NULL_IFINDEX)
6542cd45a06SAndrew Lunn 		in_dev = dev_get_by_index(net, ifindex);
6550c69aeccSAntonio Quartulli 
65610b1bbb4SSven Eckelmann 	if (in_dev)
65710b1bbb4SSven Eckelmann 		in_hardif = batadv_hardif_get_by_netdev(in_dev);
65810b1bbb4SSven Eckelmann 
659c018ad3dSAntonio Quartulli 	tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
660c5caf4efSLinus Lüssing 
661c5caf4efSLinus Lüssing 	if (!is_multicast_ether_addr(addr))
662c018ad3dSAntonio Quartulli 		tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
663c6c8fea2SSven Eckelmann 
66447c94655SAntonio Quartulli 	if (tt_local) {
66547c94655SAntonio Quartulli 		tt_local->last_seen = jiffies;
666068ee6e2SAntonio Quartulli 		if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
667068ee6e2SAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
66816052789SAntonio Quartulli 				   "Re-adding pending client %pM (vid: %d)\n",
669f7a2bd65SSven Eckelmann 				   addr, batadv_print_vid(vid));
670068ee6e2SAntonio Quartulli 			/* whatever the reason why the PENDING flag was set,
671068ee6e2SAntonio Quartulli 			 * this is a client which was enqueued to be removed in
672068ee6e2SAntonio Quartulli 			 * this orig_interval. Since it popped up again, the
673068ee6e2SAntonio Quartulli 			 * flag can be reset like it was never enqueued
674068ee6e2SAntonio Quartulli 			 */
67547c94655SAntonio Quartulli 			tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
676068ee6e2SAntonio Quartulli 			goto add_event;
677068ee6e2SAntonio Quartulli 		}
678068ee6e2SAntonio Quartulli 
679068ee6e2SAntonio Quartulli 		if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
680068ee6e2SAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
68116052789SAntonio Quartulli 				   "Roaming client %pM (vid: %d) came back to its original location\n",
682f7a2bd65SSven Eckelmann 				   addr, batadv_print_vid(vid));
683068ee6e2SAntonio Quartulli 			/* the ROAM flag is set because this client roamed away
684068ee6e2SAntonio Quartulli 			 * and the node got a roaming_advertisement message. Now
685068ee6e2SAntonio Quartulli 			 * that the client popped up again at its original
686068ee6e2SAntonio Quartulli 			 * location such flag can be unset
687068ee6e2SAntonio Quartulli 			 */
688068ee6e2SAntonio Quartulli 			tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
689068ee6e2SAntonio Quartulli 			roamed_back = true;
690068ee6e2SAntonio Quartulli 		}
691068ee6e2SAntonio Quartulli 		goto check_roaming;
692c6c8fea2SSven Eckelmann 	}
693c6c8fea2SSven Eckelmann 
694a19d3d85SMarek Lindner 	/* Ignore the client if we cannot send it in a full table response. */
695a19d3d85SMarek Lindner 	table_size = batadv_tt_local_table_transmit_size(bat_priv);
696a19d3d85SMarek Lindner 	table_size += batadv_tt_len(1);
697a19d3d85SMarek Lindner 	packet_size_max = atomic_read(&bat_priv->packet_size_max);
698a19d3d85SMarek Lindner 	if (table_size > packet_size_max) {
699a19d3d85SMarek Lindner 		net_ratelimited_function(batadv_info, soft_iface,
700a19d3d85SMarek Lindner 					 "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
701a19d3d85SMarek Lindner 					 table_size, packet_size_max, addr);
702a19d3d85SMarek Lindner 		goto out;
703a19d3d85SMarek Lindner 	}
704a19d3d85SMarek Lindner 
70586452f81SSven Eckelmann 	tt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);
70647c94655SAntonio Quartulli 	if (!tt_local)
7077683fdc1SAntonio Quartulli 		goto out;
708a73105b8SAntonio Quartulli 
70935df3b29SAntonio Quartulli 	/* increase the refcounter of the related vlan */
71035df3b29SAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
7110b3dd7dfSSimon Wunderlich 	if (!vlan) {
7120b3dd7dfSSimon Wunderlich 		net_ratelimited_function(batadv_info, soft_iface,
7130b3dd7dfSSimon Wunderlich 					 "adding TT local entry %pM to non-existent VLAN %d\n",
714f7a2bd65SSven Eckelmann 					 addr, batadv_print_vid(vid));
71586452f81SSven Eckelmann 		kmem_cache_free(batadv_tl_cache, tt_local);
716fd7dec25SSven Eckelmann 		tt_local = NULL;
717354136bcSMarek Lindner 		goto out;
718fd7dec25SSven Eckelmann 	}
71935df3b29SAntonio Quartulli 
72039c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
72116052789SAntonio Quartulli 		   "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
722f7a2bd65SSven Eckelmann 		   addr, batadv_print_vid(vid),
7236b5e971aSSven Eckelmann 		   (u8)atomic_read(&bat_priv->tt.vn));
724c6c8fea2SSven Eckelmann 
7258fdd0153SAntonio Quartulli 	ether_addr_copy(tt_local->common.addr, addr);
7268425ec6aSAntonio Quartulli 	/* The local entry has to be marked as NEW to avoid to send it in
7278425ec6aSAntonio Quartulli 	 * a full table response going out before the next ttvn increment
7288425ec6aSAntonio Quartulli 	 * (consistency check)
7298425ec6aSAntonio Quartulli 	 */
7308425ec6aSAntonio Quartulli 	tt_local->common.flags = BATADV_TT_CLIENT_NEW;
731c018ad3dSAntonio Quartulli 	tt_local->common.vid = vid;
73210b1bbb4SSven Eckelmann 	if (batadv_is_wifi_hardif(in_hardif))
73347c94655SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
73492dcdf09SSven Eckelmann 	kref_init(&tt_local->common.refcount);
73547c94655SAntonio Quartulli 	tt_local->last_seen = jiffies;
73647c94655SAntonio Quartulli 	tt_local->common.added_at = tt_local->last_seen;
737a33d970dSSven Eckelmann 	tt_local->vlan = vlan;
738c6c8fea2SSven Eckelmann 
739c5caf4efSLinus Lüssing 	/* the batman interface mac and multicast addresses should never be
740c5caf4efSLinus Lüssing 	 * purged
741c5caf4efSLinus Lüssing 	 */
742c5caf4efSLinus Lüssing 	if (batadv_compare_eth(addr, soft_iface->dev_addr) ||
743c5caf4efSLinus Lüssing 	    is_multicast_ether_addr(addr))
74447c94655SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
745c6c8fea2SSven Eckelmann 
746e3387b26SSven Eckelmann 	kref_get(&tt_local->common.refcount);
747807736f6SSven Eckelmann 	hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
748c018ad3dSAntonio Quartulli 				     batadv_choose_tt, &tt_local->common,
74947c94655SAntonio Quartulli 				     &tt_local->common.hash_entry);
75080b3f58cSSimon Wunderlich 
75180b3f58cSSimon Wunderlich 	if (unlikely(hash_added != 0)) {
75280b3f58cSSimon Wunderlich 		/* remove the reference for the hash */
75395c0db90SSven Eckelmann 		batadv_tt_local_entry_put(tt_local);
75480b3f58cSSimon Wunderlich 		goto out;
75580b3f58cSSimon Wunderlich 	}
75680b3f58cSSimon Wunderlich 
757068ee6e2SAntonio Quartulli add_event:
7583abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
759ff66c975SAntonio Quartulli 
760068ee6e2SAntonio Quartulli check_roaming:
761068ee6e2SAntonio Quartulli 	/* Check whether it is a roaming, but don't do anything if the roaming
762068ee6e2SAntonio Quartulli 	 * process has already been handled
763068ee6e2SAntonio Quartulli 	 */
764068ee6e2SAntonio Quartulli 	if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
765db08e6e5SSimon Wunderlich 		/* These node are probably going to update their tt table */
76647c94655SAntonio Quartulli 		head = &tt_global->orig_list;
767db08e6e5SSimon Wunderlich 		rcu_read_lock();
768b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(orig_entry, head, list) {
76947c94655SAntonio Quartulli 			batadv_send_roam_adv(bat_priv, tt_global->common.addr,
770c018ad3dSAntonio Quartulli 					     tt_global->common.vid,
771db08e6e5SSimon Wunderlich 					     orig_entry->orig_node);
772db08e6e5SSimon Wunderlich 		}
773db08e6e5SSimon Wunderlich 		rcu_read_unlock();
774068ee6e2SAntonio Quartulli 		if (roamed_back) {
775068ee6e2SAntonio Quartulli 			batadv_tt_global_free(bat_priv, tt_global,
776068ee6e2SAntonio Quartulli 					      "Roaming canceled");
777068ee6e2SAntonio Quartulli 		} else {
778db08e6e5SSimon Wunderlich 			/* The global entry has to be marked as ROAMING and
779db08e6e5SSimon Wunderlich 			 * has to be kept for consistency purpose
780db08e6e5SSimon Wunderlich 			 */
78147c94655SAntonio Quartulli 			tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
78247c94655SAntonio Quartulli 			tt_global->roam_at = jiffies;
7837683fdc1SAntonio Quartulli 		}
784068ee6e2SAntonio Quartulli 	}
785068ee6e2SAntonio Quartulli 
7863c4f7ab6SAntonio Quartulli 	/* store the current remote flags before altering them. This helps
7873c4f7ab6SAntonio Quartulli 	 * understanding is flags are changing or not
7883c4f7ab6SAntonio Quartulli 	 */
7893c4f7ab6SAntonio Quartulli 	remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
790a19d3d85SMarek Lindner 
79110b1bbb4SSven Eckelmann 	if (batadv_is_wifi_hardif(in_hardif))
7923c4f7ab6SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
7933c4f7ab6SAntonio Quartulli 	else
7943c4f7ab6SAntonio Quartulli 		tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
7953c4f7ab6SAntonio Quartulli 
7969464d071SAntonio Quartulli 	/* check the mark in the skb: if it's equal to the configured
7979464d071SAntonio Quartulli 	 * isolation_mark, it means the packet is coming from an isolated
7989464d071SAntonio Quartulli 	 * non-mesh client
7999464d071SAntonio Quartulli 	 */
8009464d071SAntonio Quartulli 	match_mark = (mark & bat_priv->isolation_mark_mask);
8019464d071SAntonio Quartulli 	if (bat_priv->isolation_mark_mask &&
8029464d071SAntonio Quartulli 	    match_mark == bat_priv->isolation_mark)
8039464d071SAntonio Quartulli 		tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
8049464d071SAntonio Quartulli 	else
8059464d071SAntonio Quartulli 		tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
8069464d071SAntonio Quartulli 
8073c4f7ab6SAntonio Quartulli 	/* if any "dynamic" flag has been modified, resend an ADD event for this
8083c4f7ab6SAntonio Quartulli 	 * entry so that all the nodes can get the new flags
8093c4f7ab6SAntonio Quartulli 	 */
8103c4f7ab6SAntonio Quartulli 	if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
8113c4f7ab6SAntonio Quartulli 		batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
8123c4f7ab6SAntonio Quartulli 
8133c4f7ab6SAntonio Quartulli 	ret = true;
8147683fdc1SAntonio Quartulli out:
81510b1bbb4SSven Eckelmann 	batadv_hardif_put(in_hardif);
8160c69aeccSAntonio Quartulli 	dev_put(in_dev);
81795c0db90SSven Eckelmann 	batadv_tt_local_entry_put(tt_local);
8185dafd8a6SSven Eckelmann 	batadv_tt_global_entry_put(tt_global);
819a19d3d85SMarek Lindner 	return ret;
820c6c8fea2SSven Eckelmann }
821c6c8fea2SSven Eckelmann 
822e1bf0c14SMarek Lindner /**
8237e9a8c2cSSven Eckelmann  * batadv_tt_prepare_tvlv_global_data() - prepare the TVLV TT header to send
8247ea7b4a1SAntonio Quartulli  *  within a TT Response directed to another node
8257ea7b4a1SAntonio Quartulli  * @orig_node: originator for which the TT data has to be prepared
8267ea7b4a1SAntonio Quartulli  * @tt_data: uninitialised pointer to the address of the TVLV buffer
8277ea7b4a1SAntonio Quartulli  * @tt_change: uninitialised pointer to the address of the area where the TT
8287ea7b4a1SAntonio Quartulli  *  changed can be stored
8297ea7b4a1SAntonio Quartulli  * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
8307ea7b4a1SAntonio Quartulli  *  function reserves the amount of space needed to send the entire global TT
8317ea7b4a1SAntonio Quartulli  *  table. In case of success the value is updated with the real amount of
8327ea7b4a1SAntonio Quartulli  *  reserved bytes
8337ea7b4a1SAntonio Quartulli  * Allocate the needed amount of memory for the entire TT TVLV and write its
834bccb48c8SSven Eckelmann  * header made up of one tvlv_tt_data object and a series of tvlv_tt_vlan_data
8357ea7b4a1SAntonio Quartulli  * objects, one per active VLAN served by the originator node.
8367ea7b4a1SAntonio Quartulli  *
83762fe710fSSven Eckelmann  * Return: the size of the allocated buffer or 0 in case of failure.
8387ea7b4a1SAntonio Quartulli  */
8396b5e971aSSven Eckelmann static u16
batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node * orig_node,struct batadv_tvlv_tt_data ** tt_data,struct batadv_tvlv_tt_change ** tt_change,s32 * tt_len)8407ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
8417ea7b4a1SAntonio Quartulli 				   struct batadv_tvlv_tt_data **tt_data,
8427ea7b4a1SAntonio Quartulli 				   struct batadv_tvlv_tt_change **tt_change,
8436b5e971aSSven Eckelmann 				   s32 *tt_len)
8447ea7b4a1SAntonio Quartulli {
8454f248cffSSven Eckelmann 	u16 num_vlan = 0;
8464f248cffSSven Eckelmann 	u16 num_entries = 0;
8474f248cffSSven Eckelmann 	u16 change_offset;
8484f248cffSSven Eckelmann 	u16 tvlv_len;
8497ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
8507ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
8516b5e971aSSven Eckelmann 	u8 *tt_change_ptr;
8527ea7b4a1SAntonio Quartulli 
8538ba0f9bdSSven Eckelmann 	spin_lock_bh(&orig_node->vlan_list_lock);
8543b2582c7SSven Eckelmann 	hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
8557ea7b4a1SAntonio Quartulli 		num_vlan++;
8567ea7b4a1SAntonio Quartulli 		num_entries += atomic_read(&vlan->tt.num_entries);
8577ea7b4a1SAntonio Quartulli 	}
8587ea7b4a1SAntonio Quartulli 
8597ea7b4a1SAntonio Quartulli 	change_offset = sizeof(**tt_data);
8607ea7b4a1SAntonio Quartulli 	change_offset += num_vlan * sizeof(*tt_vlan);
8617ea7b4a1SAntonio Quartulli 
8627ea7b4a1SAntonio Quartulli 	/* if tt_len is negative, allocate the space needed by the full table */
8637ea7b4a1SAntonio Quartulli 	if (*tt_len < 0)
8647ea7b4a1SAntonio Quartulli 		*tt_len = batadv_tt_len(num_entries);
8657ea7b4a1SAntonio Quartulli 
8667ea7b4a1SAntonio Quartulli 	tvlv_len = *tt_len;
8677ea7b4a1SAntonio Quartulli 	tvlv_len += change_offset;
8687ea7b4a1SAntonio Quartulli 
8697ea7b4a1SAntonio Quartulli 	*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
8707ea7b4a1SAntonio Quartulli 	if (!*tt_data) {
8717ea7b4a1SAntonio Quartulli 		*tt_len = 0;
8727ea7b4a1SAntonio Quartulli 		goto out;
8737ea7b4a1SAntonio Quartulli 	}
8747ea7b4a1SAntonio Quartulli 
8757ea7b4a1SAntonio Quartulli 	(*tt_data)->flags = BATADV_NO_FLAGS;
8767ea7b4a1SAntonio Quartulli 	(*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn);
8777ea7b4a1SAntonio Quartulli 	(*tt_data)->num_vlan = htons(num_vlan);
8787ea7b4a1SAntonio Quartulli 
8797ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
8803b2582c7SSven Eckelmann 	hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
8817ea7b4a1SAntonio Quartulli 		tt_vlan->vid = htons(vlan->vid);
8827ea7b4a1SAntonio Quartulli 		tt_vlan->crc = htonl(vlan->tt.crc);
88308c27f33STetsuo Handa 		tt_vlan->reserved = 0;
8847ea7b4a1SAntonio Quartulli 
8857ea7b4a1SAntonio Quartulli 		tt_vlan++;
8867ea7b4a1SAntonio Quartulli 	}
8877ea7b4a1SAntonio Quartulli 
8886b5e971aSSven Eckelmann 	tt_change_ptr = (u8 *)*tt_data + change_offset;
8897ea7b4a1SAntonio Quartulli 	*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
8907ea7b4a1SAntonio Quartulli 
8917ea7b4a1SAntonio Quartulli out:
8928ba0f9bdSSven Eckelmann 	spin_unlock_bh(&orig_node->vlan_list_lock);
8937ea7b4a1SAntonio Quartulli 	return tvlv_len;
8947ea7b4a1SAntonio Quartulli }
8957ea7b4a1SAntonio Quartulli 
8967ea7b4a1SAntonio Quartulli /**
8977e9a8c2cSSven Eckelmann  * batadv_tt_prepare_tvlv_local_data() - allocate and prepare the TT TVLV for
8987e9a8c2cSSven Eckelmann  *  this node
8997ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
9007ea7b4a1SAntonio Quartulli  * @tt_data: uninitialised pointer to the address of the TVLV buffer
9017ea7b4a1SAntonio Quartulli  * @tt_change: uninitialised pointer to the address of the area where the TT
9027ea7b4a1SAntonio Quartulli  *  changes can be stored
9037ea7b4a1SAntonio Quartulli  * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
9047ea7b4a1SAntonio Quartulli  *  function reserves the amount of space needed to send the entire local TT
9057ea7b4a1SAntonio Quartulli  *  table. In case of success the value is updated with the real amount of
9067ea7b4a1SAntonio Quartulli  *  reserved bytes
9077ea7b4a1SAntonio Quartulli  *
9087ea7b4a1SAntonio Quartulli  * Allocate the needed amount of memory for the entire TT TVLV and write its
9097ea7b4a1SAntonio Quartulli  * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
9107ea7b4a1SAntonio Quartulli  * objects, one per active VLAN.
9117ea7b4a1SAntonio Quartulli  *
91262fe710fSSven Eckelmann  * Return: the size of the allocated buffer or 0 in case of failure.
9137ea7b4a1SAntonio Quartulli  */
9146b5e971aSSven Eckelmann static u16
batadv_tt_prepare_tvlv_local_data(struct batadv_priv * bat_priv,struct batadv_tvlv_tt_data ** tt_data,struct batadv_tvlv_tt_change ** tt_change,s32 * tt_len)9157ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
9167ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_data **tt_data,
9177ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_change **tt_change,
9186b5e971aSSven Eckelmann 				  s32 *tt_len)
9197ea7b4a1SAntonio Quartulli {
9207ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
9217ea7b4a1SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
9224f248cffSSven Eckelmann 	u16 num_vlan = 0;
92316116dacSMarek Lindner 	u16 vlan_entries = 0;
92416116dacSMarek Lindner 	u16 total_entries = 0;
9254f248cffSSven Eckelmann 	u16 tvlv_len;
9266b5e971aSSven Eckelmann 	u8 *tt_change_ptr;
9277ea7b4a1SAntonio Quartulli 	int change_offset;
9287ea7b4a1SAntonio Quartulli 
9298ba0f9bdSSven Eckelmann 	spin_lock_bh(&bat_priv->softif_vlan_list_lock);
9303b2582c7SSven Eckelmann 	hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
93116116dacSMarek Lindner 		vlan_entries = atomic_read(&vlan->tt.num_entries);
93216116dacSMarek Lindner 		if (vlan_entries < 1)
93316116dacSMarek Lindner 			continue;
93416116dacSMarek Lindner 
9357ea7b4a1SAntonio Quartulli 		num_vlan++;
93616116dacSMarek Lindner 		total_entries += vlan_entries;
9377ea7b4a1SAntonio Quartulli 	}
9387ea7b4a1SAntonio Quartulli 
9397ea7b4a1SAntonio Quartulli 	change_offset = sizeof(**tt_data);
9407ea7b4a1SAntonio Quartulli 	change_offset += num_vlan * sizeof(*tt_vlan);
9417ea7b4a1SAntonio Quartulli 
9427ea7b4a1SAntonio Quartulli 	/* if tt_len is negative, allocate the space needed by the full table */
9437ea7b4a1SAntonio Quartulli 	if (*tt_len < 0)
94416116dacSMarek Lindner 		*tt_len = batadv_tt_len(total_entries);
9457ea7b4a1SAntonio Quartulli 
9467ea7b4a1SAntonio Quartulli 	tvlv_len = *tt_len;
9477ea7b4a1SAntonio Quartulli 	tvlv_len += change_offset;
9487ea7b4a1SAntonio Quartulli 
9497ea7b4a1SAntonio Quartulli 	*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
9507ea7b4a1SAntonio Quartulli 	if (!*tt_data) {
9517ea7b4a1SAntonio Quartulli 		tvlv_len = 0;
9527ea7b4a1SAntonio Quartulli 		goto out;
9537ea7b4a1SAntonio Quartulli 	}
9547ea7b4a1SAntonio Quartulli 
9557ea7b4a1SAntonio Quartulli 	(*tt_data)->flags = BATADV_NO_FLAGS;
9567ea7b4a1SAntonio Quartulli 	(*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn);
9577ea7b4a1SAntonio Quartulli 	(*tt_data)->num_vlan = htons(num_vlan);
9587ea7b4a1SAntonio Quartulli 
9597ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
9603b2582c7SSven Eckelmann 	hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
96116116dacSMarek Lindner 		vlan_entries = atomic_read(&vlan->tt.num_entries);
96216116dacSMarek Lindner 		if (vlan_entries < 1)
96316116dacSMarek Lindner 			continue;
96416116dacSMarek Lindner 
9657ea7b4a1SAntonio Quartulli 		tt_vlan->vid = htons(vlan->vid);
9667ea7b4a1SAntonio Quartulli 		tt_vlan->crc = htonl(vlan->tt.crc);
96708c27f33STetsuo Handa 		tt_vlan->reserved = 0;
9687ea7b4a1SAntonio Quartulli 
9697ea7b4a1SAntonio Quartulli 		tt_vlan++;
9707ea7b4a1SAntonio Quartulli 	}
9717ea7b4a1SAntonio Quartulli 
9726b5e971aSSven Eckelmann 	tt_change_ptr = (u8 *)*tt_data + change_offset;
9737ea7b4a1SAntonio Quartulli 	*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
9747ea7b4a1SAntonio Quartulli 
9757ea7b4a1SAntonio Quartulli out:
9768ba0f9bdSSven Eckelmann 	spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
9777ea7b4a1SAntonio Quartulli 	return tvlv_len;
9787ea7b4a1SAntonio Quartulli }
9797ea7b4a1SAntonio Quartulli 
9807ea7b4a1SAntonio Quartulli /**
9817e9a8c2cSSven Eckelmann  * batadv_tt_tvlv_container_update() - update the translation table tvlv
9827e9a8c2cSSven Eckelmann  *  container after local tt changes have been committed
983e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
984e1bf0c14SMarek Lindner  */
batadv_tt_tvlv_container_update(struct batadv_priv * bat_priv)985e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
986c6c8fea2SSven Eckelmann {
987e1bf0c14SMarek Lindner 	struct batadv_tt_change_node *entry, *safe;
988e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
989e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
9907ea7b4a1SAntonio Quartulli 	int tt_diff_len, tt_change_len = 0;
9914f248cffSSven Eckelmann 	int tt_diff_entries_num = 0;
9924f248cffSSven Eckelmann 	int tt_diff_entries_count = 0;
9936b5e971aSSven Eckelmann 	u16 tvlv_len;
994c6c8fea2SSven Eckelmann 
9957ea7b4a1SAntonio Quartulli 	tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes);
9967ea7b4a1SAntonio Quartulli 	tt_diff_len = batadv_tt_len(tt_diff_entries_num);
997be9aa4c1SMarek Lindner 
998be9aa4c1SMarek Lindner 	/* if we have too many changes for one packet don't send any
999be9aa4c1SMarek Lindner 	 * and wait for the tt table request which will be fragmented
1000be9aa4c1SMarek Lindner 	 */
1001e1bf0c14SMarek Lindner 	if (tt_diff_len > bat_priv->soft_iface->mtu)
1002e1bf0c14SMarek Lindner 		tt_diff_len = 0;
1003be9aa4c1SMarek Lindner 
10047ea7b4a1SAntonio Quartulli 	tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
10057ea7b4a1SAntonio Quartulli 						     &tt_change, &tt_diff_len);
10067ea7b4a1SAntonio Quartulli 	if (!tvlv_len)
1007e1bf0c14SMarek Lindner 		return;
1008be9aa4c1SMarek Lindner 
1009e1bf0c14SMarek Lindner 	tt_data->flags = BATADV_TT_OGM_DIFF;
1010be9aa4c1SMarek Lindner 
1011e1bf0c14SMarek Lindner 	if (tt_diff_len == 0)
1012e1bf0c14SMarek Lindner 		goto container_register;
1013be9aa4c1SMarek Lindner 
1014807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
1015807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.local_changes, 0);
1016c6c8fea2SSven Eckelmann 
1017807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
1018a73105b8SAntonio Quartulli 				 list) {
1019e1bf0c14SMarek Lindner 		if (tt_diff_entries_count < tt_diff_entries_num) {
1020e1bf0c14SMarek Lindner 			memcpy(tt_change + tt_diff_entries_count,
1021e1bf0c14SMarek Lindner 			       &entry->change,
1022e1bf0c14SMarek Lindner 			       sizeof(struct batadv_tvlv_tt_change));
1023e1bf0c14SMarek Lindner 			tt_diff_entries_count++;
1024c6c8fea2SSven Eckelmann 		}
1025a73105b8SAntonio Quartulli 		list_del(&entry->list);
102686452f81SSven Eckelmann 		kmem_cache_free(batadv_tt_change_cache, entry);
1027c6c8fea2SSven Eckelmann 	}
1028807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
1029c6c8fea2SSven Eckelmann 
1030a73105b8SAntonio Quartulli 	/* Keep the buffer for possible tt_request */
1031807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.last_changeset_lock);
1032807736f6SSven Eckelmann 	kfree(bat_priv->tt.last_changeset);
1033807736f6SSven Eckelmann 	bat_priv->tt.last_changeset_len = 0;
1034807736f6SSven Eckelmann 	bat_priv->tt.last_changeset = NULL;
1035e1bf0c14SMarek Lindner 	tt_change_len = batadv_tt_len(tt_diff_entries_count);
1036be9aa4c1SMarek Lindner 	/* check whether this new OGM has no changes due to size problems */
1037e1bf0c14SMarek Lindner 	if (tt_diff_entries_count > 0) {
1038be9aa4c1SMarek Lindner 		/* if kmalloc() fails we will reply with the full table
1039a73105b8SAntonio Quartulli 		 * instead of providing the diff
1040a73105b8SAntonio Quartulli 		 */
1041e1bf0c14SMarek Lindner 		bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC);
1042807736f6SSven Eckelmann 		if (bat_priv->tt.last_changeset) {
1043e1bf0c14SMarek Lindner 			memcpy(bat_priv->tt.last_changeset,
1044e1bf0c14SMarek Lindner 			       tt_change, tt_change_len);
1045e1bf0c14SMarek Lindner 			bat_priv->tt.last_changeset_len = tt_diff_len;
1046a73105b8SAntonio Quartulli 		}
1047a73105b8SAntonio Quartulli 	}
1048807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
1049c6c8fea2SSven Eckelmann 
1050e1bf0c14SMarek Lindner container_register:
1051e1bf0c14SMarek Lindner 	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
10527ea7b4a1SAntonio Quartulli 				       tvlv_len);
1053e1bf0c14SMarek Lindner 	kfree(tt_data);
1054c6c8fea2SSven Eckelmann }
1055c6c8fea2SSven Eckelmann 
1056d34f0550SMatthias Schiffer /**
10577e9a8c2cSSven Eckelmann  * batadv_tt_local_dump_entry() - Dump one TT local entry into a message
1058d34f0550SMatthias Schiffer  * @msg :Netlink message to dump into
1059d34f0550SMatthias Schiffer  * @portid: Port making netlink request
10606b7b40aaSSven Eckelmann  * @cb: Control block containing additional options
1061d34f0550SMatthias Schiffer  * @bat_priv: The bat priv with all the soft interface information
1062d34f0550SMatthias Schiffer  * @common: tt local & tt global common data
1063d34f0550SMatthias Schiffer  *
1064d34f0550SMatthias Schiffer  * Return: Error code, or 0 on success
1065d34f0550SMatthias Schiffer  */
1066d34f0550SMatthias Schiffer static int
batadv_tt_local_dump_entry(struct sk_buff * msg,u32 portid,struct netlink_callback * cb,struct batadv_priv * bat_priv,struct batadv_tt_common_entry * common)10676b7b40aaSSven Eckelmann batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
10686b7b40aaSSven Eckelmann 			   struct netlink_callback *cb,
1069d34f0550SMatthias Schiffer 			   struct batadv_priv *bat_priv,
1070d34f0550SMatthias Schiffer 			   struct batadv_tt_common_entry *common)
1071d34f0550SMatthias Schiffer {
1072d34f0550SMatthias Schiffer 	void *hdr;
1073d34f0550SMatthias Schiffer 	struct batadv_softif_vlan *vlan;
1074d34f0550SMatthias Schiffer 	struct batadv_tt_local_entry *local;
1075d34f0550SMatthias Schiffer 	unsigned int last_seen_msecs;
1076d34f0550SMatthias Schiffer 	u32 crc;
1077d34f0550SMatthias Schiffer 
1078d34f0550SMatthias Schiffer 	local = container_of(common, struct batadv_tt_local_entry, common);
1079d34f0550SMatthias Schiffer 	last_seen_msecs = jiffies_to_msecs(jiffies - local->last_seen);
1080d34f0550SMatthias Schiffer 
1081d34f0550SMatthias Schiffer 	vlan = batadv_softif_vlan_get(bat_priv, common->vid);
1082d34f0550SMatthias Schiffer 	if (!vlan)
1083d34f0550SMatthias Schiffer 		return 0;
1084d34f0550SMatthias Schiffer 
1085d34f0550SMatthias Schiffer 	crc = vlan->tt.crc;
1086d34f0550SMatthias Schiffer 
1087d34f0550SMatthias Schiffer 	batadv_softif_vlan_put(vlan);
1088d34f0550SMatthias Schiffer 
10896b7b40aaSSven Eckelmann 	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
10906b7b40aaSSven Eckelmann 			  &batadv_netlink_family,  NLM_F_MULTI,
1091d34f0550SMatthias Schiffer 			  BATADV_CMD_GET_TRANSTABLE_LOCAL);
1092d34f0550SMatthias Schiffer 	if (!hdr)
1093d34f0550SMatthias Schiffer 		return -ENOBUFS;
1094d34f0550SMatthias Schiffer 
10956b7b40aaSSven Eckelmann 	genl_dump_check_consistent(cb, hdr);
10966b7b40aaSSven Eckelmann 
1097d34f0550SMatthias Schiffer 	if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
1098d34f0550SMatthias Schiffer 	    nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
1099d34f0550SMatthias Schiffer 	    nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
1100d34f0550SMatthias Schiffer 	    nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags))
1101d34f0550SMatthias Schiffer 		goto nla_put_failure;
1102d34f0550SMatthias Schiffer 
1103d34f0550SMatthias Schiffer 	if (!(common->flags & BATADV_TT_CLIENT_NOPURGE) &&
1104d34f0550SMatthias Schiffer 	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs))
1105d34f0550SMatthias Schiffer 		goto nla_put_failure;
1106d34f0550SMatthias Schiffer 
1107d34f0550SMatthias Schiffer 	genlmsg_end(msg, hdr);
1108d34f0550SMatthias Schiffer 	return 0;
1109d34f0550SMatthias Schiffer 
1110d34f0550SMatthias Schiffer  nla_put_failure:
1111d34f0550SMatthias Schiffer 	genlmsg_cancel(msg, hdr);
1112d34f0550SMatthias Schiffer 	return -EMSGSIZE;
1113d34f0550SMatthias Schiffer }
1114d34f0550SMatthias Schiffer 
1115d34f0550SMatthias Schiffer /**
11167e9a8c2cSSven Eckelmann  * batadv_tt_local_dump_bucket() - Dump one TT local bucket into a message
1117d34f0550SMatthias Schiffer  * @msg: Netlink message to dump into
1118d34f0550SMatthias Schiffer  * @portid: Port making netlink request
11196b7b40aaSSven Eckelmann  * @cb: Control block containing additional options
1120d34f0550SMatthias Schiffer  * @bat_priv: The bat priv with all the soft interface information
11216b7b40aaSSven Eckelmann  * @hash: hash to dump
11226b7b40aaSSven Eckelmann  * @bucket: bucket index to dump
1123d34f0550SMatthias Schiffer  * @idx_s: Number of entries to skip
1124d34f0550SMatthias Schiffer  *
1125d34f0550SMatthias Schiffer  * Return: Error code, or 0 on success
1126d34f0550SMatthias Schiffer  */
1127d34f0550SMatthias Schiffer static int
batadv_tt_local_dump_bucket(struct sk_buff * msg,u32 portid,struct netlink_callback * cb,struct batadv_priv * bat_priv,struct batadv_hashtable * hash,unsigned int bucket,int * idx_s)11286b7b40aaSSven Eckelmann batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid,
11296b7b40aaSSven Eckelmann 			    struct netlink_callback *cb,
1130d34f0550SMatthias Schiffer 			    struct batadv_priv *bat_priv,
11316b7b40aaSSven Eckelmann 			    struct batadv_hashtable *hash, unsigned int bucket,
11326b7b40aaSSven Eckelmann 			    int *idx_s)
1133d34f0550SMatthias Schiffer {
1134d34f0550SMatthias Schiffer 	struct batadv_tt_common_entry *common;
1135d34f0550SMatthias Schiffer 	int idx = 0;
1136d34f0550SMatthias Schiffer 
11376b7b40aaSSven Eckelmann 	spin_lock_bh(&hash->list_locks[bucket]);
11386b7b40aaSSven Eckelmann 	cb->seq = atomic_read(&hash->generation) << 1 | 1;
11396b7b40aaSSven Eckelmann 
11406b7b40aaSSven Eckelmann 	hlist_for_each_entry(common, &hash->table[bucket], hash_entry) {
1141d34f0550SMatthias Schiffer 		if (idx++ < *idx_s)
1142d34f0550SMatthias Schiffer 			continue;
1143d34f0550SMatthias Schiffer 
11446b7b40aaSSven Eckelmann 		if (batadv_tt_local_dump_entry(msg, portid, cb, bat_priv,
1145d34f0550SMatthias Schiffer 					       common)) {
11466b7b40aaSSven Eckelmann 			spin_unlock_bh(&hash->list_locks[bucket]);
1147d34f0550SMatthias Schiffer 			*idx_s = idx - 1;
1148d34f0550SMatthias Schiffer 			return -EMSGSIZE;
1149d34f0550SMatthias Schiffer 		}
1150d34f0550SMatthias Schiffer 	}
11516b7b40aaSSven Eckelmann 	spin_unlock_bh(&hash->list_locks[bucket]);
1152d34f0550SMatthias Schiffer 
1153d34f0550SMatthias Schiffer 	*idx_s = 0;
1154d34f0550SMatthias Schiffer 	return 0;
1155d34f0550SMatthias Schiffer }
1156d34f0550SMatthias Schiffer 
1157d34f0550SMatthias Schiffer /**
11587e9a8c2cSSven Eckelmann  * batadv_tt_local_dump() - Dump TT local entries into a message
1159d34f0550SMatthias Schiffer  * @msg: Netlink message to dump into
1160d34f0550SMatthias Schiffer  * @cb: Parameters from query
1161d34f0550SMatthias Schiffer  *
1162d34f0550SMatthias Schiffer  * Return: Error code, or 0 on success
1163d34f0550SMatthias Schiffer  */
batadv_tt_local_dump(struct sk_buff * msg,struct netlink_callback * cb)1164d34f0550SMatthias Schiffer int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
1165d34f0550SMatthias Schiffer {
1166d34f0550SMatthias Schiffer 	struct net *net = sock_net(cb->skb->sk);
1167d34f0550SMatthias Schiffer 	struct net_device *soft_iface;
1168d34f0550SMatthias Schiffer 	struct batadv_priv *bat_priv;
1169d34f0550SMatthias Schiffer 	struct batadv_hard_iface *primary_if = NULL;
1170d34f0550SMatthias Schiffer 	struct batadv_hashtable *hash;
1171d34f0550SMatthias Schiffer 	int ret;
1172d34f0550SMatthias Schiffer 	int ifindex;
1173d34f0550SMatthias Schiffer 	int bucket = cb->args[0];
1174d34f0550SMatthias Schiffer 	int idx = cb->args[1];
1175d34f0550SMatthias Schiffer 	int portid = NETLINK_CB(cb->skb).portid;
1176d34f0550SMatthias Schiffer 
1177d34f0550SMatthias Schiffer 	ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
1178d34f0550SMatthias Schiffer 	if (!ifindex)
1179d34f0550SMatthias Schiffer 		return -EINVAL;
1180d34f0550SMatthias Schiffer 
1181d34f0550SMatthias Schiffer 	soft_iface = dev_get_by_index(net, ifindex);
1182d34f0550SMatthias Schiffer 	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
1183d34f0550SMatthias Schiffer 		ret = -ENODEV;
1184d34f0550SMatthias Schiffer 		goto out;
1185d34f0550SMatthias Schiffer 	}
1186d34f0550SMatthias Schiffer 
1187d34f0550SMatthias Schiffer 	bat_priv = netdev_priv(soft_iface);
1188d34f0550SMatthias Schiffer 
1189d34f0550SMatthias Schiffer 	primary_if = batadv_primary_if_get_selected(bat_priv);
1190d34f0550SMatthias Schiffer 	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
1191d34f0550SMatthias Schiffer 		ret = -ENOENT;
1192d34f0550SMatthias Schiffer 		goto out;
1193d34f0550SMatthias Schiffer 	}
1194d34f0550SMatthias Schiffer 
1195d34f0550SMatthias Schiffer 	hash = bat_priv->tt.local_hash;
1196d34f0550SMatthias Schiffer 
1197d34f0550SMatthias Schiffer 	while (bucket < hash->size) {
11986b7b40aaSSven Eckelmann 		if (batadv_tt_local_dump_bucket(msg, portid, cb, bat_priv,
11996b7b40aaSSven Eckelmann 						hash, bucket, &idx))
1200d34f0550SMatthias Schiffer 			break;
1201d34f0550SMatthias Schiffer 
1202d34f0550SMatthias Schiffer 		bucket++;
1203d34f0550SMatthias Schiffer 	}
1204d34f0550SMatthias Schiffer 
1205d34f0550SMatthias Schiffer 	ret = msg->len;
1206d34f0550SMatthias Schiffer 
1207d34f0550SMatthias Schiffer  out:
1208d34f0550SMatthias Schiffer 	batadv_hardif_put(primary_if);
1209d34f0550SMatthias Schiffer 	dev_put(soft_iface);
1210d34f0550SMatthias Schiffer 
1211d34f0550SMatthias Schiffer 	cb->args[0] = bucket;
1212d34f0550SMatthias Schiffer 	cb->args[1] = idx;
1213d34f0550SMatthias Schiffer 
1214d34f0550SMatthias Schiffer 	return ret;
1215d34f0550SMatthias Schiffer }
1216d34f0550SMatthias Schiffer 
121756303d34SSven Eckelmann static void
batadv_tt_local_set_pending(struct batadv_priv * bat_priv,struct batadv_tt_local_entry * tt_local_entry,u16 flags,const char * message)121856303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
121956303d34SSven Eckelmann 			    struct batadv_tt_local_entry *tt_local_entry,
12206b5e971aSSven Eckelmann 			    u16 flags, const char *message)
1221c6c8fea2SSven Eckelmann {
12223abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local_entry, flags);
1223c6c8fea2SSven Eckelmann 
1224015758d0SAntonio Quartulli 	/* The local client has to be marked as "pending to be removed" but has
1225015758d0SAntonio Quartulli 	 * to be kept in the table in order to send it in a full table
12269cfc7bd6SSven Eckelmann 	 * response issued before the net ttvn increment (consistency check)
12279cfc7bd6SSven Eckelmann 	 */
1228acd34afaSSven Eckelmann 	tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
1229c566dbbeSAntonio Quartulli 
123039c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
123116052789SAntonio Quartulli 		   "Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
123216052789SAntonio Quartulli 		   tt_local_entry->common.addr,
1233f7a2bd65SSven Eckelmann 		   batadv_print_vid(tt_local_entry->common.vid), message);
1234c6c8fea2SSven Eckelmann }
1235c6c8fea2SSven Eckelmann 
12367f91d06cSAntonio Quartulli /**
12377e9a8c2cSSven Eckelmann  * batadv_tt_local_remove() - logically remove an entry from the local table
12387f91d06cSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
12397f91d06cSAntonio Quartulli  * @addr: the MAC address of the client to remove
1240c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
12417f91d06cSAntonio Quartulli  * @message: message to append to the log on deletion
12427f91d06cSAntonio Quartulli  * @roaming: true if the deletion is due to a roaming event
12437f91d06cSAntonio Quartulli  *
124462fe710fSSven Eckelmann  * Return: the flags assigned to the local entry before being deleted
12457f91d06cSAntonio Quartulli  */
batadv_tt_local_remove(struct batadv_priv * bat_priv,const u8 * addr,unsigned short vid,const char * message,bool roaming)12466b5e971aSSven Eckelmann u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
12476b5e971aSSven Eckelmann 			   unsigned short vid, const char *message,
12486b5e971aSSven Eckelmann 			   bool roaming)
1249c6c8fea2SSven Eckelmann {
12503d65b9acSSven Eckelmann 	struct batadv_tt_local_entry *tt_removed_entry;
1251170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
12526b5e971aSSven Eckelmann 	u16 flags, curr_flags = BATADV_NO_FLAGS;
12533d65b9acSSven Eckelmann 	struct hlist_node *tt_removed_node;
1254c6c8fea2SSven Eckelmann 
1255c018ad3dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
12567683fdc1SAntonio Quartulli 	if (!tt_local_entry)
12577683fdc1SAntonio Quartulli 		goto out;
12587683fdc1SAntonio Quartulli 
12597f91d06cSAntonio Quartulli 	curr_flags = tt_local_entry->common.flags;
12607f91d06cSAntonio Quartulli 
1261acd34afaSSven Eckelmann 	flags = BATADV_TT_CLIENT_DEL;
1262068ee6e2SAntonio Quartulli 	/* if this global entry addition is due to a roaming, the node has to
1263068ee6e2SAntonio Quartulli 	 * mark the local entry as "roamed" in order to correctly reroute
1264068ee6e2SAntonio Quartulli 	 * packets later
1265068ee6e2SAntonio Quartulli 	 */
12667c1fd91dSAntonio Quartulli 	if (roaming) {
1267acd34afaSSven Eckelmann 		flags |= BATADV_TT_CLIENT_ROAM;
12687c1fd91dSAntonio Quartulli 		/* mark the local client as ROAMed */
12697c1fd91dSAntonio Quartulli 		tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
12707c1fd91dSAntonio Quartulli 	}
127142d0b044SSven Eckelmann 
1272068ee6e2SAntonio Quartulli 	if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
1273068ee6e2SAntonio Quartulli 		batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
1274068ee6e2SAntonio Quartulli 					    message);
1275068ee6e2SAntonio Quartulli 		goto out;
1276068ee6e2SAntonio Quartulli 	}
1277068ee6e2SAntonio Quartulli 	/* if this client has been added right now, it is possible to
1278068ee6e2SAntonio Quartulli 	 * immediately purge it
1279068ee6e2SAntonio Quartulli 	 */
12803abe4adbSAntonio Quartulli 	batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
1281ef72706aSMarek Lindner 
12823d65b9acSSven Eckelmann 	tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash,
1283ef72706aSMarek Lindner 					     batadv_compare_tt,
1284ef72706aSMarek Lindner 					     batadv_choose_tt,
1285ef72706aSMarek Lindner 					     &tt_local_entry->common);
12863d65b9acSSven Eckelmann 	if (!tt_removed_node)
1287ef72706aSMarek Lindner 		goto out;
1288ef72706aSMarek Lindner 
12893d65b9acSSven Eckelmann 	/* drop reference of remove hash entry */
12903d65b9acSSven Eckelmann 	tt_removed_entry = hlist_entry(tt_removed_node,
12913d65b9acSSven Eckelmann 				       struct batadv_tt_local_entry,
12923d65b9acSSven Eckelmann 				       common.hash_entry);
12933d65b9acSSven Eckelmann 	batadv_tt_local_entry_put(tt_removed_entry);
12947f91d06cSAntonio Quartulli 
12957683fdc1SAntonio Quartulli out:
129695c0db90SSven Eckelmann 	batadv_tt_local_entry_put(tt_local_entry);
12977f91d06cSAntonio Quartulli 
12987f91d06cSAntonio Quartulli 	return curr_flags;
1299c6c8fea2SSven Eckelmann }
1300c6c8fea2SSven Eckelmann 
1301a19d3d85SMarek Lindner /**
13027e9a8c2cSSven Eckelmann  * batadv_tt_local_purge_list() - purge inactive tt local entries
1303a19d3d85SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
1304a19d3d85SMarek Lindner  * @head: pointer to the list containing the local tt entries
1305a19d3d85SMarek Lindner  * @timeout: parameter deciding whether a given tt local entry is considered
1306a19d3d85SMarek Lindner  *  inactive or not
1307a19d3d85SMarek Lindner  */
batadv_tt_local_purge_list(struct batadv_priv * bat_priv,struct hlist_head * head,int timeout)130856303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
1309a19d3d85SMarek Lindner 				       struct hlist_head *head,
1310a19d3d85SMarek Lindner 				       int timeout)
1311c6c8fea2SSven Eckelmann {
131256303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
131356303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
1314b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
1315acd34afaSSven Eckelmann 
1316b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
1317acd34afaSSven Eckelmann 				  hash_entry) {
1318acd34afaSSven Eckelmann 		tt_local_entry = container_of(tt_common_entry,
131956303d34SSven Eckelmann 					      struct batadv_tt_local_entry,
132056303d34SSven Eckelmann 					      common);
1321acd34afaSSven Eckelmann 		if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
1322acd34afaSSven Eckelmann 			continue;
1323acd34afaSSven Eckelmann 
1324acd34afaSSven Eckelmann 		/* entry already marked for deletion */
1325acd34afaSSven Eckelmann 		if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
1326acd34afaSSven Eckelmann 			continue;
1327acd34afaSSven Eckelmann 
1328a19d3d85SMarek Lindner 		if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
1329acd34afaSSven Eckelmann 			continue;
1330acd34afaSSven Eckelmann 
1331acd34afaSSven Eckelmann 		batadv_tt_local_set_pending(bat_priv, tt_local_entry,
1332acd34afaSSven Eckelmann 					    BATADV_TT_CLIENT_DEL, "timed out");
1333acd34afaSSven Eckelmann 	}
1334acd34afaSSven Eckelmann }
1335acd34afaSSven Eckelmann 
1336a19d3d85SMarek Lindner /**
13377e9a8c2cSSven Eckelmann  * batadv_tt_local_purge() - purge inactive tt local entries
1338a19d3d85SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
1339a19d3d85SMarek Lindner  * @timeout: parameter deciding whether a given tt local entry is considered
1340a19d3d85SMarek Lindner  *  inactive or not
1341a19d3d85SMarek Lindner  */
batadv_tt_local_purge(struct batadv_priv * bat_priv,int timeout)1342a19d3d85SMarek Lindner static void batadv_tt_local_purge(struct batadv_priv *bat_priv,
1343a19d3d85SMarek Lindner 				  int timeout)
1344acd34afaSSven Eckelmann {
1345807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
1346c6c8fea2SSven Eckelmann 	struct hlist_head *head;
13477683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
13486b5e971aSSven Eckelmann 	u32 i;
1349c6c8fea2SSven Eckelmann 
1350c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
1351c6c8fea2SSven Eckelmann 		head = &hash->table[i];
13527683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
1353c6c8fea2SSven Eckelmann 
13547683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
1355a19d3d85SMarek Lindner 		batadv_tt_local_purge_list(bat_priv, head, timeout);
13567683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
1357c6c8fea2SSven Eckelmann 	}
1358c6c8fea2SSven Eckelmann }
1359c6c8fea2SSven Eckelmann 
batadv_tt_local_table_free(struct batadv_priv * bat_priv)136056303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
1361c6c8fea2SSven Eckelmann {
13625bf74e9cSSven Eckelmann 	struct batadv_hashtable *hash;
1363a73105b8SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
136456303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
136556303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
1366b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
13677683fdc1SAntonio Quartulli 	struct hlist_head *head;
13686b5e971aSSven Eckelmann 	u32 i;
1369a73105b8SAntonio Quartulli 
1370807736f6SSven Eckelmann 	if (!bat_priv->tt.local_hash)
1371c6c8fea2SSven Eckelmann 		return;
1372c6c8fea2SSven Eckelmann 
1373807736f6SSven Eckelmann 	hash = bat_priv->tt.local_hash;
1374a73105b8SAntonio Quartulli 
1375a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1376a73105b8SAntonio Quartulli 		head = &hash->table[i];
1377a73105b8SAntonio Quartulli 		list_lock = &hash->list_locks[i];
1378a73105b8SAntonio Quartulli 
1379a73105b8SAntonio Quartulli 		spin_lock_bh(list_lock);
1380b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, node_tmp,
1381a73105b8SAntonio Quartulli 					  head, hash_entry) {
1382b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common_entry->hash_entry);
138356303d34SSven Eckelmann 			tt_local = container_of(tt_common_entry,
138456303d34SSven Eckelmann 						struct batadv_tt_local_entry,
138548100bacSAntonio Quartulli 						common);
138635df3b29SAntonio Quartulli 
138795c0db90SSven Eckelmann 			batadv_tt_local_entry_put(tt_local);
1388a73105b8SAntonio Quartulli 		}
1389a73105b8SAntonio Quartulli 		spin_unlock_bh(list_lock);
1390a73105b8SAntonio Quartulli 	}
1391a73105b8SAntonio Quartulli 
13921a8eaf07SSven Eckelmann 	batadv_hash_destroy(hash);
1393a73105b8SAntonio Quartulli 
1394807736f6SSven Eckelmann 	bat_priv->tt.local_hash = NULL;
1395c6c8fea2SSven Eckelmann }
1396c6c8fea2SSven Eckelmann 
batadv_tt_global_init(struct batadv_priv * bat_priv)139756303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv)
1398c6c8fea2SSven Eckelmann {
1399807736f6SSven Eckelmann 	if (bat_priv->tt.global_hash)
14005346c35eSSven Eckelmann 		return 0;
1401c6c8fea2SSven Eckelmann 
1402807736f6SSven Eckelmann 	bat_priv->tt.global_hash = batadv_hash_new(1024);
1403c6c8fea2SSven Eckelmann 
1404807736f6SSven Eckelmann 	if (!bat_priv->tt.global_hash)
14055346c35eSSven Eckelmann 		return -ENOMEM;
1406c6c8fea2SSven Eckelmann 
1407dec05074SAntonio Quartulli 	batadv_hash_set_lock_class(bat_priv->tt.global_hash,
1408dec05074SAntonio Quartulli 				   &batadv_tt_global_hash_lock_class_key);
1409dec05074SAntonio Quartulli 
14105346c35eSSven Eckelmann 	return 0;
1411c6c8fea2SSven Eckelmann }
1412c6c8fea2SSven Eckelmann 
batadv_tt_changes_list_free(struct batadv_priv * bat_priv)141356303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
1414a73105b8SAntonio Quartulli {
141556303d34SSven Eckelmann 	struct batadv_tt_change_node *entry, *safe;
1416a73105b8SAntonio Quartulli 
1417807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
1418a73105b8SAntonio Quartulli 
1419807736f6SSven Eckelmann 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
1420a73105b8SAntonio Quartulli 				 list) {
1421a73105b8SAntonio Quartulli 		list_del(&entry->list);
142286452f81SSven Eckelmann 		kmem_cache_free(batadv_tt_change_cache, entry);
1423a73105b8SAntonio Quartulli 	}
1424a73105b8SAntonio Quartulli 
1425807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.local_changes, 0);
1426807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
1427a73105b8SAntonio Quartulli }
1428a73105b8SAntonio Quartulli 
142962fe710fSSven Eckelmann /**
14307e9a8c2cSSven Eckelmann  * batadv_tt_global_orig_entry_find() - find a TT orig_list_entry
1431d15cd622SAntonio Quartulli  * @entry: the TT global entry where the orig_list_entry has to be
1432d15cd622SAntonio Quartulli  *  extracted from
1433d15cd622SAntonio Quartulli  * @orig_node: the originator for which the orig_list_entry has to be found
143462fe710fSSven Eckelmann  *
1435d15cd622SAntonio Quartulli  * retrieve the orig_tt_list_entry belonging to orig_node from the
1436d657e621SAntonio Quartulli  * batadv_tt_global_entry list
1437d657e621SAntonio Quartulli  *
143862fe710fSSven Eckelmann  * Return: it with an increased refcounter, NULL if not found
1439d657e621SAntonio Quartulli  */
1440d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry *
batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry * entry,const struct batadv_orig_node * orig_node)1441d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
1442d657e621SAntonio Quartulli 				 const struct batadv_orig_node *orig_node)
1443d657e621SAntonio Quartulli {
1444d657e621SAntonio Quartulli 	struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
1445d657e621SAntonio Quartulli 	const struct hlist_head *head;
1446d657e621SAntonio Quartulli 
1447d657e621SAntonio Quartulli 	rcu_read_lock();
1448d657e621SAntonio Quartulli 	head = &entry->orig_list;
1449b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(tmp_orig_entry, head, list) {
1450d657e621SAntonio Quartulli 		if (tmp_orig_entry->orig_node != orig_node)
1451d657e621SAntonio Quartulli 			continue;
14526e8ef69dSSven Eckelmann 		if (!kref_get_unless_zero(&tmp_orig_entry->refcount))
1453d657e621SAntonio Quartulli 			continue;
1454d657e621SAntonio Quartulli 
1455d657e621SAntonio Quartulli 		orig_entry = tmp_orig_entry;
1456d657e621SAntonio Quartulli 		break;
1457d657e621SAntonio Quartulli 	}
1458d657e621SAntonio Quartulli 	rcu_read_unlock();
1459d657e621SAntonio Quartulli 
1460d657e621SAntonio Quartulli 	return orig_entry;
1461d657e621SAntonio Quartulli }
1462d657e621SAntonio Quartulli 
146362fe710fSSven Eckelmann /**
14647e9a8c2cSSven Eckelmann  * batadv_tt_global_entry_has_orig() - check if a TT global entry is also
14657e9a8c2cSSven Eckelmann  *  handled by a given originator
1466d15cd622SAntonio Quartulli  * @entry: the TT global entry to check
1467d15cd622SAntonio Quartulli  * @orig_node: the originator to search in the list
14687072337eSLinus Lüssing  * @flags: a pointer to store TT flags for the given @entry received
14697072337eSLinus Lüssing  *  from @orig_node
147062fe710fSSven Eckelmann  *
147162fe710fSSven Eckelmann  * find out if an orig_node is already in the list of a tt_global_entry.
147262fe710fSSven Eckelmann  *
147362fe710fSSven Eckelmann  * Return: true if found, false otherwise
1474db08e6e5SSimon Wunderlich  */
147556303d34SSven Eckelmann static bool
batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry * entry,const struct batadv_orig_node * orig_node,u8 * flags)147656303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
14777072337eSLinus Lüssing 				const struct batadv_orig_node *orig_node,
14787072337eSLinus Lüssing 				u8 *flags)
1479db08e6e5SSimon Wunderlich {
1480d657e621SAntonio Quartulli 	struct batadv_tt_orig_list_entry *orig_entry;
1481db08e6e5SSimon Wunderlich 	bool found = false;
1482db08e6e5SSimon Wunderlich 
1483d657e621SAntonio Quartulli 	orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
1484d657e621SAntonio Quartulli 	if (orig_entry) {
1485db08e6e5SSimon Wunderlich 		found = true;
14867072337eSLinus Lüssing 
14877072337eSLinus Lüssing 		if (flags)
14887072337eSLinus Lüssing 			*flags = orig_entry->flags;
14897072337eSLinus Lüssing 
14907e2366c6SSven Eckelmann 		batadv_tt_orig_list_entry_put(orig_entry);
1491db08e6e5SSimon Wunderlich 	}
1492d657e621SAntonio Quartulli 
1493db08e6e5SSimon Wunderlich 	return found;
1494db08e6e5SSimon Wunderlich }
1495db08e6e5SSimon Wunderlich 
149654e22f26SLinus Lüssing /**
14977e9a8c2cSSven Eckelmann  * batadv_tt_global_sync_flags() - update TT sync flags
149854e22f26SLinus Lüssing  * @tt_global: the TT global entry to update sync flags in
149954e22f26SLinus Lüssing  *
150054e22f26SLinus Lüssing  * Updates the sync flag bits in the tt_global flag attribute with a logical
150154e22f26SLinus Lüssing  * OR of all sync flags from any of its TT orig entries.
150254e22f26SLinus Lüssing  */
150354e22f26SLinus Lüssing static void
batadv_tt_global_sync_flags(struct batadv_tt_global_entry * tt_global)150454e22f26SLinus Lüssing batadv_tt_global_sync_flags(struct batadv_tt_global_entry *tt_global)
150554e22f26SLinus Lüssing {
150654e22f26SLinus Lüssing 	struct batadv_tt_orig_list_entry *orig_entry;
150754e22f26SLinus Lüssing 	const struct hlist_head *head;
150854e22f26SLinus Lüssing 	u16 flags = BATADV_NO_FLAGS;
150954e22f26SLinus Lüssing 
151054e22f26SLinus Lüssing 	rcu_read_lock();
151154e22f26SLinus Lüssing 	head = &tt_global->orig_list;
151254e22f26SLinus Lüssing 	hlist_for_each_entry_rcu(orig_entry, head, list)
151354e22f26SLinus Lüssing 		flags |= orig_entry->flags;
151454e22f26SLinus Lüssing 	rcu_read_unlock();
151554e22f26SLinus Lüssing 
151654e22f26SLinus Lüssing 	flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
151754e22f26SLinus Lüssing 	tt_global->common.flags = flags;
151854e22f26SLinus Lüssing }
151954e22f26SLinus Lüssing 
152054e22f26SLinus Lüssing /**
15217e9a8c2cSSven Eckelmann  * batadv_tt_global_orig_entry_add() - add or update a TT orig entry
152254e22f26SLinus Lüssing  * @tt_global: the TT global entry to add an orig entry in
152354e22f26SLinus Lüssing  * @orig_node: the originator to add an orig entry for
152454e22f26SLinus Lüssing  * @ttvn: translation table version number of this changeset
152554e22f26SLinus Lüssing  * @flags: TT sync flags
152654e22f26SLinus Lüssing  */
1527a513088dSSven Eckelmann static void
batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry * tt_global,struct batadv_orig_node * orig_node,int ttvn,u8 flags)1528d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
152954e22f26SLinus Lüssing 				struct batadv_orig_node *orig_node, int ttvn,
153054e22f26SLinus Lüssing 				u8 flags)
1531db08e6e5SSimon Wunderlich {
153256303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
1533db08e6e5SSimon Wunderlich 
1534e7136e48SSven Eckelmann 	spin_lock_bh(&tt_global->list_lock);
1535e7136e48SSven Eckelmann 
1536d657e621SAntonio Quartulli 	orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
153730cfd02bSAntonio Quartulli 	if (orig_entry) {
153830cfd02bSAntonio Quartulli 		/* refresh the ttvn: the current value could be a bogus one that
153930cfd02bSAntonio Quartulli 		 * was added during a "temporary client detection"
154030cfd02bSAntonio Quartulli 		 */
154130cfd02bSAntonio Quartulli 		orig_entry->ttvn = ttvn;
154254e22f26SLinus Lüssing 		orig_entry->flags = flags;
154354e22f26SLinus Lüssing 		goto sync_flags;
154430cfd02bSAntonio Quartulli 	}
1545d657e621SAntonio Quartulli 
154686452f81SSven Eckelmann 	orig_entry = kmem_cache_zalloc(batadv_tt_orig_cache, GFP_ATOMIC);
1547db08e6e5SSimon Wunderlich 	if (!orig_entry)
1548d657e621SAntonio Quartulli 		goto out;
1549db08e6e5SSimon Wunderlich 
1550db08e6e5SSimon Wunderlich 	INIT_HLIST_NODE(&orig_entry->list);
15517c124391SSven Eckelmann 	kref_get(&orig_node->refcount);
15527ea7b4a1SAntonio Quartulli 	batadv_tt_global_size_inc(orig_node, tt_global->common.vid);
1553db08e6e5SSimon Wunderlich 	orig_entry->orig_node = orig_node;
1554db08e6e5SSimon Wunderlich 	orig_entry->ttvn = ttvn;
155554e22f26SLinus Lüssing 	orig_entry->flags = flags;
15566e8ef69dSSven Eckelmann 	kref_init(&orig_entry->refcount);
1557db08e6e5SSimon Wunderlich 
155823f55485SSven Eckelmann 	kref_get(&orig_entry->refcount);
1559db08e6e5SSimon Wunderlich 	hlist_add_head_rcu(&orig_entry->list,
1560d657e621SAntonio Quartulli 			   &tt_global->orig_list);
15611d8ab8d3SLinus Lüssing 	atomic_inc(&tt_global->orig_list_count);
15621d8ab8d3SLinus Lüssing 
156354e22f26SLinus Lüssing sync_flags:
156454e22f26SLinus Lüssing 	batadv_tt_global_sync_flags(tt_global);
1565d657e621SAntonio Quartulli out:
15667e2366c6SSven Eckelmann 	batadv_tt_orig_list_entry_put(orig_entry);
1567e7136e48SSven Eckelmann 
1568e7136e48SSven Eckelmann 	spin_unlock_bh(&tt_global->list_lock);
1569db08e6e5SSimon Wunderlich }
1570db08e6e5SSimon Wunderlich 
1571d4ff40f6SAntonio Quartulli /**
15727e9a8c2cSSven Eckelmann  * batadv_tt_global_add() - add a new TT global entry or update an existing one
1573d4ff40f6SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
1574d4ff40f6SAntonio Quartulli  * @orig_node: the originator announcing the client
1575d4ff40f6SAntonio Quartulli  * @tt_addr: the mac address of the non-mesh client
1576c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
1577d4ff40f6SAntonio Quartulli  * @flags: TT flags that have to be set for this non-mesh client
1578d4ff40f6SAntonio Quartulli  * @ttvn: the tt version number ever announcing this non-mesh client
1579d4ff40f6SAntonio Quartulli  *
1580d4ff40f6SAntonio Quartulli  * Add a new TT global entry for the given originator. If the entry already
1581d4ff40f6SAntonio Quartulli  * exists add a new reference to the given originator (a global entry can have
1582d4ff40f6SAntonio Quartulli  * references to multiple originators) and adjust the flags attribute to reflect
1583d4ff40f6SAntonio Quartulli  * the function argument.
1584d4ff40f6SAntonio Quartulli  * If a TT local entry exists for this non-mesh client remove it.
1585d4ff40f6SAntonio Quartulli  *
1586bccb48c8SSven Eckelmann  * The caller must hold the orig_node refcount.
15871e5d49fcSAntonio Quartulli  *
158862fe710fSSven Eckelmann  * Return: true if the new entry has been added, false otherwise
1589d4ff40f6SAntonio Quartulli  */
batadv_tt_global_add(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,const unsigned char * tt_addr,unsigned short vid,u16 flags,u8 ttvn)15901e5d49fcSAntonio Quartulli static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
159156303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node,
1592c018ad3dSAntonio Quartulli 				 const unsigned char *tt_addr,
15936b5e971aSSven Eckelmann 				 unsigned short vid, u16 flags, u8 ttvn)
1594c6c8fea2SSven Eckelmann {
1595170173bfSSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
1596170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
15971e5d49fcSAntonio Quartulli 	bool ret = false;
159880b3f58cSSimon Wunderlich 	int hash_added;
159956303d34SSven Eckelmann 	struct batadv_tt_common_entry *common;
16006b5e971aSSven Eckelmann 	u16 local_flags;
1601c6c8fea2SSven Eckelmann 
1602cfd4f757SAntonio Quartulli 	/* ignore global entries from backbone nodes */
1603cfd4f757SAntonio Quartulli 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
1604cfd4f757SAntonio Quartulli 		return true;
1605cfd4f757SAntonio Quartulli 
1606c018ad3dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid);
1607c018ad3dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid);
1608068ee6e2SAntonio Quartulli 
1609068ee6e2SAntonio Quartulli 	/* if the node already has a local client for this entry, it has to wait
1610068ee6e2SAntonio Quartulli 	 * for a roaming advertisement instead of manually messing up the global
1611068ee6e2SAntonio Quartulli 	 * table
1612068ee6e2SAntonio Quartulli 	 */
1613068ee6e2SAntonio Quartulli 	if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
1614068ee6e2SAntonio Quartulli 	    !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
1615068ee6e2SAntonio Quartulli 		goto out;
1616c6c8fea2SSven Eckelmann 
16172dafb49dSAntonio Quartulli 	if (!tt_global_entry) {
161886452f81SSven Eckelmann 		tt_global_entry = kmem_cache_zalloc(batadv_tg_cache,
161986452f81SSven Eckelmann 						    GFP_ATOMIC);
16202dafb49dSAntonio Quartulli 		if (!tt_global_entry)
16217683fdc1SAntonio Quartulli 			goto out;
16227683fdc1SAntonio Quartulli 
1623c0a55929SSven Eckelmann 		common = &tt_global_entry->common;
16248fdd0153SAntonio Quartulli 		ether_addr_copy(common->addr, tt_addr);
1625c018ad3dSAntonio Quartulli 		common->vid = vid;
1626db08e6e5SSimon Wunderlich 
1627a44ebeffSLinus Lüssing 		if (!is_multicast_ether_addr(common->addr))
16284a519b83SLinus Lüssing 			common->flags = flags & (~BATADV_TT_SYNC_MASK);
16294a519b83SLinus Lüssing 
1630cc47f66eSAntonio Quartulli 		tt_global_entry->roam_at = 0;
1631fdf79320SAntonio Quartulli 		/* node must store current time in case of roaming. This is
1632fdf79320SAntonio Quartulli 		 * needed to purge this entry out on timeout (if nobody claims
1633fdf79320SAntonio Quartulli 		 * it)
1634fdf79320SAntonio Quartulli 		 */
1635fdf79320SAntonio Quartulli 		if (flags & BATADV_TT_CLIENT_ROAM)
1636fdf79320SAntonio Quartulli 			tt_global_entry->roam_at = jiffies;
163792dcdf09SSven Eckelmann 		kref_init(&common->refcount);
163830cfd02bSAntonio Quartulli 		common->added_at = jiffies;
1639db08e6e5SSimon Wunderlich 
1640db08e6e5SSimon Wunderlich 		INIT_HLIST_HEAD(&tt_global_entry->orig_list);
16411d8ab8d3SLinus Lüssing 		atomic_set(&tt_global_entry->orig_list_count, 0);
1642db08e6e5SSimon Wunderlich 		spin_lock_init(&tt_global_entry->list_lock);
16437683fdc1SAntonio Quartulli 
164415d5ffdeSSven Eckelmann 		kref_get(&common->refcount);
1645807736f6SSven Eckelmann 		hash_added = batadv_hash_add(bat_priv->tt.global_hash,
1646a513088dSSven Eckelmann 					     batadv_compare_tt,
1647c018ad3dSAntonio Quartulli 					     batadv_choose_tt, common,
1648a513088dSSven Eckelmann 					     &common->hash_entry);
164980b3f58cSSimon Wunderlich 
165080b3f58cSSimon Wunderlich 		if (unlikely(hash_added != 0)) {
165180b3f58cSSimon Wunderlich 			/* remove the reference for the hash */
16525dafd8a6SSven Eckelmann 			batadv_tt_global_entry_put(tt_global_entry);
165380b3f58cSSimon Wunderlich 			goto out_remove;
165480b3f58cSSimon Wunderlich 		}
1655a73105b8SAntonio Quartulli 	} else {
1656068ee6e2SAntonio Quartulli 		common = &tt_global_entry->common;
165730cfd02bSAntonio Quartulli 		/* If there is already a global entry, we can use this one for
165830cfd02bSAntonio Quartulli 		 * our processing.
1659068ee6e2SAntonio Quartulli 		 * But if we are trying to add a temporary client then here are
1660068ee6e2SAntonio Quartulli 		 * two options at this point:
1661068ee6e2SAntonio Quartulli 		 * 1) the global client is not a temporary client: the global
1662068ee6e2SAntonio Quartulli 		 *    client has to be left as it is, temporary information
1663068ee6e2SAntonio Quartulli 		 *    should never override any already known client state
1664068ee6e2SAntonio Quartulli 		 * 2) the global client is a temporary client: purge the
1665068ee6e2SAntonio Quartulli 		 *    originator list and add the new one orig_entry
166630cfd02bSAntonio Quartulli 		 */
1667068ee6e2SAntonio Quartulli 		if (flags & BATADV_TT_CLIENT_TEMP) {
1668068ee6e2SAntonio Quartulli 			if (!(common->flags & BATADV_TT_CLIENT_TEMP))
166930cfd02bSAntonio Quartulli 				goto out;
1670068ee6e2SAntonio Quartulli 			if (batadv_tt_global_entry_has_orig(tt_global_entry,
16717072337eSLinus Lüssing 							    orig_node, NULL))
1672068ee6e2SAntonio Quartulli 				goto out_remove;
1673068ee6e2SAntonio Quartulli 			batadv_tt_global_del_orig_list(tt_global_entry);
1674068ee6e2SAntonio Quartulli 			goto add_orig_entry;
1675068ee6e2SAntonio Quartulli 		}
167630cfd02bSAntonio Quartulli 
167730cfd02bSAntonio Quartulli 		/* if the client was temporary added before receiving the first
1678a6cb3909SSimon Wunderlich 		 * OGM announcing it, we have to clear the TEMP flag. Also,
1679a6cb3909SSimon Wunderlich 		 * remove the previous temporary orig node and re-add it
1680a6cb3909SSimon Wunderlich 		 * if required. If the orig entry changed, the new one which
1681a6cb3909SSimon Wunderlich 		 * is a non-temporary entry is preferred.
168230cfd02bSAntonio Quartulli 		 */
1683a6cb3909SSimon Wunderlich 		if (common->flags & BATADV_TT_CLIENT_TEMP) {
1684a6cb3909SSimon Wunderlich 			batadv_tt_global_del_orig_list(tt_global_entry);
1685068ee6e2SAntonio Quartulli 			common->flags &= ~BATADV_TT_CLIENT_TEMP;
1686a6cb3909SSimon Wunderlich 		}
1687db08e6e5SSimon Wunderlich 
1688e9c00136SAntonio Quartulli 		/* the change can carry possible "attribute" flags like the
168954e22f26SLinus Lüssing 		 * TT_CLIENT_TEMP, therefore they have to be copied in the
1690e9c00136SAntonio Quartulli 		 * client entry
1691e9c00136SAntonio Quartulli 		 */
1692a44ebeffSLinus Lüssing 		if (!is_multicast_ether_addr(common->addr))
169354e22f26SLinus Lüssing 			common->flags |= flags & (~BATADV_TT_SYNC_MASK);
1694e9c00136SAntonio Quartulli 
1695acd34afaSSven Eckelmann 		/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
1696acd34afaSSven Eckelmann 		 * one originator left in the list and we previously received a
1697db08e6e5SSimon Wunderlich 		 * delete + roaming change for this originator.
1698db08e6e5SSimon Wunderlich 		 *
1699db08e6e5SSimon Wunderlich 		 * We should first delete the old originator before adding the
1700db08e6e5SSimon Wunderlich 		 * new one.
1701db08e6e5SSimon Wunderlich 		 */
1702068ee6e2SAntonio Quartulli 		if (common->flags & BATADV_TT_CLIENT_ROAM) {
1703a513088dSSven Eckelmann 			batadv_tt_global_del_orig_list(tt_global_entry);
1704068ee6e2SAntonio Quartulli 			common->flags &= ~BATADV_TT_CLIENT_ROAM;
1705cc47f66eSAntonio Quartulli 			tt_global_entry->roam_at = 0;
1706c6c8fea2SSven Eckelmann 		}
1707db08e6e5SSimon Wunderlich 	}
1708068ee6e2SAntonio Quartulli add_orig_entry:
170930cfd02bSAntonio Quartulli 	/* add the new orig_entry (if needed) or update it */
171054e22f26SLinus Lüssing 	batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn,
171154e22f26SLinus Lüssing 					flags & BATADV_TT_SYNC_MASK);
1712db08e6e5SSimon Wunderlich 
171339c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
171416052789SAntonio Quartulli 		   "Creating new global tt entry: %pM (vid: %d, via %pM)\n",
1715f7a2bd65SSven Eckelmann 		   common->addr, batadv_print_vid(common->vid),
171616052789SAntonio Quartulli 		   orig_node->orig);
17171e5d49fcSAntonio Quartulli 	ret = true;
1718a73105b8SAntonio Quartulli 
171980b3f58cSSimon Wunderlich out_remove:
1720c5caf4efSLinus Lüssing 	/* Do not remove multicast addresses from the local hash on
1721c5caf4efSLinus Lüssing 	 * global additions
1722c5caf4efSLinus Lüssing 	 */
1723c5caf4efSLinus Lüssing 	if (is_multicast_ether_addr(tt_addr))
1724c5caf4efSLinus Lüssing 		goto out;
17257f91d06cSAntonio Quartulli 
1726c6c8fea2SSven Eckelmann 	/* remove address from local hash if present */
1727c018ad3dSAntonio Quartulli 	local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
1728acd34afaSSven Eckelmann 					     "global tt received",
1729c1d07431SAntonio Quartulli 					     flags & BATADV_TT_CLIENT_ROAM);
17307f91d06cSAntonio Quartulli 	tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
17317f91d06cSAntonio Quartulli 
1732068ee6e2SAntonio Quartulli 	if (!(flags & BATADV_TT_CLIENT_ROAM))
1733068ee6e2SAntonio Quartulli 		/* this is a normal global add. Therefore the client is not in a
1734068ee6e2SAntonio Quartulli 		 * roaming state anymore.
1735068ee6e2SAntonio Quartulli 		 */
1736068ee6e2SAntonio Quartulli 		tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
1737068ee6e2SAntonio Quartulli 
17387683fdc1SAntonio Quartulli out:
17395dafd8a6SSven Eckelmann 	batadv_tt_global_entry_put(tt_global_entry);
174095c0db90SSven Eckelmann 	batadv_tt_local_entry_put(tt_local_entry);
17417683fdc1SAntonio Quartulli 	return ret;
1742c6c8fea2SSven Eckelmann }
1743c6c8fea2SSven Eckelmann 
17441b371d13SSimon Wunderlich /**
17457e9a8c2cSSven Eckelmann  * batadv_transtable_best_orig() - Get best originator list entry from tt entry
17464627456aSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
1747981d8900SSven Eckelmann  * @tt_global_entry: global translation table entry to be analyzed
1748981d8900SSven Eckelmann  *
1749bccb48c8SSven Eckelmann  * This function assumes the caller holds rcu_read_lock().
175062fe710fSSven Eckelmann  * Return: best originator list entry or NULL on errors.
1751981d8900SSven Eckelmann  */
1752981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry *
batadv_transtable_best_orig(struct batadv_priv * bat_priv,struct batadv_tt_global_entry * tt_global_entry)17534627456aSAntonio Quartulli batadv_transtable_best_orig(struct batadv_priv *bat_priv,
17544627456aSAntonio Quartulli 			    struct batadv_tt_global_entry *tt_global_entry)
1755981d8900SSven Eckelmann {
17564627456aSAntonio Quartulli 	struct batadv_neigh_node *router, *best_router = NULL;
175729824a55SAntonio Quartulli 	struct batadv_algo_ops *bao = bat_priv->algo_ops;
1758981d8900SSven Eckelmann 	struct hlist_head *head;
1759981d8900SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL;
1760981d8900SSven Eckelmann 
1761981d8900SSven Eckelmann 	head = &tt_global_entry->orig_list;
1762b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(orig_entry, head, list) {
17637351a482SSimon Wunderlich 		router = batadv_orig_router_get(orig_entry->orig_node,
17647351a482SSimon Wunderlich 						BATADV_IF_DEFAULT);
1765981d8900SSven Eckelmann 		if (!router)
1766981d8900SSven Eckelmann 			continue;
1767981d8900SSven Eckelmann 
17684627456aSAntonio Quartulli 		if (best_router &&
176929824a55SAntonio Quartulli 		    bao->neigh.cmp(router, BATADV_IF_DEFAULT, best_router,
177029824a55SAntonio Quartulli 				   BATADV_IF_DEFAULT) <= 0) {
177125bb2509SSven Eckelmann 			batadv_neigh_node_put(router);
17724627456aSAntonio Quartulli 			continue;
1773981d8900SSven Eckelmann 		}
1774981d8900SSven Eckelmann 
17754627456aSAntonio Quartulli 		/* release the refcount for the "old" best */
177625bb2509SSven Eckelmann 		batadv_neigh_node_put(best_router);
17774627456aSAntonio Quartulli 
17784627456aSAntonio Quartulli 		best_entry = orig_entry;
17794627456aSAntonio Quartulli 		best_router = router;
1780981d8900SSven Eckelmann 	}
1781981d8900SSven Eckelmann 
178225bb2509SSven Eckelmann 	batadv_neigh_node_put(best_router);
17834627456aSAntonio Quartulli 
1784981d8900SSven Eckelmann 	return best_entry;
1785981d8900SSven Eckelmann }
1786981d8900SSven Eckelmann 
17871d8ab8d3SLinus Lüssing /**
17887e9a8c2cSSven Eckelmann  * batadv_tt_global_dump_subentry() - Dump all TT local entries into a message
1789d34f0550SMatthias Schiffer  * @msg: Netlink message to dump into
1790d34f0550SMatthias Schiffer  * @portid: Port making netlink request
1791d34f0550SMatthias Schiffer  * @seq: Sequence number of netlink message
1792d34f0550SMatthias Schiffer  * @common: tt local & tt global common data
1793d34f0550SMatthias Schiffer  * @orig: Originator node announcing a non-mesh client
1794d34f0550SMatthias Schiffer  * @best: Is the best originator for the TT entry
1795d34f0550SMatthias Schiffer  *
1796d34f0550SMatthias Schiffer  * Return: Error code, or 0 on success
1797d34f0550SMatthias Schiffer  */
1798d34f0550SMatthias Schiffer static int
batadv_tt_global_dump_subentry(struct sk_buff * msg,u32 portid,u32 seq,struct batadv_tt_common_entry * common,struct batadv_tt_orig_list_entry * orig,bool best)1799d34f0550SMatthias Schiffer batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
1800d34f0550SMatthias Schiffer 			       struct batadv_tt_common_entry *common,
1801d34f0550SMatthias Schiffer 			       struct batadv_tt_orig_list_entry *orig,
1802d34f0550SMatthias Schiffer 			       bool best)
1803d34f0550SMatthias Schiffer {
180454e22f26SLinus Lüssing 	u16 flags = (common->flags & (~BATADV_TT_SYNC_MASK)) | orig->flags;
1805d34f0550SMatthias Schiffer 	void *hdr;
1806d34f0550SMatthias Schiffer 	struct batadv_orig_node_vlan *vlan;
1807d34f0550SMatthias Schiffer 	u8 last_ttvn;
1808d34f0550SMatthias Schiffer 	u32 crc;
1809d34f0550SMatthias Schiffer 
1810d34f0550SMatthias Schiffer 	vlan = batadv_orig_node_vlan_get(orig->orig_node,
1811d34f0550SMatthias Schiffer 					 common->vid);
1812d34f0550SMatthias Schiffer 	if (!vlan)
1813d34f0550SMatthias Schiffer 		return 0;
1814d34f0550SMatthias Schiffer 
1815d34f0550SMatthias Schiffer 	crc = vlan->tt.crc;
1816d34f0550SMatthias Schiffer 
1817d34f0550SMatthias Schiffer 	batadv_orig_node_vlan_put(vlan);
1818d34f0550SMatthias Schiffer 
1819d34f0550SMatthias Schiffer 	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
1820d34f0550SMatthias Schiffer 			  NLM_F_MULTI,
1821d34f0550SMatthias Schiffer 			  BATADV_CMD_GET_TRANSTABLE_GLOBAL);
1822d34f0550SMatthias Schiffer 	if (!hdr)
1823d34f0550SMatthias Schiffer 		return -ENOBUFS;
1824d34f0550SMatthias Schiffer 
1825d34f0550SMatthias Schiffer 	last_ttvn = atomic_read(&orig->orig_node->last_ttvn);
1826d34f0550SMatthias Schiffer 
1827d34f0550SMatthias Schiffer 	if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
1828d34f0550SMatthias Schiffer 	    nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
1829d34f0550SMatthias Schiffer 		    orig->orig_node->orig) ||
1830d34f0550SMatthias Schiffer 	    nla_put_u8(msg, BATADV_ATTR_TT_TTVN, orig->ttvn) ||
1831d34f0550SMatthias Schiffer 	    nla_put_u8(msg, BATADV_ATTR_TT_LAST_TTVN, last_ttvn) ||
1832d34f0550SMatthias Schiffer 	    nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
1833d34f0550SMatthias Schiffer 	    nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
183454e22f26SLinus Lüssing 	    nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, flags))
1835d34f0550SMatthias Schiffer 		goto nla_put_failure;
1836d34f0550SMatthias Schiffer 
1837d34f0550SMatthias Schiffer 	if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
1838d34f0550SMatthias Schiffer 		goto nla_put_failure;
1839d34f0550SMatthias Schiffer 
1840d34f0550SMatthias Schiffer 	genlmsg_end(msg, hdr);
1841d34f0550SMatthias Schiffer 	return 0;
1842d34f0550SMatthias Schiffer 
1843d34f0550SMatthias Schiffer  nla_put_failure:
1844d34f0550SMatthias Schiffer 	genlmsg_cancel(msg, hdr);
1845d34f0550SMatthias Schiffer 	return -EMSGSIZE;
1846d34f0550SMatthias Schiffer }
1847d34f0550SMatthias Schiffer 
1848d34f0550SMatthias Schiffer /**
18497e9a8c2cSSven Eckelmann  * batadv_tt_global_dump_entry() - Dump one TT global entry into a message
1850d34f0550SMatthias Schiffer  * @msg: Netlink message to dump into
1851d34f0550SMatthias Schiffer  * @portid: Port making netlink request
1852d34f0550SMatthias Schiffer  * @seq: Sequence number of netlink message
1853d34f0550SMatthias Schiffer  * @bat_priv: The bat priv with all the soft interface information
1854d34f0550SMatthias Schiffer  * @common: tt local & tt global common data
1855d34f0550SMatthias Schiffer  * @sub_s: Number of entries to skip
1856d34f0550SMatthias Schiffer  *
1857d34f0550SMatthias Schiffer  * This function assumes the caller holds rcu_read_lock().
1858d34f0550SMatthias Schiffer  *
1859d34f0550SMatthias Schiffer  * Return: Error code, or 0 on success
1860d34f0550SMatthias Schiffer  */
1861d34f0550SMatthias Schiffer static int
batadv_tt_global_dump_entry(struct sk_buff * msg,u32 portid,u32 seq,struct batadv_priv * bat_priv,struct batadv_tt_common_entry * common,int * sub_s)1862d34f0550SMatthias Schiffer batadv_tt_global_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
1863d34f0550SMatthias Schiffer 			    struct batadv_priv *bat_priv,
1864d34f0550SMatthias Schiffer 			    struct batadv_tt_common_entry *common, int *sub_s)
1865d34f0550SMatthias Schiffer {
1866d34f0550SMatthias Schiffer 	struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
1867d34f0550SMatthias Schiffer 	struct batadv_tt_global_entry *global;
1868d34f0550SMatthias Schiffer 	struct hlist_head *head;
1869d34f0550SMatthias Schiffer 	int sub = 0;
1870d34f0550SMatthias Schiffer 	bool best;
1871d34f0550SMatthias Schiffer 
1872d34f0550SMatthias Schiffer 	global = container_of(common, struct batadv_tt_global_entry, common);
1873d34f0550SMatthias Schiffer 	best_entry = batadv_transtable_best_orig(bat_priv, global);
1874d34f0550SMatthias Schiffer 	head = &global->orig_list;
1875d34f0550SMatthias Schiffer 
1876d34f0550SMatthias Schiffer 	hlist_for_each_entry_rcu(orig_entry, head, list) {
1877d34f0550SMatthias Schiffer 		if (sub++ < *sub_s)
1878d34f0550SMatthias Schiffer 			continue;
1879d34f0550SMatthias Schiffer 
1880d34f0550SMatthias Schiffer 		best = (orig_entry == best_entry);
1881d34f0550SMatthias Schiffer 
1882d34f0550SMatthias Schiffer 		if (batadv_tt_global_dump_subentry(msg, portid, seq, common,
1883d34f0550SMatthias Schiffer 						   orig_entry, best)) {
1884d34f0550SMatthias Schiffer 			*sub_s = sub - 1;
1885d34f0550SMatthias Schiffer 			return -EMSGSIZE;
1886d34f0550SMatthias Schiffer 		}
1887d34f0550SMatthias Schiffer 	}
1888d34f0550SMatthias Schiffer 
1889d34f0550SMatthias Schiffer 	*sub_s = 0;
1890d34f0550SMatthias Schiffer 	return 0;
1891d34f0550SMatthias Schiffer }
1892d34f0550SMatthias Schiffer 
1893d34f0550SMatthias Schiffer /**
18947e9a8c2cSSven Eckelmann  * batadv_tt_global_dump_bucket() - Dump one TT local bucket into a message
1895d34f0550SMatthias Schiffer  * @msg: Netlink message to dump into
1896d34f0550SMatthias Schiffer  * @portid: Port making netlink request
1897d34f0550SMatthias Schiffer  * @seq: Sequence number of netlink message
1898d34f0550SMatthias Schiffer  * @bat_priv: The bat priv with all the soft interface information
1899d34f0550SMatthias Schiffer  * @head: Pointer to the list containing the global tt entries
1900d34f0550SMatthias Schiffer  * @idx_s: Number of entries to skip
1901d34f0550SMatthias Schiffer  * @sub: Number of entries to skip
1902d34f0550SMatthias Schiffer  *
1903d34f0550SMatthias Schiffer  * Return: Error code, or 0 on success
1904d34f0550SMatthias Schiffer  */
1905d34f0550SMatthias Schiffer static int
batadv_tt_global_dump_bucket(struct sk_buff * msg,u32 portid,u32 seq,struct batadv_priv * bat_priv,struct hlist_head * head,int * idx_s,int * sub)1906d34f0550SMatthias Schiffer batadv_tt_global_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
1907d34f0550SMatthias Schiffer 			     struct batadv_priv *bat_priv,
1908d34f0550SMatthias Schiffer 			     struct hlist_head *head, int *idx_s, int *sub)
1909d34f0550SMatthias Schiffer {
1910d34f0550SMatthias Schiffer 	struct batadv_tt_common_entry *common;
1911d34f0550SMatthias Schiffer 	int idx = 0;
1912d34f0550SMatthias Schiffer 
1913d34f0550SMatthias Schiffer 	rcu_read_lock();
1914d34f0550SMatthias Schiffer 	hlist_for_each_entry_rcu(common, head, hash_entry) {
1915d34f0550SMatthias Schiffer 		if (idx++ < *idx_s)
1916d34f0550SMatthias Schiffer 			continue;
1917d34f0550SMatthias Schiffer 
1918d34f0550SMatthias Schiffer 		if (batadv_tt_global_dump_entry(msg, portid, seq, bat_priv,
1919d34f0550SMatthias Schiffer 						common, sub)) {
1920d34f0550SMatthias Schiffer 			rcu_read_unlock();
1921d34f0550SMatthias Schiffer 			*idx_s = idx - 1;
1922d34f0550SMatthias Schiffer 			return -EMSGSIZE;
1923d34f0550SMatthias Schiffer 		}
1924d34f0550SMatthias Schiffer 	}
1925d34f0550SMatthias Schiffer 	rcu_read_unlock();
1926d34f0550SMatthias Schiffer 
1927d34f0550SMatthias Schiffer 	*idx_s = 0;
1928d34f0550SMatthias Schiffer 	*sub = 0;
1929d34f0550SMatthias Schiffer 	return 0;
1930d34f0550SMatthias Schiffer }
1931d34f0550SMatthias Schiffer 
1932d34f0550SMatthias Schiffer /**
19337e9a8c2cSSven Eckelmann  * batadv_tt_global_dump() -  Dump TT global entries into a message
1934d34f0550SMatthias Schiffer  * @msg: Netlink message to dump into
1935d34f0550SMatthias Schiffer  * @cb: Parameters from query
1936d34f0550SMatthias Schiffer  *
1937d34f0550SMatthias Schiffer  * Return: Error code, or length of message on success
1938d34f0550SMatthias Schiffer  */
batadv_tt_global_dump(struct sk_buff * msg,struct netlink_callback * cb)1939d34f0550SMatthias Schiffer int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb)
1940d34f0550SMatthias Schiffer {
1941d34f0550SMatthias Schiffer 	struct net *net = sock_net(cb->skb->sk);
1942d34f0550SMatthias Schiffer 	struct net_device *soft_iface;
1943d34f0550SMatthias Schiffer 	struct batadv_priv *bat_priv;
1944d34f0550SMatthias Schiffer 	struct batadv_hard_iface *primary_if = NULL;
1945d34f0550SMatthias Schiffer 	struct batadv_hashtable *hash;
1946d34f0550SMatthias Schiffer 	struct hlist_head *head;
1947d34f0550SMatthias Schiffer 	int ret;
1948d34f0550SMatthias Schiffer 	int ifindex;
1949d34f0550SMatthias Schiffer 	int bucket = cb->args[0];
1950d34f0550SMatthias Schiffer 	int idx = cb->args[1];
1951d34f0550SMatthias Schiffer 	int sub = cb->args[2];
1952d34f0550SMatthias Schiffer 	int portid = NETLINK_CB(cb->skb).portid;
1953d34f0550SMatthias Schiffer 
1954d34f0550SMatthias Schiffer 	ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
1955d34f0550SMatthias Schiffer 	if (!ifindex)
1956d34f0550SMatthias Schiffer 		return -EINVAL;
1957d34f0550SMatthias Schiffer 
1958d34f0550SMatthias Schiffer 	soft_iface = dev_get_by_index(net, ifindex);
1959d34f0550SMatthias Schiffer 	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
1960d34f0550SMatthias Schiffer 		ret = -ENODEV;
1961d34f0550SMatthias Schiffer 		goto out;
1962d34f0550SMatthias Schiffer 	}
1963d34f0550SMatthias Schiffer 
1964d34f0550SMatthias Schiffer 	bat_priv = netdev_priv(soft_iface);
1965d34f0550SMatthias Schiffer 
1966d34f0550SMatthias Schiffer 	primary_if = batadv_primary_if_get_selected(bat_priv);
1967d34f0550SMatthias Schiffer 	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
1968d34f0550SMatthias Schiffer 		ret = -ENOENT;
1969d34f0550SMatthias Schiffer 		goto out;
1970d34f0550SMatthias Schiffer 	}
1971d34f0550SMatthias Schiffer 
1972d34f0550SMatthias Schiffer 	hash = bat_priv->tt.global_hash;
1973d34f0550SMatthias Schiffer 
1974d34f0550SMatthias Schiffer 	while (bucket < hash->size) {
1975d34f0550SMatthias Schiffer 		head = &hash->table[bucket];
1976d34f0550SMatthias Schiffer 
1977d34f0550SMatthias Schiffer 		if (batadv_tt_global_dump_bucket(msg, portid,
1978d34f0550SMatthias Schiffer 						 cb->nlh->nlmsg_seq, bat_priv,
1979d34f0550SMatthias Schiffer 						 head, &idx, &sub))
1980d34f0550SMatthias Schiffer 			break;
1981d34f0550SMatthias Schiffer 
1982d34f0550SMatthias Schiffer 		bucket++;
1983d34f0550SMatthias Schiffer 	}
1984d34f0550SMatthias Schiffer 
1985d34f0550SMatthias Schiffer 	ret = msg->len;
1986d34f0550SMatthias Schiffer 
1987d34f0550SMatthias Schiffer  out:
1988d34f0550SMatthias Schiffer 	batadv_hardif_put(primary_if);
1989d34f0550SMatthias Schiffer 	dev_put(soft_iface);
1990d34f0550SMatthias Schiffer 
1991d34f0550SMatthias Schiffer 	cb->args[0] = bucket;
1992d34f0550SMatthias Schiffer 	cb->args[1] = idx;
1993d34f0550SMatthias Schiffer 	cb->args[2] = sub;
1994d34f0550SMatthias Schiffer 
1995d34f0550SMatthias Schiffer 	return ret;
1996d34f0550SMatthias Schiffer }
1997d34f0550SMatthias Schiffer 
1998d34f0550SMatthias Schiffer /**
19997e9a8c2cSSven Eckelmann  * _batadv_tt_global_del_orig_entry() - remove and free an orig_entry
20001d8ab8d3SLinus Lüssing  * @tt_global_entry: the global entry to remove the orig_entry from
20011d8ab8d3SLinus Lüssing  * @orig_entry: the orig entry to remove and free
20021d8ab8d3SLinus Lüssing  *
20031d8ab8d3SLinus Lüssing  * Remove an orig_entry from its list in the given tt_global_entry and
20041d8ab8d3SLinus Lüssing  * free this orig_entry afterwards.
2005433ff98fSMarek Lindner  *
2006433ff98fSMarek Lindner  * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is
2007433ff98fSMarek Lindner  * part of a list.
20081d8ab8d3SLinus Lüssing  */
20091d8ab8d3SLinus Lüssing static void
_batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry * tt_global_entry,struct batadv_tt_orig_list_entry * orig_entry)2010433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
20111d8ab8d3SLinus Lüssing 				 struct batadv_tt_orig_list_entry *orig_entry)
20121d8ab8d3SLinus Lüssing {
20132c72d655SSven Eckelmann 	lockdep_assert_held(&tt_global_entry->list_lock);
20142c72d655SSven Eckelmann 
20151d8ab8d3SLinus Lüssing 	batadv_tt_global_size_dec(orig_entry->orig_node,
20161d8ab8d3SLinus Lüssing 				  tt_global_entry->common.vid);
20171d8ab8d3SLinus Lüssing 	atomic_dec(&tt_global_entry->orig_list_count);
2018433ff98fSMarek Lindner 	/* requires holding tt_global_entry->list_lock and orig_entry->list
2019433ff98fSMarek Lindner 	 * being part of a list
2020433ff98fSMarek Lindner 	 */
20211d8ab8d3SLinus Lüssing 	hlist_del_rcu(&orig_entry->list);
20227e2366c6SSven Eckelmann 	batadv_tt_orig_list_entry_put(orig_entry);
20231d8ab8d3SLinus Lüssing }
20241d8ab8d3SLinus Lüssing 
2025db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */
2026a513088dSSven Eckelmann static void
batadv_tt_global_del_orig_list(struct batadv_tt_global_entry * tt_global_entry)202756303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
2028db08e6e5SSimon Wunderlich {
2029db08e6e5SSimon Wunderlich 	struct hlist_head *head;
2030b67bfe0dSSasha Levin 	struct hlist_node *safe;
203156303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
2032db08e6e5SSimon Wunderlich 
2033db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
2034db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
20351d8ab8d3SLinus Lüssing 	hlist_for_each_entry_safe(orig_entry, safe, head, list)
2036433ff98fSMarek Lindner 		_batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry);
2037db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
2038db08e6e5SSimon Wunderlich }
2039db08e6e5SSimon Wunderlich 
20401d8ab8d3SLinus Lüssing /**
20417e9a8c2cSSven Eckelmann  * batadv_tt_global_del_orig_node() - remove orig_node from a global tt entry
20421d8ab8d3SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
20431d8ab8d3SLinus Lüssing  * @tt_global_entry: the global entry to remove the orig_node from
20441d8ab8d3SLinus Lüssing  * @orig_node: the originator announcing the client
20451d8ab8d3SLinus Lüssing  * @message: message to append to the log on deletion
20461d8ab8d3SLinus Lüssing  *
20471d8ab8d3SLinus Lüssing  * Remove the given orig_node and its according orig_entry from the given
20481d8ab8d3SLinus Lüssing  * global tt entry.
20491d8ab8d3SLinus Lüssing  */
2050a513088dSSven Eckelmann static void
batadv_tt_global_del_orig_node(struct batadv_priv * bat_priv,struct batadv_tt_global_entry * tt_global_entry,struct batadv_orig_node * orig_node,const char * message)20511d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv,
205256303d34SSven Eckelmann 			       struct batadv_tt_global_entry *tt_global_entry,
205356303d34SSven Eckelmann 			       struct batadv_orig_node *orig_node,
2054db08e6e5SSimon Wunderlich 			       const char *message)
2055db08e6e5SSimon Wunderlich {
2056db08e6e5SSimon Wunderlich 	struct hlist_head *head;
2057b67bfe0dSSasha Levin 	struct hlist_node *safe;
205856303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
205916052789SAntonio Quartulli 	unsigned short vid;
2060db08e6e5SSimon Wunderlich 
2061db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
2062db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
2063b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(orig_entry, safe, head, list) {
2064db08e6e5SSimon Wunderlich 		if (orig_entry->orig_node == orig_node) {
206516052789SAntonio Quartulli 			vid = tt_global_entry->common.vid;
206639c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
206716052789SAntonio Quartulli 				   "Deleting %pM from global tt entry %pM (vid: %d): %s\n",
20681eda58bfSSven Eckelmann 				   orig_node->orig,
206916052789SAntonio Quartulli 				   tt_global_entry->common.addr,
2070f7a2bd65SSven Eckelmann 				   batadv_print_vid(vid), message);
2071433ff98fSMarek Lindner 			_batadv_tt_global_del_orig_entry(tt_global_entry,
20721d8ab8d3SLinus Lüssing 							 orig_entry);
2073db08e6e5SSimon Wunderlich 		}
2074db08e6e5SSimon Wunderlich 	}
2075db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
2076db08e6e5SSimon Wunderlich }
2077db08e6e5SSimon Wunderlich 
2078db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry
2079acd34afaSSven Eckelmann  * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
2080acd34afaSSven Eckelmann  * timer, otherwise we simply remove the originator scheduled for deletion.
2081db08e6e5SSimon Wunderlich  */
2082a513088dSSven Eckelmann static void
batadv_tt_global_del_roaming(struct batadv_priv * bat_priv,struct batadv_tt_global_entry * tt_global_entry,struct batadv_orig_node * orig_node,const char * message)208356303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
208456303d34SSven Eckelmann 			     struct batadv_tt_global_entry *tt_global_entry,
208556303d34SSven Eckelmann 			     struct batadv_orig_node *orig_node,
208656303d34SSven Eckelmann 			     const char *message)
2087db08e6e5SSimon Wunderlich {
2088db08e6e5SSimon Wunderlich 	bool last_entry = true;
2089db08e6e5SSimon Wunderlich 	struct hlist_head *head;
209056303d34SSven Eckelmann 	struct batadv_tt_orig_list_entry *orig_entry;
2091db08e6e5SSimon Wunderlich 
2092db08e6e5SSimon Wunderlich 	/* no local entry exists, case 1:
2093db08e6e5SSimon Wunderlich 	 * Check if this is the last one or if other entries exist.
2094db08e6e5SSimon Wunderlich 	 */
2095db08e6e5SSimon Wunderlich 
2096db08e6e5SSimon Wunderlich 	rcu_read_lock();
2097db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
2098b67bfe0dSSasha Levin 	hlist_for_each_entry_rcu(orig_entry, head, list) {
2099db08e6e5SSimon Wunderlich 		if (orig_entry->orig_node != orig_node) {
2100db08e6e5SSimon Wunderlich 			last_entry = false;
2101db08e6e5SSimon Wunderlich 			break;
2102db08e6e5SSimon Wunderlich 		}
2103db08e6e5SSimon Wunderlich 	}
2104db08e6e5SSimon Wunderlich 	rcu_read_unlock();
2105db08e6e5SSimon Wunderlich 
2106db08e6e5SSimon Wunderlich 	if (last_entry) {
2107db08e6e5SSimon Wunderlich 		/* its the last one, mark for roaming. */
2108acd34afaSSven Eckelmann 		tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
2109db08e6e5SSimon Wunderlich 		tt_global_entry->roam_at = jiffies;
21101fda4c0aSSven Eckelmann 	} else {
2111db08e6e5SSimon Wunderlich 		/* there is another entry, we can simply delete this
2112db08e6e5SSimon Wunderlich 		 * one and can still use the other one.
2113db08e6e5SSimon Wunderlich 		 */
21141d8ab8d3SLinus Lüssing 		batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
2115db08e6e5SSimon Wunderlich 					       orig_node, message);
2116db08e6e5SSimon Wunderlich 	}
21171fda4c0aSSven Eckelmann }
2118db08e6e5SSimon Wunderlich 
2119c018ad3dSAntonio Quartulli /**
21207e9a8c2cSSven Eckelmann  * batadv_tt_global_del() - remove a client from the global table
2121c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2122c018ad3dSAntonio Quartulli  * @orig_node: an originator serving this client
2123c018ad3dSAntonio Quartulli  * @addr: the mac address of the client
2124c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
2125c018ad3dSAntonio Quartulli  * @message: a message explaining the reason for deleting the client to print
2126c018ad3dSAntonio Quartulli  *  for debugging purpose
2127c018ad3dSAntonio Quartulli  * @roaming: true if the deletion has been triggered by a roaming event
2128c018ad3dSAntonio Quartulli  */
batadv_tt_global_del(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,const unsigned char * addr,unsigned short vid,const char * message,bool roaming)212956303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv,
213056303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node,
2131c018ad3dSAntonio Quartulli 				 const unsigned char *addr, unsigned short vid,
2132cc47f66eSAntonio Quartulli 				 const char *message, bool roaming)
2133a73105b8SAntonio Quartulli {
2134170173bfSSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
213556303d34SSven Eckelmann 	struct batadv_tt_local_entry *local_entry = NULL;
2136a73105b8SAntonio Quartulli 
2137c018ad3dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
2138db08e6e5SSimon Wunderlich 	if (!tt_global_entry)
21397683fdc1SAntonio Quartulli 		goto out;
2140a73105b8SAntonio Quartulli 
2141db08e6e5SSimon Wunderlich 	if (!roaming) {
21421d8ab8d3SLinus Lüssing 		batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
2143a513088dSSven Eckelmann 					       orig_node, message);
214492f90f56SSven Eckelmann 
2145db08e6e5SSimon Wunderlich 		if (hlist_empty(&tt_global_entry->orig_list))
2146be73b488SAntonio Quartulli 			batadv_tt_global_free(bat_priv, tt_global_entry,
2147db08e6e5SSimon Wunderlich 					      message);
2148db08e6e5SSimon Wunderlich 
2149cc47f66eSAntonio Quartulli 		goto out;
2150cc47f66eSAntonio Quartulli 	}
215192f90f56SSven Eckelmann 
2152db08e6e5SSimon Wunderlich 	/* if we are deleting a global entry due to a roam
2153db08e6e5SSimon Wunderlich 	 * event, there are two possibilities:
2154db08e6e5SSimon Wunderlich 	 * 1) the client roamed from node A to node B => if there
2155db08e6e5SSimon Wunderlich 	 *    is only one originator left for this client, we mark
2156acd34afaSSven Eckelmann 	 *    it with BATADV_TT_CLIENT_ROAM, we start a timer and we
2157db08e6e5SSimon Wunderlich 	 *    wait for node B to claim it. In case of timeout
2158db08e6e5SSimon Wunderlich 	 *    the entry is purged.
2159db08e6e5SSimon Wunderlich 	 *
2160db08e6e5SSimon Wunderlich 	 *    If there are other originators left, we directly delete
2161db08e6e5SSimon Wunderlich 	 *    the originator.
2162db08e6e5SSimon Wunderlich 	 * 2) the client roamed to us => we can directly delete
21639cfc7bd6SSven Eckelmann 	 *    the global entry, since it is useless now.
21649cfc7bd6SSven Eckelmann 	 */
2165a513088dSSven Eckelmann 	local_entry = batadv_tt_local_hash_find(bat_priv,
2166c018ad3dSAntonio Quartulli 						tt_global_entry->common.addr,
2167c018ad3dSAntonio Quartulli 						vid);
2168a513088dSSven Eckelmann 	if (local_entry) {
2169db08e6e5SSimon Wunderlich 		/* local entry exists, case 2: client roamed to us. */
2170a513088dSSven Eckelmann 		batadv_tt_global_del_orig_list(tt_global_entry);
2171be73b488SAntonio Quartulli 		batadv_tt_global_free(bat_priv, tt_global_entry, message);
21721fda4c0aSSven Eckelmann 	} else {
2173db08e6e5SSimon Wunderlich 		/* no local entry exists, case 1: check for roaming */
2174a513088dSSven Eckelmann 		batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
2175a513088dSSven Eckelmann 					     orig_node, message);
21761fda4c0aSSven Eckelmann 	}
2177db08e6e5SSimon Wunderlich 
2178cc47f66eSAntonio Quartulli out:
21795dafd8a6SSven Eckelmann 	batadv_tt_global_entry_put(tt_global_entry);
218095c0db90SSven Eckelmann 	batadv_tt_local_entry_put(local_entry);
2181a73105b8SAntonio Quartulli }
2182a73105b8SAntonio Quartulli 
218395fb130dSAntonio Quartulli /**
21847e9a8c2cSSven Eckelmann  * batadv_tt_global_del_orig() - remove all the TT global entries belonging to
21857e9a8c2cSSven Eckelmann  *  the given originator matching the provided vid
218695fb130dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
218795fb130dSAntonio Quartulli  * @orig_node: the originator owning the entries to remove
218895fb130dSAntonio Quartulli  * @match_vid: the VLAN identifier to match. If negative all the entries will be
218995fb130dSAntonio Quartulli  *  removed
219095fb130dSAntonio Quartulli  * @message: debug message to print as "reason"
219195fb130dSAntonio Quartulli  */
batadv_tt_global_del_orig(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,s32 match_vid,const char * message)219256303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
219356303d34SSven Eckelmann 			       struct batadv_orig_node *orig_node,
21946b5e971aSSven Eckelmann 			       s32 match_vid,
219556303d34SSven Eckelmann 			       const char *message)
2196c6c8fea2SSven Eckelmann {
219756303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
219856303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
21996b5e971aSSven Eckelmann 	u32 i;
2200807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
2201b67bfe0dSSasha Levin 	struct hlist_node *safe;
2202a73105b8SAntonio Quartulli 	struct hlist_head *head;
22037683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
220416052789SAntonio Quartulli 	unsigned short vid;
2205c6c8fea2SSven Eckelmann 
22066e801494SSimon Wunderlich 	if (!hash)
22076e801494SSimon Wunderlich 		return;
22086e801494SSimon Wunderlich 
2209a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2210a73105b8SAntonio Quartulli 		head = &hash->table[i];
22117683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
2212c6c8fea2SSven Eckelmann 
22137683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
2214b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, safe,
2215a73105b8SAntonio Quartulli 					  head, hash_entry) {
221695fb130dSAntonio Quartulli 			/* remove only matching entries */
221795fb130dSAntonio Quartulli 			if (match_vid >= 0 && tt_common_entry->vid != match_vid)
221895fb130dSAntonio Quartulli 				continue;
221995fb130dSAntonio Quartulli 
222056303d34SSven Eckelmann 			tt_global = container_of(tt_common_entry,
222156303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
222248100bacSAntonio Quartulli 						 common);
2223db08e6e5SSimon Wunderlich 
22241d8ab8d3SLinus Lüssing 			batadv_tt_global_del_orig_node(bat_priv, tt_global,
2225db08e6e5SSimon Wunderlich 						       orig_node, message);
2226db08e6e5SSimon Wunderlich 
222756303d34SSven Eckelmann 			if (hlist_empty(&tt_global->orig_list)) {
222816052789SAntonio Quartulli 				vid = tt_global->common.vid;
222939c75a51SSven Eckelmann 				batadv_dbg(BATADV_DBG_TT, bat_priv,
223016052789SAntonio Quartulli 					   "Deleting global tt entry %pM (vid: %d): %s\n",
223116052789SAntonio Quartulli 					   tt_global->common.addr,
2232f7a2bd65SSven Eckelmann 					   batadv_print_vid(vid), message);
2233b67bfe0dSSasha Levin 				hlist_del_rcu(&tt_common_entry->hash_entry);
22345dafd8a6SSven Eckelmann 				batadv_tt_global_entry_put(tt_global);
2235c6c8fea2SSven Eckelmann 			}
2236a73105b8SAntonio Quartulli 		}
22377683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
22387683fdc1SAntonio Quartulli 	}
2239ac4eebd4SLinus Lüssing 	clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
2240c6c8fea2SSven Eckelmann }
2241c6c8fea2SSven Eckelmann 
batadv_tt_global_to_purge(struct batadv_tt_global_entry * tt_global,char ** msg)224230cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
224330cfd02bSAntonio Quartulli 				      char **msg)
2244cc47f66eSAntonio Quartulli {
224530cfd02bSAntonio Quartulli 	bool purge = false;
224630cfd02bSAntonio Quartulli 	unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT;
224730cfd02bSAntonio Quartulli 	unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
2248cc47f66eSAntonio Quartulli 
224930cfd02bSAntonio Quartulli 	if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
225030cfd02bSAntonio Quartulli 	    batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
225130cfd02bSAntonio Quartulli 		purge = true;
225230cfd02bSAntonio Quartulli 		*msg = "Roaming timeout\n";
225342d0b044SSven Eckelmann 	}
225442d0b044SSven Eckelmann 
225530cfd02bSAntonio Quartulli 	if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
225630cfd02bSAntonio Quartulli 	    batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
225730cfd02bSAntonio Quartulli 		purge = true;
225830cfd02bSAntonio Quartulli 		*msg = "Temporary client timeout\n";
225930cfd02bSAntonio Quartulli 	}
226030cfd02bSAntonio Quartulli 
226130cfd02bSAntonio Quartulli 	return purge;
226230cfd02bSAntonio Quartulli }
226330cfd02bSAntonio Quartulli 
batadv_tt_global_purge(struct batadv_priv * bat_priv)226430cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
226542d0b044SSven Eckelmann {
2266807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
226742d0b044SSven Eckelmann 	struct hlist_head *head;
2268b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
226942d0b044SSven Eckelmann 	spinlock_t *list_lock; /* protects write access to the hash lists */
22706b5e971aSSven Eckelmann 	u32 i;
227130cfd02bSAntonio Quartulli 	char *msg = NULL;
227230cfd02bSAntonio Quartulli 	struct batadv_tt_common_entry *tt_common;
227330cfd02bSAntonio Quartulli 	struct batadv_tt_global_entry *tt_global;
227442d0b044SSven Eckelmann 
227542d0b044SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
227642d0b044SSven Eckelmann 		head = &hash->table[i];
227742d0b044SSven Eckelmann 		list_lock = &hash->list_locks[i];
227842d0b044SSven Eckelmann 
227942d0b044SSven Eckelmann 		spin_lock_bh(list_lock);
2280b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common, node_tmp, head,
228130cfd02bSAntonio Quartulli 					  hash_entry) {
228230cfd02bSAntonio Quartulli 			tt_global = container_of(tt_common,
228330cfd02bSAntonio Quartulli 						 struct batadv_tt_global_entry,
228430cfd02bSAntonio Quartulli 						 common);
228530cfd02bSAntonio Quartulli 
228630cfd02bSAntonio Quartulli 			if (!batadv_tt_global_to_purge(tt_global, &msg))
228730cfd02bSAntonio Quartulli 				continue;
228830cfd02bSAntonio Quartulli 
228930cfd02bSAntonio Quartulli 			batadv_dbg(BATADV_DBG_TT, bat_priv,
229016052789SAntonio Quartulli 				   "Deleting global tt entry %pM (vid: %d): %s\n",
229116052789SAntonio Quartulli 				   tt_global->common.addr,
2292f7a2bd65SSven Eckelmann 				   batadv_print_vid(tt_global->common.vid),
229316052789SAntonio Quartulli 				   msg);
229430cfd02bSAntonio Quartulli 
2295b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common->hash_entry);
229630cfd02bSAntonio Quartulli 
22975dafd8a6SSven Eckelmann 			batadv_tt_global_entry_put(tt_global);
229830cfd02bSAntonio Quartulli 		}
22997683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
2300cc47f66eSAntonio Quartulli 	}
2301cc47f66eSAntonio Quartulli }
2302cc47f66eSAntonio Quartulli 
batadv_tt_global_table_free(struct batadv_priv * bat_priv)230356303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
2304c6c8fea2SSven Eckelmann {
23055bf74e9cSSven Eckelmann 	struct batadv_hashtable *hash;
23067683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
230756303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
230856303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
2309b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
23107683fdc1SAntonio Quartulli 	struct hlist_head *head;
23116b5e971aSSven Eckelmann 	u32 i;
23127683fdc1SAntonio Quartulli 
2313807736f6SSven Eckelmann 	if (!bat_priv->tt.global_hash)
2314c6c8fea2SSven Eckelmann 		return;
2315c6c8fea2SSven Eckelmann 
2316807736f6SSven Eckelmann 	hash = bat_priv->tt.global_hash;
23177683fdc1SAntonio Quartulli 
23187683fdc1SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
23197683fdc1SAntonio Quartulli 		head = &hash->table[i];
23207683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
23217683fdc1SAntonio Quartulli 
23227683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
2323b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common_entry, node_tmp,
23247683fdc1SAntonio Quartulli 					  head, hash_entry) {
2325b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common_entry->hash_entry);
232656303d34SSven Eckelmann 			tt_global = container_of(tt_common_entry,
232756303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
232848100bacSAntonio Quartulli 						 common);
23295dafd8a6SSven Eckelmann 			batadv_tt_global_entry_put(tt_global);
23307683fdc1SAntonio Quartulli 		}
23317683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
23327683fdc1SAntonio Quartulli 	}
23337683fdc1SAntonio Quartulli 
23341a8eaf07SSven Eckelmann 	batadv_hash_destroy(hash);
23357683fdc1SAntonio Quartulli 
2336807736f6SSven Eckelmann 	bat_priv->tt.global_hash = NULL;
2337c6c8fea2SSven Eckelmann }
2338c6c8fea2SSven Eckelmann 
233956303d34SSven Eckelmann static bool
_batadv_is_ap_isolated(struct batadv_tt_local_entry * tt_local_entry,struct batadv_tt_global_entry * tt_global_entry)234056303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
234156303d34SSven Eckelmann 		       struct batadv_tt_global_entry *tt_global_entry)
234259b699cdSAntonio Quartulli {
2343acd34afaSSven Eckelmann 	if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
2344acd34afaSSven Eckelmann 	    tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
234575ae84a4SSimon Wunderlich 		return true;
234659b699cdSAntonio Quartulli 
23472d2fcc2aSAntonio Quartulli 	/* check if the two clients are marked as isolated */
23482d2fcc2aSAntonio Quartulli 	if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
23492d2fcc2aSAntonio Quartulli 	    tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
235075ae84a4SSimon Wunderlich 		return true;
23512d2fcc2aSAntonio Quartulli 
235275ae84a4SSimon Wunderlich 	return false;
235359b699cdSAntonio Quartulli }
235459b699cdSAntonio Quartulli 
2355c018ad3dSAntonio Quartulli /**
23567e9a8c2cSSven Eckelmann  * batadv_transtable_search() - get the mesh destination for a given client
2357c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2358c018ad3dSAntonio Quartulli  * @src: mac address of the source client
2359c018ad3dSAntonio Quartulli  * @addr: mac address of the destination client
2360c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
2361c018ad3dSAntonio Quartulli  *
236262fe710fSSven Eckelmann  * Return: a pointer to the originator that was selected as destination in the
2363c018ad3dSAntonio Quartulli  * mesh for contacting the client 'addr', NULL otherwise.
2364c018ad3dSAntonio Quartulli  * In case of multiple originators serving the same client, the function returns
2365c018ad3dSAntonio Quartulli  * the best one (best in terms of metric towards the destination node).
2366c018ad3dSAntonio Quartulli  *
2367c018ad3dSAntonio Quartulli  * If the two clients are AP isolated the function returns NULL.
2368c018ad3dSAntonio Quartulli  */
batadv_transtable_search(struct batadv_priv * bat_priv,const u8 * src,const u8 * addr,unsigned short vid)236956303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
23706b5e971aSSven Eckelmann 						  const u8 *src,
23716b5e971aSSven Eckelmann 						  const u8 *addr,
2372c018ad3dSAntonio Quartulli 						  unsigned short vid)
2373c6c8fea2SSven Eckelmann {
237456303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry = NULL;
237556303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry = NULL;
237656303d34SSven Eckelmann 	struct batadv_orig_node *orig_node = NULL;
2377981d8900SSven Eckelmann 	struct batadv_tt_orig_list_entry *best_entry;
2378c6c8fea2SSven Eckelmann 
2379eceb22aeSAntonio Quartulli 	if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
2380c018ad3dSAntonio Quartulli 		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
2381068ee6e2SAntonio Quartulli 		if (!tt_local_entry ||
2382068ee6e2SAntonio Quartulli 		    (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
23833d393e47SAntonio Quartulli 			goto out;
23843d393e47SAntonio Quartulli 	}
23857aadf889SMarek Lindner 
2386c018ad3dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
23872dafb49dSAntonio Quartulli 	if (!tt_global_entry)
23887b36e8eeSMarek Lindner 		goto out;
2389c6c8fea2SSven Eckelmann 
23903d393e47SAntonio Quartulli 	/* check whether the clients should not communicate due to AP
23919cfc7bd6SSven Eckelmann 	 * isolation
23929cfc7bd6SSven Eckelmann 	 */
2393a513088dSSven Eckelmann 	if (tt_local_entry &&
2394a513088dSSven Eckelmann 	    _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
23953d393e47SAntonio Quartulli 		goto out;
23963d393e47SAntonio Quartulli 
2397db08e6e5SSimon Wunderlich 	rcu_read_lock();
23984627456aSAntonio Quartulli 	best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
2399db08e6e5SSimon Wunderlich 	/* found anything? */
2400981d8900SSven Eckelmann 	if (best_entry)
2401981d8900SSven Eckelmann 		orig_node = best_entry->orig_node;
24027c124391SSven Eckelmann 	if (orig_node && !kref_get_unless_zero(&orig_node->refcount))
2403db08e6e5SSimon Wunderlich 		orig_node = NULL;
2404db08e6e5SSimon Wunderlich 	rcu_read_unlock();
2405981d8900SSven Eckelmann 
24067b36e8eeSMarek Lindner out:
24075dafd8a6SSven Eckelmann 	batadv_tt_global_entry_put(tt_global_entry);
240895c0db90SSven Eckelmann 	batadv_tt_local_entry_put(tt_local_entry);
24093d393e47SAntonio Quartulli 
24107b36e8eeSMarek Lindner 	return orig_node;
2411c6c8fea2SSven Eckelmann }
2412a73105b8SAntonio Quartulli 
2413ced72933SAntonio Quartulli /**
24147e9a8c2cSSven Eckelmann  * batadv_tt_global_crc() - calculates the checksum of the local table belonging
2415ced72933SAntonio Quartulli  *  to the given orig_node
2416ced72933SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
24170ffa9e8dSAntonio Quartulli  * @orig_node: originator for which the CRC should be computed
24187ea7b4a1SAntonio Quartulli  * @vid: VLAN identifier for which the CRC32 has to be computed
24190ffa9e8dSAntonio Quartulli  *
24200ffa9e8dSAntonio Quartulli  * This function computes the checksum for the global table corresponding to a
24210ffa9e8dSAntonio Quartulli  * specific originator. In particular, the checksum is computed as follows: For
24220ffa9e8dSAntonio Quartulli  * each client connected to the originator the CRC32C of the MAC address and the
24230ffa9e8dSAntonio Quartulli  * VID is computed and then all the CRC32Cs of the various clients are xor'ed
24240ffa9e8dSAntonio Quartulli  * together.
24250ffa9e8dSAntonio Quartulli  *
24260ffa9e8dSAntonio Quartulli  * The idea behind is that CRC32C should be used as much as possible in order to
24270ffa9e8dSAntonio Quartulli  * produce a unique hash of the table, but since the order which is used to feed
24280ffa9e8dSAntonio Quartulli  * the CRC32C function affects the result and since every node in the network
24290ffa9e8dSAntonio Quartulli  * probably sorts the clients differently, the hash function cannot be directly
24300ffa9e8dSAntonio Quartulli  * computed over the entire table. Hence the CRC32C is used only on
24310ffa9e8dSAntonio Quartulli  * the single client entry, while all the results are then xor'ed together
24320ffa9e8dSAntonio Quartulli  * because the XOR operation can combine them all while trying to reduce the
24330ffa9e8dSAntonio Quartulli  * noise as much as possible.
24340ffa9e8dSAntonio Quartulli  *
243562fe710fSSven Eckelmann  * Return: the checksum of the global table of a given originator.
2436ced72933SAntonio Quartulli  */
batadv_tt_global_crc(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,unsigned short vid)24376b5e971aSSven Eckelmann static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
24387ea7b4a1SAntonio Quartulli 				struct batadv_orig_node *orig_node,
24397ea7b4a1SAntonio Quartulli 				unsigned short vid)
2440a73105b8SAntonio Quartulli {
2441807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
244254e22f26SLinus Lüssing 	struct batadv_tt_orig_list_entry *tt_orig;
244356303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
244456303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global;
2445a73105b8SAntonio Quartulli 	struct hlist_head *head;
24466b5e971aSSven Eckelmann 	u32 i, crc_tmp, crc = 0;
24476b5e971aSSven Eckelmann 	u8 flags;
2448a30e22caSAntonio Quartulli 	__be16 tmp_vid;
2449a73105b8SAntonio Quartulli 
2450a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2451a73105b8SAntonio Quartulli 		head = &hash->table[i];
2452a73105b8SAntonio Quartulli 
2453a73105b8SAntonio Quartulli 		rcu_read_lock();
2454b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
245556303d34SSven Eckelmann 			tt_global = container_of(tt_common,
245656303d34SSven Eckelmann 						 struct batadv_tt_global_entry,
245748100bacSAntonio Quartulli 						 common);
24587ea7b4a1SAntonio Quartulli 			/* compute the CRC only for entries belonging to the
24597ea7b4a1SAntonio Quartulli 			 * VLAN identified by the vid passed as parameter
24607ea7b4a1SAntonio Quartulli 			 */
24617ea7b4a1SAntonio Quartulli 			if (tt_common->vid != vid)
24627ea7b4a1SAntonio Quartulli 				continue;
24637ea7b4a1SAntonio Quartulli 
2464cc47f66eSAntonio Quartulli 			/* Roaming clients are in the global table for
2465cc47f66eSAntonio Quartulli 			 * consistency only. They don't have to be
2466cc47f66eSAntonio Quartulli 			 * taken into account while computing the
2467db08e6e5SSimon Wunderlich 			 * global crc
2468db08e6e5SSimon Wunderlich 			 */
2469acd34afaSSven Eckelmann 			if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
2470cc47f66eSAntonio Quartulli 				continue;
247130cfd02bSAntonio Quartulli 			/* Temporary clients have not been announced yet, so
247230cfd02bSAntonio Quartulli 			 * they have to be skipped while computing the global
247330cfd02bSAntonio Quartulli 			 * crc
247430cfd02bSAntonio Quartulli 			 */
247530cfd02bSAntonio Quartulli 			if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
247630cfd02bSAntonio Quartulli 				continue;
2477db08e6e5SSimon Wunderlich 
2478db08e6e5SSimon Wunderlich 			/* find out if this global entry is announced by this
2479db08e6e5SSimon Wunderlich 			 * originator
2480db08e6e5SSimon Wunderlich 			 */
248154e22f26SLinus Lüssing 			tt_orig = batadv_tt_global_orig_entry_find(tt_global,
248254e22f26SLinus Lüssing 								   orig_node);
248354e22f26SLinus Lüssing 			if (!tt_orig)
2484db08e6e5SSimon Wunderlich 				continue;
2485db08e6e5SSimon Wunderlich 
2486a30e22caSAntonio Quartulli 			/* use network order to read the VID: this ensures that
2487a30e22caSAntonio Quartulli 			 * every node reads the bytes in the same order.
2488a30e22caSAntonio Quartulli 			 */
2489a30e22caSAntonio Quartulli 			tmp_vid = htons(tt_common->vid);
2490a30e22caSAntonio Quartulli 			crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
24910eb01568SAntonio Quartulli 
24920eb01568SAntonio Quartulli 			/* compute the CRC on flags that have to be kept in sync
24930eb01568SAntonio Quartulli 			 * among nodes
24940eb01568SAntonio Quartulli 			 */
249554e22f26SLinus Lüssing 			flags = tt_orig->flags;
24960eb01568SAntonio Quartulli 			crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
24970eb01568SAntonio Quartulli 
24980ffa9e8dSAntonio Quartulli 			crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
249954e22f26SLinus Lüssing 
250054e22f26SLinus Lüssing 			batadv_tt_orig_list_entry_put(tt_orig);
2501a73105b8SAntonio Quartulli 		}
2502a73105b8SAntonio Quartulli 		rcu_read_unlock();
2503a73105b8SAntonio Quartulli 	}
2504a73105b8SAntonio Quartulli 
2505ced72933SAntonio Quartulli 	return crc;
2506a73105b8SAntonio Quartulli }
2507a73105b8SAntonio Quartulli 
2508ced72933SAntonio Quartulli /**
25097e9a8c2cSSven Eckelmann  * batadv_tt_local_crc() - calculates the checksum of the local table
2510ced72933SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
25117ea7b4a1SAntonio Quartulli  * @vid: VLAN identifier for which the CRC32 has to be computed
25120ffa9e8dSAntonio Quartulli  *
25130ffa9e8dSAntonio Quartulli  * For details about the computation, please refer to the documentation for
25140ffa9e8dSAntonio Quartulli  * batadv_tt_global_crc().
25150ffa9e8dSAntonio Quartulli  *
251662fe710fSSven Eckelmann  * Return: the checksum of the local table
2517ced72933SAntonio Quartulli  */
batadv_tt_local_crc(struct batadv_priv * bat_priv,unsigned short vid)25186b5e971aSSven Eckelmann static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
25197ea7b4a1SAntonio Quartulli 			       unsigned short vid)
2520a73105b8SAntonio Quartulli {
2521807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
252256303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
2523a73105b8SAntonio Quartulli 	struct hlist_head *head;
25246b5e971aSSven Eckelmann 	u32 i, crc_tmp, crc = 0;
25256b5e971aSSven Eckelmann 	u8 flags;
2526a30e22caSAntonio Quartulli 	__be16 tmp_vid;
2527a73105b8SAntonio Quartulli 
2528a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2529a73105b8SAntonio Quartulli 		head = &hash->table[i];
2530a73105b8SAntonio Quartulli 
2531a73105b8SAntonio Quartulli 		rcu_read_lock();
2532b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
25337ea7b4a1SAntonio Quartulli 			/* compute the CRC only for entries belonging to the
25347ea7b4a1SAntonio Quartulli 			 * VLAN identified by vid
25357ea7b4a1SAntonio Quartulli 			 */
25367ea7b4a1SAntonio Quartulli 			if (tt_common->vid != vid)
25377ea7b4a1SAntonio Quartulli 				continue;
25387ea7b4a1SAntonio Quartulli 
2539058d0e26SAntonio Quartulli 			/* not yet committed clients have not to be taken into
25409cfc7bd6SSven Eckelmann 			 * account while computing the CRC
25419cfc7bd6SSven Eckelmann 			 */
2542acd34afaSSven Eckelmann 			if (tt_common->flags & BATADV_TT_CLIENT_NEW)
2543058d0e26SAntonio Quartulli 				continue;
2544ced72933SAntonio Quartulli 
2545a30e22caSAntonio Quartulli 			/* use network order to read the VID: this ensures that
2546a30e22caSAntonio Quartulli 			 * every node reads the bytes in the same order.
2547a30e22caSAntonio Quartulli 			 */
2548a30e22caSAntonio Quartulli 			tmp_vid = htons(tt_common->vid);
2549a30e22caSAntonio Quartulli 			crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
25500eb01568SAntonio Quartulli 
25510eb01568SAntonio Quartulli 			/* compute the CRC on flags that have to be kept in sync
25520eb01568SAntonio Quartulli 			 * among nodes
25530eb01568SAntonio Quartulli 			 */
25540eb01568SAntonio Quartulli 			flags = tt_common->flags & BATADV_TT_SYNC_MASK;
25550eb01568SAntonio Quartulli 			crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
25560eb01568SAntonio Quartulli 
25570ffa9e8dSAntonio Quartulli 			crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
2558a73105b8SAntonio Quartulli 		}
2559a73105b8SAntonio Quartulli 		rcu_read_unlock();
2560a73105b8SAntonio Quartulli 	}
2561a73105b8SAntonio Quartulli 
2562ced72933SAntonio Quartulli 	return crc;
2563a73105b8SAntonio Quartulli }
2564a73105b8SAntonio Quartulli 
25659c4604a2SSven Eckelmann /**
25667e9a8c2cSSven Eckelmann  * batadv_tt_req_node_release() - free tt_req node entry
25679c4604a2SSven Eckelmann  * @ref: kref pointer of the tt req_node entry
25689c4604a2SSven Eckelmann  */
batadv_tt_req_node_release(struct kref * ref)25699c4604a2SSven Eckelmann static void batadv_tt_req_node_release(struct kref *ref)
25709c4604a2SSven Eckelmann {
25719c4604a2SSven Eckelmann 	struct batadv_tt_req_node *tt_req_node;
25729c4604a2SSven Eckelmann 
25739c4604a2SSven Eckelmann 	tt_req_node = container_of(ref, struct batadv_tt_req_node, refcount);
25749c4604a2SSven Eckelmann 
257586452f81SSven Eckelmann 	kmem_cache_free(batadv_tt_req_cache, tt_req_node);
25769c4604a2SSven Eckelmann }
25779c4604a2SSven Eckelmann 
25789c4604a2SSven Eckelmann /**
25797e9a8c2cSSven Eckelmann  * batadv_tt_req_node_put() - decrement the tt_req_node refcounter and
25809c4604a2SSven Eckelmann  *  possibly release it
25819c4604a2SSven Eckelmann  * @tt_req_node: tt_req_node to be free'd
25829c4604a2SSven Eckelmann  */
batadv_tt_req_node_put(struct batadv_tt_req_node * tt_req_node)25839c4604a2SSven Eckelmann static void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node)
25849c4604a2SSven Eckelmann {
25856340dcbdSSven Eckelmann 	if (!tt_req_node)
25866340dcbdSSven Eckelmann 		return;
25876340dcbdSSven Eckelmann 
25889c4604a2SSven Eckelmann 	kref_put(&tt_req_node->refcount, batadv_tt_req_node_release);
25899c4604a2SSven Eckelmann }
25909c4604a2SSven Eckelmann 
batadv_tt_req_list_free(struct batadv_priv * bat_priv)259156303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
2592a73105b8SAntonio Quartulli {
25937c26a53bSMarek Lindner 	struct batadv_tt_req_node *node;
25947c26a53bSMarek Lindner 	struct hlist_node *safe;
2595a73105b8SAntonio Quartulli 
2596807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
2597a73105b8SAntonio Quartulli 
25987c26a53bSMarek Lindner 	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
25997c26a53bSMarek Lindner 		hlist_del_init(&node->list);
26009c4604a2SSven Eckelmann 		batadv_tt_req_node_put(node);
2601a73105b8SAntonio Quartulli 	}
2602a73105b8SAntonio Quartulli 
2603807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
2604a73105b8SAntonio Quartulli }
2605a73105b8SAntonio Quartulli 
batadv_tt_save_orig_buffer(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,const void * tt_buff,u16 tt_buff_len)260656303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv,
260756303d34SSven Eckelmann 				       struct batadv_orig_node *orig_node,
2608e8cf234aSAntonio Quartulli 				       const void *tt_buff,
26096b5e971aSSven Eckelmann 				       u16 tt_buff_len)
2610a73105b8SAntonio Quartulli {
2611a73105b8SAntonio Quartulli 	/* Replace the old buffer only if I received something in the
26129cfc7bd6SSven Eckelmann 	 * last OGM (the OGM could carry no changes)
26139cfc7bd6SSven Eckelmann 	 */
2614a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
2615a73105b8SAntonio Quartulli 	if (tt_buff_len > 0) {
2616a73105b8SAntonio Quartulli 		kfree(orig_node->tt_buff);
2617a73105b8SAntonio Quartulli 		orig_node->tt_buff_len = 0;
2618a73105b8SAntonio Quartulli 		orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
2619a73105b8SAntonio Quartulli 		if (orig_node->tt_buff) {
2620a73105b8SAntonio Quartulli 			memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
2621a73105b8SAntonio Quartulli 			orig_node->tt_buff_len = tt_buff_len;
2622a73105b8SAntonio Quartulli 		}
2623a73105b8SAntonio Quartulli 	}
2624a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
2625a73105b8SAntonio Quartulli }
2626a73105b8SAntonio Quartulli 
batadv_tt_req_purge(struct batadv_priv * bat_priv)262756303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv)
2628a73105b8SAntonio Quartulli {
26297c26a53bSMarek Lindner 	struct batadv_tt_req_node *node;
26307c26a53bSMarek Lindner 	struct hlist_node *safe;
2631a73105b8SAntonio Quartulli 
2632807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
26337c26a53bSMarek Lindner 	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
263442d0b044SSven Eckelmann 		if (batadv_has_timed_out(node->issued_at,
263542d0b044SSven Eckelmann 					 BATADV_TT_REQUEST_TIMEOUT)) {
26367c26a53bSMarek Lindner 			hlist_del_init(&node->list);
26379c4604a2SSven Eckelmann 			batadv_tt_req_node_put(node);
2638a73105b8SAntonio Quartulli 		}
2639a73105b8SAntonio Quartulli 	}
2640807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
2641a73105b8SAntonio Quartulli }
2642a73105b8SAntonio Quartulli 
2643383b8636SMarek Lindner /**
26447e9a8c2cSSven Eckelmann  * batadv_tt_req_node_new() - search and possibly create a tt_req_node object
2645383b8636SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2646383b8636SMarek Lindner  * @orig_node: orig node this request is being issued for
2647383b8636SMarek Lindner  *
264862fe710fSSven Eckelmann  * Return: the pointer to the new tt_req_node struct if no request
2649383b8636SMarek Lindner  * has already been issued for this orig_node, NULL otherwise.
26509cfc7bd6SSven Eckelmann  */
265156303d34SSven Eckelmann static struct batadv_tt_req_node *
batadv_tt_req_node_new(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node)2652383b8636SMarek Lindner batadv_tt_req_node_new(struct batadv_priv *bat_priv,
265356303d34SSven Eckelmann 		       struct batadv_orig_node *orig_node)
2654a73105b8SAntonio Quartulli {
265556303d34SSven Eckelmann 	struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
2656a73105b8SAntonio Quartulli 
2657807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
26587c26a53bSMarek Lindner 	hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) {
26591eda58bfSSven Eckelmann 		if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
26601eda58bfSSven Eckelmann 		    !batadv_has_timed_out(tt_req_node_tmp->issued_at,
266142d0b044SSven Eckelmann 					  BATADV_TT_REQUEST_TIMEOUT))
2662a73105b8SAntonio Quartulli 			goto unlock;
2663a73105b8SAntonio Quartulli 	}
2664a73105b8SAntonio Quartulli 
266586452f81SSven Eckelmann 	tt_req_node = kmem_cache_alloc(batadv_tt_req_cache, GFP_ATOMIC);
2666a73105b8SAntonio Quartulli 	if (!tt_req_node)
2667a73105b8SAntonio Quartulli 		goto unlock;
2668a73105b8SAntonio Quartulli 
26699c4604a2SSven Eckelmann 	kref_init(&tt_req_node->refcount);
26708fdd0153SAntonio Quartulli 	ether_addr_copy(tt_req_node->addr, orig_node->orig);
2671a73105b8SAntonio Quartulli 	tt_req_node->issued_at = jiffies;
2672a73105b8SAntonio Quartulli 
26739c4604a2SSven Eckelmann 	kref_get(&tt_req_node->refcount);
26747c26a53bSMarek Lindner 	hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list);
2675a73105b8SAntonio Quartulli unlock:
2676807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
2677a73105b8SAntonio Quartulli 	return tt_req_node;
2678a73105b8SAntonio Quartulli }
2679a73105b8SAntonio Quartulli 
2680335fbe0fSMarek Lindner /**
26817072337eSLinus Lüssing  * batadv_tt_local_valid() - verify local tt entry and get flags
2682335fbe0fSMarek Lindner  * @entry_ptr: to be checked local tt entry
2683335fbe0fSMarek Lindner  * @data_ptr: not used but definition required to satisfy the callback prototype
26847072337eSLinus Lüssing  * @flags: a pointer to store TT flags for this client to
26857072337eSLinus Lüssing  *
26867072337eSLinus Lüssing  * Checks the validity of the given local TT entry. If it is, then the provided
26877072337eSLinus Lüssing  * flags pointer is updated.
2688335fbe0fSMarek Lindner  *
26894b426b10SSven Eckelmann  * Return: true if the entry is a valid, false otherwise.
2690335fbe0fSMarek Lindner  */
batadv_tt_local_valid(const void * entry_ptr,const void * data_ptr,u8 * flags)26917072337eSLinus Lüssing static bool batadv_tt_local_valid(const void *entry_ptr,
26927072337eSLinus Lüssing 				  const void *data_ptr,
26937072337eSLinus Lüssing 				  u8 *flags)
2694058d0e26SAntonio Quartulli {
269556303d34SSven Eckelmann 	const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
2696058d0e26SAntonio Quartulli 
2697acd34afaSSven Eckelmann 	if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
26984b426b10SSven Eckelmann 		return false;
26997072337eSLinus Lüssing 
27007072337eSLinus Lüssing 	if (flags)
27017072337eSLinus Lüssing 		*flags = tt_common_entry->flags;
27027072337eSLinus Lüssing 
27034b426b10SSven Eckelmann 	return true;
2704058d0e26SAntonio Quartulli }
2705058d0e26SAntonio Quartulli 
27067072337eSLinus Lüssing /**
27077072337eSLinus Lüssing  * batadv_tt_global_valid() - verify global tt entry and get flags
27087072337eSLinus Lüssing  * @entry_ptr: to be checked global tt entry
27097072337eSLinus Lüssing  * @data_ptr: an orig_node object (may be NULL)
27107072337eSLinus Lüssing  * @flags: a pointer to store TT flags for this client to
27117072337eSLinus Lüssing  *
27127072337eSLinus Lüssing  * Checks the validity of the given global TT entry. If it is, then the provided
27137072337eSLinus Lüssing  * flags pointer is updated either with the common (summed) TT flags if data_ptr
27147072337eSLinus Lüssing  * is NULL or the specific, per originator TT flags otherwise.
27157072337eSLinus Lüssing  *
27167072337eSLinus Lüssing  * Return: true if the entry is a valid, false otherwise.
27177072337eSLinus Lüssing  */
batadv_tt_global_valid(const void * entry_ptr,const void * data_ptr,u8 * flags)27184b426b10SSven Eckelmann static bool batadv_tt_global_valid(const void *entry_ptr,
27197072337eSLinus Lüssing 				   const void *data_ptr,
27207072337eSLinus Lüssing 				   u8 *flags)
2721a73105b8SAntonio Quartulli {
272256303d34SSven Eckelmann 	const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
272356303d34SSven Eckelmann 	const struct batadv_tt_global_entry *tt_global_entry;
272456303d34SSven Eckelmann 	const struct batadv_orig_node *orig_node = data_ptr;
2725a73105b8SAntonio Quartulli 
272630cfd02bSAntonio Quartulli 	if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
272730cfd02bSAntonio Quartulli 	    tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
27284b426b10SSven Eckelmann 		return false;
2729cc47f66eSAntonio Quartulli 
273056303d34SSven Eckelmann 	tt_global_entry = container_of(tt_common_entry,
273156303d34SSven Eckelmann 				       struct batadv_tt_global_entry,
273248100bacSAntonio Quartulli 				       common);
273348100bacSAntonio Quartulli 
27347072337eSLinus Lüssing 	return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node,
27357072337eSLinus Lüssing 					       flags);
2736a73105b8SAntonio Quartulli }
2737a73105b8SAntonio Quartulli 
2738335fbe0fSMarek Lindner /**
27397e9a8c2cSSven Eckelmann  * batadv_tt_tvlv_generate() - fill the tvlv buff with the tt entries from the
27407ea7b4a1SAntonio Quartulli  *  specified tt hash
2741335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2742335fbe0fSMarek Lindner  * @hash: hash table containing the tt entries
2743335fbe0fSMarek Lindner  * @tt_len: expected tvlv tt data buffer length in number of bytes
27447ea7b4a1SAntonio Quartulli  * @tvlv_buff: pointer to the buffer to fill with the TT data
27457072337eSLinus Lüssing  * @valid_cb: function to filter tt change entries and to return TT flags
2746335fbe0fSMarek Lindner  * @cb_data: data passed to the filter function as argument
27477072337eSLinus Lüssing  *
27487072337eSLinus Lüssing  * Fills the tvlv buff with the tt entries from the specified hash. If valid_cb
27497072337eSLinus Lüssing  * is not provided then this becomes a no-op.
2750335fbe0fSMarek Lindner  */
batadv_tt_tvlv_generate(struct batadv_priv * bat_priv,struct batadv_hashtable * hash,void * tvlv_buff,u16 tt_len,bool (* valid_cb)(const void *,const void *,u8 * flags),void * cb_data)27517ea7b4a1SAntonio Quartulli static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
27527ea7b4a1SAntonio Quartulli 				    struct batadv_hashtable *hash,
27536b5e971aSSven Eckelmann 				    void *tvlv_buff, u16 tt_len,
27544b426b10SSven Eckelmann 				    bool (*valid_cb)(const void *,
27557072337eSLinus Lüssing 						     const void *,
27567072337eSLinus Lüssing 						     u8 *flags),
2757a73105b8SAntonio Quartulli 				    void *cb_data)
2758a73105b8SAntonio Quartulli {
275956303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common_entry;
2760335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
2761a73105b8SAntonio Quartulli 	struct hlist_head *head;
27626b5e971aSSven Eckelmann 	u16 tt_tot, tt_num_entries = 0;
27637072337eSLinus Lüssing 	u8 flags;
27647072337eSLinus Lüssing 	bool ret;
27656b5e971aSSven Eckelmann 	u32 i;
2766a73105b8SAntonio Quartulli 
2767298e6e68SAntonio Quartulli 	tt_tot = batadv_tt_entries(tt_len);
27688864d2fcSYu Zhe 	tt_change = tvlv_buff;
2769a73105b8SAntonio Quartulli 
27707072337eSLinus Lüssing 	if (!valid_cb)
27717072337eSLinus Lüssing 		return;
27727072337eSLinus Lüssing 
2773a73105b8SAntonio Quartulli 	rcu_read_lock();
2774a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2775a73105b8SAntonio Quartulli 		head = &hash->table[i];
2776a73105b8SAntonio Quartulli 
2777b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
2778a73105b8SAntonio Quartulli 					 head, hash_entry) {
2779335fbe0fSMarek Lindner 			if (tt_tot == tt_num_entries)
2780a73105b8SAntonio Quartulli 				break;
2781a73105b8SAntonio Quartulli 
27827072337eSLinus Lüssing 			ret = valid_cb(tt_common_entry, cb_data, &flags);
27837072337eSLinus Lüssing 			if (!ret)
2784a73105b8SAntonio Quartulli 				continue;
2785a73105b8SAntonio Quartulli 
27868fdd0153SAntonio Quartulli 			ether_addr_copy(tt_change->addr, tt_common_entry->addr);
27877072337eSLinus Lüssing 			tt_change->flags = flags;
2788c018ad3dSAntonio Quartulli 			tt_change->vid = htons(tt_common_entry->vid);
2789ca663046SAntonio Quartulli 			memset(tt_change->reserved, 0,
2790ca663046SAntonio Quartulli 			       sizeof(tt_change->reserved));
2791a73105b8SAntonio Quartulli 
2792335fbe0fSMarek Lindner 			tt_num_entries++;
2793a73105b8SAntonio Quartulli 			tt_change++;
2794a73105b8SAntonio Quartulli 		}
2795a73105b8SAntonio Quartulli 	}
2796a73105b8SAntonio Quartulli 	rcu_read_unlock();
27977ea7b4a1SAntonio Quartulli }
2798a73105b8SAntonio Quartulli 
27997ea7b4a1SAntonio Quartulli /**
28007e9a8c2cSSven Eckelmann  * batadv_tt_global_check_crc() - check if all the CRCs are correct
28017ea7b4a1SAntonio Quartulli  * @orig_node: originator for which the CRCs have to be checked
28027ea7b4a1SAntonio Quartulli  * @tt_vlan: pointer to the first tvlv VLAN entry
28037ea7b4a1SAntonio Quartulli  * @num_vlan: number of tvlv VLAN entries
28047ea7b4a1SAntonio Quartulli  *
280562fe710fSSven Eckelmann  * Return: true if all the received CRCs match the locally stored ones, false
28067ea7b4a1SAntonio Quartulli  * otherwise
28077ea7b4a1SAntonio Quartulli  */
batadv_tt_global_check_crc(struct batadv_orig_node * orig_node,struct batadv_tvlv_tt_vlan_data * tt_vlan,u16 num_vlan)28087ea7b4a1SAntonio Quartulli static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
28097ea7b4a1SAntonio Quartulli 				       struct batadv_tvlv_tt_vlan_data *tt_vlan,
28106b5e971aSSven Eckelmann 				       u16 num_vlan)
28117ea7b4a1SAntonio Quartulli {
28127ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
28137ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
2814c169c59dSSimon Wunderlich 	int i, orig_num_vlan;
28156b5e971aSSven Eckelmann 	u32 crc;
28167ea7b4a1SAntonio Quartulli 
28177ea7b4a1SAntonio Quartulli 	/* check if each received CRC matches the locally stored one */
28187ea7b4a1SAntonio Quartulli 	for (i = 0; i < num_vlan; i++) {
28197ea7b4a1SAntonio Quartulli 		tt_vlan_tmp = tt_vlan + i;
28207ea7b4a1SAntonio Quartulli 
28217ea7b4a1SAntonio Quartulli 		/* if orig_node is a backbone node for this VLAN, don't check
28227ea7b4a1SAntonio Quartulli 		 * the CRC as we ignore all the global entries over it
28237ea7b4a1SAntonio Quartulli 		 */
28247ea7b4a1SAntonio Quartulli 		if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv,
2825cfd4f757SAntonio Quartulli 						   orig_node->orig,
2826cfd4f757SAntonio Quartulli 						   ntohs(tt_vlan_tmp->vid)))
28277ea7b4a1SAntonio Quartulli 			continue;
28287ea7b4a1SAntonio Quartulli 
28297ea7b4a1SAntonio Quartulli 		vlan = batadv_orig_node_vlan_get(orig_node,
28307ea7b4a1SAntonio Quartulli 						 ntohs(tt_vlan_tmp->vid));
28317ea7b4a1SAntonio Quartulli 		if (!vlan)
28327ea7b4a1SAntonio Quartulli 			return false;
28337ea7b4a1SAntonio Quartulli 
283491c2b1a9SAntonio Quartulli 		crc = vlan->tt.crc;
283521754e25SSven Eckelmann 		batadv_orig_node_vlan_put(vlan);
283691c2b1a9SAntonio Quartulli 
283791c2b1a9SAntonio Quartulli 		if (crc != ntohl(tt_vlan_tmp->crc))
28387ea7b4a1SAntonio Quartulli 			return false;
28397ea7b4a1SAntonio Quartulli 	}
28407ea7b4a1SAntonio Quartulli 
2841c169c59dSSimon Wunderlich 	/* check if any excess VLANs exist locally for the originator
2842c169c59dSSimon Wunderlich 	 * which are not mentioned in the TVLV from the originator.
2843c169c59dSSimon Wunderlich 	 */
2844c169c59dSSimon Wunderlich 	rcu_read_lock();
2845c169c59dSSimon Wunderlich 	orig_num_vlan = 0;
2846c169c59dSSimon Wunderlich 	hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list)
2847c169c59dSSimon Wunderlich 		orig_num_vlan++;
2848c169c59dSSimon Wunderlich 	rcu_read_unlock();
2849c169c59dSSimon Wunderlich 
2850c169c59dSSimon Wunderlich 	if (orig_num_vlan > num_vlan)
2851c169c59dSSimon Wunderlich 		return false;
2852c169c59dSSimon Wunderlich 
28537ea7b4a1SAntonio Quartulli 	return true;
28547ea7b4a1SAntonio Quartulli }
28557ea7b4a1SAntonio Quartulli 
28567ea7b4a1SAntonio Quartulli /**
28577e9a8c2cSSven Eckelmann  * batadv_tt_local_update_crc() - update all the local CRCs
28587ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
28597ea7b4a1SAntonio Quartulli  */
batadv_tt_local_update_crc(struct batadv_priv * bat_priv)28607ea7b4a1SAntonio Quartulli static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv)
28617ea7b4a1SAntonio Quartulli {
28627ea7b4a1SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
28637ea7b4a1SAntonio Quartulli 
28647ea7b4a1SAntonio Quartulli 	/* recompute the global CRC for each VLAN */
28657ea7b4a1SAntonio Quartulli 	rcu_read_lock();
28667ea7b4a1SAntonio Quartulli 	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
28677ea7b4a1SAntonio Quartulli 		vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid);
28687ea7b4a1SAntonio Quartulli 	}
28697ea7b4a1SAntonio Quartulli 	rcu_read_unlock();
28707ea7b4a1SAntonio Quartulli }
28717ea7b4a1SAntonio Quartulli 
28727ea7b4a1SAntonio Quartulli /**
28737e9a8c2cSSven Eckelmann  * batadv_tt_global_update_crc() - update all the global CRCs for this orig_node
28747ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
28757ea7b4a1SAntonio Quartulli  * @orig_node: the orig_node for which the CRCs have to be updated
28767ea7b4a1SAntonio Quartulli  */
batadv_tt_global_update_crc(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node)28777ea7b4a1SAntonio Quartulli static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
28787ea7b4a1SAntonio Quartulli 					struct batadv_orig_node *orig_node)
28797ea7b4a1SAntonio Quartulli {
28807ea7b4a1SAntonio Quartulli 	struct batadv_orig_node_vlan *vlan;
28816b5e971aSSven Eckelmann 	u32 crc;
28827ea7b4a1SAntonio Quartulli 
28837ea7b4a1SAntonio Quartulli 	/* recompute the global CRC for each VLAN */
28847ea7b4a1SAntonio Quartulli 	rcu_read_lock();
2885d0fa4f3fSMarek Lindner 	hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
28867ea7b4a1SAntonio Quartulli 		/* if orig_node is a backbone node for this VLAN, don't compute
28877ea7b4a1SAntonio Quartulli 		 * the CRC as we ignore all the global entries over it
28887ea7b4a1SAntonio Quartulli 		 */
2889cfd4f757SAntonio Quartulli 		if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig,
2890cfd4f757SAntonio Quartulli 						   vlan->vid))
28917ea7b4a1SAntonio Quartulli 			continue;
28927ea7b4a1SAntonio Quartulli 
28937ea7b4a1SAntonio Quartulli 		crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid);
28947ea7b4a1SAntonio Quartulli 		vlan->tt.crc = crc;
28957ea7b4a1SAntonio Quartulli 	}
28967ea7b4a1SAntonio Quartulli 	rcu_read_unlock();
2897a73105b8SAntonio Quartulli }
2898a73105b8SAntonio Quartulli 
2899ced72933SAntonio Quartulli /**
29007e9a8c2cSSven Eckelmann  * batadv_send_tt_request() - send a TT Request message to a given node
2901ced72933SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
2902ced72933SAntonio Quartulli  * @dst_orig_node: the destination of the message
2903ced72933SAntonio Quartulli  * @ttvn: the version number that the source of the message is looking for
29047ea7b4a1SAntonio Quartulli  * @tt_vlan: pointer to the first tvlv VLAN object to request
29057ea7b4a1SAntonio Quartulli  * @num_vlan: number of tvlv VLAN entries
2906ced72933SAntonio Quartulli  * @full_table: ask for the entire translation table if true, while only for the
2907ced72933SAntonio Quartulli  *  last TT diff otherwise
2908d15cd622SAntonio Quartulli  *
2909d15cd622SAntonio Quartulli  * Return: true if the TT Request was sent, false otherwise
2910ced72933SAntonio Quartulli  */
batadv_send_tt_request(struct batadv_priv * bat_priv,struct batadv_orig_node * dst_orig_node,u8 ttvn,struct batadv_tvlv_tt_vlan_data * tt_vlan,u16 num_vlan,bool full_table)29114b426b10SSven Eckelmann static bool batadv_send_tt_request(struct batadv_priv *bat_priv,
291256303d34SSven Eckelmann 				   struct batadv_orig_node *dst_orig_node,
29136b5e971aSSven Eckelmann 				   u8 ttvn,
29147ea7b4a1SAntonio Quartulli 				   struct batadv_tvlv_tt_vlan_data *tt_vlan,
29156b5e971aSSven Eckelmann 				   u16 num_vlan, bool full_table)
2916a73105b8SAntonio Quartulli {
2917335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
291856303d34SSven Eckelmann 	struct batadv_tt_req_node *tt_req_node = NULL;
29197ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan_req;
29207ea7b4a1SAntonio Quartulli 	struct batadv_hard_iface *primary_if;
2921335fbe0fSMarek Lindner 	bool ret = false;
29227ea7b4a1SAntonio Quartulli 	int i, size;
2923a73105b8SAntonio Quartulli 
2924e5d89254SSven Eckelmann 	primary_if = batadv_primary_if_get_selected(bat_priv);
2925a73105b8SAntonio Quartulli 	if (!primary_if)
2926a73105b8SAntonio Quartulli 		goto out;
2927a73105b8SAntonio Quartulli 
2928a73105b8SAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
29299cfc7bd6SSven Eckelmann 	 * reply from the same orig_node yet
29309cfc7bd6SSven Eckelmann 	 */
2931383b8636SMarek Lindner 	tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node);
2932a73105b8SAntonio Quartulli 	if (!tt_req_node)
2933a73105b8SAntonio Quartulli 		goto out;
2934a73105b8SAntonio Quartulli 
29357ea7b4a1SAntonio Quartulli 	size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan;
29367ea7b4a1SAntonio Quartulli 	tvlv_tt_data = kzalloc(size, GFP_ATOMIC);
2937335fbe0fSMarek Lindner 	if (!tvlv_tt_data)
2938a73105b8SAntonio Quartulli 		goto out;
2939a73105b8SAntonio Quartulli 
2940335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_REQUEST;
2941335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = ttvn;
29427ea7b4a1SAntonio Quartulli 	tvlv_tt_data->num_vlan = htons(num_vlan);
29437ea7b4a1SAntonio Quartulli 
29447ea7b4a1SAntonio Quartulli 	/* send all the CRCs within the request. This is needed by intermediate
29457ea7b4a1SAntonio Quartulli 	 * nodes to ensure they have the correct table before replying
29467ea7b4a1SAntonio Quartulli 	 */
29477ea7b4a1SAntonio Quartulli 	tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1);
29487ea7b4a1SAntonio Quartulli 	for (i = 0; i < num_vlan; i++) {
29497ea7b4a1SAntonio Quartulli 		tt_vlan_req->vid = tt_vlan->vid;
29507ea7b4a1SAntonio Quartulli 		tt_vlan_req->crc = tt_vlan->crc;
29517ea7b4a1SAntonio Quartulli 
29527ea7b4a1SAntonio Quartulli 		tt_vlan_req++;
29537ea7b4a1SAntonio Quartulli 		tt_vlan++;
29547ea7b4a1SAntonio Quartulli 	}
2955a73105b8SAntonio Quartulli 
2956a73105b8SAntonio Quartulli 	if (full_table)
2957335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
2958a73105b8SAntonio Quartulli 
2959bb351ba0SMartin Hundebøll 	batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n",
2960335fbe0fSMarek Lindner 		   dst_orig_node->orig, full_table ? 'F' : '.');
2961a73105b8SAntonio Quartulli 
2962d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX);
2963335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
2964335fbe0fSMarek Lindner 				 dst_orig_node->orig, BATADV_TVLV_TT, 1,
29657ea7b4a1SAntonio Quartulli 				 tvlv_tt_data, size);
2966335fbe0fSMarek Lindner 	ret = true;
2967a73105b8SAntonio Quartulli 
2968a73105b8SAntonio Quartulli out:
296982047ad7SSven Eckelmann 	batadv_hardif_put(primary_if);
29709c4604a2SSven Eckelmann 
2971a73105b8SAntonio Quartulli 	if (ret && tt_req_node) {
2972807736f6SSven Eckelmann 		spin_lock_bh(&bat_priv->tt.req_list_lock);
29739c4604a2SSven Eckelmann 		if (!hlist_unhashed(&tt_req_node->list)) {
29747c26a53bSMarek Lindner 			hlist_del_init(&tt_req_node->list);
29759c4604a2SSven Eckelmann 			batadv_tt_req_node_put(tt_req_node);
2976a73105b8SAntonio Quartulli 		}
29779c4604a2SSven Eckelmann 		spin_unlock_bh(&bat_priv->tt.req_list_lock);
29789c4604a2SSven Eckelmann 	}
29799c4604a2SSven Eckelmann 
29809c4604a2SSven Eckelmann 	batadv_tt_req_node_put(tt_req_node);
29819c4604a2SSven Eckelmann 
2982335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
2983a73105b8SAntonio Quartulli 	return ret;
2984a73105b8SAntonio Quartulli }
2985a73105b8SAntonio Quartulli 
2986335fbe0fSMarek Lindner /**
29877e9a8c2cSSven Eckelmann  * batadv_send_other_tt_response() - send reply to tt request concerning another
2988335fbe0fSMarek Lindner  *  node's translation table
2989335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
2990335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
2991335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
2992335fbe0fSMarek Lindner  * @req_dst: mac address of tt request recipient
2993335fbe0fSMarek Lindner  *
299462fe710fSSven Eckelmann  * Return: true if tt request reply was sent, false otherwise.
2995335fbe0fSMarek Lindner  */
batadv_send_other_tt_response(struct batadv_priv * bat_priv,struct batadv_tvlv_tt_data * tt_data,u8 * req_src,u8 * req_dst)2996335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
2997335fbe0fSMarek Lindner 					  struct batadv_tvlv_tt_data *tt_data,
29986b5e971aSSven Eckelmann 					  u8 *req_src, u8 *req_dst)
2999a73105b8SAntonio Quartulli {
3000170173bfSSven Eckelmann 	struct batadv_orig_node *req_dst_orig_node;
300156303d34SSven Eckelmann 	struct batadv_orig_node *res_dst_orig_node = NULL;
30027ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_change *tt_change;
3003335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
30047ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
3005335fbe0fSMarek Lindner 	bool ret = false, full_table;
30066b5e971aSSven Eckelmann 	u8 orig_ttvn, req_ttvn;
30076b5e971aSSven Eckelmann 	u16 tvlv_len;
30086b5e971aSSven Eckelmann 	s32 tt_len;
3009a73105b8SAntonio Quartulli 
301039c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
301186ceb360SSven Eckelmann 		   "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
3012335fbe0fSMarek Lindner 		   req_src, tt_data->ttvn, req_dst,
3013a2f2b6cdSSven Eckelmann 		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
3014a73105b8SAntonio Quartulli 
3015a73105b8SAntonio Quartulli 	/* Let's get the orig node of the REAL destination */
3016335fbe0fSMarek Lindner 	req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst);
3017a73105b8SAntonio Quartulli 	if (!req_dst_orig_node)
3018a73105b8SAntonio Quartulli 		goto out;
3019a73105b8SAntonio Quartulli 
3020335fbe0fSMarek Lindner 	res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src);
3021a73105b8SAntonio Quartulli 	if (!res_dst_orig_node)
3022a73105b8SAntonio Quartulli 		goto out;
3023a73105b8SAntonio Quartulli 
30246b5e971aSSven Eckelmann 	orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn);
3025335fbe0fSMarek Lindner 	req_ttvn = tt_data->ttvn;
3026a73105b8SAntonio Quartulli 
30277ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
3028335fbe0fSMarek Lindner 	/* this node doesn't have the requested data */
3029a73105b8SAntonio Quartulli 	if (orig_ttvn != req_ttvn ||
30307ea7b4a1SAntonio Quartulli 	    !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan,
30317ea7b4a1SAntonio Quartulli 					ntohs(tt_data->num_vlan)))
3032a73105b8SAntonio Quartulli 		goto out;
3033a73105b8SAntonio Quartulli 
3034015758d0SAntonio Quartulli 	/* If the full table has been explicitly requested */
3035335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE ||
3036a73105b8SAntonio Quartulli 	    !req_dst_orig_node->tt_buff)
3037a73105b8SAntonio Quartulli 		full_table = true;
3038a73105b8SAntonio Quartulli 	else
3039a73105b8SAntonio Quartulli 		full_table = false;
3040a73105b8SAntonio Quartulli 
3041335fbe0fSMarek Lindner 	/* TT fragmentation hasn't been implemented yet, so send as many
3042335fbe0fSMarek Lindner 	 * TT entries fit a single packet as possible only
30439cfc7bd6SSven Eckelmann 	 */
3044a73105b8SAntonio Quartulli 	if (!full_table) {
3045a73105b8SAntonio Quartulli 		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
3046a73105b8SAntonio Quartulli 		tt_len = req_dst_orig_node->tt_buff_len;
3047a73105b8SAntonio Quartulli 
30487ea7b4a1SAntonio Quartulli 		tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
30497ea7b4a1SAntonio Quartulli 							      &tvlv_tt_data,
30507ea7b4a1SAntonio Quartulli 							      &tt_change,
30517ea7b4a1SAntonio Quartulli 							      &tt_len);
30527ea7b4a1SAntonio Quartulli 		if (!tt_len)
3053a73105b8SAntonio Quartulli 			goto unlock;
3054a73105b8SAntonio Quartulli 
3055a73105b8SAntonio Quartulli 		/* Copy the last orig_node's OGM buffer */
30567ea7b4a1SAntonio Quartulli 		memcpy(tt_change, req_dst_orig_node->tt_buff,
3057a73105b8SAntonio Quartulli 		       req_dst_orig_node->tt_buff_len);
3058a73105b8SAntonio Quartulli 		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
3059a73105b8SAntonio Quartulli 	} else {
30607ea7b4a1SAntonio Quartulli 		/* allocate the tvlv, put the tt_data and all the tt_vlan_data
30617ea7b4a1SAntonio Quartulli 		 * in the initial part
30627ea7b4a1SAntonio Quartulli 		 */
30637ea7b4a1SAntonio Quartulli 		tt_len = -1;
30647ea7b4a1SAntonio Quartulli 		tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
30657ea7b4a1SAntonio Quartulli 							      &tvlv_tt_data,
30667ea7b4a1SAntonio Quartulli 							      &tt_change,
30677ea7b4a1SAntonio Quartulli 							      &tt_len);
30687ea7b4a1SAntonio Quartulli 		if (!tt_len)
30697ea7b4a1SAntonio Quartulli 			goto out;
3070a73105b8SAntonio Quartulli 
30717ea7b4a1SAntonio Quartulli 		/* fill the rest of the tvlv with the real TT entries */
30727ea7b4a1SAntonio Quartulli 		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash,
30737ea7b4a1SAntonio Quartulli 					tt_change, tt_len,
3074a513088dSSven Eckelmann 					batadv_tt_global_valid,
3075a73105b8SAntonio Quartulli 					req_dst_orig_node);
3076a73105b8SAntonio Quartulli 	}
3077a73105b8SAntonio Quartulli 
3078a19d3d85SMarek Lindner 	/* Don't send the response, if larger than fragmented packet. */
3079a19d3d85SMarek Lindner 	tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
3080a19d3d85SMarek Lindner 	if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
3081a19d3d85SMarek Lindner 		net_ratelimited_function(batadv_info, bat_priv->soft_iface,
3082a19d3d85SMarek Lindner 					 "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
3083a19d3d85SMarek Lindner 					 res_dst_orig_node->orig);
3084a19d3d85SMarek Lindner 		goto out;
3085a19d3d85SMarek Lindner 	}
3086a19d3d85SMarek Lindner 
3087335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
3088335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = req_ttvn;
3089a73105b8SAntonio Quartulli 
3090a73105b8SAntonio Quartulli 	if (full_table)
3091335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
3092a73105b8SAntonio Quartulli 
309339c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
3094335fbe0fSMarek Lindner 		   "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n",
3095335fbe0fSMarek Lindner 		   res_dst_orig_node->orig, req_dst_orig_node->orig,
3096335fbe0fSMarek Lindner 		   full_table ? 'F' : '.', req_ttvn);
3097a73105b8SAntonio Quartulli 
3098d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
3099f8214865SMartin Hundebøll 
3100335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig,
31017ea7b4a1SAntonio Quartulli 				 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
31027ea7b4a1SAntonio Quartulli 				 tvlv_len);
3103e91ecfc6SMartin Hundebøll 
3104335fbe0fSMarek Lindner 	ret = true;
3105a73105b8SAntonio Quartulli 	goto out;
3106a73105b8SAntonio Quartulli 
3107a73105b8SAntonio Quartulli unlock:
3108a73105b8SAntonio Quartulli 	spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
3109a73105b8SAntonio Quartulli 
3110a73105b8SAntonio Quartulli out:
31115d967310SSven Eckelmann 	batadv_orig_node_put(res_dst_orig_node);
31125d967310SSven Eckelmann 	batadv_orig_node_put(req_dst_orig_node);
3113335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
3114a73105b8SAntonio Quartulli 	return ret;
3115a73105b8SAntonio Quartulli }
311696412690SSven Eckelmann 
3117335fbe0fSMarek Lindner /**
31187e9a8c2cSSven Eckelmann  * batadv_send_my_tt_response() - send reply to tt request concerning this
31197e9a8c2cSSven Eckelmann  *  node's translation table
3120335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3121335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
3122335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
3123335fbe0fSMarek Lindner  *
312462fe710fSSven Eckelmann  * Return: true if tt request reply was sent, false otherwise.
3125335fbe0fSMarek Lindner  */
batadv_send_my_tt_response(struct batadv_priv * bat_priv,struct batadv_tvlv_tt_data * tt_data,u8 * req_src)3126335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
3127335fbe0fSMarek Lindner 				       struct batadv_tvlv_tt_data *tt_data,
31286b5e971aSSven Eckelmann 				       u8 *req_src)
3129a73105b8SAntonio Quartulli {
3130335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
313156303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if = NULL;
31327ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_change *tt_change;
31337ea7b4a1SAntonio Quartulli 	struct batadv_orig_node *orig_node;
31346b5e971aSSven Eckelmann 	u8 my_ttvn, req_ttvn;
31356b5e971aSSven Eckelmann 	u16 tvlv_len;
3136a73105b8SAntonio Quartulli 	bool full_table;
31376b5e971aSSven Eckelmann 	s32 tt_len;
3138a73105b8SAntonio Quartulli 
313939c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
314086ceb360SSven Eckelmann 		   "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
3141335fbe0fSMarek Lindner 		   req_src, tt_data->ttvn,
3142a2f2b6cdSSven Eckelmann 		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
3143a73105b8SAntonio Quartulli 
3144a70a9aa9SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt.commit_lock);
3145a73105b8SAntonio Quartulli 
31466b5e971aSSven Eckelmann 	my_ttvn = (u8)atomic_read(&bat_priv->tt.vn);
3147335fbe0fSMarek Lindner 	req_ttvn = tt_data->ttvn;
3148a73105b8SAntonio Quartulli 
3149335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, req_src);
3150a73105b8SAntonio Quartulli 	if (!orig_node)
3151a73105b8SAntonio Quartulli 		goto out;
3152a73105b8SAntonio Quartulli 
3153e5d89254SSven Eckelmann 	primary_if = batadv_primary_if_get_selected(bat_priv);
3154a73105b8SAntonio Quartulli 	if (!primary_if)
3155a73105b8SAntonio Quartulli 		goto out;
3156a73105b8SAntonio Quartulli 
3157a73105b8SAntonio Quartulli 	/* If the full table has been explicitly requested or the gap
31589cfc7bd6SSven Eckelmann 	 * is too big send the whole local translation table
31599cfc7bd6SSven Eckelmann 	 */
3160335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn ||
3161807736f6SSven Eckelmann 	    !bat_priv->tt.last_changeset)
3162a73105b8SAntonio Quartulli 		full_table = true;
3163a73105b8SAntonio Quartulli 	else
3164a73105b8SAntonio Quartulli 		full_table = false;
3165a73105b8SAntonio Quartulli 
3166335fbe0fSMarek Lindner 	/* TT fragmentation hasn't been implemented yet, so send as many
3167335fbe0fSMarek Lindner 	 * TT entries fit a single packet as possible only
31689cfc7bd6SSven Eckelmann 	 */
3169a73105b8SAntonio Quartulli 	if (!full_table) {
3170807736f6SSven Eckelmann 		spin_lock_bh(&bat_priv->tt.last_changeset_lock);
3171a73105b8SAntonio Quartulli 
31727ea7b4a1SAntonio Quartulli 		tt_len = bat_priv->tt.last_changeset_len;
31737ea7b4a1SAntonio Quartulli 		tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
31747ea7b4a1SAntonio Quartulli 							     &tvlv_tt_data,
31757ea7b4a1SAntonio Quartulli 							     &tt_change,
31767ea7b4a1SAntonio Quartulli 							     &tt_len);
3177c2d0f48aSSven Eckelmann 		if (!tt_len || !tvlv_len)
3178a73105b8SAntonio Quartulli 			goto unlock;
3179a73105b8SAntonio Quartulli 
3180335fbe0fSMarek Lindner 		/* Copy the last orig_node's OGM buffer */
31817ea7b4a1SAntonio Quartulli 		memcpy(tt_change, bat_priv->tt.last_changeset,
3182807736f6SSven Eckelmann 		       bat_priv->tt.last_changeset_len);
3183807736f6SSven Eckelmann 		spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
3184a73105b8SAntonio Quartulli 	} else {
31856b5e971aSSven Eckelmann 		req_ttvn = (u8)atomic_read(&bat_priv->tt.vn);
3186a73105b8SAntonio Quartulli 
31877ea7b4a1SAntonio Quartulli 		/* allocate the tvlv, put the tt_data and all the tt_vlan_data
31887ea7b4a1SAntonio Quartulli 		 * in the initial part
31897ea7b4a1SAntonio Quartulli 		 */
31907ea7b4a1SAntonio Quartulli 		tt_len = -1;
31917ea7b4a1SAntonio Quartulli 		tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
31927ea7b4a1SAntonio Quartulli 							     &tvlv_tt_data,
31937ea7b4a1SAntonio Quartulli 							     &tt_change,
31947ea7b4a1SAntonio Quartulli 							     &tt_len);
3195c2d0f48aSSven Eckelmann 		if (!tt_len || !tvlv_len)
3196a73105b8SAntonio Quartulli 			goto out;
31977ea7b4a1SAntonio Quartulli 
31987ea7b4a1SAntonio Quartulli 		/* fill the rest of the tvlv with the real TT entries */
31997ea7b4a1SAntonio Quartulli 		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash,
32007ea7b4a1SAntonio Quartulli 					tt_change, tt_len,
32017ea7b4a1SAntonio Quartulli 					batadv_tt_local_valid, NULL);
3202a73105b8SAntonio Quartulli 	}
3203a73105b8SAntonio Quartulli 
3204335fbe0fSMarek Lindner 	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
3205335fbe0fSMarek Lindner 	tvlv_tt_data->ttvn = req_ttvn;
3206a73105b8SAntonio Quartulli 
3207a73105b8SAntonio Quartulli 	if (full_table)
3208335fbe0fSMarek Lindner 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
3209a73105b8SAntonio Quartulli 
321039c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
3211335fbe0fSMarek Lindner 		   "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n",
3212335fbe0fSMarek Lindner 		   orig_node->orig, full_table ? 'F' : '.', req_ttvn);
3213a73105b8SAntonio Quartulli 
3214d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
3215f8214865SMartin Hundebøll 
3216335fbe0fSMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
32177ea7b4a1SAntonio Quartulli 				 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
32187ea7b4a1SAntonio Quartulli 				 tvlv_len);
3219335fbe0fSMarek Lindner 
3220a73105b8SAntonio Quartulli 	goto out;
3221a73105b8SAntonio Quartulli 
3222a73105b8SAntonio Quartulli unlock:
3223807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
3224a73105b8SAntonio Quartulli out:
3225a70a9aa9SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt.commit_lock);
32265d967310SSven Eckelmann 	batadv_orig_node_put(orig_node);
322782047ad7SSven Eckelmann 	batadv_hardif_put(primary_if);
3228335fbe0fSMarek Lindner 	kfree(tvlv_tt_data);
3229335fbe0fSMarek Lindner 	/* The packet was for this host, so it doesn't need to be re-routed */
3230a73105b8SAntonio Quartulli 	return true;
3231a73105b8SAntonio Quartulli }
3232a73105b8SAntonio Quartulli 
3233335fbe0fSMarek Lindner /**
32347e9a8c2cSSven Eckelmann  * batadv_send_tt_response() - send reply to tt request
3235335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3236335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
3237335fbe0fSMarek Lindner  * @req_src: mac address of tt request sender
3238335fbe0fSMarek Lindner  * @req_dst: mac address of tt request recipient
3239335fbe0fSMarek Lindner  *
324062fe710fSSven Eckelmann  * Return: true if tt request reply was sent, false otherwise.
3241335fbe0fSMarek Lindner  */
batadv_send_tt_response(struct batadv_priv * bat_priv,struct batadv_tvlv_tt_data * tt_data,u8 * req_src,u8 * req_dst)3242335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv,
3243335fbe0fSMarek Lindner 				    struct batadv_tvlv_tt_data *tt_data,
32446b5e971aSSven Eckelmann 				    u8 *req_src, u8 *req_dst)
3245a73105b8SAntonio Quartulli {
3246cfd4f757SAntonio Quartulli 	if (batadv_is_my_mac(bat_priv, req_dst))
3247335fbe0fSMarek Lindner 		return batadv_send_my_tt_response(bat_priv, tt_data, req_src);
324824820df1SAntonio Quartulli 	return batadv_send_other_tt_response(bat_priv, tt_data, req_src,
324924820df1SAntonio Quartulli 					     req_dst);
3250a73105b8SAntonio Quartulli }
3251a73105b8SAntonio Quartulli 
_batadv_tt_update_changes(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,struct batadv_tvlv_tt_change * tt_change,u16 tt_num_changes,u8 ttvn)325256303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
325356303d34SSven Eckelmann 				      struct batadv_orig_node *orig_node,
3254335fbe0fSMarek Lindner 				      struct batadv_tvlv_tt_change *tt_change,
32556b5e971aSSven Eckelmann 				      u16 tt_num_changes, u8 ttvn)
3256a73105b8SAntonio Quartulli {
3257a73105b8SAntonio Quartulli 	int i;
3258a513088dSSven Eckelmann 	int roams;
3259a73105b8SAntonio Quartulli 
3260a73105b8SAntonio Quartulli 	for (i = 0; i < tt_num_changes; i++) {
3261acd34afaSSven Eckelmann 		if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
3262acd34afaSSven Eckelmann 			roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
3263a513088dSSven Eckelmann 			batadv_tt_global_del(bat_priv, orig_node,
3264a73105b8SAntonio Quartulli 					     (tt_change + i)->addr,
3265c018ad3dSAntonio Quartulli 					     ntohs((tt_change + i)->vid),
3266cc47f66eSAntonio Quartulli 					     "tt removed by changes",
3267a513088dSSven Eckelmann 					     roams);
326808c36d3eSSven Eckelmann 		} else {
326908c36d3eSSven Eckelmann 			if (!batadv_tt_global_add(bat_priv, orig_node,
3270d4f44692SAntonio Quartulli 						  (tt_change + i)->addr,
3271c018ad3dSAntonio Quartulli 						  ntohs((tt_change + i)->vid),
3272d4f44692SAntonio Quartulli 						  (tt_change + i)->flags, ttvn))
3273a73105b8SAntonio Quartulli 				/* In case of problem while storing a
3274a73105b8SAntonio Quartulli 				 * global_entry, we stop the updating
3275a73105b8SAntonio Quartulli 				 * procedure without committing the
3276a73105b8SAntonio Quartulli 				 * ttvn change. This will avoid to send
3277a73105b8SAntonio Quartulli 				 * corrupted data on tt_request
3278a73105b8SAntonio Quartulli 				 */
3279a73105b8SAntonio Quartulli 				return;
3280a73105b8SAntonio Quartulli 		}
328108c36d3eSSven Eckelmann 	}
3282ac4eebd4SLinus Lüssing 	set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
3283a73105b8SAntonio Quartulli }
3284a73105b8SAntonio Quartulli 
batadv_tt_fill_gtable(struct batadv_priv * bat_priv,struct batadv_tvlv_tt_change * tt_change,u8 ttvn,u8 * resp_src,u16 num_entries)328556303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
32867ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_change *tt_change,
32876b5e971aSSven Eckelmann 				  u8 ttvn, u8 *resp_src,
32886b5e971aSSven Eckelmann 				  u16 num_entries)
3289a73105b8SAntonio Quartulli {
3290170173bfSSven Eckelmann 	struct batadv_orig_node *orig_node;
3291a73105b8SAntonio Quartulli 
3292335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
3293a73105b8SAntonio Quartulli 	if (!orig_node)
3294a73105b8SAntonio Quartulli 		goto out;
3295a73105b8SAntonio Quartulli 
3296a73105b8SAntonio Quartulli 	/* Purge the old table first.. */
329795fb130dSAntonio Quartulli 	batadv_tt_global_del_orig(bat_priv, orig_node, -1,
329895fb130dSAntonio Quartulli 				  "Received full table");
3299a73105b8SAntonio Quartulli 
33007ea7b4a1SAntonio Quartulli 	_batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries,
33017ea7b4a1SAntonio Quartulli 				  ttvn);
3302a73105b8SAntonio Quartulli 
3303a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
3304a73105b8SAntonio Quartulli 	kfree(orig_node->tt_buff);
3305a73105b8SAntonio Quartulli 	orig_node->tt_buff_len = 0;
3306a73105b8SAntonio Quartulli 	orig_node->tt_buff = NULL;
3307a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
3308a73105b8SAntonio Quartulli 
33097ea7b4a1SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, ttvn);
3310a73105b8SAntonio Quartulli 
3311a73105b8SAntonio Quartulli out:
33125d967310SSven Eckelmann 	batadv_orig_node_put(orig_node);
3313a73105b8SAntonio Quartulli }
3314a73105b8SAntonio Quartulli 
batadv_tt_update_changes(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,u16 tt_num_changes,u8 ttvn,struct batadv_tvlv_tt_change * tt_change)331556303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
331656303d34SSven Eckelmann 				     struct batadv_orig_node *orig_node,
33176b5e971aSSven Eckelmann 				     u16 tt_num_changes, u8 ttvn,
3318335fbe0fSMarek Lindner 				     struct batadv_tvlv_tt_change *tt_change)
3319a73105b8SAntonio Quartulli {
3320a513088dSSven Eckelmann 	_batadv_tt_update_changes(bat_priv, orig_node, tt_change,
3321a513088dSSven Eckelmann 				  tt_num_changes, ttvn);
3322a73105b8SAntonio Quartulli 
3323e8cf234aSAntonio Quartulli 	batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change,
3324e8cf234aSAntonio Quartulli 				   batadv_tt_len(tt_num_changes));
3325a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, ttvn);
3326a73105b8SAntonio Quartulli }
3327a73105b8SAntonio Quartulli 
3328c018ad3dSAntonio Quartulli /**
33297e9a8c2cSSven Eckelmann  * batadv_is_my_client() - check if a client is served by the local node
3330c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
33313f68785eSAntonio Quartulli  * @addr: the mac address of the client to check
3332c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
3333c018ad3dSAntonio Quartulli  *
333462fe710fSSven Eckelmann  * Return: true if the client is served by this node, false otherwise.
3335c018ad3dSAntonio Quartulli  */
batadv_is_my_client(struct batadv_priv * bat_priv,const u8 * addr,unsigned short vid)33366b5e971aSSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
3337c018ad3dSAntonio Quartulli 			 unsigned short vid)
3338a73105b8SAntonio Quartulli {
3339170173bfSSven Eckelmann 	struct batadv_tt_local_entry *tt_local_entry;
33407683fdc1SAntonio Quartulli 	bool ret = false;
3341a73105b8SAntonio Quartulli 
3342c018ad3dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
33437683fdc1SAntonio Quartulli 	if (!tt_local_entry)
33447683fdc1SAntonio Quartulli 		goto out;
3345058d0e26SAntonio Quartulli 	/* Check if the client has been logically deleted (but is kept for
33469cfc7bd6SSven Eckelmann 	 * consistency purpose)
33479cfc7bd6SSven Eckelmann 	 */
33487c1fd91dSAntonio Quartulli 	if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
33497c1fd91dSAntonio Quartulli 	    (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
3350058d0e26SAntonio Quartulli 		goto out;
33517683fdc1SAntonio Quartulli 	ret = true;
33527683fdc1SAntonio Quartulli out:
335395c0db90SSven Eckelmann 	batadv_tt_local_entry_put(tt_local_entry);
33547683fdc1SAntonio Quartulli 	return ret;
3355a73105b8SAntonio Quartulli }
3356a73105b8SAntonio Quartulli 
3357335fbe0fSMarek Lindner /**
33587e9a8c2cSSven Eckelmann  * batadv_handle_tt_response() - process incoming tt reply
3359335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3360335fbe0fSMarek Lindner  * @tt_data: tt data containing the tt request information
3361335fbe0fSMarek Lindner  * @resp_src: mac address of tt reply sender
3362335fbe0fSMarek Lindner  * @num_entries: number of tt change entries appended to the tt data
3363335fbe0fSMarek Lindner  */
batadv_handle_tt_response(struct batadv_priv * bat_priv,struct batadv_tvlv_tt_data * tt_data,u8 * resp_src,u16 num_entries)3364335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
3365335fbe0fSMarek Lindner 				      struct batadv_tvlv_tt_data *tt_data,
33666b5e971aSSven Eckelmann 				      u8 *resp_src, u16 num_entries)
3367a73105b8SAntonio Quartulli {
33687c26a53bSMarek Lindner 	struct batadv_tt_req_node *node;
33697c26a53bSMarek Lindner 	struct hlist_node *safe;
337056303d34SSven Eckelmann 	struct batadv_orig_node *orig_node = NULL;
3371335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_change *tt_change;
33726b5e971aSSven Eckelmann 	u8 *tvlv_ptr = (u8 *)tt_data;
33736b5e971aSSven Eckelmann 	u16 change_offset;
3374a73105b8SAntonio Quartulli 
337539c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
337686ceb360SSven Eckelmann 		   "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
3377335fbe0fSMarek Lindner 		   resp_src, tt_data->ttvn, num_entries,
3378a2f2b6cdSSven Eckelmann 		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
3379a73105b8SAntonio Quartulli 
3380335fbe0fSMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
3381a73105b8SAntonio Quartulli 	if (!orig_node)
3382a73105b8SAntonio Quartulli 		goto out;
3383a73105b8SAntonio Quartulli 
3384a70a9aa9SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_lock);
3385a70a9aa9SAntonio Quartulli 
33867ea7b4a1SAntonio Quartulli 	change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
33877ea7b4a1SAntonio Quartulli 	change_offset *= ntohs(tt_data->num_vlan);
33887ea7b4a1SAntonio Quartulli 	change_offset += sizeof(*tt_data);
33897ea7b4a1SAntonio Quartulli 	tvlv_ptr += change_offset;
33907ea7b4a1SAntonio Quartulli 
33917ea7b4a1SAntonio Quartulli 	tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
3392335fbe0fSMarek Lindner 	if (tt_data->flags & BATADV_TT_FULL_TABLE) {
33937ea7b4a1SAntonio Quartulli 		batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn,
33947ea7b4a1SAntonio Quartulli 				      resp_src, num_entries);
339596412690SSven Eckelmann 	} else {
3396335fbe0fSMarek Lindner 		batadv_tt_update_changes(bat_priv, orig_node, num_entries,
3397335fbe0fSMarek Lindner 					 tt_data->ttvn, tt_change);
339896412690SSven Eckelmann 	}
3399a73105b8SAntonio Quartulli 
3400a70a9aa9SAntonio Quartulli 	/* Recalculate the CRC for this orig_node and store it */
34017ea7b4a1SAntonio Quartulli 	batadv_tt_global_update_crc(bat_priv, orig_node);
3402a70a9aa9SAntonio Quartulli 
3403a70a9aa9SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_lock);
3404a70a9aa9SAntonio Quartulli 
3405a73105b8SAntonio Quartulli 	/* Delete the tt_req_node from pending tt_requests list */
3406807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.req_list_lock);
34077c26a53bSMarek Lindner 	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
3408335fbe0fSMarek Lindner 		if (!batadv_compare_eth(node->addr, resp_src))
3409a73105b8SAntonio Quartulli 			continue;
34107c26a53bSMarek Lindner 		hlist_del_init(&node->list);
34119c4604a2SSven Eckelmann 		batadv_tt_req_node_put(node);
3412a73105b8SAntonio Quartulli 	}
34137ea7b4a1SAntonio Quartulli 
3414807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
3415a73105b8SAntonio Quartulli out:
34165d967310SSven Eckelmann 	batadv_orig_node_put(orig_node);
3417a73105b8SAntonio Quartulli }
3418a73105b8SAntonio Quartulli 
batadv_tt_roam_list_free(struct batadv_priv * bat_priv)341956303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv)
3420a73105b8SAntonio Quartulli {
342156303d34SSven Eckelmann 	struct batadv_tt_roam_node *node, *safe;
3422a73105b8SAntonio Quartulli 
3423807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
3424a73105b8SAntonio Quartulli 
3425807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
3426cc47f66eSAntonio Quartulli 		list_del(&node->list);
342786452f81SSven Eckelmann 		kmem_cache_free(batadv_tt_roam_cache, node);
3428cc47f66eSAntonio Quartulli 	}
3429cc47f66eSAntonio Quartulli 
3430807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
3431cc47f66eSAntonio Quartulli }
3432cc47f66eSAntonio Quartulli 
batadv_tt_roam_purge(struct batadv_priv * bat_priv)343356303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)
3434cc47f66eSAntonio Quartulli {
343556303d34SSven Eckelmann 	struct batadv_tt_roam_node *node, *safe;
3436cc47f66eSAntonio Quartulli 
3437807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
3438807736f6SSven Eckelmann 	list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
343942d0b044SSven Eckelmann 		if (!batadv_has_timed_out(node->first_time,
344042d0b044SSven Eckelmann 					  BATADV_ROAMING_MAX_TIME))
3441cc47f66eSAntonio Quartulli 			continue;
3442cc47f66eSAntonio Quartulli 
3443cc47f66eSAntonio Quartulli 		list_del(&node->list);
344486452f81SSven Eckelmann 		kmem_cache_free(batadv_tt_roam_cache, node);
3445cc47f66eSAntonio Quartulli 	}
3446807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
3447cc47f66eSAntonio Quartulli }
3448cc47f66eSAntonio Quartulli 
344962fe710fSSven Eckelmann /**
34507e9a8c2cSSven Eckelmann  * batadv_tt_check_roam_count() - check if a client has roamed too frequently
3451d15cd622SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3452d15cd622SAntonio Quartulli  * @client: mac address of the roaming client
345362fe710fSSven Eckelmann  *
345462fe710fSSven Eckelmann  * This function checks whether the client already reached the
3455cc47f66eSAntonio Quartulli  * maximum number of possible roaming phases. In this case the ROAMING_ADV
3456cc47f66eSAntonio Quartulli  * will not be sent.
3457cc47f66eSAntonio Quartulli  *
345862fe710fSSven Eckelmann  * Return: true if the ROAMING_ADV can be sent, false otherwise
34599cfc7bd6SSven Eckelmann  */
batadv_tt_check_roam_count(struct batadv_priv * bat_priv,u8 * client)34606b5e971aSSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client)
3461cc47f66eSAntonio Quartulli {
346256303d34SSven Eckelmann 	struct batadv_tt_roam_node *tt_roam_node;
3463cc47f66eSAntonio Quartulli 	bool ret = false;
3464cc47f66eSAntonio Quartulli 
3465807736f6SSven Eckelmann 	spin_lock_bh(&bat_priv->tt.roam_list_lock);
3466cc47f66eSAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
34679cfc7bd6SSven Eckelmann 	 * reply from the same orig_node yet
34689cfc7bd6SSven Eckelmann 	 */
3469807736f6SSven Eckelmann 	list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) {
34701eda58bfSSven Eckelmann 		if (!batadv_compare_eth(tt_roam_node->addr, client))
3471cc47f66eSAntonio Quartulli 			continue;
3472cc47f66eSAntonio Quartulli 
34731eda58bfSSven Eckelmann 		if (batadv_has_timed_out(tt_roam_node->first_time,
347442d0b044SSven Eckelmann 					 BATADV_ROAMING_MAX_TIME))
3475cc47f66eSAntonio Quartulli 			continue;
3476cc47f66eSAntonio Quartulli 
34773e34819eSSven Eckelmann 		if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter))
3478cc47f66eSAntonio Quartulli 			/* Sorry, you roamed too many times! */
3479cc47f66eSAntonio Quartulli 			goto unlock;
3480cc47f66eSAntonio Quartulli 		ret = true;
3481cc47f66eSAntonio Quartulli 		break;
3482cc47f66eSAntonio Quartulli 	}
3483cc47f66eSAntonio Quartulli 
3484cc47f66eSAntonio Quartulli 	if (!ret) {
348586452f81SSven Eckelmann 		tt_roam_node = kmem_cache_alloc(batadv_tt_roam_cache,
348686452f81SSven Eckelmann 						GFP_ATOMIC);
3487cc47f66eSAntonio Quartulli 		if (!tt_roam_node)
3488cc47f66eSAntonio Quartulli 			goto unlock;
3489cc47f66eSAntonio Quartulli 
3490cc47f66eSAntonio Quartulli 		tt_roam_node->first_time = jiffies;
349142d0b044SSven Eckelmann 		atomic_set(&tt_roam_node->counter,
349242d0b044SSven Eckelmann 			   BATADV_ROAMING_MAX_COUNT - 1);
34938fdd0153SAntonio Quartulli 		ether_addr_copy(tt_roam_node->addr, client);
3494cc47f66eSAntonio Quartulli 
3495807736f6SSven Eckelmann 		list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
3496cc47f66eSAntonio Quartulli 		ret = true;
3497cc47f66eSAntonio Quartulli 	}
3498cc47f66eSAntonio Quartulli 
3499cc47f66eSAntonio Quartulli unlock:
3500807736f6SSven Eckelmann 	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
3501cc47f66eSAntonio Quartulli 	return ret;
3502cc47f66eSAntonio Quartulli }
3503cc47f66eSAntonio Quartulli 
3504c018ad3dSAntonio Quartulli /**
35057e9a8c2cSSven Eckelmann  * batadv_send_roam_adv() - send a roaming advertisement message
3506c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3507c018ad3dSAntonio Quartulli  * @client: mac address of the roaming client
3508c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
3509c018ad3dSAntonio Quartulli  * @orig_node: message destination
3510c018ad3dSAntonio Quartulli  *
3511c018ad3dSAntonio Quartulli  * Send a ROAMING_ADV message to the node which was previously serving this
3512c018ad3dSAntonio Quartulli  * client. This is done to inform the node that from now on all traffic destined
3513c018ad3dSAntonio Quartulli  * for this particular roamed client has to be forwarded to the sender of the
3514c018ad3dSAntonio Quartulli  * roaming message.
3515c018ad3dSAntonio Quartulli  */
batadv_send_roam_adv(struct batadv_priv * bat_priv,u8 * client,unsigned short vid,struct batadv_orig_node * orig_node)35166b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
3517c018ad3dSAntonio Quartulli 				 unsigned short vid,
351856303d34SSven Eckelmann 				 struct batadv_orig_node *orig_node)
3519cc47f66eSAntonio Quartulli {
352056303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if;
3521122edaa0SMarek Lindner 	struct batadv_tvlv_roam_adv tvlv_roam;
3522122edaa0SMarek Lindner 
3523122edaa0SMarek Lindner 	primary_if = batadv_primary_if_get_selected(bat_priv);
3524122edaa0SMarek Lindner 	if (!primary_if)
3525122edaa0SMarek Lindner 		goto out;
3526cc47f66eSAntonio Quartulli 
3527cc47f66eSAntonio Quartulli 	/* before going on we have to check whether the client has
35289cfc7bd6SSven Eckelmann 	 * already roamed to us too many times
35299cfc7bd6SSven Eckelmann 	 */
3530a513088dSSven Eckelmann 	if (!batadv_tt_check_roam_count(bat_priv, client))
3531cc47f66eSAntonio Quartulli 		goto out;
3532cc47f66eSAntonio Quartulli 
353339c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
353416052789SAntonio Quartulli 		   "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n",
3535f7a2bd65SSven Eckelmann 		   orig_node->orig, client, batadv_print_vid(vid));
3536cc47f66eSAntonio Quartulli 
3537d69909d2SSven Eckelmann 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
3538f8214865SMartin Hundebøll 
3539122edaa0SMarek Lindner 	memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client));
3540c018ad3dSAntonio Quartulli 	tvlv_roam.vid = htons(vid);
3541122edaa0SMarek Lindner 
3542122edaa0SMarek Lindner 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
3543122edaa0SMarek Lindner 				 orig_node->orig, BATADV_TVLV_ROAM, 1,
3544122edaa0SMarek Lindner 				 &tvlv_roam, sizeof(tvlv_roam));
3545cc47f66eSAntonio Quartulli 
3546cc47f66eSAntonio Quartulli out:
354782047ad7SSven Eckelmann 	batadv_hardif_put(primary_if);
3548a73105b8SAntonio Quartulli }
3549a73105b8SAntonio Quartulli 
batadv_tt_purge(struct work_struct * work)3550a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work)
3551a73105b8SAntonio Quartulli {
355256303d34SSven Eckelmann 	struct delayed_work *delayed_work;
3553807736f6SSven Eckelmann 	struct batadv_priv_tt *priv_tt;
355456303d34SSven Eckelmann 	struct batadv_priv *bat_priv;
355556303d34SSven Eckelmann 
35564ba4bc0fSGeliang Tang 	delayed_work = to_delayed_work(work);
3557807736f6SSven Eckelmann 	priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
3558807736f6SSven Eckelmann 	bat_priv = container_of(priv_tt, struct batadv_priv, tt);
3559a73105b8SAntonio Quartulli 
3560a19d3d85SMarek Lindner 	batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
356130cfd02bSAntonio Quartulli 	batadv_tt_global_purge(bat_priv);
3562a513088dSSven Eckelmann 	batadv_tt_req_purge(bat_priv);
3563a513088dSSven Eckelmann 	batadv_tt_roam_purge(bat_priv);
3564a73105b8SAntonio Quartulli 
356572414442SAntonio Quartulli 	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
356672414442SAntonio Quartulli 			   msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
3567a73105b8SAntonio Quartulli }
3568cc47f66eSAntonio Quartulli 
3569ff15c27cSSven Eckelmann /**
3570ff15c27cSSven Eckelmann  * batadv_tt_free() - Free translation table of soft interface
3571ff15c27cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
3572ff15c27cSSven Eckelmann  */
batadv_tt_free(struct batadv_priv * bat_priv)357356303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv)
3574cc47f66eSAntonio Quartulli {
357517f78dd1SJeremy Sowden 	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_ROAM, 1);
357617f78dd1SJeremy Sowden 
3577e1bf0c14SMarek Lindner 	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1);
3578e1bf0c14SMarek Lindner 	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1);
3579e1bf0c14SMarek Lindner 
3580807736f6SSven Eckelmann 	cancel_delayed_work_sync(&bat_priv->tt.work);
3581cc47f66eSAntonio Quartulli 
3582a513088dSSven Eckelmann 	batadv_tt_local_table_free(bat_priv);
3583a513088dSSven Eckelmann 	batadv_tt_global_table_free(bat_priv);
3584a513088dSSven Eckelmann 	batadv_tt_req_list_free(bat_priv);
3585a513088dSSven Eckelmann 	batadv_tt_changes_list_free(bat_priv);
3586a513088dSSven Eckelmann 	batadv_tt_roam_list_free(bat_priv);
3587cc47f66eSAntonio Quartulli 
3588807736f6SSven Eckelmann 	kfree(bat_priv->tt.last_changeset);
3589cc47f66eSAntonio Quartulli }
3590058d0e26SAntonio Quartulli 
35917ea7b4a1SAntonio Quartulli /**
35927e9a8c2cSSven Eckelmann  * batadv_tt_local_set_flags() - set or unset the specified flags on the local
35937ea7b4a1SAntonio Quartulli  *  table and possibly count them in the TT size
35947ea7b4a1SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
35957ea7b4a1SAntonio Quartulli  * @flags: the flag to switch
35967ea7b4a1SAntonio Quartulli  * @enable: whether to set or unset the flag
35977ea7b4a1SAntonio Quartulli  * @count: whether to increase the TT size by the number of changed entries
35989cfc7bd6SSven Eckelmann  */
batadv_tt_local_set_flags(struct batadv_priv * bat_priv,u16 flags,bool enable,bool count)35996b5e971aSSven Eckelmann static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
36006b5e971aSSven Eckelmann 				      bool enable, bool count)
3601058d0e26SAntonio Quartulli {
36027ea7b4a1SAntonio Quartulli 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
36037ea7b4a1SAntonio Quartulli 	struct batadv_tt_common_entry *tt_common_entry;
3604058d0e26SAntonio Quartulli 	struct hlist_head *head;
36056b5e971aSSven Eckelmann 	u32 i;
3606058d0e26SAntonio Quartulli 
3607058d0e26SAntonio Quartulli 	if (!hash)
36087ea7b4a1SAntonio Quartulli 		return;
3609058d0e26SAntonio Quartulli 
3610058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
3611058d0e26SAntonio Quartulli 		head = &hash->table[i];
3612058d0e26SAntonio Quartulli 
3613058d0e26SAntonio Quartulli 		rcu_read_lock();
3614b67bfe0dSSasha Levin 		hlist_for_each_entry_rcu(tt_common_entry,
3615058d0e26SAntonio Quartulli 					 head, hash_entry) {
3616697f2531SAntonio Quartulli 			if (enable) {
3617697f2531SAntonio Quartulli 				if ((tt_common_entry->flags & flags) == flags)
3618697f2531SAntonio Quartulli 					continue;
3619697f2531SAntonio Quartulli 				tt_common_entry->flags |= flags;
3620697f2531SAntonio Quartulli 			} else {
362148100bacSAntonio Quartulli 				if (!(tt_common_entry->flags & flags))
362231901264SAntonio Quartulli 					continue;
362348100bacSAntonio Quartulli 				tt_common_entry->flags &= ~flags;
3624697f2531SAntonio Quartulli 			}
36257ea7b4a1SAntonio Quartulli 
36267ea7b4a1SAntonio Quartulli 			if (!count)
36277ea7b4a1SAntonio Quartulli 				continue;
36287ea7b4a1SAntonio Quartulli 
36297ea7b4a1SAntonio Quartulli 			batadv_tt_local_size_inc(bat_priv,
36307ea7b4a1SAntonio Quartulli 						 tt_common_entry->vid);
3631058d0e26SAntonio Quartulli 		}
3632058d0e26SAntonio Quartulli 		rcu_read_unlock();
3633058d0e26SAntonio Quartulli 	}
3634058d0e26SAntonio Quartulli }
3635058d0e26SAntonio Quartulli 
3636acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */
batadv_tt_local_purge_pending_clients(struct batadv_priv * bat_priv)363756303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
3638058d0e26SAntonio Quartulli {
3639807736f6SSven Eckelmann 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
364056303d34SSven Eckelmann 	struct batadv_tt_common_entry *tt_common;
364156303d34SSven Eckelmann 	struct batadv_tt_local_entry *tt_local;
3642b67bfe0dSSasha Levin 	struct hlist_node *node_tmp;
3643058d0e26SAntonio Quartulli 	struct hlist_head *head;
3644058d0e26SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
36456b5e971aSSven Eckelmann 	u32 i;
3646058d0e26SAntonio Quartulli 
3647058d0e26SAntonio Quartulli 	if (!hash)
3648058d0e26SAntonio Quartulli 		return;
3649058d0e26SAntonio Quartulli 
3650058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
3651058d0e26SAntonio Quartulli 		head = &hash->table[i];
3652058d0e26SAntonio Quartulli 		list_lock = &hash->list_locks[i];
3653058d0e26SAntonio Quartulli 
3654058d0e26SAntonio Quartulli 		spin_lock_bh(list_lock);
3655b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(tt_common, node_tmp, head,
3656acd34afaSSven Eckelmann 					  hash_entry) {
3657acd34afaSSven Eckelmann 			if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
3658058d0e26SAntonio Quartulli 				continue;
3659058d0e26SAntonio Quartulli 
366039c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
366116052789SAntonio Quartulli 				   "Deleting local tt entry (%pM, vid: %d): pending\n",
366216052789SAntonio Quartulli 				   tt_common->addr,
3663f7a2bd65SSven Eckelmann 				   batadv_print_vid(tt_common->vid));
3664058d0e26SAntonio Quartulli 
36657ea7b4a1SAntonio Quartulli 			batadv_tt_local_size_dec(bat_priv, tt_common->vid);
3666b67bfe0dSSasha Levin 			hlist_del_rcu(&tt_common->hash_entry);
366756303d34SSven Eckelmann 			tt_local = container_of(tt_common,
366856303d34SSven Eckelmann 						struct batadv_tt_local_entry,
366948100bacSAntonio Quartulli 						common);
367035df3b29SAntonio Quartulli 
367195c0db90SSven Eckelmann 			batadv_tt_local_entry_put(tt_local);
3672058d0e26SAntonio Quartulli 		}
3673058d0e26SAntonio Quartulli 		spin_unlock_bh(list_lock);
3674058d0e26SAntonio Quartulli 	}
3675058d0e26SAntonio Quartulli }
3676058d0e26SAntonio Quartulli 
3677e1bf0c14SMarek Lindner /**
36787e9a8c2cSSven Eckelmann  * batadv_tt_local_commit_changes_nolock() - commit all pending local tt changes
3679a19d3d85SMarek Lindner  *  which have been queued in the time since the last commit
3680e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3681a19d3d85SMarek Lindner  *
3682a19d3d85SMarek Lindner  * Caller must hold tt->commit_lock.
3683e1bf0c14SMarek Lindner  */
batadv_tt_local_commit_changes_nolock(struct batadv_priv * bat_priv)3684a19d3d85SMarek Lindner static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
3685058d0e26SAntonio Quartulli {
36865274cd68SSven Eckelmann 	lockdep_assert_held(&bat_priv->tt.commit_lock);
36875274cd68SSven Eckelmann 
3688e1bf0c14SMarek Lindner 	if (atomic_read(&bat_priv->tt.local_changes) < 1) {
3689e1bf0c14SMarek Lindner 		if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
3690e1bf0c14SMarek Lindner 			batadv_tt_tvlv_container_update(bat_priv);
3691a19d3d85SMarek Lindner 		return;
3692e1bf0c14SMarek Lindner 	}
3693be9aa4c1SMarek Lindner 
36947ea7b4a1SAntonio Quartulli 	batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
3695be9aa4c1SMarek Lindner 
3696a513088dSSven Eckelmann 	batadv_tt_local_purge_pending_clients(bat_priv);
36977ea7b4a1SAntonio Quartulli 	batadv_tt_local_update_crc(bat_priv);
3698058d0e26SAntonio Quartulli 
3699058d0e26SAntonio Quartulli 	/* Increment the TTVN only once per OGM interval */
3700807736f6SSven Eckelmann 	atomic_inc(&bat_priv->tt.vn);
370139c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_TT, bat_priv,
37021eda58bfSSven Eckelmann 		   "Local changes committed, updating to ttvn %u\n",
37036b5e971aSSven Eckelmann 		   (u8)atomic_read(&bat_priv->tt.vn));
3704be9aa4c1SMarek Lindner 
3705be9aa4c1SMarek Lindner 	/* reset the sending counter */
3706807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
3707e1bf0c14SMarek Lindner 	batadv_tt_tvlv_container_update(bat_priv);
3708a19d3d85SMarek Lindner }
3709a70a9aa9SAntonio Quartulli 
3710a19d3d85SMarek Lindner /**
37117e9a8c2cSSven Eckelmann  * batadv_tt_local_commit_changes() - commit all pending local tt changes which
3712a19d3d85SMarek Lindner  *  have been queued in the time since the last commit
3713a19d3d85SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3714a19d3d85SMarek Lindner  */
batadv_tt_local_commit_changes(struct batadv_priv * bat_priv)3715a19d3d85SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
3716a19d3d85SMarek Lindner {
3717a19d3d85SMarek Lindner 	spin_lock_bh(&bat_priv->tt.commit_lock);
3718a19d3d85SMarek Lindner 	batadv_tt_local_commit_changes_nolock(bat_priv);
3719a70a9aa9SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt.commit_lock);
3720058d0e26SAntonio Quartulli }
372159b699cdSAntonio Quartulli 
3722ff15c27cSSven Eckelmann /**
3723ff15c27cSSven Eckelmann  * batadv_is_ap_isolated() - Check if packet from upper layer should be dropped
3724ff15c27cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
3725ff15c27cSSven Eckelmann  * @src: source mac address of packet
3726ff15c27cSSven Eckelmann  * @dst: destination mac address of packet
3727ff15c27cSSven Eckelmann  * @vid: vlan id of packet
3728ff15c27cSSven Eckelmann  *
3729ff15c27cSSven Eckelmann  * Return: true when src+dst(+vid) pair should be isolated, false otherwise
3730ff15c27cSSven Eckelmann  */
batadv_is_ap_isolated(struct batadv_priv * bat_priv,u8 * src,u8 * dst,unsigned short vid)37316b5e971aSSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst,
37326b5e971aSSven Eckelmann 			   unsigned short vid)
373359b699cdSAntonio Quartulli {
3734393b299dSMarkus Elfring 	struct batadv_tt_local_entry *tt_local_entry;
3735393b299dSMarkus Elfring 	struct batadv_tt_global_entry *tt_global_entry;
3736b8cbd81dSAntonio Quartulli 	struct batadv_softif_vlan *vlan;
37375870adc6SMarek Lindner 	bool ret = false;
373859b699cdSAntonio Quartulli 
3739b8cbd81dSAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
3740e087f34fSMarkus Elfring 	if (!vlan)
3741e087f34fSMarkus Elfring 		return false;
3742e087f34fSMarkus Elfring 
3743e087f34fSMarkus Elfring 	if (!atomic_read(&vlan->ap_isolation))
3744393b299dSMarkus Elfring 		goto vlan_put;
374559b699cdSAntonio Quartulli 
3746b8cbd81dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid);
374759b699cdSAntonio Quartulli 	if (!tt_local_entry)
3748393b299dSMarkus Elfring 		goto vlan_put;
374959b699cdSAntonio Quartulli 
3750b8cbd81dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid);
375159b699cdSAntonio Quartulli 	if (!tt_global_entry)
3752393b299dSMarkus Elfring 		goto local_entry_put;
375359b699cdSAntonio Quartulli 
3754393b299dSMarkus Elfring 	if (_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
37555870adc6SMarek Lindner 		ret = true;
375659b699cdSAntonio Quartulli 
37575dafd8a6SSven Eckelmann 	batadv_tt_global_entry_put(tt_global_entry);
3758393b299dSMarkus Elfring local_entry_put:
375995c0db90SSven Eckelmann 	batadv_tt_local_entry_put(tt_local_entry);
3760393b299dSMarkus Elfring vlan_put:
3761393b299dSMarkus Elfring 	batadv_softif_vlan_put(vlan);
376259b699cdSAntonio Quartulli 	return ret;
376359b699cdSAntonio Quartulli }
3764a943cac1SMarek Lindner 
3765e1bf0c14SMarek Lindner /**
37667e9a8c2cSSven Eckelmann  * batadv_tt_update_orig() - update global translation table with new tt
3767e1bf0c14SMarek Lindner  *  information received via ogms
3768e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3769e51f0397SSven Eckelmann  * @orig_node: the orig_node of the ogm
3770e51f0397SSven Eckelmann  * @tt_buff: pointer to the first tvlv VLAN entry
37717ea7b4a1SAntonio Quartulli  * @tt_num_vlan: number of tvlv VLAN entries
37727ea7b4a1SAntonio Quartulli  * @tt_change: pointer to the first entry in the TT buffer
3773e1bf0c14SMarek Lindner  * @tt_num_changes: number of tt changes inside the tt buffer
3774e1bf0c14SMarek Lindner  * @ttvn: translation table version number of this changeset
3775e1bf0c14SMarek Lindner  */
batadv_tt_update_orig(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,const void * tt_buff,u16 tt_num_vlan,struct batadv_tvlv_tt_change * tt_change,u16 tt_num_changes,u8 ttvn)3776e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
377756303d34SSven Eckelmann 				  struct batadv_orig_node *orig_node,
37786b5e971aSSven Eckelmann 				  const void *tt_buff, u16 tt_num_vlan,
37797ea7b4a1SAntonio Quartulli 				  struct batadv_tvlv_tt_change *tt_change,
37806b5e971aSSven Eckelmann 				  u16 tt_num_changes, u8 ttvn)
3781a943cac1SMarek Lindner {
37826b5e971aSSven Eckelmann 	u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn);
37837ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
3784a943cac1SMarek Lindner 	bool full_table = true;
3785e17931d1SLinus Lüssing 	bool has_tt_init;
3786a943cac1SMarek Lindner 
37877ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
3788ac4eebd4SLinus Lüssing 	has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT,
3789ac4eebd4SLinus Lüssing 			       &orig_node->capa_initialized);
3790e17931d1SLinus Lüssing 
379117071578SAntonio Quartulli 	/* orig table not initialised AND first diff is in the OGM OR the ttvn
37929cfc7bd6SSven Eckelmann 	 * increased by one -> we can apply the attached changes
37939cfc7bd6SSven Eckelmann 	 */
3794e17931d1SLinus Lüssing 	if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) {
3795a943cac1SMarek Lindner 		/* the OGM could not contain the changes due to their size or
379642d0b044SSven Eckelmann 		 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
379742d0b044SSven Eckelmann 		 * times.
37989cfc7bd6SSven Eckelmann 		 * In this case send a tt request
37999cfc7bd6SSven Eckelmann 		 */
3800a943cac1SMarek Lindner 		if (!tt_num_changes) {
3801a943cac1SMarek Lindner 			full_table = false;
3802a943cac1SMarek Lindner 			goto request_table;
3803a943cac1SMarek Lindner 		}
3804a943cac1SMarek Lindner 
3805a70a9aa9SAntonio Quartulli 		spin_lock_bh(&orig_node->tt_lock);
3806a70a9aa9SAntonio Quartulli 
3807a513088dSSven Eckelmann 		batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
380896412690SSven Eckelmann 					 ttvn, tt_change);
3809a943cac1SMarek Lindner 
3810a943cac1SMarek Lindner 		/* Even if we received the precomputed crc with the OGM, we
3811a943cac1SMarek Lindner 		 * prefer to recompute it to spot any possible inconsistency
38129cfc7bd6SSven Eckelmann 		 * in the global table
38139cfc7bd6SSven Eckelmann 		 */
38147ea7b4a1SAntonio Quartulli 		batadv_tt_global_update_crc(bat_priv, orig_node);
3815a943cac1SMarek Lindner 
3816a70a9aa9SAntonio Quartulli 		spin_unlock_bh(&orig_node->tt_lock);
3817a70a9aa9SAntonio Quartulli 
3818a943cac1SMarek Lindner 		/* The ttvn alone is not enough to guarantee consistency
3819a943cac1SMarek Lindner 		 * because a single value could represent different states
3820a943cac1SMarek Lindner 		 * (due to the wrap around). Thus a node has to check whether
3821a943cac1SMarek Lindner 		 * the resulting table (after applying the changes) is still
3822a943cac1SMarek Lindner 		 * consistent or not. E.g. a node could disconnect while its
3823a943cac1SMarek Lindner 		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
3824a943cac1SMarek Lindner 		 * checking the CRC value is mandatory to detect the
38259cfc7bd6SSven Eckelmann 		 * inconsistency
38269cfc7bd6SSven Eckelmann 		 */
38277ea7b4a1SAntonio Quartulli 		if (!batadv_tt_global_check_crc(orig_node, tt_vlan,
38287ea7b4a1SAntonio Quartulli 						tt_num_vlan))
3829a943cac1SMarek Lindner 			goto request_table;
3830a943cac1SMarek Lindner 	} else {
3831a943cac1SMarek Lindner 		/* if we missed more than one change or our tables are not
38329cfc7bd6SSven Eckelmann 		 * in sync anymore -> request fresh tt data
38339cfc7bd6SSven Eckelmann 		 */
3834e17931d1SLinus Lüssing 		if (!has_tt_init || ttvn != orig_ttvn ||
38357ea7b4a1SAntonio Quartulli 		    !batadv_tt_global_check_crc(orig_node, tt_vlan,
38367ea7b4a1SAntonio Quartulli 						tt_num_vlan)) {
3837a943cac1SMarek Lindner request_table:
383839c75a51SSven Eckelmann 			batadv_dbg(BATADV_DBG_TT, bat_priv,
38397ea7b4a1SAntonio Quartulli 				   "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n",
38407ea7b4a1SAntonio Quartulli 				   orig_node->orig, ttvn, orig_ttvn,
38417ea7b4a1SAntonio Quartulli 				   tt_num_changes);
3842a513088dSSven Eckelmann 			batadv_send_tt_request(bat_priv, orig_node, ttvn,
38437ea7b4a1SAntonio Quartulli 					       tt_vlan, tt_num_vlan,
38447ea7b4a1SAntonio Quartulli 					       full_table);
3845a943cac1SMarek Lindner 			return;
3846a943cac1SMarek Lindner 		}
3847a943cac1SMarek Lindner 	}
3848a943cac1SMarek Lindner }
38493275e7ccSAntonio Quartulli 
3850c018ad3dSAntonio Quartulli /**
38517e9a8c2cSSven Eckelmann  * batadv_tt_global_client_is_roaming() - check if a client is marked as roaming
3852c018ad3dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3853c018ad3dSAntonio Quartulli  * @addr: the mac address of the client to check
3854c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
3855c018ad3dSAntonio Quartulli  *
385662fe710fSSven Eckelmann  * Return: true if we know that the client has moved from its old originator
3857c018ad3dSAntonio Quartulli  * to another one. This entry is still kept for consistency purposes and will be
3858c018ad3dSAntonio Quartulli  * deleted later by a DEL or because of timeout
38593275e7ccSAntonio Quartulli  */
batadv_tt_global_client_is_roaming(struct batadv_priv * bat_priv,u8 * addr,unsigned short vid)386056303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
38616b5e971aSSven Eckelmann 					u8 *addr, unsigned short vid)
38623275e7ccSAntonio Quartulli {
386356303d34SSven Eckelmann 	struct batadv_tt_global_entry *tt_global_entry;
38643275e7ccSAntonio Quartulli 	bool ret = false;
38653275e7ccSAntonio Quartulli 
3866c018ad3dSAntonio Quartulli 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
38673275e7ccSAntonio Quartulli 	if (!tt_global_entry)
38683275e7ccSAntonio Quartulli 		goto out;
38693275e7ccSAntonio Quartulli 
3870c1d07431SAntonio Quartulli 	ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
38715dafd8a6SSven Eckelmann 	batadv_tt_global_entry_put(tt_global_entry);
38723275e7ccSAntonio Quartulli out:
38733275e7ccSAntonio Quartulli 	return ret;
38743275e7ccSAntonio Quartulli }
387530cfd02bSAntonio Quartulli 
38767c1fd91dSAntonio Quartulli /**
38777e9a8c2cSSven Eckelmann  * batadv_tt_local_client_is_roaming() - tells whether the client is roaming
38787c1fd91dSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
3879c018ad3dSAntonio Quartulli  * @addr: the mac address of the local client to query
3880c018ad3dSAntonio Quartulli  * @vid: VLAN identifier
38817c1fd91dSAntonio Quartulli  *
388262fe710fSSven Eckelmann  * Return: true if the local client is known to be roaming (it is not served by
38837c1fd91dSAntonio Quartulli  * this node anymore) or not. If yes, the client is still present in the table
38847c1fd91dSAntonio Quartulli  * to keep the latter consistent with the node TTVN
38857c1fd91dSAntonio Quartulli  */
batadv_tt_local_client_is_roaming(struct batadv_priv * bat_priv,u8 * addr,unsigned short vid)38867c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
38876b5e971aSSven Eckelmann 				       u8 *addr, unsigned short vid)
38887c1fd91dSAntonio Quartulli {
38897c1fd91dSAntonio Quartulli 	struct batadv_tt_local_entry *tt_local_entry;
38907c1fd91dSAntonio Quartulli 	bool ret = false;
38917c1fd91dSAntonio Quartulli 
3892c018ad3dSAntonio Quartulli 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
38937c1fd91dSAntonio Quartulli 	if (!tt_local_entry)
38947c1fd91dSAntonio Quartulli 		goto out;
38957c1fd91dSAntonio Quartulli 
38967c1fd91dSAntonio Quartulli 	ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
389795c0db90SSven Eckelmann 	batadv_tt_local_entry_put(tt_local_entry);
38987c1fd91dSAntonio Quartulli out:
38997c1fd91dSAntonio Quartulli 	return ret;
39007c1fd91dSAntonio Quartulli }
39017c1fd91dSAntonio Quartulli 
3902ff15c27cSSven Eckelmann /**
3903ff15c27cSSven Eckelmann  * batadv_tt_add_temporary_global_entry() - Add temporary entry to global TT
3904ff15c27cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
3905ff15c27cSSven Eckelmann  * @orig_node: orig node which the temporary entry should be associated with
3906ff15c27cSSven Eckelmann  * @addr: mac address of the client
3907ff15c27cSSven Eckelmann  * @vid: VLAN id of the new temporary global translation table
3908ff15c27cSSven Eckelmann  *
3909ff15c27cSSven Eckelmann  * Return: true when temporary tt entry could be added, false otherwise
3910ff15c27cSSven Eckelmann  */
batadv_tt_add_temporary_global_entry(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,const unsigned char * addr,unsigned short vid)391130cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
391230cfd02bSAntonio Quartulli 					  struct batadv_orig_node *orig_node,
3913c018ad3dSAntonio Quartulli 					  const unsigned char *addr,
391416052789SAntonio Quartulli 					  unsigned short vid)
391530cfd02bSAntonio Quartulli {
39161227c9aeSSimon Wunderlich 	/* ignore loop detect macs, they are not supposed to be in the tt local
39171227c9aeSSimon Wunderlich 	 * data as well.
39181227c9aeSSimon Wunderlich 	 */
39191227c9aeSSimon Wunderlich 	if (batadv_bla_is_loopdetect_mac(addr))
39201227c9aeSSimon Wunderlich 		return false;
39211227c9aeSSimon Wunderlich 
392216052789SAntonio Quartulli 	if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid,
392330cfd02bSAntonio Quartulli 				  BATADV_TT_CLIENT_TEMP,
392430cfd02bSAntonio Quartulli 				  atomic_read(&orig_node->last_ttvn)))
392575ae84a4SSimon Wunderlich 		return false;
392630cfd02bSAntonio Quartulli 
392730cfd02bSAntonio Quartulli 	batadv_dbg(BATADV_DBG_TT, bat_priv,
392816052789SAntonio Quartulli 		   "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n",
3929f7a2bd65SSven Eckelmann 		   addr, batadv_print_vid(vid), orig_node->orig);
393075ae84a4SSimon Wunderlich 
393175ae84a4SSimon Wunderlich 	return true;
393230cfd02bSAntonio Quartulli }
3933e1bf0c14SMarek Lindner 
3934e1bf0c14SMarek Lindner /**
39357e9a8c2cSSven Eckelmann  * batadv_tt_local_resize_to_mtu() - resize the local translation table fit the
3936a19d3d85SMarek Lindner  *  maximum packet size that can be transported through the mesh
3937a19d3d85SMarek Lindner  * @soft_iface: netdev struct of the mesh interface
3938a19d3d85SMarek Lindner  *
3939a19d3d85SMarek Lindner  * Remove entries older than 'timeout' and half timeout if more entries need
3940a19d3d85SMarek Lindner  * to be removed.
3941a19d3d85SMarek Lindner  */
batadv_tt_local_resize_to_mtu(struct net_device * soft_iface)3942a19d3d85SMarek Lindner void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
3943a19d3d85SMarek Lindner {
3944a19d3d85SMarek Lindner 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
3945a19d3d85SMarek Lindner 	int packet_size_max = atomic_read(&bat_priv->packet_size_max);
3946a19d3d85SMarek Lindner 	int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
3947a19d3d85SMarek Lindner 	bool reduced = false;
3948a19d3d85SMarek Lindner 
3949a19d3d85SMarek Lindner 	spin_lock_bh(&bat_priv->tt.commit_lock);
3950a19d3d85SMarek Lindner 
39514ca2a5fbSSven Eckelmann 	while (timeout) {
3952a19d3d85SMarek Lindner 		table_size = batadv_tt_local_table_transmit_size(bat_priv);
3953a19d3d85SMarek Lindner 		if (packet_size_max >= table_size)
3954a19d3d85SMarek Lindner 			break;
3955a19d3d85SMarek Lindner 
3956a19d3d85SMarek Lindner 		batadv_tt_local_purge(bat_priv, timeout);
3957a19d3d85SMarek Lindner 		batadv_tt_local_purge_pending_clients(bat_priv);
3958a19d3d85SMarek Lindner 
3959a19d3d85SMarek Lindner 		timeout /= 2;
3960a19d3d85SMarek Lindner 		reduced = true;
3961a19d3d85SMarek Lindner 		net_ratelimited_function(batadv_info, soft_iface,
3962a19d3d85SMarek Lindner 					 "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
3963a19d3d85SMarek Lindner 					 packet_size_max);
3964a19d3d85SMarek Lindner 	}
3965a19d3d85SMarek Lindner 
3966a19d3d85SMarek Lindner 	/* commit these changes immediately, to avoid synchronization problem
3967a19d3d85SMarek Lindner 	 * with the TTVN
3968a19d3d85SMarek Lindner 	 */
3969a19d3d85SMarek Lindner 	if (reduced)
3970a19d3d85SMarek Lindner 		batadv_tt_local_commit_changes_nolock(bat_priv);
3971a19d3d85SMarek Lindner 
3972a19d3d85SMarek Lindner 	spin_unlock_bh(&bat_priv->tt.commit_lock);
3973a19d3d85SMarek Lindner }
3974a19d3d85SMarek Lindner 
3975a19d3d85SMarek Lindner /**
39767e9a8c2cSSven Eckelmann  * batadv_tt_tvlv_ogm_handler_v1() - process incoming tt tvlv container
3977e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
3978e1bf0c14SMarek Lindner  * @orig: the orig_node of the ogm
3979e1bf0c14SMarek Lindner  * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
3980e1bf0c14SMarek Lindner  * @tvlv_value: tvlv buffer containing the gateway data
3981e1bf0c14SMarek Lindner  * @tvlv_value_len: tvlv buffer length
3982e1bf0c14SMarek Lindner  */
batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv * bat_priv,struct batadv_orig_node * orig,u8 flags,void * tvlv_value,u16 tvlv_value_len)3983e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
3984e1bf0c14SMarek Lindner 					  struct batadv_orig_node *orig,
39856b5e971aSSven Eckelmann 					  u8 flags, void *tvlv_value,
39866b5e971aSSven Eckelmann 					  u16 tvlv_value_len)
3987e1bf0c14SMarek Lindner {
39887ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_vlan_data *tt_vlan;
39897ea7b4a1SAntonio Quartulli 	struct batadv_tvlv_tt_change *tt_change;
3990e1bf0c14SMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
39916b5e971aSSven Eckelmann 	u16 num_entries, num_vlan;
3992e1bf0c14SMarek Lindner 
3993e1bf0c14SMarek Lindner 	if (tvlv_value_len < sizeof(*tt_data))
3994e1bf0c14SMarek Lindner 		return;
3995e1bf0c14SMarek Lindner 
39968864d2fcSYu Zhe 	tt_data = tvlv_value;
3997e1bf0c14SMarek Lindner 	tvlv_value_len -= sizeof(*tt_data);
3998e1bf0c14SMarek Lindner 
39997ea7b4a1SAntonio Quartulli 	num_vlan = ntohs(tt_data->num_vlan);
40007ea7b4a1SAntonio Quartulli 
40017ea7b4a1SAntonio Quartulli 	if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan)
40027ea7b4a1SAntonio Quartulli 		return;
40037ea7b4a1SAntonio Quartulli 
40047ea7b4a1SAntonio Quartulli 	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
40057ea7b4a1SAntonio Quartulli 	tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan);
40067ea7b4a1SAntonio Quartulli 	tvlv_value_len -= sizeof(*tt_vlan) * num_vlan;
40077ea7b4a1SAntonio Quartulli 
4008298e6e68SAntonio Quartulli 	num_entries = batadv_tt_entries(tvlv_value_len);
4009e1bf0c14SMarek Lindner 
40107ea7b4a1SAntonio Quartulli 	batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change,
40117ea7b4a1SAntonio Quartulli 			      num_entries, tt_data->ttvn);
4012e1bf0c14SMarek Lindner }
4013e1bf0c14SMarek Lindner 
4014e1bf0c14SMarek Lindner /**
40157e9a8c2cSSven Eckelmann  * batadv_tt_tvlv_unicast_handler_v1() - process incoming (unicast) tt tvlv
4016335fbe0fSMarek Lindner  *  container
4017335fbe0fSMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
4018335fbe0fSMarek Lindner  * @src: mac address of tt tvlv sender
4019335fbe0fSMarek Lindner  * @dst: mac address of tt tvlv recipient
4020335fbe0fSMarek Lindner  * @tvlv_value: tvlv buffer containing the tt data
4021335fbe0fSMarek Lindner  * @tvlv_value_len: tvlv buffer length
4022335fbe0fSMarek Lindner  *
402362fe710fSSven Eckelmann  * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS
4024335fbe0fSMarek Lindner  * otherwise.
4025335fbe0fSMarek Lindner  */
batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv * bat_priv,u8 * src,u8 * dst,void * tvlv_value,u16 tvlv_value_len)4026335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
40276b5e971aSSven Eckelmann 					     u8 *src, u8 *dst,
4028335fbe0fSMarek Lindner 					     void *tvlv_value,
40296b5e971aSSven Eckelmann 					     u16 tvlv_value_len)
4030335fbe0fSMarek Lindner {
4031335fbe0fSMarek Lindner 	struct batadv_tvlv_tt_data *tt_data;
40326b5e971aSSven Eckelmann 	u16 tt_vlan_len, tt_num_entries;
4033335fbe0fSMarek Lindner 	char tt_flag;
4034335fbe0fSMarek Lindner 	bool ret;
4035335fbe0fSMarek Lindner 
4036335fbe0fSMarek Lindner 	if (tvlv_value_len < sizeof(*tt_data))
4037335fbe0fSMarek Lindner 		return NET_RX_SUCCESS;
4038335fbe0fSMarek Lindner 
40398864d2fcSYu Zhe 	tt_data = tvlv_value;
4040335fbe0fSMarek Lindner 	tvlv_value_len -= sizeof(*tt_data);
4041335fbe0fSMarek Lindner 
40427ea7b4a1SAntonio Quartulli 	tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data);
40437ea7b4a1SAntonio Quartulli 	tt_vlan_len *= ntohs(tt_data->num_vlan);
40447ea7b4a1SAntonio Quartulli 
40457ea7b4a1SAntonio Quartulli 	if (tvlv_value_len < tt_vlan_len)
40467ea7b4a1SAntonio Quartulli 		return NET_RX_SUCCESS;
40477ea7b4a1SAntonio Quartulli 
40487ea7b4a1SAntonio Quartulli 	tvlv_value_len -= tt_vlan_len;
40497ea7b4a1SAntonio Quartulli 	tt_num_entries = batadv_tt_entries(tvlv_value_len);
4050335fbe0fSMarek Lindner 
4051335fbe0fSMarek Lindner 	switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
4052335fbe0fSMarek Lindner 	case BATADV_TT_REQUEST:
4053335fbe0fSMarek Lindner 		batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX);
4054335fbe0fSMarek Lindner 
4055335fbe0fSMarek Lindner 		/* If this node cannot provide a TT response the tt_request is
4056335fbe0fSMarek Lindner 		 * forwarded
4057335fbe0fSMarek Lindner 		 */
4058335fbe0fSMarek Lindner 		ret = batadv_send_tt_response(bat_priv, tt_data, src, dst);
4059335fbe0fSMarek Lindner 		if (!ret) {
4060335fbe0fSMarek Lindner 			if (tt_data->flags & BATADV_TT_FULL_TABLE)
4061335fbe0fSMarek Lindner 				tt_flag = 'F';
4062335fbe0fSMarek Lindner 			else
4063335fbe0fSMarek Lindner 				tt_flag = '.';
4064335fbe0fSMarek Lindner 
4065335fbe0fSMarek Lindner 			batadv_dbg(BATADV_DBG_TT, bat_priv,
4066335fbe0fSMarek Lindner 				   "Routing TT_REQUEST to %pM [%c]\n",
4067335fbe0fSMarek Lindner 				   dst, tt_flag);
4068335fbe0fSMarek Lindner 			/* tvlv API will re-route the packet */
4069335fbe0fSMarek Lindner 			return NET_RX_DROP;
4070335fbe0fSMarek Lindner 		}
4071335fbe0fSMarek Lindner 		break;
4072335fbe0fSMarek Lindner 	case BATADV_TT_RESPONSE:
4073335fbe0fSMarek Lindner 		batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
4074335fbe0fSMarek Lindner 
4075335fbe0fSMarek Lindner 		if (batadv_is_my_mac(bat_priv, dst)) {
4076335fbe0fSMarek Lindner 			batadv_handle_tt_response(bat_priv, tt_data,
40777ea7b4a1SAntonio Quartulli 						  src, tt_num_entries);
4078335fbe0fSMarek Lindner 			return NET_RX_SUCCESS;
4079335fbe0fSMarek Lindner 		}
4080335fbe0fSMarek Lindner 
4081335fbe0fSMarek Lindner 		if (tt_data->flags & BATADV_TT_FULL_TABLE)
4082335fbe0fSMarek Lindner 			tt_flag =  'F';
4083335fbe0fSMarek Lindner 		else
4084335fbe0fSMarek Lindner 			tt_flag = '.';
4085335fbe0fSMarek Lindner 
4086335fbe0fSMarek Lindner 		batadv_dbg(BATADV_DBG_TT, bat_priv,
4087335fbe0fSMarek Lindner 			   "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag);
4088335fbe0fSMarek Lindner 
4089335fbe0fSMarek Lindner 		/* tvlv API will re-route the packet */
4090335fbe0fSMarek Lindner 		return NET_RX_DROP;
4091335fbe0fSMarek Lindner 	}
4092335fbe0fSMarek Lindner 
4093335fbe0fSMarek Lindner 	return NET_RX_SUCCESS;
4094335fbe0fSMarek Lindner }
4095335fbe0fSMarek Lindner 
4096335fbe0fSMarek Lindner /**
40977e9a8c2cSSven Eckelmann  * batadv_roam_tvlv_unicast_handler_v1() - process incoming tt roam tvlv
40987e9a8c2cSSven Eckelmann  *  container
4099122edaa0SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
4100122edaa0SMarek Lindner  * @src: mac address of tt tvlv sender
4101122edaa0SMarek Lindner  * @dst: mac address of tt tvlv recipient
4102122edaa0SMarek Lindner  * @tvlv_value: tvlv buffer containing the tt data
4103122edaa0SMarek Lindner  * @tvlv_value_len: tvlv buffer length
4104122edaa0SMarek Lindner  *
410562fe710fSSven Eckelmann  * Return: NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS
4106122edaa0SMarek Lindner  * otherwise.
4107122edaa0SMarek Lindner  */
batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv * bat_priv,u8 * src,u8 * dst,void * tvlv_value,u16 tvlv_value_len)4108122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
41096b5e971aSSven Eckelmann 					       u8 *src, u8 *dst,
4110122edaa0SMarek Lindner 					       void *tvlv_value,
41116b5e971aSSven Eckelmann 					       u16 tvlv_value_len)
4112122edaa0SMarek Lindner {
4113122edaa0SMarek Lindner 	struct batadv_tvlv_roam_adv *roaming_adv;
4114122edaa0SMarek Lindner 	struct batadv_orig_node *orig_node = NULL;
4115122edaa0SMarek Lindner 
4116122edaa0SMarek Lindner 	/* If this node is not the intended recipient of the
4117122edaa0SMarek Lindner 	 * roaming advertisement the packet is forwarded
4118122edaa0SMarek Lindner 	 * (the tvlv API will re-route the packet).
4119122edaa0SMarek Lindner 	 */
4120122edaa0SMarek Lindner 	if (!batadv_is_my_mac(bat_priv, dst))
4121122edaa0SMarek Lindner 		return NET_RX_DROP;
4122122edaa0SMarek Lindner 
4123122edaa0SMarek Lindner 	if (tvlv_value_len < sizeof(*roaming_adv))
4124122edaa0SMarek Lindner 		goto out;
4125122edaa0SMarek Lindner 
4126122edaa0SMarek Lindner 	orig_node = batadv_orig_hash_find(bat_priv, src);
4127122edaa0SMarek Lindner 	if (!orig_node)
4128122edaa0SMarek Lindner 		goto out;
4129122edaa0SMarek Lindner 
4130122edaa0SMarek Lindner 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
41318864d2fcSYu Zhe 	roaming_adv = tvlv_value;
4132122edaa0SMarek Lindner 
4133122edaa0SMarek Lindner 	batadv_dbg(BATADV_DBG_TT, bat_priv,
4134122edaa0SMarek Lindner 		   "Received ROAMING_ADV from %pM (client %pM)\n",
4135122edaa0SMarek Lindner 		   src, roaming_adv->client);
4136122edaa0SMarek Lindner 
4137122edaa0SMarek Lindner 	batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client,
4138c018ad3dSAntonio Quartulli 			     ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM,
4139122edaa0SMarek Lindner 			     atomic_read(&orig_node->last_ttvn) + 1);
4140122edaa0SMarek Lindner 
4141122edaa0SMarek Lindner out:
41425d967310SSven Eckelmann 	batadv_orig_node_put(orig_node);
4143122edaa0SMarek Lindner 	return NET_RX_SUCCESS;
4144122edaa0SMarek Lindner }
4145122edaa0SMarek Lindner 
4146122edaa0SMarek Lindner /**
41477e9a8c2cSSven Eckelmann  * batadv_tt_init() - initialise the translation table internals
4148e1bf0c14SMarek Lindner  * @bat_priv: the bat priv with all the soft interface information
4149e1bf0c14SMarek Lindner  *
415062fe710fSSven Eckelmann  * Return: 0 on success or negative error number in case of failure.
4151e1bf0c14SMarek Lindner  */
batadv_tt_init(struct batadv_priv * bat_priv)4152e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv)
4153e1bf0c14SMarek Lindner {
4154e1bf0c14SMarek Lindner 	int ret;
4155e1bf0c14SMarek Lindner 
41560eb01568SAntonio Quartulli 	/* synchronized flags must be remote */
41570eb01568SAntonio Quartulli 	BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK));
41580eb01568SAntonio Quartulli 
4159e1bf0c14SMarek Lindner 	ret = batadv_tt_local_init(bat_priv);
4160e1bf0c14SMarek Lindner 	if (ret < 0)
4161e1bf0c14SMarek Lindner 		return ret;
4162e1bf0c14SMarek Lindner 
4163e1bf0c14SMarek Lindner 	ret = batadv_tt_global_init(bat_priv);
41646f68cd63SPavel Skripkin 	if (ret < 0) {
41656f68cd63SPavel Skripkin 		batadv_tt_local_table_free(bat_priv);
4166e1bf0c14SMarek Lindner 		return ret;
41676f68cd63SPavel Skripkin 	}
4168e1bf0c14SMarek Lindner 
4169e1bf0c14SMarek Lindner 	batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1,
41700c4061c0SLinus Lüssing 				     batadv_tt_tvlv_unicast_handler_v1, NULL,
4171335fbe0fSMarek Lindner 				     BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
4172e1bf0c14SMarek Lindner 
4173122edaa0SMarek Lindner 	batadv_tvlv_handler_register(bat_priv, NULL,
41740c4061c0SLinus Lüssing 				     batadv_roam_tvlv_unicast_handler_v1, NULL,
4175122edaa0SMarek Lindner 				     BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS);
4176122edaa0SMarek Lindner 
4177e1bf0c14SMarek Lindner 	INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
4178e1bf0c14SMarek Lindner 	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
4179e1bf0c14SMarek Lindner 			   msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
4180e1bf0c14SMarek Lindner 
4181e1bf0c14SMarek Lindner 	return 1;
4182e1bf0c14SMarek Lindner }
418342cb0befSAntonio Quartulli 
418442cb0befSAntonio Quartulli /**
41857e9a8c2cSSven Eckelmann  * batadv_tt_global_is_isolated() - check if a client is marked as isolated
418642cb0befSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
418742cb0befSAntonio Quartulli  * @addr: the mac address of the client
418842cb0befSAntonio Quartulli  * @vid: the identifier of the VLAN where this client is connected
418942cb0befSAntonio Quartulli  *
419062fe710fSSven Eckelmann  * Return: true if the client is marked with the TT_CLIENT_ISOLA flag, false
419142cb0befSAntonio Quartulli  * otherwise
419242cb0befSAntonio Quartulli  */
batadv_tt_global_is_isolated(struct batadv_priv * bat_priv,const u8 * addr,unsigned short vid)419342cb0befSAntonio Quartulli bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
41946b5e971aSSven Eckelmann 				  const u8 *addr, unsigned short vid)
419542cb0befSAntonio Quartulli {
419642cb0befSAntonio Quartulli 	struct batadv_tt_global_entry *tt;
419742cb0befSAntonio Quartulli 	bool ret;
419842cb0befSAntonio Quartulli 
419942cb0befSAntonio Quartulli 	tt = batadv_tt_global_hash_find(bat_priv, addr, vid);
420042cb0befSAntonio Quartulli 	if (!tt)
420142cb0befSAntonio Quartulli 		return false;
420242cb0befSAntonio Quartulli 
420342cb0befSAntonio Quartulli 	ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
420442cb0befSAntonio Quartulli 
42055dafd8a6SSven Eckelmann 	batadv_tt_global_entry_put(tt);
420642cb0befSAntonio Quartulli 
420742cb0befSAntonio Quartulli 	return ret;
420842cb0befSAntonio Quartulli }
420986452f81SSven Eckelmann 
421086452f81SSven Eckelmann /**
42117e9a8c2cSSven Eckelmann  * batadv_tt_cache_init() - Initialize tt memory object cache
421286452f81SSven Eckelmann  *
421386452f81SSven Eckelmann  * Return: 0 on success or negative error number in case of failure.
421486452f81SSven Eckelmann  */
batadv_tt_cache_init(void)421586452f81SSven Eckelmann int __init batadv_tt_cache_init(void)
421686452f81SSven Eckelmann {
421786452f81SSven Eckelmann 	size_t tl_size = sizeof(struct batadv_tt_local_entry);
421886452f81SSven Eckelmann 	size_t tg_size = sizeof(struct batadv_tt_global_entry);
421986452f81SSven Eckelmann 	size_t tt_orig_size = sizeof(struct batadv_tt_orig_list_entry);
422086452f81SSven Eckelmann 	size_t tt_change_size = sizeof(struct batadv_tt_change_node);
422186452f81SSven Eckelmann 	size_t tt_req_size = sizeof(struct batadv_tt_req_node);
422286452f81SSven Eckelmann 	size_t tt_roam_size = sizeof(struct batadv_tt_roam_node);
422386452f81SSven Eckelmann 
422486452f81SSven Eckelmann 	batadv_tl_cache = kmem_cache_create("batadv_tl_cache", tl_size, 0,
422586452f81SSven Eckelmann 					    SLAB_HWCACHE_ALIGN, NULL);
422686452f81SSven Eckelmann 	if (!batadv_tl_cache)
422786452f81SSven Eckelmann 		return -ENOMEM;
422886452f81SSven Eckelmann 
422986452f81SSven Eckelmann 	batadv_tg_cache = kmem_cache_create("batadv_tg_cache", tg_size, 0,
423086452f81SSven Eckelmann 					    SLAB_HWCACHE_ALIGN, NULL);
423186452f81SSven Eckelmann 	if (!batadv_tg_cache)
423286452f81SSven Eckelmann 		goto err_tt_tl_destroy;
423386452f81SSven Eckelmann 
423486452f81SSven Eckelmann 	batadv_tt_orig_cache = kmem_cache_create("batadv_tt_orig_cache",
423586452f81SSven Eckelmann 						 tt_orig_size, 0,
423686452f81SSven Eckelmann 						 SLAB_HWCACHE_ALIGN, NULL);
423786452f81SSven Eckelmann 	if (!batadv_tt_orig_cache)
423886452f81SSven Eckelmann 		goto err_tt_tg_destroy;
423986452f81SSven Eckelmann 
424086452f81SSven Eckelmann 	batadv_tt_change_cache = kmem_cache_create("batadv_tt_change_cache",
424186452f81SSven Eckelmann 						   tt_change_size, 0,
424286452f81SSven Eckelmann 						   SLAB_HWCACHE_ALIGN, NULL);
424386452f81SSven Eckelmann 	if (!batadv_tt_change_cache)
424486452f81SSven Eckelmann 		goto err_tt_orig_destroy;
424586452f81SSven Eckelmann 
424686452f81SSven Eckelmann 	batadv_tt_req_cache = kmem_cache_create("batadv_tt_req_cache",
424786452f81SSven Eckelmann 						tt_req_size, 0,
424886452f81SSven Eckelmann 						SLAB_HWCACHE_ALIGN, NULL);
424986452f81SSven Eckelmann 	if (!batadv_tt_req_cache)
425086452f81SSven Eckelmann 		goto err_tt_change_destroy;
425186452f81SSven Eckelmann 
425286452f81SSven Eckelmann 	batadv_tt_roam_cache = kmem_cache_create("batadv_tt_roam_cache",
425386452f81SSven Eckelmann 						 tt_roam_size, 0,
425486452f81SSven Eckelmann 						 SLAB_HWCACHE_ALIGN, NULL);
425586452f81SSven Eckelmann 	if (!batadv_tt_roam_cache)
425686452f81SSven Eckelmann 		goto err_tt_req_destroy;
425786452f81SSven Eckelmann 
425886452f81SSven Eckelmann 	return 0;
425986452f81SSven Eckelmann 
426086452f81SSven Eckelmann err_tt_req_destroy:
426186452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tt_req_cache);
426286452f81SSven Eckelmann 	batadv_tt_req_cache = NULL;
426386452f81SSven Eckelmann err_tt_change_destroy:
426486452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tt_change_cache);
426586452f81SSven Eckelmann 	batadv_tt_change_cache = NULL;
426686452f81SSven Eckelmann err_tt_orig_destroy:
426786452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tt_orig_cache);
426886452f81SSven Eckelmann 	batadv_tt_orig_cache = NULL;
426986452f81SSven Eckelmann err_tt_tg_destroy:
427086452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tg_cache);
427186452f81SSven Eckelmann 	batadv_tg_cache = NULL;
427286452f81SSven Eckelmann err_tt_tl_destroy:
427386452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tl_cache);
427486452f81SSven Eckelmann 	batadv_tl_cache = NULL;
427586452f81SSven Eckelmann 
427686452f81SSven Eckelmann 	return -ENOMEM;
427786452f81SSven Eckelmann }
427886452f81SSven Eckelmann 
427986452f81SSven Eckelmann /**
42807e9a8c2cSSven Eckelmann  * batadv_tt_cache_destroy() - Destroy tt memory object cache
428186452f81SSven Eckelmann  */
batadv_tt_cache_destroy(void)428286452f81SSven Eckelmann void batadv_tt_cache_destroy(void)
428386452f81SSven Eckelmann {
428486452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tl_cache);
428586452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tg_cache);
428686452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tt_orig_cache);
428786452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tt_change_cache);
428886452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tt_req_cache);
428986452f81SSven Eckelmann 	kmem_cache_destroy(batadv_tt_roam_cache);
429086452f81SSven Eckelmann }
4291