1c6c8fea2SSven Eckelmann /*
264afe353SSven Eckelmann  * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
3c6c8fea2SSven Eckelmann  *
4c6c8fea2SSven Eckelmann  * Marek Lindner, Simon Wunderlich
5c6c8fea2SSven Eckelmann  *
6c6c8fea2SSven Eckelmann  * This program is free software; you can redistribute it and/or
7c6c8fea2SSven Eckelmann  * modify it under the terms of version 2 of the GNU General Public
8c6c8fea2SSven Eckelmann  * License as published by the Free Software Foundation.
9c6c8fea2SSven Eckelmann  *
10c6c8fea2SSven Eckelmann  * This program is distributed in the hope that it will be useful, but
11c6c8fea2SSven Eckelmann  * WITHOUT ANY WARRANTY; without even the implied warranty of
12c6c8fea2SSven Eckelmann  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13c6c8fea2SSven Eckelmann  * General Public License for more details.
14c6c8fea2SSven Eckelmann  *
15c6c8fea2SSven Eckelmann  * You should have received a copy of the GNU General Public License
16c6c8fea2SSven Eckelmann  * along with this program; if not, write to the Free Software
17c6c8fea2SSven Eckelmann  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18c6c8fea2SSven Eckelmann  * 02110-1301, USA
19c6c8fea2SSven Eckelmann  *
20c6c8fea2SSven Eckelmann  */
21c6c8fea2SSven Eckelmann 
22c6c8fea2SSven Eckelmann #include "main.h"
23c6c8fea2SSven Eckelmann #include "translation-table.h"
24c6c8fea2SSven Eckelmann #include "soft-interface.h"
2532ae9b22SMarek Lindner #include "hard-interface.h"
26a73105b8SAntonio Quartulli #include "send.h"
27c6c8fea2SSven Eckelmann #include "hash.h"
28c6c8fea2SSven Eckelmann #include "originator.h"
29a73105b8SAntonio Quartulli #include "routing.h"
30c6c8fea2SSven Eckelmann 
31a73105b8SAntonio Quartulli #include <linux/crc16.h>
32a73105b8SAntonio Quartulli 
33a73105b8SAntonio Quartulli static void _tt_global_del(struct bat_priv *bat_priv,
342dafb49dSAntonio Quartulli 			   struct tt_global_entry *tt_global_entry,
35747e4221SSven Eckelmann 			   const char *message);
36a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work);
37c6c8fea2SSven Eckelmann 
387aadf889SMarek Lindner /* returns 1 if they are the same mac addr */
3948100bacSAntonio Quartulli static int compare_tt(const struct hlist_node *node, const void *data2)
407aadf889SMarek Lindner {
4148100bacSAntonio Quartulli 	const void *data1 = container_of(node, struct tt_common_entry,
42747e4221SSven Eckelmann 					 hash_entry);
437aadf889SMarek Lindner 
447aadf889SMarek Lindner 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
457aadf889SMarek Lindner }
467aadf889SMarek Lindner 
47a73105b8SAntonio Quartulli static void tt_start_timer(struct bat_priv *bat_priv)
48c6c8fea2SSven Eckelmann {
49a73105b8SAntonio Quartulli 	INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
50a73105b8SAntonio Quartulli 	queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
51a73105b8SAntonio Quartulli 			   msecs_to_jiffies(5000));
52c6c8fea2SSven Eckelmann }
53c6c8fea2SSven Eckelmann 
5448100bacSAntonio Quartulli static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash,
55747e4221SSven Eckelmann 					    const void *data)
567aadf889SMarek Lindner {
577aadf889SMarek Lindner 	struct hlist_head *head;
587aadf889SMarek Lindner 	struct hlist_node *node;
5948100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL;
60c90681b8SAntonio Quartulli 	uint32_t index;
617aadf889SMarek Lindner 
627aadf889SMarek Lindner 	if (!hash)
637aadf889SMarek Lindner 		return NULL;
647aadf889SMarek Lindner 
657aadf889SMarek Lindner 	index = choose_orig(data, hash->size);
667aadf889SMarek Lindner 	head = &hash->table[index];
677aadf889SMarek Lindner 
687aadf889SMarek Lindner 	rcu_read_lock();
6948100bacSAntonio Quartulli 	hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) {
7048100bacSAntonio Quartulli 		if (!compare_eth(tt_common_entry, data))
717aadf889SMarek Lindner 			continue;
727aadf889SMarek Lindner 
7348100bacSAntonio Quartulli 		if (!atomic_inc_not_zero(&tt_common_entry->refcount))
747683fdc1SAntonio Quartulli 			continue;
757683fdc1SAntonio Quartulli 
7648100bacSAntonio Quartulli 		tt_common_entry_tmp = tt_common_entry;
777aadf889SMarek Lindner 		break;
787aadf889SMarek Lindner 	}
797aadf889SMarek Lindner 	rcu_read_unlock();
807aadf889SMarek Lindner 
8148100bacSAntonio Quartulli 	return tt_common_entry_tmp;
8248100bacSAntonio Quartulli }
8348100bacSAntonio Quartulli 
8448100bacSAntonio Quartulli static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
8548100bacSAntonio Quartulli 						 const void *data)
8648100bacSAntonio Quartulli {
8748100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
8848100bacSAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
8948100bacSAntonio Quartulli 
9048100bacSAntonio Quartulli 	tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data);
9148100bacSAntonio Quartulli 	if (tt_common_entry)
9248100bacSAntonio Quartulli 		tt_local_entry = container_of(tt_common_entry,
9348100bacSAntonio Quartulli 					      struct tt_local_entry, common);
9448100bacSAntonio Quartulli 	return tt_local_entry;
957aadf889SMarek Lindner }
967aadf889SMarek Lindner 
972dafb49dSAntonio Quartulli static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
98747e4221SSven Eckelmann 						   const void *data)
997aadf889SMarek Lindner {
10048100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
10148100bacSAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
1027aadf889SMarek Lindner 
10348100bacSAntonio Quartulli 	tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data);
10448100bacSAntonio Quartulli 	if (tt_common_entry)
10548100bacSAntonio Quartulli 		tt_global_entry = container_of(tt_common_entry,
10648100bacSAntonio Quartulli 					       struct tt_global_entry, common);
10748100bacSAntonio Quartulli 	return tt_global_entry;
1087aadf889SMarek Lindner 
1097aadf889SMarek Lindner }
1107aadf889SMarek Lindner 
111a73105b8SAntonio Quartulli static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
112a73105b8SAntonio Quartulli {
113a73105b8SAntonio Quartulli 	unsigned long deadline;
114a73105b8SAntonio Quartulli 	deadline = starting_time + msecs_to_jiffies(timeout);
115a73105b8SAntonio Quartulli 
116a73105b8SAntonio Quartulli 	return time_after(jiffies, deadline);
117a73105b8SAntonio Quartulli }
118a73105b8SAntonio Quartulli 
1197683fdc1SAntonio Quartulli static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
1207683fdc1SAntonio Quartulli {
12148100bacSAntonio Quartulli 	if (atomic_dec_and_test(&tt_local_entry->common.refcount))
12248100bacSAntonio Quartulli 		kfree_rcu(tt_local_entry, common.rcu);
1237683fdc1SAntonio Quartulli }
1247683fdc1SAntonio Quartulli 
125531027fcSSimon Wunderlich static void tt_global_entry_free_rcu(struct rcu_head *rcu)
126531027fcSSimon Wunderlich {
12748100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
128531027fcSSimon Wunderlich 	struct tt_global_entry *tt_global_entry;
129531027fcSSimon Wunderlich 
13048100bacSAntonio Quartulli 	tt_common_entry = container_of(rcu, struct tt_common_entry, rcu);
13148100bacSAntonio Quartulli 	tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
13248100bacSAntonio Quartulli 				       common);
133531027fcSSimon Wunderlich 
134531027fcSSimon Wunderlich 	if (tt_global_entry->orig_node)
135531027fcSSimon Wunderlich 		orig_node_free_ref(tt_global_entry->orig_node);
136531027fcSSimon Wunderlich 
137531027fcSSimon Wunderlich 	kfree(tt_global_entry);
138531027fcSSimon Wunderlich }
139531027fcSSimon Wunderlich 
1407683fdc1SAntonio Quartulli static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
1417683fdc1SAntonio Quartulli {
14248100bacSAntonio Quartulli 	if (atomic_dec_and_test(&tt_global_entry->common.refcount))
14348100bacSAntonio Quartulli 		call_rcu(&tt_global_entry->common.rcu,
14448100bacSAntonio Quartulli 			 tt_global_entry_free_rcu);
1457683fdc1SAntonio Quartulli }
1467683fdc1SAntonio Quartulli 
147ff66c975SAntonio Quartulli static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
148ff66c975SAntonio Quartulli 			   uint8_t flags)
149a73105b8SAntonio Quartulli {
150a73105b8SAntonio Quartulli 	struct tt_change_node *tt_change_node;
151a73105b8SAntonio Quartulli 
152a73105b8SAntonio Quartulli 	tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
153a73105b8SAntonio Quartulli 
154a73105b8SAntonio Quartulli 	if (!tt_change_node)
155a73105b8SAntonio Quartulli 		return;
156a73105b8SAntonio Quartulli 
157ff66c975SAntonio Quartulli 	tt_change_node->change.flags = flags;
158a73105b8SAntonio Quartulli 	memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
159a73105b8SAntonio Quartulli 
160a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
161a73105b8SAntonio Quartulli 	/* track the change in the OGMinterval list */
162a73105b8SAntonio Quartulli 	list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
163a73105b8SAntonio Quartulli 	atomic_inc(&bat_priv->tt_local_changes);
164a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
165a73105b8SAntonio Quartulli 
166a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
167a73105b8SAntonio Quartulli }
168a73105b8SAntonio Quartulli 
169a73105b8SAntonio Quartulli int tt_len(int changes_num)
170a73105b8SAntonio Quartulli {
171a73105b8SAntonio Quartulli 	return changes_num * sizeof(struct tt_change);
172a73105b8SAntonio Quartulli }
173a73105b8SAntonio Quartulli 
174a73105b8SAntonio Quartulli static int tt_local_init(struct bat_priv *bat_priv)
175c6c8fea2SSven Eckelmann {
1762dafb49dSAntonio Quartulli 	if (bat_priv->tt_local_hash)
177c6c8fea2SSven Eckelmann 		return 1;
178c6c8fea2SSven Eckelmann 
1792dafb49dSAntonio Quartulli 	bat_priv->tt_local_hash = hash_new(1024);
180c6c8fea2SSven Eckelmann 
1812dafb49dSAntonio Quartulli 	if (!bat_priv->tt_local_hash)
182c6c8fea2SSven Eckelmann 		return 0;
183c6c8fea2SSven Eckelmann 
184c6c8fea2SSven Eckelmann 	return 1;
185c6c8fea2SSven Eckelmann }
186c6c8fea2SSven Eckelmann 
187bc279080SAntonio Quartulli void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
188bc279080SAntonio Quartulli 		  int ifindex)
189c6c8fea2SSven Eckelmann {
190c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
1917683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
1927683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
19380b3f58cSSimon Wunderlich 	int hash_added;
194c6c8fea2SSven Eckelmann 
1952dafb49dSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
196c6c8fea2SSven Eckelmann 
1972dafb49dSAntonio Quartulli 	if (tt_local_entry) {
1982dafb49dSAntonio Quartulli 		tt_local_entry->last_seen = jiffies;
1997683fdc1SAntonio Quartulli 		goto out;
200c6c8fea2SSven Eckelmann 	}
201c6c8fea2SSven Eckelmann 
202704509b8SSven Eckelmann 	tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
2032dafb49dSAntonio Quartulli 	if (!tt_local_entry)
2047683fdc1SAntonio Quartulli 		goto out;
205a73105b8SAntonio Quartulli 
206a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
207a73105b8SAntonio Quartulli 		"Creating new local tt entry: %pM (ttvn: %d)\n", addr,
208a73105b8SAntonio Quartulli 		(uint8_t)atomic_read(&bat_priv->ttvn));
209c6c8fea2SSven Eckelmann 
21048100bacSAntonio Quartulli 	memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
21148100bacSAntonio Quartulli 	tt_local_entry->common.flags = NO_FLAGS;
212bc279080SAntonio Quartulli 	if (is_wifi_iface(ifindex))
21348100bacSAntonio Quartulli 		tt_local_entry->common.flags |= TT_CLIENT_WIFI;
21448100bacSAntonio Quartulli 	atomic_set(&tt_local_entry->common.refcount, 2);
21548100bacSAntonio Quartulli 	tt_local_entry->last_seen = jiffies;
216c6c8fea2SSven Eckelmann 
217c6c8fea2SSven Eckelmann 	/* the batman interface mac address should never be purged */
21839901e71SMarek Lindner 	if (compare_eth(addr, soft_iface->dev_addr))
21948100bacSAntonio Quartulli 		tt_local_entry->common.flags |= TT_CLIENT_NOPURGE;
220c6c8fea2SSven Eckelmann 
22180b3f58cSSimon Wunderlich 	hash_added = hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig,
22280b3f58cSSimon Wunderlich 			 &tt_local_entry->common,
22380b3f58cSSimon Wunderlich 			 &tt_local_entry->common.hash_entry);
22480b3f58cSSimon Wunderlich 
22580b3f58cSSimon Wunderlich 	if (unlikely(hash_added != 0)) {
22680b3f58cSSimon Wunderlich 		/* remove the reference for the hash */
22780b3f58cSSimon Wunderlich 		tt_local_entry_free_ref(tt_local_entry);
22880b3f58cSSimon Wunderlich 		goto out;
22980b3f58cSSimon Wunderlich 	}
23080b3f58cSSimon Wunderlich 
23148100bacSAntonio Quartulli 	tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
232ff66c975SAntonio Quartulli 
233058d0e26SAntonio Quartulli 	/* The local entry has to be marked as NEW to avoid to send it in
234058d0e26SAntonio Quartulli 	 * a full table response going out before the next ttvn increment
235058d0e26SAntonio Quartulli 	 * (consistency check) */
23648100bacSAntonio Quartulli 	tt_local_entry->common.flags |= TT_CLIENT_NEW;
237058d0e26SAntonio Quartulli 
238c6c8fea2SSven Eckelmann 	/* remove address from global hash if present */
2392dafb49dSAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
240c6c8fea2SSven Eckelmann 
241cc47f66eSAntonio Quartulli 	/* Check whether it is a roaming! */
242cc47f66eSAntonio Quartulli 	if (tt_global_entry) {
243cc47f66eSAntonio Quartulli 		/* This node is probably going to update its tt table */
244cc47f66eSAntonio Quartulli 		tt_global_entry->orig_node->tt_poss_change = true;
24503fc3070SAntonio Quartulli 		/* The global entry has to be marked as ROAMING and has to be
246980d55b2SAntonio Quartulli 		 * kept for consistency purpose */
247220b07e9SDavid S. Miller 		tt_global_entry->common.flags |= TT_CLIENT_ROAM;
24803fc3070SAntonio Quartulli 		tt_global_entry->roam_at = jiffies;
24948100bacSAntonio Quartulli 		send_roam_adv(bat_priv, tt_global_entry->common.addr,
250cc47f66eSAntonio Quartulli 			      tt_global_entry->orig_node);
2517683fdc1SAntonio Quartulli 	}
2527683fdc1SAntonio Quartulli out:
2537683fdc1SAntonio Quartulli 	if (tt_local_entry)
2547683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
2557683fdc1SAntonio Quartulli 	if (tt_global_entry)
2567683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
257c6c8fea2SSven Eckelmann }
258c6c8fea2SSven Eckelmann 
259a73105b8SAntonio Quartulli int tt_changes_fill_buffer(struct bat_priv *bat_priv,
260c6c8fea2SSven Eckelmann 			   unsigned char *buff, int buff_len)
261c6c8fea2SSven Eckelmann {
262a73105b8SAntonio Quartulli 	int count = 0, tot_changes = 0;
263a73105b8SAntonio Quartulli 	struct tt_change_node *entry, *safe;
264c6c8fea2SSven Eckelmann 
265a73105b8SAntonio Quartulli 	if (buff_len > 0)
266a73105b8SAntonio Quartulli 		tot_changes = buff_len / tt_len(1);
267c6c8fea2SSven Eckelmann 
268a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
269a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_local_changes, 0);
270c6c8fea2SSven Eckelmann 
271a73105b8SAntonio Quartulli 	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
272a73105b8SAntonio Quartulli 			list) {
273a73105b8SAntonio Quartulli 		if (count < tot_changes) {
274a73105b8SAntonio Quartulli 			memcpy(buff + tt_len(count),
275a73105b8SAntonio Quartulli 			       &entry->change, sizeof(struct tt_change));
276c6c8fea2SSven Eckelmann 			count++;
277c6c8fea2SSven Eckelmann 		}
278a73105b8SAntonio Quartulli 		list_del(&entry->list);
279a73105b8SAntonio Quartulli 		kfree(entry);
280c6c8fea2SSven Eckelmann 	}
281a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
282c6c8fea2SSven Eckelmann 
283a73105b8SAntonio Quartulli 	/* Keep the buffer for possible tt_request */
284a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_buff_lock);
285a73105b8SAntonio Quartulli 	kfree(bat_priv->tt_buff);
286a73105b8SAntonio Quartulli 	bat_priv->tt_buff_len = 0;
287a73105b8SAntonio Quartulli 	bat_priv->tt_buff = NULL;
288a73105b8SAntonio Quartulli 	/* We check whether this new OGM has no changes due to size
289a73105b8SAntonio Quartulli 	 * problems */
290a73105b8SAntonio Quartulli 	if (buff_len > 0) {
291a73105b8SAntonio Quartulli 		/**
292a73105b8SAntonio Quartulli 		 * if kmalloc() fails we will reply with the full table
293a73105b8SAntonio Quartulli 		 * instead of providing the diff
294a73105b8SAntonio Quartulli 		 */
295a73105b8SAntonio Quartulli 		bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
296a73105b8SAntonio Quartulli 		if (bat_priv->tt_buff) {
297a73105b8SAntonio Quartulli 			memcpy(bat_priv->tt_buff, buff, buff_len);
298a73105b8SAntonio Quartulli 			bat_priv->tt_buff_len = buff_len;
299a73105b8SAntonio Quartulli 		}
300a73105b8SAntonio Quartulli 	}
301a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_buff_lock);
302c6c8fea2SSven Eckelmann 
303a73105b8SAntonio Quartulli 	return tot_changes;
304c6c8fea2SSven Eckelmann }
305c6c8fea2SSven Eckelmann 
3062dafb49dSAntonio Quartulli int tt_local_seq_print_text(struct seq_file *seq, void *offset)
307c6c8fea2SSven Eckelmann {
308c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
309c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(net_dev);
3102dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
31148100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
31232ae9b22SMarek Lindner 	struct hard_iface *primary_if;
3137aadf889SMarek Lindner 	struct hlist_node *node;
314c6c8fea2SSven Eckelmann 	struct hlist_head *head;
315c90681b8SAntonio Quartulli 	uint32_t i;
316c90681b8SAntonio Quartulli 	int ret = 0;
317c6c8fea2SSven Eckelmann 
31832ae9b22SMarek Lindner 	primary_if = primary_if_get_selected(bat_priv);
31932ae9b22SMarek Lindner 	if (!primary_if) {
32032ae9b22SMarek Lindner 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
321c6c8fea2SSven Eckelmann 				 "please specify interfaces to enable it\n",
322c6c8fea2SSven Eckelmann 				 net_dev->name);
32332ae9b22SMarek Lindner 		goto out;
32432ae9b22SMarek Lindner 	}
32532ae9b22SMarek Lindner 
32632ae9b22SMarek Lindner 	if (primary_if->if_status != IF_ACTIVE) {
32732ae9b22SMarek Lindner 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
32832ae9b22SMarek Lindner 				 "primary interface not active\n",
32932ae9b22SMarek Lindner 				 net_dev->name);
33032ae9b22SMarek Lindner 		goto out;
331c6c8fea2SSven Eckelmann 	}
332c6c8fea2SSven Eckelmann 
333c6c8fea2SSven Eckelmann 	seq_printf(seq, "Locally retrieved addresses (from %s) "
334a73105b8SAntonio Quartulli 		   "announced via TT (TTVN: %u):\n",
335a73105b8SAntonio Quartulli 		   net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
336c6c8fea2SSven Eckelmann 
337c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
338c6c8fea2SSven Eckelmann 		head = &hash->table[i];
339c6c8fea2SSven Eckelmann 
3407aadf889SMarek Lindner 		rcu_read_lock();
34148100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
3427aadf889SMarek Lindner 					 head, hash_entry) {
343d099c2c5SSimon Wunderlich 			seq_printf(seq, " * %pM [%c%c%c%c%c]\n",
34448100bacSAntonio Quartulli 					tt_common_entry->addr,
34548100bacSAntonio Quartulli 					(tt_common_entry->flags &
346df6edb9eSAntonio Quartulli 					 TT_CLIENT_ROAM ? 'R' : '.'),
34748100bacSAntonio Quartulli 					(tt_common_entry->flags &
348df6edb9eSAntonio Quartulli 					 TT_CLIENT_NOPURGE ? 'P' : '.'),
34948100bacSAntonio Quartulli 					(tt_common_entry->flags &
350df6edb9eSAntonio Quartulli 					 TT_CLIENT_NEW ? 'N' : '.'),
35148100bacSAntonio Quartulli 					(tt_common_entry->flags &
352df6edb9eSAntonio Quartulli 					 TT_CLIENT_PENDING ? 'X' : '.'),
35348100bacSAntonio Quartulli 					(tt_common_entry->flags &
354df6edb9eSAntonio Quartulli 					 TT_CLIENT_WIFI ? 'W' : '.'));
355c6c8fea2SSven Eckelmann 		}
3567aadf889SMarek Lindner 		rcu_read_unlock();
357c6c8fea2SSven Eckelmann 	}
35832ae9b22SMarek Lindner out:
35932ae9b22SMarek Lindner 	if (primary_if)
36032ae9b22SMarek Lindner 		hardif_free_ref(primary_if);
36132ae9b22SMarek Lindner 	return ret;
362c6c8fea2SSven Eckelmann }
363c6c8fea2SSven Eckelmann 
364058d0e26SAntonio Quartulli static void tt_local_set_pending(struct bat_priv *bat_priv,
3652dafb49dSAntonio Quartulli 				 struct tt_local_entry *tt_local_entry,
366058d0e26SAntonio Quartulli 				 uint16_t flags)
367c6c8fea2SSven Eckelmann {
36848100bacSAntonio Quartulli 	tt_local_event(bat_priv, tt_local_entry->common.addr,
36948100bacSAntonio Quartulli 		       tt_local_entry->common.flags | flags);
370c6c8fea2SSven Eckelmann 
371015758d0SAntonio Quartulli 	/* The local client has to be marked as "pending to be removed" but has
372015758d0SAntonio Quartulli 	 * to be kept in the table in order to send it in a full table
373058d0e26SAntonio Quartulli 	 * response issued before the net ttvn increment (consistency check) */
37448100bacSAntonio Quartulli 	tt_local_entry->common.flags |= TT_CLIENT_PENDING;
375c6c8fea2SSven Eckelmann }
376c6c8fea2SSven Eckelmann 
377a73105b8SAntonio Quartulli void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
378cc47f66eSAntonio Quartulli 		     const char *message, bool roaming)
379c6c8fea2SSven Eckelmann {
3807683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
381c6c8fea2SSven Eckelmann 
3822dafb49dSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
3837683fdc1SAntonio Quartulli 	if (!tt_local_entry)
3847683fdc1SAntonio Quartulli 		goto out;
3857683fdc1SAntonio Quartulli 
386058d0e26SAntonio Quartulli 	tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
387ff66c975SAntonio Quartulli 			     (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
388058d0e26SAntonio Quartulli 
389058d0e26SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
39048100bacSAntonio Quartulli 		"%s\n", tt_local_entry->common.addr, message);
3917683fdc1SAntonio Quartulli out:
3927683fdc1SAntonio Quartulli 	if (tt_local_entry)
3937683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
394c6c8fea2SSven Eckelmann }
395c6c8fea2SSven Eckelmann 
396a73105b8SAntonio Quartulli static void tt_local_purge(struct bat_priv *bat_priv)
397c6c8fea2SSven Eckelmann {
3982dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
3992dafb49dSAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
40048100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
4017aadf889SMarek Lindner 	struct hlist_node *node, *node_tmp;
402c6c8fea2SSven Eckelmann 	struct hlist_head *head;
4037683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
404c90681b8SAntonio Quartulli 	uint32_t i;
405c6c8fea2SSven Eckelmann 
406c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
407c6c8fea2SSven Eckelmann 		head = &hash->table[i];
4087683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
409c6c8fea2SSven Eckelmann 
4107683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
41148100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
4127aadf889SMarek Lindner 					  head, hash_entry) {
41348100bacSAntonio Quartulli 			tt_local_entry = container_of(tt_common_entry,
41448100bacSAntonio Quartulli 						      struct tt_local_entry,
41548100bacSAntonio Quartulli 						      common);
41648100bacSAntonio Quartulli 			if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE)
4177aadf889SMarek Lindner 				continue;
418c6c8fea2SSven Eckelmann 
419058d0e26SAntonio Quartulli 			/* entry already marked for deletion */
42048100bacSAntonio Quartulli 			if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
421058d0e26SAntonio Quartulli 				continue;
422058d0e26SAntonio Quartulli 
423a73105b8SAntonio Quartulli 			if (!is_out_of_time(tt_local_entry->last_seen,
424a73105b8SAntonio Quartulli 					    TT_LOCAL_TIMEOUT * 1000))
4257aadf889SMarek Lindner 				continue;
4267aadf889SMarek Lindner 
427058d0e26SAntonio Quartulli 			tt_local_set_pending(bat_priv, tt_local_entry,
428058d0e26SAntonio Quartulli 					     TT_CLIENT_DEL);
429058d0e26SAntonio Quartulli 			bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
430058d0e26SAntonio Quartulli 				"pending to be removed: timed out\n",
43148100bacSAntonio Quartulli 				tt_local_entry->common.addr);
432c6c8fea2SSven Eckelmann 		}
4337683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
434c6c8fea2SSven Eckelmann 	}
435c6c8fea2SSven Eckelmann 
436c6c8fea2SSven Eckelmann }
437c6c8fea2SSven Eckelmann 
438a73105b8SAntonio Quartulli static void tt_local_table_free(struct bat_priv *bat_priv)
439c6c8fea2SSven Eckelmann {
440a73105b8SAntonio Quartulli 	struct hashtable_t *hash;
441a73105b8SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
44248100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
443a73105b8SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
4447683fdc1SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
4457683fdc1SAntonio Quartulli 	struct hlist_head *head;
446c90681b8SAntonio Quartulli 	uint32_t i;
447a73105b8SAntonio Quartulli 
4482dafb49dSAntonio Quartulli 	if (!bat_priv->tt_local_hash)
449c6c8fea2SSven Eckelmann 		return;
450c6c8fea2SSven Eckelmann 
451a73105b8SAntonio Quartulli 	hash = bat_priv->tt_local_hash;
452a73105b8SAntonio Quartulli 
453a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
454a73105b8SAntonio Quartulli 		head = &hash->table[i];
455a73105b8SAntonio Quartulli 		list_lock = &hash->list_locks[i];
456a73105b8SAntonio Quartulli 
457a73105b8SAntonio Quartulli 		spin_lock_bh(list_lock);
45848100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
459a73105b8SAntonio Quartulli 					  head, hash_entry) {
460a73105b8SAntonio Quartulli 			hlist_del_rcu(node);
46148100bacSAntonio Quartulli 			tt_local_entry = container_of(tt_common_entry,
46248100bacSAntonio Quartulli 						      struct tt_local_entry,
46348100bacSAntonio Quartulli 						      common);
4647683fdc1SAntonio Quartulli 			tt_local_entry_free_ref(tt_local_entry);
465a73105b8SAntonio Quartulli 		}
466a73105b8SAntonio Quartulli 		spin_unlock_bh(list_lock);
467a73105b8SAntonio Quartulli 	}
468a73105b8SAntonio Quartulli 
469a73105b8SAntonio Quartulli 	hash_destroy(hash);
470a73105b8SAntonio Quartulli 
4712dafb49dSAntonio Quartulli 	bat_priv->tt_local_hash = NULL;
472c6c8fea2SSven Eckelmann }
473c6c8fea2SSven Eckelmann 
474a73105b8SAntonio Quartulli static int tt_global_init(struct bat_priv *bat_priv)
475c6c8fea2SSven Eckelmann {
4762dafb49dSAntonio Quartulli 	if (bat_priv->tt_global_hash)
477c6c8fea2SSven Eckelmann 		return 1;
478c6c8fea2SSven Eckelmann 
4792dafb49dSAntonio Quartulli 	bat_priv->tt_global_hash = hash_new(1024);
480c6c8fea2SSven Eckelmann 
4812dafb49dSAntonio Quartulli 	if (!bat_priv->tt_global_hash)
482c6c8fea2SSven Eckelmann 		return 0;
483c6c8fea2SSven Eckelmann 
484c6c8fea2SSven Eckelmann 	return 1;
485c6c8fea2SSven Eckelmann }
486c6c8fea2SSven Eckelmann 
487a73105b8SAntonio Quartulli static void tt_changes_list_free(struct bat_priv *bat_priv)
488a73105b8SAntonio Quartulli {
489a73105b8SAntonio Quartulli 	struct tt_change_node *entry, *safe;
490a73105b8SAntonio Quartulli 
491a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
492a73105b8SAntonio Quartulli 
493a73105b8SAntonio Quartulli 	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
494a73105b8SAntonio Quartulli 				 list) {
495a73105b8SAntonio Quartulli 		list_del(&entry->list);
496a73105b8SAntonio Quartulli 		kfree(entry);
497a73105b8SAntonio Quartulli 	}
498a73105b8SAntonio Quartulli 
499a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_local_changes, 0);
500a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
501a73105b8SAntonio Quartulli }
502a73105b8SAntonio Quartulli 
503a73105b8SAntonio Quartulli /* caller must hold orig_node refcount */
504a73105b8SAntonio Quartulli int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
505bc279080SAntonio Quartulli 		  const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
506bc279080SAntonio Quartulli 		  bool wifi)
507c6c8fea2SSven Eckelmann {
5082dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
509a73105b8SAntonio Quartulli 	struct orig_node *orig_node_tmp;
5107683fdc1SAntonio Quartulli 	int ret = 0;
51180b3f58cSSimon Wunderlich 	int hash_added;
512c6c8fea2SSven Eckelmann 
513a73105b8SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
514c6c8fea2SSven Eckelmann 
5152dafb49dSAntonio Quartulli 	if (!tt_global_entry) {
516a73105b8SAntonio Quartulli 		tt_global_entry =
517a73105b8SAntonio Quartulli 			kmalloc(sizeof(*tt_global_entry),
518c6c8fea2SSven Eckelmann 				GFP_ATOMIC);
5192dafb49dSAntonio Quartulli 		if (!tt_global_entry)
5207683fdc1SAntonio Quartulli 			goto out;
5217683fdc1SAntonio Quartulli 
52248100bacSAntonio Quartulli 		memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
52348100bacSAntonio Quartulli 		tt_global_entry->common.flags = NO_FLAGS;
52448100bacSAntonio Quartulli 		atomic_set(&tt_global_entry->common.refcount, 2);
525a73105b8SAntonio Quartulli 		/* Assign the new orig_node */
526a73105b8SAntonio Quartulli 		atomic_inc(&orig_node->refcount);
527a73105b8SAntonio Quartulli 		tt_global_entry->orig_node = orig_node;
528a73105b8SAntonio Quartulli 		tt_global_entry->ttvn = ttvn;
529cc47f66eSAntonio Quartulli 		tt_global_entry->roam_at = 0;
5307683fdc1SAntonio Quartulli 
53180b3f58cSSimon Wunderlich 		hash_added = hash_add(bat_priv->tt_global_hash, compare_tt,
53248100bacSAntonio Quartulli 				 choose_orig, &tt_global_entry->common,
53348100bacSAntonio Quartulli 				 &tt_global_entry->common.hash_entry);
53480b3f58cSSimon Wunderlich 
53580b3f58cSSimon Wunderlich 		if (unlikely(hash_added != 0)) {
53680b3f58cSSimon Wunderlich 			/* remove the reference for the hash */
53780b3f58cSSimon Wunderlich 			tt_global_entry_free_ref(tt_global_entry);
53880b3f58cSSimon Wunderlich 			goto out_remove;
53980b3f58cSSimon Wunderlich 		}
5407683fdc1SAntonio Quartulli 		atomic_inc(&orig_node->tt_size);
541a73105b8SAntonio Quartulli 	} else {
542a73105b8SAntonio Quartulli 		if (tt_global_entry->orig_node != orig_node) {
543a73105b8SAntonio Quartulli 			atomic_dec(&tt_global_entry->orig_node->tt_size);
544a73105b8SAntonio Quartulli 			orig_node_tmp = tt_global_entry->orig_node;
545a73105b8SAntonio Quartulli 			atomic_inc(&orig_node->refcount);
546a73105b8SAntonio Quartulli 			tt_global_entry->orig_node = orig_node;
547a73105b8SAntonio Quartulli 			orig_node_free_ref(orig_node_tmp);
548a73105b8SAntonio Quartulli 			atomic_inc(&orig_node->tt_size);
549a73105b8SAntonio Quartulli 		}
55048100bacSAntonio Quartulli 		tt_global_entry->common.flags = NO_FLAGS;
551cc47f66eSAntonio Quartulli 		tt_global_entry->ttvn = ttvn;
552cc47f66eSAntonio Quartulli 		tt_global_entry->roam_at = 0;
553c6c8fea2SSven Eckelmann 	}
554c6c8fea2SSven Eckelmann 
555bc279080SAntonio Quartulli 	if (wifi)
55648100bacSAntonio Quartulli 		tt_global_entry->common.flags |= TT_CLIENT_WIFI;
557bc279080SAntonio Quartulli 
558a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
559a73105b8SAntonio Quartulli 		"Creating new global tt entry: %pM (via %pM)\n",
56048100bacSAntonio Quartulli 		tt_global_entry->common.addr, orig_node->orig);
561a73105b8SAntonio Quartulli 
56280b3f58cSSimon Wunderlich out_remove:
563c6c8fea2SSven Eckelmann 	/* remove address from local hash if present */
56448100bacSAntonio Quartulli 	tt_local_remove(bat_priv, tt_global_entry->common.addr,
565cc47f66eSAntonio Quartulli 			"global tt received", roaming);
5667683fdc1SAntonio Quartulli 	ret = 1;
5677683fdc1SAntonio Quartulli out:
5687683fdc1SAntonio Quartulli 	if (tt_global_entry)
5697683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
5707683fdc1SAntonio Quartulli 	return ret;
571c6c8fea2SSven Eckelmann }
572c6c8fea2SSven Eckelmann 
5732dafb49dSAntonio Quartulli int tt_global_seq_print_text(struct seq_file *seq, void *offset)
574c6c8fea2SSven Eckelmann {
575c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
576c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(net_dev);
5772dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
57848100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
5792dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
58032ae9b22SMarek Lindner 	struct hard_iface *primary_if;
5817aadf889SMarek Lindner 	struct hlist_node *node;
582c6c8fea2SSven Eckelmann 	struct hlist_head *head;
583c90681b8SAntonio Quartulli 	uint32_t i;
584c90681b8SAntonio Quartulli 	int ret = 0;
585c6c8fea2SSven Eckelmann 
58632ae9b22SMarek Lindner 	primary_if = primary_if_get_selected(bat_priv);
58732ae9b22SMarek Lindner 	if (!primary_if) {
58832ae9b22SMarek Lindner 		ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
58932ae9b22SMarek Lindner 				 "specify interfaces to enable it\n",
590c6c8fea2SSven Eckelmann 				 net_dev->name);
59132ae9b22SMarek Lindner 		goto out;
59232ae9b22SMarek Lindner 	}
59332ae9b22SMarek Lindner 
59432ae9b22SMarek Lindner 	if (primary_if->if_status != IF_ACTIVE) {
59532ae9b22SMarek Lindner 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
59632ae9b22SMarek Lindner 				 "primary interface not active\n",
59732ae9b22SMarek Lindner 				 net_dev->name);
59832ae9b22SMarek Lindner 		goto out;
599c6c8fea2SSven Eckelmann 	}
600c6c8fea2SSven Eckelmann 
6012dafb49dSAntonio Quartulli 	seq_printf(seq,
6022dafb49dSAntonio Quartulli 		   "Globally announced TT entries received via the mesh %s\n",
603c6c8fea2SSven Eckelmann 		   net_dev->name);
604df6edb9eSAntonio Quartulli 	seq_printf(seq, "       %-13s %s       %-15s %s %s\n",
605df6edb9eSAntonio Quartulli 		   "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
606c6c8fea2SSven Eckelmann 
607c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
608c6c8fea2SSven Eckelmann 		head = &hash->table[i];
609c6c8fea2SSven Eckelmann 
6107aadf889SMarek Lindner 		rcu_read_lock();
61148100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
6127aadf889SMarek Lindner 					 head, hash_entry) {
61348100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
61448100bacSAntonio Quartulli 						       struct tt_global_entry,
61548100bacSAntonio Quartulli 						       common);
616d099c2c5SSimon Wunderlich 			seq_printf(seq, " * %pM  (%3u) via %pM     (%3u)   "
61748100bacSAntonio Quartulli 					"[%c%c%c]\n",
61848100bacSAntonio Quartulli 					tt_global_entry->common.addr,
619a73105b8SAntonio Quartulli 					tt_global_entry->ttvn,
620a73105b8SAntonio Quartulli 					tt_global_entry->orig_node->orig,
621a73105b8SAntonio Quartulli 					(uint8_t) atomic_read(
622a73105b8SAntonio Quartulli 						&tt_global_entry->orig_node->
623df6edb9eSAntonio Quartulli 						last_ttvn),
62448100bacSAntonio Quartulli 					(tt_global_entry->common.flags &
625df6edb9eSAntonio Quartulli 					 TT_CLIENT_ROAM ? 'R' : '.'),
62648100bacSAntonio Quartulli 					(tt_global_entry->common.flags &
627df6edb9eSAntonio Quartulli 					 TT_CLIENT_PENDING ? 'X' : '.'),
62848100bacSAntonio Quartulli 					(tt_global_entry->common.flags &
629df6edb9eSAntonio Quartulli 					 TT_CLIENT_WIFI ? 'W' : '.'));
630c6c8fea2SSven Eckelmann 		}
6317aadf889SMarek Lindner 		rcu_read_unlock();
632c6c8fea2SSven Eckelmann 	}
63332ae9b22SMarek Lindner out:
63432ae9b22SMarek Lindner 	if (primary_if)
63532ae9b22SMarek Lindner 		hardif_free_ref(primary_if);
63632ae9b22SMarek Lindner 	return ret;
637c6c8fea2SSven Eckelmann }
638c6c8fea2SSven Eckelmann 
639a73105b8SAntonio Quartulli static void _tt_global_del(struct bat_priv *bat_priv,
6402dafb49dSAntonio Quartulli 			   struct tt_global_entry *tt_global_entry,
641747e4221SSven Eckelmann 			   const char *message)
642c6c8fea2SSven Eckelmann {
643a73105b8SAntonio Quartulli 	if (!tt_global_entry)
6447683fdc1SAntonio Quartulli 		goto out;
645a73105b8SAntonio Quartulli 
646a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
6472dafb49dSAntonio Quartulli 		"Deleting global tt entry %pM (via %pM): %s\n",
64848100bacSAntonio Quartulli 		tt_global_entry->common.addr, tt_global_entry->orig_node->orig,
649c6c8fea2SSven Eckelmann 		message);
650c6c8fea2SSven Eckelmann 
651a73105b8SAntonio Quartulli 	atomic_dec(&tt_global_entry->orig_node->tt_size);
6527683fdc1SAntonio Quartulli 
65348100bacSAntonio Quartulli 	hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
65448100bacSAntonio Quartulli 		    tt_global_entry->common.addr);
6557683fdc1SAntonio Quartulli out:
6567683fdc1SAntonio Quartulli 	if (tt_global_entry)
6577683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
658c6c8fea2SSven Eckelmann }
659c6c8fea2SSven Eckelmann 
660a73105b8SAntonio Quartulli void tt_global_del(struct bat_priv *bat_priv,
661a73105b8SAntonio Quartulli 		   struct orig_node *orig_node, const unsigned char *addr,
662cc47f66eSAntonio Quartulli 		   const char *message, bool roaming)
663a73105b8SAntonio Quartulli {
6647683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
665797399b4SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
666a73105b8SAntonio Quartulli 
667a73105b8SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
6687683fdc1SAntonio Quartulli 	if (!tt_global_entry)
6697683fdc1SAntonio Quartulli 		goto out;
670a73105b8SAntonio Quartulli 
6717683fdc1SAntonio Quartulli 	if (tt_global_entry->orig_node == orig_node) {
672cc47f66eSAntonio Quartulli 		if (roaming) {
673797399b4SAntonio Quartulli 			/* if we are deleting a global entry due to a roam
674797399b4SAntonio Quartulli 			 * event, there are two possibilities:
675797399b4SAntonio Quartulli 			 * 1) the client roamed from node A to node B => we mark
676797399b4SAntonio Quartulli 			 *    it with TT_CLIENT_ROAM, we start a timer and we
677797399b4SAntonio Quartulli 			 *    wait for node B to claim it. In case of timeout
678797399b4SAntonio Quartulli 			 *    the entry is purged.
679797399b4SAntonio Quartulli 			 * 2) the client roamed to us => we can directly delete
680797399b4SAntonio Quartulli 			 *    the global entry, since it is useless now. */
681797399b4SAntonio Quartulli 			tt_local_entry = tt_local_hash_find(bat_priv,
682b26e478fSDavid S. Miller 							    tt_global_entry->common.addr);
683797399b4SAntonio Quartulli 			if (!tt_local_entry) {
68448100bacSAntonio Quartulli 				tt_global_entry->common.flags |= TT_CLIENT_ROAM;
685cc47f66eSAntonio Quartulli 				tt_global_entry->roam_at = jiffies;
686cc47f66eSAntonio Quartulli 				goto out;
687cc47f66eSAntonio Quartulli 			}
688797399b4SAntonio Quartulli 		}
689a73105b8SAntonio Quartulli 		_tt_global_del(bat_priv, tt_global_entry, message);
690a73105b8SAntonio Quartulli 	}
691cc47f66eSAntonio Quartulli out:
6927683fdc1SAntonio Quartulli 	if (tt_global_entry)
6937683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
694797399b4SAntonio Quartulli 	if (tt_local_entry)
695797399b4SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
696a73105b8SAntonio Quartulli }
697a73105b8SAntonio Quartulli 
6982dafb49dSAntonio Quartulli void tt_global_del_orig(struct bat_priv *bat_priv,
699747e4221SSven Eckelmann 			struct orig_node *orig_node, const char *message)
700c6c8fea2SSven Eckelmann {
7012dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
70248100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
703c90681b8SAntonio Quartulli 	uint32_t i;
704a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
705a73105b8SAntonio Quartulli 	struct hlist_node *node, *safe;
706a73105b8SAntonio Quartulli 	struct hlist_head *head;
7077683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
708c6c8fea2SSven Eckelmann 
7096e801494SSimon Wunderlich 	if (!hash)
7106e801494SSimon Wunderlich 		return;
7116e801494SSimon Wunderlich 
712a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
713a73105b8SAntonio Quartulli 		head = &hash->table[i];
7147683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
715c6c8fea2SSven Eckelmann 
7167683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
71748100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, safe,
718a73105b8SAntonio Quartulli 					 head, hash_entry) {
71948100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
72048100bacSAntonio Quartulli 						       struct tt_global_entry,
72148100bacSAntonio Quartulli 						       common);
7227683fdc1SAntonio Quartulli 			if (tt_global_entry->orig_node == orig_node) {
7237683fdc1SAntonio Quartulli 				bat_dbg(DBG_TT, bat_priv,
7247683fdc1SAntonio Quartulli 					"Deleting global tt entry %pM "
72587944973SAntonio Quartulli 					"(via %pM): %s\n",
72648100bacSAntonio Quartulli 					tt_global_entry->common.addr,
72787944973SAntonio Quartulli 					tt_global_entry->orig_node->orig,
72887944973SAntonio Quartulli 					message);
7297683fdc1SAntonio Quartulli 				hlist_del_rcu(node);
7307683fdc1SAntonio Quartulli 				tt_global_entry_free_ref(tt_global_entry);
731c6c8fea2SSven Eckelmann 			}
732a73105b8SAntonio Quartulli 		}
7337683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
7347683fdc1SAntonio Quartulli 	}
735a73105b8SAntonio Quartulli 	atomic_set(&orig_node->tt_size, 0);
736c6c8fea2SSven Eckelmann }
737c6c8fea2SSven Eckelmann 
738cc47f66eSAntonio Quartulli static void tt_global_roam_purge(struct bat_priv *bat_priv)
739cc47f66eSAntonio Quartulli {
740cc47f66eSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
74148100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
742cc47f66eSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
743cc47f66eSAntonio Quartulli 	struct hlist_node *node, *node_tmp;
744cc47f66eSAntonio Quartulli 	struct hlist_head *head;
7457683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
746c90681b8SAntonio Quartulli 	uint32_t i;
747cc47f66eSAntonio Quartulli 
748cc47f66eSAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
749cc47f66eSAntonio Quartulli 		head = &hash->table[i];
7507683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
751cc47f66eSAntonio Quartulli 
7527683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
75348100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
754cc47f66eSAntonio Quartulli 					  head, hash_entry) {
75548100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
75648100bacSAntonio Quartulli 						       struct tt_global_entry,
75748100bacSAntonio Quartulli 						       common);
75848100bacSAntonio Quartulli 			if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
759cc47f66eSAntonio Quartulli 				continue;
760cc47f66eSAntonio Quartulli 			if (!is_out_of_time(tt_global_entry->roam_at,
761cc47f66eSAntonio Quartulli 					    TT_CLIENT_ROAM_TIMEOUT * 1000))
762cc47f66eSAntonio Quartulli 				continue;
763cc47f66eSAntonio Quartulli 
7647683fdc1SAntonio Quartulli 			bat_dbg(DBG_TT, bat_priv, "Deleting global "
7657683fdc1SAntonio Quartulli 				"tt entry (%pM): Roaming timeout\n",
76648100bacSAntonio Quartulli 				tt_global_entry->common.addr);
7677683fdc1SAntonio Quartulli 			atomic_dec(&tt_global_entry->orig_node->tt_size);
7687683fdc1SAntonio Quartulli 			hlist_del_rcu(node);
7697683fdc1SAntonio Quartulli 			tt_global_entry_free_ref(tt_global_entry);
770cc47f66eSAntonio Quartulli 		}
7717683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
772cc47f66eSAntonio Quartulli 	}
773cc47f66eSAntonio Quartulli 
774cc47f66eSAntonio Quartulli }
775cc47f66eSAntonio Quartulli 
776a73105b8SAntonio Quartulli static void tt_global_table_free(struct bat_priv *bat_priv)
777c6c8fea2SSven Eckelmann {
7787683fdc1SAntonio Quartulli 	struct hashtable_t *hash;
7797683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
78048100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
7817683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
7827683fdc1SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
7837683fdc1SAntonio Quartulli 	struct hlist_head *head;
784c90681b8SAntonio Quartulli 	uint32_t i;
7857683fdc1SAntonio Quartulli 
7862dafb49dSAntonio Quartulli 	if (!bat_priv->tt_global_hash)
787c6c8fea2SSven Eckelmann 		return;
788c6c8fea2SSven Eckelmann 
7897683fdc1SAntonio Quartulli 	hash = bat_priv->tt_global_hash;
7907683fdc1SAntonio Quartulli 
7917683fdc1SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
7927683fdc1SAntonio Quartulli 		head = &hash->table[i];
7937683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
7947683fdc1SAntonio Quartulli 
7957683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
79648100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
7977683fdc1SAntonio Quartulli 					  head, hash_entry) {
7987683fdc1SAntonio Quartulli 			hlist_del_rcu(node);
79948100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
80048100bacSAntonio Quartulli 						       struct tt_global_entry,
80148100bacSAntonio Quartulli 						       common);
8027683fdc1SAntonio Quartulli 			tt_global_entry_free_ref(tt_global_entry);
8037683fdc1SAntonio Quartulli 		}
8047683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
8057683fdc1SAntonio Quartulli 	}
8067683fdc1SAntonio Quartulli 
8077683fdc1SAntonio Quartulli 	hash_destroy(hash);
8087683fdc1SAntonio Quartulli 
8092dafb49dSAntonio Quartulli 	bat_priv->tt_global_hash = NULL;
810c6c8fea2SSven Eckelmann }
811c6c8fea2SSven Eckelmann 
81259b699cdSAntonio Quartulli static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
81359b699cdSAntonio Quartulli 			    struct tt_global_entry *tt_global_entry)
81459b699cdSAntonio Quartulli {
81559b699cdSAntonio Quartulli 	bool ret = false;
81659b699cdSAntonio Quartulli 
81748100bacSAntonio Quartulli 	if (tt_local_entry->common.flags & TT_CLIENT_WIFI &&
81848100bacSAntonio Quartulli 	    tt_global_entry->common.flags & TT_CLIENT_WIFI)
81959b699cdSAntonio Quartulli 		ret = true;
82059b699cdSAntonio Quartulli 
82159b699cdSAntonio Quartulli 	return ret;
82259b699cdSAntonio Quartulli }
82359b699cdSAntonio Quartulli 
824747e4221SSven Eckelmann struct orig_node *transtable_search(struct bat_priv *bat_priv,
8253d393e47SAntonio Quartulli 				    const uint8_t *src, const uint8_t *addr)
826c6c8fea2SSven Eckelmann {
8273d393e47SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
8283d393e47SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
8297b36e8eeSMarek Lindner 	struct orig_node *orig_node = NULL;
830c6c8fea2SSven Eckelmann 
8313d393e47SAntonio Quartulli 	if (src && atomic_read(&bat_priv->ap_isolation)) {
8323d393e47SAntonio Quartulli 		tt_local_entry = tt_local_hash_find(bat_priv, src);
8333d393e47SAntonio Quartulli 		if (!tt_local_entry)
8343d393e47SAntonio Quartulli 			goto out;
8353d393e47SAntonio Quartulli 	}
8367aadf889SMarek Lindner 
8373d393e47SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
8382dafb49dSAntonio Quartulli 	if (!tt_global_entry)
8397b36e8eeSMarek Lindner 		goto out;
840c6c8fea2SSven Eckelmann 
8413d393e47SAntonio Quartulli 	/* check whether the clients should not communicate due to AP
8423d393e47SAntonio Quartulli 	 * isolation */
8433d393e47SAntonio Quartulli 	if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
8443d393e47SAntonio Quartulli 		goto out;
8453d393e47SAntonio Quartulli 
8462dafb49dSAntonio Quartulli 	if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
8473d393e47SAntonio Quartulli 		goto out;
8487b36e8eeSMarek Lindner 
849980d55b2SAntonio Quartulli 	/* A global client marked as PENDING has already moved from that
850980d55b2SAntonio Quartulli 	 * originator */
85148100bacSAntonio Quartulli 	if (tt_global_entry->common.flags & TT_CLIENT_PENDING)
8523d393e47SAntonio Quartulli 		goto out;
853980d55b2SAntonio Quartulli 
8542dafb49dSAntonio Quartulli 	orig_node = tt_global_entry->orig_node;
8557b36e8eeSMarek Lindner 
8567b36e8eeSMarek Lindner out:
8573d393e47SAntonio Quartulli 	if (tt_global_entry)
8583d393e47SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
8593d393e47SAntonio Quartulli 	if (tt_local_entry)
8603d393e47SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
8613d393e47SAntonio Quartulli 
8627b36e8eeSMarek Lindner 	return orig_node;
863c6c8fea2SSven Eckelmann }
864a73105b8SAntonio Quartulli 
865a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */
866a73105b8SAntonio Quartulli uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
867a73105b8SAntonio Quartulli {
868a73105b8SAntonio Quartulli 	uint16_t total = 0, total_one;
869a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
87048100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
871a73105b8SAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
872a73105b8SAntonio Quartulli 	struct hlist_node *node;
873a73105b8SAntonio Quartulli 	struct hlist_head *head;
874c90681b8SAntonio Quartulli 	uint32_t i;
875c90681b8SAntonio Quartulli 	int j;
876a73105b8SAntonio Quartulli 
877a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
878a73105b8SAntonio Quartulli 		head = &hash->table[i];
879a73105b8SAntonio Quartulli 
880a73105b8SAntonio Quartulli 		rcu_read_lock();
88148100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
882a73105b8SAntonio Quartulli 					 head, hash_entry) {
88348100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
88448100bacSAntonio Quartulli 						       struct tt_global_entry,
88548100bacSAntonio Quartulli 						       common);
886a73105b8SAntonio Quartulli 			if (compare_eth(tt_global_entry->orig_node,
887a73105b8SAntonio Quartulli 					orig_node)) {
888cc47f66eSAntonio Quartulli 				/* Roaming clients are in the global table for
889cc47f66eSAntonio Quartulli 				 * consistency only. They don't have to be
890cc47f66eSAntonio Quartulli 				 * taken into account while computing the
891cc47f66eSAntonio Quartulli 				 * global crc */
89248100bacSAntonio Quartulli 				if (tt_common_entry->flags & TT_CLIENT_ROAM)
893cc47f66eSAntonio Quartulli 					continue;
894a73105b8SAntonio Quartulli 				total_one = 0;
895a73105b8SAntonio Quartulli 				for (j = 0; j < ETH_ALEN; j++)
896a73105b8SAntonio Quartulli 					total_one = crc16_byte(total_one,
89748100bacSAntonio Quartulli 						tt_common_entry->addr[j]);
898a73105b8SAntonio Quartulli 				total ^= total_one;
899a73105b8SAntonio Quartulli 			}
900a73105b8SAntonio Quartulli 		}
901a73105b8SAntonio Quartulli 		rcu_read_unlock();
902a73105b8SAntonio Quartulli 	}
903a73105b8SAntonio Quartulli 
904a73105b8SAntonio Quartulli 	return total;
905a73105b8SAntonio Quartulli }
906a73105b8SAntonio Quartulli 
907a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */
908a73105b8SAntonio Quartulli uint16_t tt_local_crc(struct bat_priv *bat_priv)
909a73105b8SAntonio Quartulli {
910a73105b8SAntonio Quartulli 	uint16_t total = 0, total_one;
911a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
91248100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
913a73105b8SAntonio Quartulli 	struct hlist_node *node;
914a73105b8SAntonio Quartulli 	struct hlist_head *head;
915c90681b8SAntonio Quartulli 	uint32_t i;
916c90681b8SAntonio Quartulli 	int j;
917a73105b8SAntonio Quartulli 
918a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
919a73105b8SAntonio Quartulli 		head = &hash->table[i];
920a73105b8SAntonio Quartulli 
921a73105b8SAntonio Quartulli 		rcu_read_lock();
92248100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
923a73105b8SAntonio Quartulli 					 head, hash_entry) {
924058d0e26SAntonio Quartulli 			/* not yet committed clients have not to be taken into
925058d0e26SAntonio Quartulli 			 * account while computing the CRC */
92648100bacSAntonio Quartulli 			if (tt_common_entry->flags & TT_CLIENT_NEW)
927058d0e26SAntonio Quartulli 				continue;
928a73105b8SAntonio Quartulli 			total_one = 0;
929a73105b8SAntonio Quartulli 			for (j = 0; j < ETH_ALEN; j++)
930a73105b8SAntonio Quartulli 				total_one = crc16_byte(total_one,
93148100bacSAntonio Quartulli 						   tt_common_entry->addr[j]);
932a73105b8SAntonio Quartulli 			total ^= total_one;
933a73105b8SAntonio Quartulli 		}
934a73105b8SAntonio Quartulli 		rcu_read_unlock();
935a73105b8SAntonio Quartulli 	}
936a73105b8SAntonio Quartulli 
937a73105b8SAntonio Quartulli 	return total;
938a73105b8SAntonio Quartulli }
939a73105b8SAntonio Quartulli 
940a73105b8SAntonio Quartulli static void tt_req_list_free(struct bat_priv *bat_priv)
941a73105b8SAntonio Quartulli {
942a73105b8SAntonio Quartulli 	struct tt_req_node *node, *safe;
943a73105b8SAntonio Quartulli 
944a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
945a73105b8SAntonio Quartulli 
946a73105b8SAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
947a73105b8SAntonio Quartulli 		list_del(&node->list);
948a73105b8SAntonio Quartulli 		kfree(node);
949a73105b8SAntonio Quartulli 	}
950a73105b8SAntonio Quartulli 
951a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
952a73105b8SAntonio Quartulli }
953a73105b8SAntonio Quartulli 
954a73105b8SAntonio Quartulli void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
955a73105b8SAntonio Quartulli 			 const unsigned char *tt_buff, uint8_t tt_num_changes)
956a73105b8SAntonio Quartulli {
957a73105b8SAntonio Quartulli 	uint16_t tt_buff_len = tt_len(tt_num_changes);
958a73105b8SAntonio Quartulli 
959a73105b8SAntonio Quartulli 	/* Replace the old buffer only if I received something in the
960a73105b8SAntonio Quartulli 	 * last OGM (the OGM could carry no changes) */
961a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
962a73105b8SAntonio Quartulli 	if (tt_buff_len > 0) {
963a73105b8SAntonio Quartulli 		kfree(orig_node->tt_buff);
964a73105b8SAntonio Quartulli 		orig_node->tt_buff_len = 0;
965a73105b8SAntonio Quartulli 		orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
966a73105b8SAntonio Quartulli 		if (orig_node->tt_buff) {
967a73105b8SAntonio Quartulli 			memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
968a73105b8SAntonio Quartulli 			orig_node->tt_buff_len = tt_buff_len;
969a73105b8SAntonio Quartulli 		}
970a73105b8SAntonio Quartulli 	}
971a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
972a73105b8SAntonio Quartulli }
973a73105b8SAntonio Quartulli 
974a73105b8SAntonio Quartulli static void tt_req_purge(struct bat_priv *bat_priv)
975a73105b8SAntonio Quartulli {
976a73105b8SAntonio Quartulli 	struct tt_req_node *node, *safe;
977a73105b8SAntonio Quartulli 
978a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
979a73105b8SAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
980a73105b8SAntonio Quartulli 		if (is_out_of_time(node->issued_at,
981a73105b8SAntonio Quartulli 		    TT_REQUEST_TIMEOUT * 1000)) {
982a73105b8SAntonio Quartulli 			list_del(&node->list);
983a73105b8SAntonio Quartulli 			kfree(node);
984a73105b8SAntonio Quartulli 		}
985a73105b8SAntonio Quartulli 	}
986a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
987a73105b8SAntonio Quartulli }
988a73105b8SAntonio Quartulli 
989a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request
990a73105b8SAntonio Quartulli  * has already been issued for this orig_node, NULL otherwise */
991a73105b8SAntonio Quartulli static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
992a73105b8SAntonio Quartulli 					  struct orig_node *orig_node)
993a73105b8SAntonio Quartulli {
994a73105b8SAntonio Quartulli 	struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
995a73105b8SAntonio Quartulli 
996a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
997a73105b8SAntonio Quartulli 	list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
998a73105b8SAntonio Quartulli 		if (compare_eth(tt_req_node_tmp, orig_node) &&
999a73105b8SAntonio Quartulli 		    !is_out_of_time(tt_req_node_tmp->issued_at,
1000a73105b8SAntonio Quartulli 				    TT_REQUEST_TIMEOUT * 1000))
1001a73105b8SAntonio Quartulli 			goto unlock;
1002a73105b8SAntonio Quartulli 	}
1003a73105b8SAntonio Quartulli 
1004a73105b8SAntonio Quartulli 	tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
1005a73105b8SAntonio Quartulli 	if (!tt_req_node)
1006a73105b8SAntonio Quartulli 		goto unlock;
1007a73105b8SAntonio Quartulli 
1008a73105b8SAntonio Quartulli 	memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
1009a73105b8SAntonio Quartulli 	tt_req_node->issued_at = jiffies;
1010a73105b8SAntonio Quartulli 
1011a73105b8SAntonio Quartulli 	list_add(&tt_req_node->list, &bat_priv->tt_req_list);
1012a73105b8SAntonio Quartulli unlock:
1013a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
1014a73105b8SAntonio Quartulli 	return tt_req_node;
1015a73105b8SAntonio Quartulli }
1016a73105b8SAntonio Quartulli 
1017058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */
1018058d0e26SAntonio Quartulli static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
1019058d0e26SAntonio Quartulli {
102048100bacSAntonio Quartulli 	const struct tt_common_entry *tt_common_entry = entry_ptr;
1021058d0e26SAntonio Quartulli 
102248100bacSAntonio Quartulli 	if (tt_common_entry->flags & TT_CLIENT_NEW)
1023058d0e26SAntonio Quartulli 		return 0;
1024058d0e26SAntonio Quartulli 	return 1;
1025058d0e26SAntonio Quartulli }
1026058d0e26SAntonio Quartulli 
1027a73105b8SAntonio Quartulli static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
1028a73105b8SAntonio Quartulli {
102948100bacSAntonio Quartulli 	const struct tt_common_entry *tt_common_entry = entry_ptr;
103048100bacSAntonio Quartulli 	const struct tt_global_entry *tt_global_entry;
1031a73105b8SAntonio Quartulli 	const struct orig_node *orig_node = data_ptr;
1032a73105b8SAntonio Quartulli 
103348100bacSAntonio Quartulli 	if (tt_common_entry->flags & TT_CLIENT_ROAM)
1034cc47f66eSAntonio Quartulli 		return 0;
1035cc47f66eSAntonio Quartulli 
103648100bacSAntonio Quartulli 	tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
103748100bacSAntonio Quartulli 				       common);
103848100bacSAntonio Quartulli 
1039a73105b8SAntonio Quartulli 	return (tt_global_entry->orig_node == orig_node);
1040a73105b8SAntonio Quartulli }
1041a73105b8SAntonio Quartulli 
1042a73105b8SAntonio Quartulli static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
1043a73105b8SAntonio Quartulli 					      struct hashtable_t *hash,
1044a73105b8SAntonio Quartulli 					      struct hard_iface *primary_if,
1045a73105b8SAntonio Quartulli 					      int (*valid_cb)(const void *,
1046a73105b8SAntonio Quartulli 							      const void *),
1047a73105b8SAntonio Quartulli 					      void *cb_data)
1048a73105b8SAntonio Quartulli {
104948100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
1050a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1051a73105b8SAntonio Quartulli 	struct tt_change *tt_change;
1052a73105b8SAntonio Quartulli 	struct hlist_node *node;
1053a73105b8SAntonio Quartulli 	struct hlist_head *head;
1054a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1055a73105b8SAntonio Quartulli 	uint16_t tt_tot, tt_count;
1056a73105b8SAntonio Quartulli 	ssize_t tt_query_size = sizeof(struct tt_query_packet);
1057c90681b8SAntonio Quartulli 	uint32_t i;
1058a73105b8SAntonio Quartulli 
1059a73105b8SAntonio Quartulli 	if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
1060a73105b8SAntonio Quartulli 		tt_len = primary_if->soft_iface->mtu - tt_query_size;
1061a73105b8SAntonio Quartulli 		tt_len -= tt_len % sizeof(struct tt_change);
1062a73105b8SAntonio Quartulli 	}
1063a73105b8SAntonio Quartulli 	tt_tot = tt_len / sizeof(struct tt_change);
1064a73105b8SAntonio Quartulli 
1065a73105b8SAntonio Quartulli 	skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
1066a73105b8SAntonio Quartulli 	if (!skb)
1067a73105b8SAntonio Quartulli 		goto out;
1068a73105b8SAntonio Quartulli 
1069a73105b8SAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1070a73105b8SAntonio Quartulli 	tt_response = (struct tt_query_packet *)skb_put(skb,
1071a73105b8SAntonio Quartulli 						     tt_query_size + tt_len);
1072a73105b8SAntonio Quartulli 	tt_response->ttvn = ttvn;
1073a73105b8SAntonio Quartulli 
1074a73105b8SAntonio Quartulli 	tt_change = (struct tt_change *)(skb->data + tt_query_size);
1075a73105b8SAntonio Quartulli 	tt_count = 0;
1076a73105b8SAntonio Quartulli 
1077a73105b8SAntonio Quartulli 	rcu_read_lock();
1078a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1079a73105b8SAntonio Quartulli 		head = &hash->table[i];
1080a73105b8SAntonio Quartulli 
108148100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
1082a73105b8SAntonio Quartulli 					 head, hash_entry) {
1083a73105b8SAntonio Quartulli 			if (tt_count == tt_tot)
1084a73105b8SAntonio Quartulli 				break;
1085a73105b8SAntonio Quartulli 
108648100bacSAntonio Quartulli 			if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
1087a73105b8SAntonio Quartulli 				continue;
1088a73105b8SAntonio Quartulli 
108948100bacSAntonio Quartulli 			memcpy(tt_change->addr, tt_common_entry->addr,
109048100bacSAntonio Quartulli 			       ETH_ALEN);
1091a73105b8SAntonio Quartulli 			tt_change->flags = NO_FLAGS;
1092a73105b8SAntonio Quartulli 
1093a73105b8SAntonio Quartulli 			tt_count++;
1094a73105b8SAntonio Quartulli 			tt_change++;
1095a73105b8SAntonio Quartulli 		}
1096a73105b8SAntonio Quartulli 	}
1097a73105b8SAntonio Quartulli 	rcu_read_unlock();
1098a73105b8SAntonio Quartulli 
10999d852393SAntonio Quartulli 	/* store in the message the number of entries we have successfully
11009d852393SAntonio Quartulli 	 * copied */
11019d852393SAntonio Quartulli 	tt_response->tt_data = htons(tt_count);
11029d852393SAntonio Quartulli 
1103a73105b8SAntonio Quartulli out:
1104a73105b8SAntonio Quartulli 	return skb;
1105a73105b8SAntonio Quartulli }
1106a73105b8SAntonio Quartulli 
1107a943cac1SMarek Lindner static int send_tt_request(struct bat_priv *bat_priv,
1108a943cac1SMarek Lindner 			   struct orig_node *dst_orig_node,
1109a73105b8SAntonio Quartulli 			   uint8_t ttvn, uint16_t tt_crc, bool full_table)
1110a73105b8SAntonio Quartulli {
1111a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1112a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_request;
1113a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1114a73105b8SAntonio Quartulli 	struct hard_iface *primary_if;
1115a73105b8SAntonio Quartulli 	struct tt_req_node *tt_req_node = NULL;
1116a73105b8SAntonio Quartulli 	int ret = 1;
1117a73105b8SAntonio Quartulli 
1118a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1119a73105b8SAntonio Quartulli 	if (!primary_if)
1120a73105b8SAntonio Quartulli 		goto out;
1121a73105b8SAntonio Quartulli 
1122a73105b8SAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
1123a73105b8SAntonio Quartulli 	 * reply from the same orig_node yet */
1124a73105b8SAntonio Quartulli 	tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
1125a73105b8SAntonio Quartulli 	if (!tt_req_node)
1126a73105b8SAntonio Quartulli 		goto out;
1127a73105b8SAntonio Quartulli 
1128a73105b8SAntonio Quartulli 	skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
1129a73105b8SAntonio Quartulli 	if (!skb)
1130a73105b8SAntonio Quartulli 		goto out;
1131a73105b8SAntonio Quartulli 
1132a73105b8SAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1133a73105b8SAntonio Quartulli 
1134a73105b8SAntonio Quartulli 	tt_request = (struct tt_query_packet *)skb_put(skb,
1135a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet));
1136a73105b8SAntonio Quartulli 
1137a73105b8SAntonio Quartulli 	tt_request->packet_type = BAT_TT_QUERY;
1138a73105b8SAntonio Quartulli 	tt_request->version = COMPAT_VERSION;
1139a73105b8SAntonio Quartulli 	memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1140a73105b8SAntonio Quartulli 	memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
1141a73105b8SAntonio Quartulli 	tt_request->ttl = TTL;
1142a73105b8SAntonio Quartulli 	tt_request->ttvn = ttvn;
1143a73105b8SAntonio Quartulli 	tt_request->tt_data = tt_crc;
1144a73105b8SAntonio Quartulli 	tt_request->flags = TT_REQUEST;
1145a73105b8SAntonio Quartulli 
1146a73105b8SAntonio Quartulli 	if (full_table)
1147a73105b8SAntonio Quartulli 		tt_request->flags |= TT_FULL_TABLE;
1148a73105b8SAntonio Quartulli 
1149a73105b8SAntonio Quartulli 	neigh_node = orig_node_get_router(dst_orig_node);
1150a73105b8SAntonio Quartulli 	if (!neigh_node)
1151a73105b8SAntonio Quartulli 		goto out;
1152a73105b8SAntonio Quartulli 
1153a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
1154a73105b8SAntonio Quartulli 		"[%c]\n", dst_orig_node->orig, neigh_node->addr,
1155a73105b8SAntonio Quartulli 		(full_table ? 'F' : '.'));
1156a73105b8SAntonio Quartulli 
1157a73105b8SAntonio Quartulli 	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1158a73105b8SAntonio Quartulli 	ret = 0;
1159a73105b8SAntonio Quartulli 
1160a73105b8SAntonio Quartulli out:
1161a73105b8SAntonio Quartulli 	if (neigh_node)
1162a73105b8SAntonio Quartulli 		neigh_node_free_ref(neigh_node);
1163a73105b8SAntonio Quartulli 	if (primary_if)
1164a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1165a73105b8SAntonio Quartulli 	if (ret)
1166a73105b8SAntonio Quartulli 		kfree_skb(skb);
1167a73105b8SAntonio Quartulli 	if (ret && tt_req_node) {
1168a73105b8SAntonio Quartulli 		spin_lock_bh(&bat_priv->tt_req_list_lock);
1169a73105b8SAntonio Quartulli 		list_del(&tt_req_node->list);
1170a73105b8SAntonio Quartulli 		spin_unlock_bh(&bat_priv->tt_req_list_lock);
1171a73105b8SAntonio Quartulli 		kfree(tt_req_node);
1172a73105b8SAntonio Quartulli 	}
1173a73105b8SAntonio Quartulli 	return ret;
1174a73105b8SAntonio Quartulli }
1175a73105b8SAntonio Quartulli 
1176a73105b8SAntonio Quartulli static bool send_other_tt_response(struct bat_priv *bat_priv,
1177a73105b8SAntonio Quartulli 				   struct tt_query_packet *tt_request)
1178a73105b8SAntonio Quartulli {
1179a73105b8SAntonio Quartulli 	struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
1180a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1181a73105b8SAntonio Quartulli 	struct hard_iface *primary_if = NULL;
1182a73105b8SAntonio Quartulli 	uint8_t orig_ttvn, req_ttvn, ttvn;
1183a73105b8SAntonio Quartulli 	int ret = false;
1184a73105b8SAntonio Quartulli 	unsigned char *tt_buff;
1185a73105b8SAntonio Quartulli 	bool full_table;
1186a73105b8SAntonio Quartulli 	uint16_t tt_len, tt_tot;
1187a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1188a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1189a73105b8SAntonio Quartulli 
1190a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1191a73105b8SAntonio Quartulli 		"Received TT_REQUEST from %pM for "
1192a73105b8SAntonio Quartulli 		"ttvn: %u (%pM) [%c]\n", tt_request->src,
1193a73105b8SAntonio Quartulli 		tt_request->ttvn, tt_request->dst,
1194a73105b8SAntonio Quartulli 		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1195a73105b8SAntonio Quartulli 
1196a73105b8SAntonio Quartulli 	/* Let's get the orig node of the REAL destination */
1197eb7e2a1eSAntonio Quartulli 	req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst);
1198a73105b8SAntonio Quartulli 	if (!req_dst_orig_node)
1199a73105b8SAntonio Quartulli 		goto out;
1200a73105b8SAntonio Quartulli 
1201eb7e2a1eSAntonio Quartulli 	res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src);
1202a73105b8SAntonio Quartulli 	if (!res_dst_orig_node)
1203a73105b8SAntonio Quartulli 		goto out;
1204a73105b8SAntonio Quartulli 
1205a73105b8SAntonio Quartulli 	neigh_node = orig_node_get_router(res_dst_orig_node);
1206a73105b8SAntonio Quartulli 	if (!neigh_node)
1207a73105b8SAntonio Quartulli 		goto out;
1208a73105b8SAntonio Quartulli 
1209a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1210a73105b8SAntonio Quartulli 	if (!primary_if)
1211a73105b8SAntonio Quartulli 		goto out;
1212a73105b8SAntonio Quartulli 
1213a73105b8SAntonio Quartulli 	orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1214a73105b8SAntonio Quartulli 	req_ttvn = tt_request->ttvn;
1215a73105b8SAntonio Quartulli 
1216015758d0SAntonio Quartulli 	/* I don't have the requested data */
1217a73105b8SAntonio Quartulli 	if (orig_ttvn != req_ttvn ||
1218a73105b8SAntonio Quartulli 	    tt_request->tt_data != req_dst_orig_node->tt_crc)
1219a73105b8SAntonio Quartulli 		goto out;
1220a73105b8SAntonio Quartulli 
1221015758d0SAntonio Quartulli 	/* If the full table has been explicitly requested */
1222a73105b8SAntonio Quartulli 	if (tt_request->flags & TT_FULL_TABLE ||
1223a73105b8SAntonio Quartulli 	    !req_dst_orig_node->tt_buff)
1224a73105b8SAntonio Quartulli 		full_table = true;
1225a73105b8SAntonio Quartulli 	else
1226a73105b8SAntonio Quartulli 		full_table = false;
1227a73105b8SAntonio Quartulli 
1228a73105b8SAntonio Quartulli 	/* In this version, fragmentation is not implemented, then
1229a73105b8SAntonio Quartulli 	 * I'll send only one packet with as much TT entries as I can */
1230a73105b8SAntonio Quartulli 	if (!full_table) {
1231a73105b8SAntonio Quartulli 		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1232a73105b8SAntonio Quartulli 		tt_len = req_dst_orig_node->tt_buff_len;
1233a73105b8SAntonio Quartulli 		tt_tot = tt_len / sizeof(struct tt_change);
1234a73105b8SAntonio Quartulli 
1235a73105b8SAntonio Quartulli 		skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1236a73105b8SAntonio Quartulli 				    tt_len + ETH_HLEN);
1237a73105b8SAntonio Quartulli 		if (!skb)
1238a73105b8SAntonio Quartulli 			goto unlock;
1239a73105b8SAntonio Quartulli 
1240a73105b8SAntonio Quartulli 		skb_reserve(skb, ETH_HLEN);
1241a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb_put(skb,
1242a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet) + tt_len);
1243a73105b8SAntonio Quartulli 		tt_response->ttvn = req_ttvn;
1244a73105b8SAntonio Quartulli 		tt_response->tt_data = htons(tt_tot);
1245a73105b8SAntonio Quartulli 
1246a73105b8SAntonio Quartulli 		tt_buff = skb->data + sizeof(struct tt_query_packet);
1247a73105b8SAntonio Quartulli 		/* Copy the last orig_node's OGM buffer */
1248a73105b8SAntonio Quartulli 		memcpy(tt_buff, req_dst_orig_node->tt_buff,
1249a73105b8SAntonio Quartulli 		       req_dst_orig_node->tt_buff_len);
1250a73105b8SAntonio Quartulli 
1251a73105b8SAntonio Quartulli 		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1252a73105b8SAntonio Quartulli 	} else {
1253a73105b8SAntonio Quartulli 		tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
1254a73105b8SAntonio Quartulli 						sizeof(struct tt_change);
1255a73105b8SAntonio Quartulli 		ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1256a73105b8SAntonio Quartulli 
1257a73105b8SAntonio Quartulli 		skb = tt_response_fill_table(tt_len, ttvn,
1258a73105b8SAntonio Quartulli 					     bat_priv->tt_global_hash,
1259a73105b8SAntonio Quartulli 					     primary_if, tt_global_valid_entry,
1260a73105b8SAntonio Quartulli 					     req_dst_orig_node);
1261a73105b8SAntonio Quartulli 		if (!skb)
1262a73105b8SAntonio Quartulli 			goto out;
1263a73105b8SAntonio Quartulli 
1264a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb->data;
1265a73105b8SAntonio Quartulli 	}
1266a73105b8SAntonio Quartulli 
1267a73105b8SAntonio Quartulli 	tt_response->packet_type = BAT_TT_QUERY;
1268a73105b8SAntonio Quartulli 	tt_response->version = COMPAT_VERSION;
1269a73105b8SAntonio Quartulli 	tt_response->ttl = TTL;
1270a73105b8SAntonio Quartulli 	memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
1271a73105b8SAntonio Quartulli 	memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1272a73105b8SAntonio Quartulli 	tt_response->flags = TT_RESPONSE;
1273a73105b8SAntonio Quartulli 
1274a73105b8SAntonio Quartulli 	if (full_table)
1275a73105b8SAntonio Quartulli 		tt_response->flags |= TT_FULL_TABLE;
1276a73105b8SAntonio Quartulli 
1277a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1278a73105b8SAntonio Quartulli 		"Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
1279a73105b8SAntonio Quartulli 		res_dst_orig_node->orig, neigh_node->addr,
1280a73105b8SAntonio Quartulli 		req_dst_orig_node->orig, req_ttvn);
1281a73105b8SAntonio Quartulli 
1282a73105b8SAntonio Quartulli 	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1283a73105b8SAntonio Quartulli 	ret = true;
1284a73105b8SAntonio Quartulli 	goto out;
1285a73105b8SAntonio Quartulli 
1286a73105b8SAntonio Quartulli unlock:
1287a73105b8SAntonio Quartulli 	spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1288a73105b8SAntonio Quartulli 
1289a73105b8SAntonio Quartulli out:
1290a73105b8SAntonio Quartulli 	if (res_dst_orig_node)
1291a73105b8SAntonio Quartulli 		orig_node_free_ref(res_dst_orig_node);
1292a73105b8SAntonio Quartulli 	if (req_dst_orig_node)
1293a73105b8SAntonio Quartulli 		orig_node_free_ref(req_dst_orig_node);
1294a73105b8SAntonio Quartulli 	if (neigh_node)
1295a73105b8SAntonio Quartulli 		neigh_node_free_ref(neigh_node);
1296a73105b8SAntonio Quartulli 	if (primary_if)
1297a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1298a73105b8SAntonio Quartulli 	if (!ret)
1299a73105b8SAntonio Quartulli 		kfree_skb(skb);
1300a73105b8SAntonio Quartulli 	return ret;
1301a73105b8SAntonio Quartulli 
1302a73105b8SAntonio Quartulli }
1303a73105b8SAntonio Quartulli static bool send_my_tt_response(struct bat_priv *bat_priv,
1304a73105b8SAntonio Quartulli 				struct tt_query_packet *tt_request)
1305a73105b8SAntonio Quartulli {
1306a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1307a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1308a73105b8SAntonio Quartulli 	struct hard_iface *primary_if = NULL;
1309a73105b8SAntonio Quartulli 	uint8_t my_ttvn, req_ttvn, ttvn;
1310a73105b8SAntonio Quartulli 	int ret = false;
1311a73105b8SAntonio Quartulli 	unsigned char *tt_buff;
1312a73105b8SAntonio Quartulli 	bool full_table;
1313a73105b8SAntonio Quartulli 	uint16_t tt_len, tt_tot;
1314a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1315a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1316a73105b8SAntonio Quartulli 
1317a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1318a73105b8SAntonio Quartulli 		"Received TT_REQUEST from %pM for "
1319a73105b8SAntonio Quartulli 		"ttvn: %u (me) [%c]\n", tt_request->src,
1320a73105b8SAntonio Quartulli 		tt_request->ttvn,
1321a73105b8SAntonio Quartulli 		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1322a73105b8SAntonio Quartulli 
1323a73105b8SAntonio Quartulli 
1324a73105b8SAntonio Quartulli 	my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1325a73105b8SAntonio Quartulli 	req_ttvn = tt_request->ttvn;
1326a73105b8SAntonio Quartulli 
1327eb7e2a1eSAntonio Quartulli 	orig_node = orig_hash_find(bat_priv, tt_request->src);
1328a73105b8SAntonio Quartulli 	if (!orig_node)
1329a73105b8SAntonio Quartulli 		goto out;
1330a73105b8SAntonio Quartulli 
1331a73105b8SAntonio Quartulli 	neigh_node = orig_node_get_router(orig_node);
1332a73105b8SAntonio Quartulli 	if (!neigh_node)
1333a73105b8SAntonio Quartulli 		goto out;
1334a73105b8SAntonio Quartulli 
1335a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1336a73105b8SAntonio Quartulli 	if (!primary_if)
1337a73105b8SAntonio Quartulli 		goto out;
1338a73105b8SAntonio Quartulli 
1339a73105b8SAntonio Quartulli 	/* If the full table has been explicitly requested or the gap
1340a73105b8SAntonio Quartulli 	 * is too big send the whole local translation table */
1341a73105b8SAntonio Quartulli 	if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
1342a73105b8SAntonio Quartulli 	    !bat_priv->tt_buff)
1343a73105b8SAntonio Quartulli 		full_table = true;
1344a73105b8SAntonio Quartulli 	else
1345a73105b8SAntonio Quartulli 		full_table = false;
1346a73105b8SAntonio Quartulli 
1347a73105b8SAntonio Quartulli 	/* In this version, fragmentation is not implemented, then
1348a73105b8SAntonio Quartulli 	 * I'll send only one packet with as much TT entries as I can */
1349a73105b8SAntonio Quartulli 	if (!full_table) {
1350a73105b8SAntonio Quartulli 		spin_lock_bh(&bat_priv->tt_buff_lock);
1351a73105b8SAntonio Quartulli 		tt_len = bat_priv->tt_buff_len;
1352a73105b8SAntonio Quartulli 		tt_tot = tt_len / sizeof(struct tt_change);
1353a73105b8SAntonio Quartulli 
1354a73105b8SAntonio Quartulli 		skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1355a73105b8SAntonio Quartulli 				    tt_len + ETH_HLEN);
1356a73105b8SAntonio Quartulli 		if (!skb)
1357a73105b8SAntonio Quartulli 			goto unlock;
1358a73105b8SAntonio Quartulli 
1359a73105b8SAntonio Quartulli 		skb_reserve(skb, ETH_HLEN);
1360a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb_put(skb,
1361a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet) + tt_len);
1362a73105b8SAntonio Quartulli 		tt_response->ttvn = req_ttvn;
1363a73105b8SAntonio Quartulli 		tt_response->tt_data = htons(tt_tot);
1364a73105b8SAntonio Quartulli 
1365a73105b8SAntonio Quartulli 		tt_buff = skb->data + sizeof(struct tt_query_packet);
1366a73105b8SAntonio Quartulli 		memcpy(tt_buff, bat_priv->tt_buff,
1367a73105b8SAntonio Quartulli 		       bat_priv->tt_buff_len);
1368a73105b8SAntonio Quartulli 		spin_unlock_bh(&bat_priv->tt_buff_lock);
1369a73105b8SAntonio Quartulli 	} else {
1370a73105b8SAntonio Quartulli 		tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
1371a73105b8SAntonio Quartulli 						sizeof(struct tt_change);
1372a73105b8SAntonio Quartulli 		ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1373a73105b8SAntonio Quartulli 
1374a73105b8SAntonio Quartulli 		skb = tt_response_fill_table(tt_len, ttvn,
1375a73105b8SAntonio Quartulli 					     bat_priv->tt_local_hash,
1376058d0e26SAntonio Quartulli 					     primary_if, tt_local_valid_entry,
1377058d0e26SAntonio Quartulli 					     NULL);
1378a73105b8SAntonio Quartulli 		if (!skb)
1379a73105b8SAntonio Quartulli 			goto out;
1380a73105b8SAntonio Quartulli 
1381a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb->data;
1382a73105b8SAntonio Quartulli 	}
1383a73105b8SAntonio Quartulli 
1384a73105b8SAntonio Quartulli 	tt_response->packet_type = BAT_TT_QUERY;
1385a73105b8SAntonio Quartulli 	tt_response->version = COMPAT_VERSION;
1386a73105b8SAntonio Quartulli 	tt_response->ttl = TTL;
1387a73105b8SAntonio Quartulli 	memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1388a73105b8SAntonio Quartulli 	memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1389a73105b8SAntonio Quartulli 	tt_response->flags = TT_RESPONSE;
1390a73105b8SAntonio Quartulli 
1391a73105b8SAntonio Quartulli 	if (full_table)
1392a73105b8SAntonio Quartulli 		tt_response->flags |= TT_FULL_TABLE;
1393a73105b8SAntonio Quartulli 
1394a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1395a73105b8SAntonio Quartulli 		"Sending TT_RESPONSE to %pM via %pM [%c]\n",
1396a73105b8SAntonio Quartulli 		orig_node->orig, neigh_node->addr,
1397a73105b8SAntonio Quartulli 		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1398a73105b8SAntonio Quartulli 
1399a73105b8SAntonio Quartulli 	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1400a73105b8SAntonio Quartulli 	ret = true;
1401a73105b8SAntonio Quartulli 	goto out;
1402a73105b8SAntonio Quartulli 
1403a73105b8SAntonio Quartulli unlock:
1404a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_buff_lock);
1405a73105b8SAntonio Quartulli out:
1406a73105b8SAntonio Quartulli 	if (orig_node)
1407a73105b8SAntonio Quartulli 		orig_node_free_ref(orig_node);
1408a73105b8SAntonio Quartulli 	if (neigh_node)
1409a73105b8SAntonio Quartulli 		neigh_node_free_ref(neigh_node);
1410a73105b8SAntonio Quartulli 	if (primary_if)
1411a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1412a73105b8SAntonio Quartulli 	if (!ret)
1413a73105b8SAntonio Quartulli 		kfree_skb(skb);
1414a73105b8SAntonio Quartulli 	/* This packet was for me, so it doesn't need to be re-routed */
1415a73105b8SAntonio Quartulli 	return true;
1416a73105b8SAntonio Quartulli }
1417a73105b8SAntonio Quartulli 
1418a73105b8SAntonio Quartulli bool send_tt_response(struct bat_priv *bat_priv,
1419a73105b8SAntonio Quartulli 		      struct tt_query_packet *tt_request)
1420a73105b8SAntonio Quartulli {
1421a73105b8SAntonio Quartulli 	if (is_my_mac(tt_request->dst))
1422a73105b8SAntonio Quartulli 		return send_my_tt_response(bat_priv, tt_request);
1423a73105b8SAntonio Quartulli 	else
1424a73105b8SAntonio Quartulli 		return send_other_tt_response(bat_priv, tt_request);
1425a73105b8SAntonio Quartulli }
1426a73105b8SAntonio Quartulli 
1427a73105b8SAntonio Quartulli static void _tt_update_changes(struct bat_priv *bat_priv,
1428a73105b8SAntonio Quartulli 			       struct orig_node *orig_node,
1429a73105b8SAntonio Quartulli 			       struct tt_change *tt_change,
1430a73105b8SAntonio Quartulli 			       uint16_t tt_num_changes, uint8_t ttvn)
1431a73105b8SAntonio Quartulli {
1432a73105b8SAntonio Quartulli 	int i;
1433a73105b8SAntonio Quartulli 
1434a73105b8SAntonio Quartulli 	for (i = 0; i < tt_num_changes; i++) {
14355fbc1598SAntonio Quartulli 		if ((tt_change + i)->flags & TT_CLIENT_DEL)
1436a73105b8SAntonio Quartulli 			tt_global_del(bat_priv, orig_node,
1437a73105b8SAntonio Quartulli 				      (tt_change + i)->addr,
1438cc47f66eSAntonio Quartulli 				      "tt removed by changes",
1439cc47f66eSAntonio Quartulli 				      (tt_change + i)->flags & TT_CLIENT_ROAM);
1440a73105b8SAntonio Quartulli 		else
1441a73105b8SAntonio Quartulli 			if (!tt_global_add(bat_priv, orig_node,
1442bc279080SAntonio Quartulli 					   (tt_change + i)->addr, ttvn, false,
1443bc279080SAntonio Quartulli 					   (tt_change + i)->flags &
1444bc279080SAntonio Quartulli 							TT_CLIENT_WIFI))
1445a73105b8SAntonio Quartulli 				/* In case of problem while storing a
1446a73105b8SAntonio Quartulli 				 * global_entry, we stop the updating
1447a73105b8SAntonio Quartulli 				 * procedure without committing the
1448a73105b8SAntonio Quartulli 				 * ttvn change. This will avoid to send
1449a73105b8SAntonio Quartulli 				 * corrupted data on tt_request
1450a73105b8SAntonio Quartulli 				 */
1451a73105b8SAntonio Quartulli 				return;
1452a73105b8SAntonio Quartulli 	}
1453a73105b8SAntonio Quartulli }
1454a73105b8SAntonio Quartulli 
1455a73105b8SAntonio Quartulli static void tt_fill_gtable(struct bat_priv *bat_priv,
1456a73105b8SAntonio Quartulli 			   struct tt_query_packet *tt_response)
1457a73105b8SAntonio Quartulli {
1458a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1459a73105b8SAntonio Quartulli 
1460a73105b8SAntonio Quartulli 	orig_node = orig_hash_find(bat_priv, tt_response->src);
1461a73105b8SAntonio Quartulli 	if (!orig_node)
1462a73105b8SAntonio Quartulli 		goto out;
1463a73105b8SAntonio Quartulli 
1464a73105b8SAntonio Quartulli 	/* Purge the old table first.. */
1465a73105b8SAntonio Quartulli 	tt_global_del_orig(bat_priv, orig_node, "Received full table");
1466a73105b8SAntonio Quartulli 
1467a73105b8SAntonio Quartulli 	_tt_update_changes(bat_priv, orig_node,
1468a73105b8SAntonio Quartulli 			   (struct tt_change *)(tt_response + 1),
1469a73105b8SAntonio Quartulli 			   tt_response->tt_data, tt_response->ttvn);
1470a73105b8SAntonio Quartulli 
1471a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
1472a73105b8SAntonio Quartulli 	kfree(orig_node->tt_buff);
1473a73105b8SAntonio Quartulli 	orig_node->tt_buff_len = 0;
1474a73105b8SAntonio Quartulli 	orig_node->tt_buff = NULL;
1475a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
1476a73105b8SAntonio Quartulli 
1477a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
1478a73105b8SAntonio Quartulli 
1479a73105b8SAntonio Quartulli out:
1480a73105b8SAntonio Quartulli 	if (orig_node)
1481a73105b8SAntonio Quartulli 		orig_node_free_ref(orig_node);
1482a73105b8SAntonio Quartulli }
1483a73105b8SAntonio Quartulli 
1484a943cac1SMarek Lindner static void tt_update_changes(struct bat_priv *bat_priv,
1485a943cac1SMarek Lindner 			      struct orig_node *orig_node,
1486a73105b8SAntonio Quartulli 			      uint16_t tt_num_changes, uint8_t ttvn,
1487a73105b8SAntonio Quartulli 			      struct tt_change *tt_change)
1488a73105b8SAntonio Quartulli {
1489a73105b8SAntonio Quartulli 	_tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
1490a73105b8SAntonio Quartulli 			   ttvn);
1491a73105b8SAntonio Quartulli 
1492a73105b8SAntonio Quartulli 	tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
1493a73105b8SAntonio Quartulli 			    tt_num_changes);
1494a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, ttvn);
1495a73105b8SAntonio Quartulli }
1496a73105b8SAntonio Quartulli 
1497a73105b8SAntonio Quartulli bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
1498a73105b8SAntonio Quartulli {
14997683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
15007683fdc1SAntonio Quartulli 	bool ret = false;
1501a73105b8SAntonio Quartulli 
1502a73105b8SAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
15037683fdc1SAntonio Quartulli 	if (!tt_local_entry)
15047683fdc1SAntonio Quartulli 		goto out;
1505058d0e26SAntonio Quartulli 	/* Check if the client has been logically deleted (but is kept for
1506058d0e26SAntonio Quartulli 	 * consistency purpose) */
150748100bacSAntonio Quartulli 	if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
1508058d0e26SAntonio Quartulli 		goto out;
15097683fdc1SAntonio Quartulli 	ret = true;
15107683fdc1SAntonio Quartulli out:
1511a73105b8SAntonio Quartulli 	if (tt_local_entry)
15127683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
15137683fdc1SAntonio Quartulli 	return ret;
1514a73105b8SAntonio Quartulli }
1515a73105b8SAntonio Quartulli 
1516a73105b8SAntonio Quartulli void handle_tt_response(struct bat_priv *bat_priv,
1517a73105b8SAntonio Quartulli 			struct tt_query_packet *tt_response)
1518a73105b8SAntonio Quartulli {
1519a73105b8SAntonio Quartulli 	struct tt_req_node *node, *safe;
1520a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1521a73105b8SAntonio Quartulli 
1522a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
1523a73105b8SAntonio Quartulli 		"ttvn %d t_size: %d [%c]\n",
1524a73105b8SAntonio Quartulli 		tt_response->src, tt_response->ttvn,
1525a73105b8SAntonio Quartulli 		tt_response->tt_data,
1526a73105b8SAntonio Quartulli 		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1527a73105b8SAntonio Quartulli 
1528a73105b8SAntonio Quartulli 	orig_node = orig_hash_find(bat_priv, tt_response->src);
1529a73105b8SAntonio Quartulli 	if (!orig_node)
1530a73105b8SAntonio Quartulli 		goto out;
1531a73105b8SAntonio Quartulli 
1532a73105b8SAntonio Quartulli 	if (tt_response->flags & TT_FULL_TABLE)
1533a73105b8SAntonio Quartulli 		tt_fill_gtable(bat_priv, tt_response);
1534a73105b8SAntonio Quartulli 	else
1535a73105b8SAntonio Quartulli 		tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
1536a73105b8SAntonio Quartulli 				  tt_response->ttvn,
1537a73105b8SAntonio Quartulli 				  (struct tt_change *)(tt_response + 1));
1538a73105b8SAntonio Quartulli 
1539a73105b8SAntonio Quartulli 	/* Delete the tt_req_node from pending tt_requests list */
1540a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
1541a73105b8SAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1542a73105b8SAntonio Quartulli 		if (!compare_eth(node->addr, tt_response->src))
1543a73105b8SAntonio Quartulli 			continue;
1544a73105b8SAntonio Quartulli 		list_del(&node->list);
1545a73105b8SAntonio Quartulli 		kfree(node);
1546a73105b8SAntonio Quartulli 	}
1547a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
1548a73105b8SAntonio Quartulli 
1549a73105b8SAntonio Quartulli 	/* Recalculate the CRC for this orig_node and store it */
1550a73105b8SAntonio Quartulli 	orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1551cc47f66eSAntonio Quartulli 	/* Roaming phase is over: tables are in sync again. I can
1552cc47f66eSAntonio Quartulli 	 * unset the flag */
1553cc47f66eSAntonio Quartulli 	orig_node->tt_poss_change = false;
1554a73105b8SAntonio Quartulli out:
1555a73105b8SAntonio Quartulli 	if (orig_node)
1556a73105b8SAntonio Quartulli 		orig_node_free_ref(orig_node);
1557a73105b8SAntonio Quartulli }
1558a73105b8SAntonio Quartulli 
1559a73105b8SAntonio Quartulli int tt_init(struct bat_priv *bat_priv)
1560a73105b8SAntonio Quartulli {
1561a73105b8SAntonio Quartulli 	if (!tt_local_init(bat_priv))
1562a73105b8SAntonio Quartulli 		return 0;
1563a73105b8SAntonio Quartulli 
1564a73105b8SAntonio Quartulli 	if (!tt_global_init(bat_priv))
1565a73105b8SAntonio Quartulli 		return 0;
1566a73105b8SAntonio Quartulli 
1567a73105b8SAntonio Quartulli 	tt_start_timer(bat_priv);
1568a73105b8SAntonio Quartulli 
1569a73105b8SAntonio Quartulli 	return 1;
1570a73105b8SAntonio Quartulli }
1571a73105b8SAntonio Quartulli 
1572cc47f66eSAntonio Quartulli static void tt_roam_list_free(struct bat_priv *bat_priv)
1573a73105b8SAntonio Quartulli {
1574cc47f66eSAntonio Quartulli 	struct tt_roam_node *node, *safe;
1575a73105b8SAntonio Quartulli 
1576cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1577a73105b8SAntonio Quartulli 
1578cc47f66eSAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1579cc47f66eSAntonio Quartulli 		list_del(&node->list);
1580cc47f66eSAntonio Quartulli 		kfree(node);
1581cc47f66eSAntonio Quartulli 	}
1582cc47f66eSAntonio Quartulli 
1583cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1584cc47f66eSAntonio Quartulli }
1585cc47f66eSAntonio Quartulli 
1586cc47f66eSAntonio Quartulli static void tt_roam_purge(struct bat_priv *bat_priv)
1587cc47f66eSAntonio Quartulli {
1588cc47f66eSAntonio Quartulli 	struct tt_roam_node *node, *safe;
1589cc47f66eSAntonio Quartulli 
1590cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1591cc47f66eSAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1592cc47f66eSAntonio Quartulli 		if (!is_out_of_time(node->first_time,
1593cc47f66eSAntonio Quartulli 				    ROAMING_MAX_TIME * 1000))
1594cc47f66eSAntonio Quartulli 			continue;
1595cc47f66eSAntonio Quartulli 
1596cc47f66eSAntonio Quartulli 		list_del(&node->list);
1597cc47f66eSAntonio Quartulli 		kfree(node);
1598cc47f66eSAntonio Quartulli 	}
1599cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1600cc47f66eSAntonio Quartulli }
1601cc47f66eSAntonio Quartulli 
1602cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the
1603cc47f66eSAntonio Quartulli  * maximum number of possible roaming phases. In this case the ROAMING_ADV
1604cc47f66eSAntonio Quartulli  * will not be sent.
1605cc47f66eSAntonio Quartulli  *
1606cc47f66eSAntonio Quartulli  * returns true if the ROAMING_ADV can be sent, false otherwise */
1607cc47f66eSAntonio Quartulli static bool tt_check_roam_count(struct bat_priv *bat_priv,
1608cc47f66eSAntonio Quartulli 				uint8_t *client)
1609cc47f66eSAntonio Quartulli {
1610cc47f66eSAntonio Quartulli 	struct tt_roam_node *tt_roam_node;
1611cc47f66eSAntonio Quartulli 	bool ret = false;
1612cc47f66eSAntonio Quartulli 
1613cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1614cc47f66eSAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
1615cc47f66eSAntonio Quartulli 	 * reply from the same orig_node yet */
1616cc47f66eSAntonio Quartulli 	list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
1617cc47f66eSAntonio Quartulli 		if (!compare_eth(tt_roam_node->addr, client))
1618cc47f66eSAntonio Quartulli 			continue;
1619cc47f66eSAntonio Quartulli 
1620cc47f66eSAntonio Quartulli 		if (is_out_of_time(tt_roam_node->first_time,
1621cc47f66eSAntonio Quartulli 				   ROAMING_MAX_TIME * 1000))
1622cc47f66eSAntonio Quartulli 			continue;
1623cc47f66eSAntonio Quartulli 
1624cc47f66eSAntonio Quartulli 		if (!atomic_dec_not_zero(&tt_roam_node->counter))
1625cc47f66eSAntonio Quartulli 			/* Sorry, you roamed too many times! */
1626cc47f66eSAntonio Quartulli 			goto unlock;
1627cc47f66eSAntonio Quartulli 		ret = true;
1628cc47f66eSAntonio Quartulli 		break;
1629cc47f66eSAntonio Quartulli 	}
1630cc47f66eSAntonio Quartulli 
1631cc47f66eSAntonio Quartulli 	if (!ret) {
1632cc47f66eSAntonio Quartulli 		tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
1633cc47f66eSAntonio Quartulli 		if (!tt_roam_node)
1634cc47f66eSAntonio Quartulli 			goto unlock;
1635cc47f66eSAntonio Quartulli 
1636cc47f66eSAntonio Quartulli 		tt_roam_node->first_time = jiffies;
1637cc47f66eSAntonio Quartulli 		atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
1638cc47f66eSAntonio Quartulli 		memcpy(tt_roam_node->addr, client, ETH_ALEN);
1639cc47f66eSAntonio Quartulli 
1640cc47f66eSAntonio Quartulli 		list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
1641cc47f66eSAntonio Quartulli 		ret = true;
1642cc47f66eSAntonio Quartulli 	}
1643cc47f66eSAntonio Quartulli 
1644cc47f66eSAntonio Quartulli unlock:
1645cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1646cc47f66eSAntonio Quartulli 	return ret;
1647cc47f66eSAntonio Quartulli }
1648cc47f66eSAntonio Quartulli 
1649cc47f66eSAntonio Quartulli void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
1650cc47f66eSAntonio Quartulli 		   struct orig_node *orig_node)
1651cc47f66eSAntonio Quartulli {
1652cc47f66eSAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1653cc47f66eSAntonio Quartulli 	struct sk_buff *skb = NULL;
1654cc47f66eSAntonio Quartulli 	struct roam_adv_packet *roam_adv_packet;
1655cc47f66eSAntonio Quartulli 	int ret = 1;
1656cc47f66eSAntonio Quartulli 	struct hard_iface *primary_if;
1657cc47f66eSAntonio Quartulli 
1658cc47f66eSAntonio Quartulli 	/* before going on we have to check whether the client has
1659cc47f66eSAntonio Quartulli 	 * already roamed to us too many times */
1660cc47f66eSAntonio Quartulli 	if (!tt_check_roam_count(bat_priv, client))
1661cc47f66eSAntonio Quartulli 		goto out;
1662cc47f66eSAntonio Quartulli 
1663cc47f66eSAntonio Quartulli 	skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
1664cc47f66eSAntonio Quartulli 	if (!skb)
1665cc47f66eSAntonio Quartulli 		goto out;
1666cc47f66eSAntonio Quartulli 
1667cc47f66eSAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1668cc47f66eSAntonio Quartulli 
1669cc47f66eSAntonio Quartulli 	roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
1670cc47f66eSAntonio Quartulli 					sizeof(struct roam_adv_packet));
1671cc47f66eSAntonio Quartulli 
1672cc47f66eSAntonio Quartulli 	roam_adv_packet->packet_type = BAT_ROAM_ADV;
1673cc47f66eSAntonio Quartulli 	roam_adv_packet->version = COMPAT_VERSION;
1674cc47f66eSAntonio Quartulli 	roam_adv_packet->ttl = TTL;
1675cc47f66eSAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1676cc47f66eSAntonio Quartulli 	if (!primary_if)
1677cc47f66eSAntonio Quartulli 		goto out;
1678cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1679cc47f66eSAntonio Quartulli 	hardif_free_ref(primary_if);
1680cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
1681cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->client, client, ETH_ALEN);
1682cc47f66eSAntonio Quartulli 
1683cc47f66eSAntonio Quartulli 	neigh_node = orig_node_get_router(orig_node);
1684cc47f66eSAntonio Quartulli 	if (!neigh_node)
1685cc47f66eSAntonio Quartulli 		goto out;
1686cc47f66eSAntonio Quartulli 
1687cc47f66eSAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1688cc47f66eSAntonio Quartulli 		"Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
1689cc47f66eSAntonio Quartulli 		orig_node->orig, client, neigh_node->addr);
1690cc47f66eSAntonio Quartulli 
1691cc47f66eSAntonio Quartulli 	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1692cc47f66eSAntonio Quartulli 	ret = 0;
1693cc47f66eSAntonio Quartulli 
1694cc47f66eSAntonio Quartulli out:
1695cc47f66eSAntonio Quartulli 	if (neigh_node)
1696cc47f66eSAntonio Quartulli 		neigh_node_free_ref(neigh_node);
1697cc47f66eSAntonio Quartulli 	if (ret)
1698cc47f66eSAntonio Quartulli 		kfree_skb(skb);
1699cc47f66eSAntonio Quartulli 	return;
1700a73105b8SAntonio Quartulli }
1701a73105b8SAntonio Quartulli 
1702a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work)
1703a73105b8SAntonio Quartulli {
1704a73105b8SAntonio Quartulli 	struct delayed_work *delayed_work =
1705a73105b8SAntonio Quartulli 		container_of(work, struct delayed_work, work);
1706a73105b8SAntonio Quartulli 	struct bat_priv *bat_priv =
1707a73105b8SAntonio Quartulli 		container_of(delayed_work, struct bat_priv, tt_work);
1708a73105b8SAntonio Quartulli 
1709a73105b8SAntonio Quartulli 	tt_local_purge(bat_priv);
1710cc47f66eSAntonio Quartulli 	tt_global_roam_purge(bat_priv);
1711a73105b8SAntonio Quartulli 	tt_req_purge(bat_priv);
1712cc47f66eSAntonio Quartulli 	tt_roam_purge(bat_priv);
1713a73105b8SAntonio Quartulli 
1714a73105b8SAntonio Quartulli 	tt_start_timer(bat_priv);
1715a73105b8SAntonio Quartulli }
1716cc47f66eSAntonio Quartulli 
1717cc47f66eSAntonio Quartulli void tt_free(struct bat_priv *bat_priv)
1718cc47f66eSAntonio Quartulli {
1719cc47f66eSAntonio Quartulli 	cancel_delayed_work_sync(&bat_priv->tt_work);
1720cc47f66eSAntonio Quartulli 
1721cc47f66eSAntonio Quartulli 	tt_local_table_free(bat_priv);
1722cc47f66eSAntonio Quartulli 	tt_global_table_free(bat_priv);
1723cc47f66eSAntonio Quartulli 	tt_req_list_free(bat_priv);
1724cc47f66eSAntonio Quartulli 	tt_changes_list_free(bat_priv);
1725cc47f66eSAntonio Quartulli 	tt_roam_list_free(bat_priv);
1726cc47f66eSAntonio Quartulli 
1727cc47f66eSAntonio Quartulli 	kfree(bat_priv->tt_buff);
1728cc47f66eSAntonio Quartulli }
1729058d0e26SAntonio Quartulli 
1730697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries
1731697f2531SAntonio Quartulli  * in the given hash table and returns the number of modified entries */
1732697f2531SAntonio Quartulli static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags,
1733697f2531SAntonio Quartulli 			     bool enable)
1734058d0e26SAntonio Quartulli {
1735c90681b8SAntonio Quartulli 	uint32_t i;
1736697f2531SAntonio Quartulli 	uint16_t changed_num = 0;
1737058d0e26SAntonio Quartulli 	struct hlist_head *head;
1738058d0e26SAntonio Quartulli 	struct hlist_node *node;
173948100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
1740058d0e26SAntonio Quartulli 
1741058d0e26SAntonio Quartulli 	if (!hash)
1742697f2531SAntonio Quartulli 		goto out;
1743058d0e26SAntonio Quartulli 
1744058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1745058d0e26SAntonio Quartulli 		head = &hash->table[i];
1746058d0e26SAntonio Quartulli 
1747058d0e26SAntonio Quartulli 		rcu_read_lock();
174848100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
1749058d0e26SAntonio Quartulli 					 head, hash_entry) {
1750697f2531SAntonio Quartulli 			if (enable) {
1751697f2531SAntonio Quartulli 				if ((tt_common_entry->flags & flags) == flags)
1752697f2531SAntonio Quartulli 					continue;
1753697f2531SAntonio Quartulli 				tt_common_entry->flags |= flags;
1754697f2531SAntonio Quartulli 			} else {
175548100bacSAntonio Quartulli 				if (!(tt_common_entry->flags & flags))
175631901264SAntonio Quartulli 					continue;
175748100bacSAntonio Quartulli 				tt_common_entry->flags &= ~flags;
1758697f2531SAntonio Quartulli 			}
1759697f2531SAntonio Quartulli 			changed_num++;
1760058d0e26SAntonio Quartulli 		}
1761058d0e26SAntonio Quartulli 		rcu_read_unlock();
1762058d0e26SAntonio Quartulli 	}
1763697f2531SAntonio Quartulli out:
1764697f2531SAntonio Quartulli 	return changed_num;
1765058d0e26SAntonio Quartulli }
1766058d0e26SAntonio Quartulli 
1767058d0e26SAntonio Quartulli /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
1768058d0e26SAntonio Quartulli static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
1769058d0e26SAntonio Quartulli {
1770058d0e26SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
177148100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
1772058d0e26SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
1773058d0e26SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
1774058d0e26SAntonio Quartulli 	struct hlist_head *head;
1775058d0e26SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
1776c90681b8SAntonio Quartulli 	uint32_t i;
1777058d0e26SAntonio Quartulli 
1778058d0e26SAntonio Quartulli 	if (!hash)
1779058d0e26SAntonio Quartulli 		return;
1780058d0e26SAntonio Quartulli 
1781058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1782058d0e26SAntonio Quartulli 		head = &hash->table[i];
1783058d0e26SAntonio Quartulli 		list_lock = &hash->list_locks[i];
1784058d0e26SAntonio Quartulli 
1785058d0e26SAntonio Quartulli 		spin_lock_bh(list_lock);
178648100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
1787058d0e26SAntonio Quartulli 					  head, hash_entry) {
178848100bacSAntonio Quartulli 			if (!(tt_common_entry->flags & TT_CLIENT_PENDING))
1789058d0e26SAntonio Quartulli 				continue;
1790058d0e26SAntonio Quartulli 
1791058d0e26SAntonio Quartulli 			bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
179248100bacSAntonio Quartulli 				"(%pM): pending\n", tt_common_entry->addr);
1793058d0e26SAntonio Quartulli 
1794058d0e26SAntonio Quartulli 			atomic_dec(&bat_priv->num_local_tt);
1795058d0e26SAntonio Quartulli 			hlist_del_rcu(node);
179648100bacSAntonio Quartulli 			tt_local_entry = container_of(tt_common_entry,
179748100bacSAntonio Quartulli 						      struct tt_local_entry,
179848100bacSAntonio Quartulli 						      common);
1799058d0e26SAntonio Quartulli 			tt_local_entry_free_ref(tt_local_entry);
1800058d0e26SAntonio Quartulli 		}
1801058d0e26SAntonio Quartulli 		spin_unlock_bh(list_lock);
1802058d0e26SAntonio Quartulli 	}
1803058d0e26SAntonio Quartulli 
1804058d0e26SAntonio Quartulli }
1805058d0e26SAntonio Quartulli 
1806058d0e26SAntonio Quartulli void tt_commit_changes(struct bat_priv *bat_priv)
1807058d0e26SAntonio Quartulli {
1808697f2531SAntonio Quartulli 	uint16_t changed_num = tt_set_flags(bat_priv->tt_local_hash,
1809697f2531SAntonio Quartulli 					    TT_CLIENT_NEW, false);
1810697f2531SAntonio Quartulli 	/* all the reset entries have now to be effectively counted as local
1811697f2531SAntonio Quartulli 	 * entries */
1812697f2531SAntonio Quartulli 	atomic_add(changed_num, &bat_priv->num_local_tt);
1813058d0e26SAntonio Quartulli 	tt_local_purge_pending_clients(bat_priv);
1814058d0e26SAntonio Quartulli 
1815058d0e26SAntonio Quartulli 	/* Increment the TTVN only once per OGM interval */
1816058d0e26SAntonio Quartulli 	atomic_inc(&bat_priv->ttvn);
1817058d0e26SAntonio Quartulli 	bat_priv->tt_poss_change = false;
1818058d0e26SAntonio Quartulli }
181959b699cdSAntonio Quartulli 
182059b699cdSAntonio Quartulli bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
182159b699cdSAntonio Quartulli {
182259b699cdSAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
182359b699cdSAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
182459b699cdSAntonio Quartulli 	bool ret = true;
182559b699cdSAntonio Quartulli 
182659b699cdSAntonio Quartulli 	if (!atomic_read(&bat_priv->ap_isolation))
182759b699cdSAntonio Quartulli 		return false;
182859b699cdSAntonio Quartulli 
182959b699cdSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, dst);
183059b699cdSAntonio Quartulli 	if (!tt_local_entry)
183159b699cdSAntonio Quartulli 		goto out;
183259b699cdSAntonio Quartulli 
183359b699cdSAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, src);
183459b699cdSAntonio Quartulli 	if (!tt_global_entry)
183559b699cdSAntonio Quartulli 		goto out;
183659b699cdSAntonio Quartulli 
183759b699cdSAntonio Quartulli 	if (_is_ap_isolated(tt_local_entry, tt_global_entry))
183859b699cdSAntonio Quartulli 		goto out;
183959b699cdSAntonio Quartulli 
184059b699cdSAntonio Quartulli 	ret = false;
184159b699cdSAntonio Quartulli 
184259b699cdSAntonio Quartulli out:
184359b699cdSAntonio Quartulli 	if (tt_global_entry)
184459b699cdSAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
184559b699cdSAntonio Quartulli 	if (tt_local_entry)
184659b699cdSAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
184759b699cdSAntonio Quartulli 	return ret;
184859b699cdSAntonio Quartulli }
1849a943cac1SMarek Lindner 
1850a943cac1SMarek Lindner void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
1851a943cac1SMarek Lindner 		    const unsigned char *tt_buff, uint8_t tt_num_changes,
1852a943cac1SMarek Lindner 		    uint8_t ttvn, uint16_t tt_crc)
1853a943cac1SMarek Lindner {
1854a943cac1SMarek Lindner 	uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
1855a943cac1SMarek Lindner 	bool full_table = true;
1856a943cac1SMarek Lindner 
1857a943cac1SMarek Lindner 	/* the ttvn increased by one -> we can apply the attached changes */
1858a943cac1SMarek Lindner 	if (ttvn - orig_ttvn == 1) {
1859a943cac1SMarek Lindner 		/* the OGM could not contain the changes due to their size or
1860a943cac1SMarek Lindner 		 * because they have already been sent TT_OGM_APPEND_MAX times.
1861a943cac1SMarek Lindner 		 * In this case send a tt request */
1862a943cac1SMarek Lindner 		if (!tt_num_changes) {
1863a943cac1SMarek Lindner 			full_table = false;
1864a943cac1SMarek Lindner 			goto request_table;
1865a943cac1SMarek Lindner 		}
1866a943cac1SMarek Lindner 
1867a943cac1SMarek Lindner 		tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
1868a943cac1SMarek Lindner 				  (struct tt_change *)tt_buff);
1869a943cac1SMarek Lindner 
1870a943cac1SMarek Lindner 		/* Even if we received the precomputed crc with the OGM, we
1871a943cac1SMarek Lindner 		 * prefer to recompute it to spot any possible inconsistency
1872a943cac1SMarek Lindner 		 * in the global table */
1873a943cac1SMarek Lindner 		orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1874a943cac1SMarek Lindner 
1875a943cac1SMarek Lindner 		/* The ttvn alone is not enough to guarantee consistency
1876a943cac1SMarek Lindner 		 * because a single value could represent different states
1877a943cac1SMarek Lindner 		 * (due to the wrap around). Thus a node has to check whether
1878a943cac1SMarek Lindner 		 * the resulting table (after applying the changes) is still
1879a943cac1SMarek Lindner 		 * consistent or not. E.g. a node could disconnect while its
1880a943cac1SMarek Lindner 		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
1881a943cac1SMarek Lindner 		 * checking the CRC value is mandatory to detect the
1882a943cac1SMarek Lindner 		 * inconsistency */
1883a943cac1SMarek Lindner 		if (orig_node->tt_crc != tt_crc)
1884a943cac1SMarek Lindner 			goto request_table;
1885a943cac1SMarek Lindner 
1886a943cac1SMarek Lindner 		/* Roaming phase is over: tables are in sync again. I can
1887a943cac1SMarek Lindner 		 * unset the flag */
1888a943cac1SMarek Lindner 		orig_node->tt_poss_change = false;
1889a943cac1SMarek Lindner 	} else {
1890a943cac1SMarek Lindner 		/* if we missed more than one change or our tables are not
1891a943cac1SMarek Lindner 		 * in sync anymore -> request fresh tt data */
1892a943cac1SMarek Lindner 		if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
1893a943cac1SMarek Lindner request_table:
1894a943cac1SMarek Lindner 			bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
1895a943cac1SMarek Lindner 				"Need to retrieve the correct information "
1896a943cac1SMarek Lindner 				"(ttvn: %u last_ttvn: %u crc: %u last_crc: "
1897a943cac1SMarek Lindner 				"%u num_changes: %u)\n", orig_node->orig, ttvn,
1898a943cac1SMarek Lindner 				orig_ttvn, tt_crc, orig_node->tt_crc,
1899a943cac1SMarek Lindner 				tt_num_changes);
1900a943cac1SMarek Lindner 			send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
1901a943cac1SMarek Lindner 					full_table);
1902a943cac1SMarek Lindner 			return;
1903a943cac1SMarek Lindner 		}
1904a943cac1SMarek Lindner 	}
1905a943cac1SMarek Lindner }
1906