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 */
39747e4221SSven Eckelmann static int compare_ltt(const struct hlist_node *node, const void *data2)
407aadf889SMarek Lindner {
41747e4221SSven Eckelmann 	const void *data1 = container_of(node, struct tt_local_entry,
42747e4221SSven Eckelmann 					 hash_entry);
437aadf889SMarek Lindner 
447aadf889SMarek Lindner 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
457aadf889SMarek Lindner }
467aadf889SMarek Lindner 
477aadf889SMarek Lindner /* returns 1 if they are the same mac addr */
48747e4221SSven Eckelmann static int compare_gtt(const struct hlist_node *node, const void *data2)
497aadf889SMarek Lindner {
50747e4221SSven Eckelmann 	const void *data1 = container_of(node, struct tt_global_entry,
51747e4221SSven Eckelmann 					 hash_entry);
527aadf889SMarek Lindner 
537aadf889SMarek Lindner 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
547aadf889SMarek Lindner }
557aadf889SMarek Lindner 
56a73105b8SAntonio Quartulli static void tt_start_timer(struct bat_priv *bat_priv)
57c6c8fea2SSven Eckelmann {
58a73105b8SAntonio Quartulli 	INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
59a73105b8SAntonio Quartulli 	queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
60a73105b8SAntonio Quartulli 			   msecs_to_jiffies(5000));
61c6c8fea2SSven Eckelmann }
62c6c8fea2SSven Eckelmann 
632dafb49dSAntonio Quartulli static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
64747e4221SSven Eckelmann 						 const void *data)
657aadf889SMarek Lindner {
662dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
677aadf889SMarek Lindner 	struct hlist_head *head;
687aadf889SMarek Lindner 	struct hlist_node *node;
692dafb49dSAntonio Quartulli 	struct tt_local_entry *tt_local_entry, *tt_local_entry_tmp = NULL;
707aadf889SMarek Lindner 	int index;
717aadf889SMarek Lindner 
727aadf889SMarek Lindner 	if (!hash)
737aadf889SMarek Lindner 		return NULL;
747aadf889SMarek Lindner 
757aadf889SMarek Lindner 	index = choose_orig(data, hash->size);
767aadf889SMarek Lindner 	head = &hash->table[index];
777aadf889SMarek Lindner 
787aadf889SMarek Lindner 	rcu_read_lock();
792dafb49dSAntonio Quartulli 	hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) {
802dafb49dSAntonio Quartulli 		if (!compare_eth(tt_local_entry, data))
817aadf889SMarek Lindner 			continue;
827aadf889SMarek Lindner 
837683fdc1SAntonio Quartulli 		if (!atomic_inc_not_zero(&tt_local_entry->refcount))
847683fdc1SAntonio Quartulli 			continue;
857683fdc1SAntonio Quartulli 
862dafb49dSAntonio Quartulli 		tt_local_entry_tmp = tt_local_entry;
877aadf889SMarek Lindner 		break;
887aadf889SMarek Lindner 	}
897aadf889SMarek Lindner 	rcu_read_unlock();
907aadf889SMarek Lindner 
912dafb49dSAntonio Quartulli 	return tt_local_entry_tmp;
927aadf889SMarek Lindner }
937aadf889SMarek Lindner 
942dafb49dSAntonio Quartulli static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
95747e4221SSven Eckelmann 						   const void *data)
967aadf889SMarek Lindner {
972dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
987aadf889SMarek Lindner 	struct hlist_head *head;
997aadf889SMarek Lindner 	struct hlist_node *node;
1002dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
1012dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry_tmp = NULL;
1027aadf889SMarek Lindner 	int index;
1037aadf889SMarek Lindner 
1047aadf889SMarek Lindner 	if (!hash)
1057aadf889SMarek Lindner 		return NULL;
1067aadf889SMarek Lindner 
1077aadf889SMarek Lindner 	index = choose_orig(data, hash->size);
1087aadf889SMarek Lindner 	head = &hash->table[index];
1097aadf889SMarek Lindner 
1107aadf889SMarek Lindner 	rcu_read_lock();
1112dafb49dSAntonio Quartulli 	hlist_for_each_entry_rcu(tt_global_entry, node, head, hash_entry) {
1122dafb49dSAntonio Quartulli 		if (!compare_eth(tt_global_entry, data))
1137aadf889SMarek Lindner 			continue;
1147aadf889SMarek Lindner 
1157683fdc1SAntonio Quartulli 		if (!atomic_inc_not_zero(&tt_global_entry->refcount))
1167683fdc1SAntonio Quartulli 			continue;
1177683fdc1SAntonio Quartulli 
1182dafb49dSAntonio Quartulli 		tt_global_entry_tmp = tt_global_entry;
1197aadf889SMarek Lindner 		break;
1207aadf889SMarek Lindner 	}
1217aadf889SMarek Lindner 	rcu_read_unlock();
1227aadf889SMarek Lindner 
1232dafb49dSAntonio Quartulli 	return tt_global_entry_tmp;
1247aadf889SMarek Lindner }
1257aadf889SMarek Lindner 
126a73105b8SAntonio Quartulli static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
127a73105b8SAntonio Quartulli {
128a73105b8SAntonio Quartulli 	unsigned long deadline;
129a73105b8SAntonio Quartulli 	deadline = starting_time + msecs_to_jiffies(timeout);
130a73105b8SAntonio Quartulli 
131a73105b8SAntonio Quartulli 	return time_after(jiffies, deadline);
132a73105b8SAntonio Quartulli }
133a73105b8SAntonio Quartulli 
1347683fdc1SAntonio Quartulli static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
1357683fdc1SAntonio Quartulli {
1367683fdc1SAntonio Quartulli 	if (atomic_dec_and_test(&tt_local_entry->refcount))
1377683fdc1SAntonio Quartulli 		kfree_rcu(tt_local_entry, rcu);
1387683fdc1SAntonio Quartulli }
1397683fdc1SAntonio Quartulli 
1407683fdc1SAntonio Quartulli static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
1417683fdc1SAntonio Quartulli {
1427683fdc1SAntonio Quartulli 	if (atomic_dec_and_test(&tt_global_entry->refcount))
1437683fdc1SAntonio Quartulli 		kfree_rcu(tt_global_entry, rcu);
1447683fdc1SAntonio Quartulli }
1457683fdc1SAntonio Quartulli 
146ff66c975SAntonio Quartulli static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
147ff66c975SAntonio Quartulli 			   uint8_t flags)
148a73105b8SAntonio Quartulli {
149a73105b8SAntonio Quartulli 	struct tt_change_node *tt_change_node;
150a73105b8SAntonio Quartulli 
151a73105b8SAntonio Quartulli 	tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
152a73105b8SAntonio Quartulli 
153a73105b8SAntonio Quartulli 	if (!tt_change_node)
154a73105b8SAntonio Quartulli 		return;
155a73105b8SAntonio Quartulli 
156ff66c975SAntonio Quartulli 	tt_change_node->change.flags = flags;
157a73105b8SAntonio Quartulli 	memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
158a73105b8SAntonio Quartulli 
159a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
160a73105b8SAntonio Quartulli 	/* track the change in the OGMinterval list */
161a73105b8SAntonio Quartulli 	list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
162a73105b8SAntonio Quartulli 	atomic_inc(&bat_priv->tt_local_changes);
163a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
164a73105b8SAntonio Quartulli 
165a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
166a73105b8SAntonio Quartulli }
167a73105b8SAntonio Quartulli 
168a73105b8SAntonio Quartulli int tt_len(int changes_num)
169a73105b8SAntonio Quartulli {
170a73105b8SAntonio Quartulli 	return changes_num * sizeof(struct tt_change);
171a73105b8SAntonio Quartulli }
172a73105b8SAntonio Quartulli 
173a73105b8SAntonio Quartulli static int tt_local_init(struct bat_priv *bat_priv)
174c6c8fea2SSven Eckelmann {
1752dafb49dSAntonio Quartulli 	if (bat_priv->tt_local_hash)
176c6c8fea2SSven Eckelmann 		return 1;
177c6c8fea2SSven Eckelmann 
1782dafb49dSAntonio Quartulli 	bat_priv->tt_local_hash = hash_new(1024);
179c6c8fea2SSven Eckelmann 
1802dafb49dSAntonio Quartulli 	if (!bat_priv->tt_local_hash)
181c6c8fea2SSven Eckelmann 		return 0;
182c6c8fea2SSven Eckelmann 
183c6c8fea2SSven Eckelmann 	return 1;
184c6c8fea2SSven Eckelmann }
185c6c8fea2SSven Eckelmann 
186bc279080SAntonio Quartulli void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
187bc279080SAntonio Quartulli 		  int ifindex)
188c6c8fea2SSven Eckelmann {
189c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
1907683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
1917683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
192c6c8fea2SSven Eckelmann 
1932dafb49dSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
194c6c8fea2SSven Eckelmann 
1952dafb49dSAntonio Quartulli 	if (tt_local_entry) {
1962dafb49dSAntonio Quartulli 		tt_local_entry->last_seen = jiffies;
1977683fdc1SAntonio Quartulli 		goto out;
198c6c8fea2SSven Eckelmann 	}
199c6c8fea2SSven Eckelmann 
200704509b8SSven Eckelmann 	tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
2012dafb49dSAntonio Quartulli 	if (!tt_local_entry)
2027683fdc1SAntonio Quartulli 		goto out;
203a73105b8SAntonio Quartulli 
204a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
205a73105b8SAntonio Quartulli 		"Creating new local tt entry: %pM (ttvn: %d)\n", addr,
206a73105b8SAntonio Quartulli 		(uint8_t)atomic_read(&bat_priv->ttvn));
207c6c8fea2SSven Eckelmann 
2082dafb49dSAntonio Quartulli 	memcpy(tt_local_entry->addr, addr, ETH_ALEN);
2092dafb49dSAntonio Quartulli 	tt_local_entry->last_seen = jiffies;
2105fbc1598SAntonio Quartulli 	tt_local_entry->flags = NO_FLAGS;
211bc279080SAntonio Quartulli 	if (is_wifi_iface(ifindex))
212bc279080SAntonio Quartulli 		tt_local_entry->flags |= TT_CLIENT_WIFI;
2137683fdc1SAntonio Quartulli 	atomic_set(&tt_local_entry->refcount, 2);
214c6c8fea2SSven Eckelmann 
215c6c8fea2SSven Eckelmann 	/* the batman interface mac address should never be purged */
21639901e71SMarek Lindner 	if (compare_eth(addr, soft_iface->dev_addr))
2175fbc1598SAntonio Quartulli 		tt_local_entry->flags |= TT_CLIENT_NOPURGE;
218c6c8fea2SSven Eckelmann 
219ff66c975SAntonio Quartulli 	tt_local_event(bat_priv, addr, tt_local_entry->flags);
220ff66c975SAntonio Quartulli 
221058d0e26SAntonio Quartulli 	/* The local entry has to be marked as NEW to avoid to send it in
222058d0e26SAntonio Quartulli 	 * a full table response going out before the next ttvn increment
223058d0e26SAntonio Quartulli 	 * (consistency check) */
224058d0e26SAntonio Quartulli 	tt_local_entry->flags |= TT_CLIENT_NEW;
225058d0e26SAntonio Quartulli 
2262dafb49dSAntonio Quartulli 	hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
2272dafb49dSAntonio Quartulli 		 tt_local_entry, &tt_local_entry->hash_entry);
2287683fdc1SAntonio Quartulli 
229c6c8fea2SSven Eckelmann 	/* remove address from global hash if present */
2302dafb49dSAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
231c6c8fea2SSven Eckelmann 
232cc47f66eSAntonio Quartulli 	/* Check whether it is a roaming! */
233cc47f66eSAntonio Quartulli 	if (tt_global_entry) {
234cc47f66eSAntonio Quartulli 		/* This node is probably going to update its tt table */
235cc47f66eSAntonio Quartulli 		tt_global_entry->orig_node->tt_poss_change = true;
236980d55b2SAntonio Quartulli 		/* The global entry has to be marked as PENDING and has to be
237980d55b2SAntonio Quartulli 		 * kept for consistency purpose */
238980d55b2SAntonio Quartulli 		tt_global_entry->flags |= TT_CLIENT_PENDING;
239cc47f66eSAntonio Quartulli 		send_roam_adv(bat_priv, tt_global_entry->addr,
240cc47f66eSAntonio Quartulli 			      tt_global_entry->orig_node);
2417683fdc1SAntonio Quartulli 	}
2427683fdc1SAntonio Quartulli out:
2437683fdc1SAntonio Quartulli 	if (tt_local_entry)
2447683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
2457683fdc1SAntonio Quartulli 	if (tt_global_entry)
2467683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
247c6c8fea2SSven Eckelmann }
248c6c8fea2SSven Eckelmann 
249a73105b8SAntonio Quartulli int tt_changes_fill_buffer(struct bat_priv *bat_priv,
250c6c8fea2SSven Eckelmann 			   unsigned char *buff, int buff_len)
251c6c8fea2SSven Eckelmann {
252a73105b8SAntonio Quartulli 	int count = 0, tot_changes = 0;
253a73105b8SAntonio Quartulli 	struct tt_change_node *entry, *safe;
254c6c8fea2SSven Eckelmann 
255a73105b8SAntonio Quartulli 	if (buff_len > 0)
256a73105b8SAntonio Quartulli 		tot_changes = buff_len / tt_len(1);
257c6c8fea2SSven Eckelmann 
258a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
259a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_local_changes, 0);
260c6c8fea2SSven Eckelmann 
261a73105b8SAntonio Quartulli 	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
262a73105b8SAntonio Quartulli 			list) {
263a73105b8SAntonio Quartulli 		if (count < tot_changes) {
264a73105b8SAntonio Quartulli 			memcpy(buff + tt_len(count),
265a73105b8SAntonio Quartulli 			       &entry->change, sizeof(struct tt_change));
266c6c8fea2SSven Eckelmann 			count++;
267c6c8fea2SSven Eckelmann 		}
268a73105b8SAntonio Quartulli 		list_del(&entry->list);
269a73105b8SAntonio Quartulli 		kfree(entry);
270c6c8fea2SSven Eckelmann 	}
271a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
272c6c8fea2SSven Eckelmann 
273a73105b8SAntonio Quartulli 	/* Keep the buffer for possible tt_request */
274a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_buff_lock);
275a73105b8SAntonio Quartulli 	kfree(bat_priv->tt_buff);
276a73105b8SAntonio Quartulli 	bat_priv->tt_buff_len = 0;
277a73105b8SAntonio Quartulli 	bat_priv->tt_buff = NULL;
278a73105b8SAntonio Quartulli 	/* We check whether this new OGM has no changes due to size
279a73105b8SAntonio Quartulli 	 * problems */
280a73105b8SAntonio Quartulli 	if (buff_len > 0) {
281a73105b8SAntonio Quartulli 		/**
282a73105b8SAntonio Quartulli 		 * if kmalloc() fails we will reply with the full table
283a73105b8SAntonio Quartulli 		 * instead of providing the diff
284a73105b8SAntonio Quartulli 		 */
285a73105b8SAntonio Quartulli 		bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
286a73105b8SAntonio Quartulli 		if (bat_priv->tt_buff) {
287a73105b8SAntonio Quartulli 			memcpy(bat_priv->tt_buff, buff, buff_len);
288a73105b8SAntonio Quartulli 			bat_priv->tt_buff_len = buff_len;
289a73105b8SAntonio Quartulli 		}
290a73105b8SAntonio Quartulli 	}
291a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_buff_lock);
292c6c8fea2SSven Eckelmann 
293a73105b8SAntonio Quartulli 	return tot_changes;
294c6c8fea2SSven Eckelmann }
295c6c8fea2SSven Eckelmann 
2962dafb49dSAntonio Quartulli int tt_local_seq_print_text(struct seq_file *seq, void *offset)
297c6c8fea2SSven Eckelmann {
298c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
299c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(net_dev);
3002dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
3012dafb49dSAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
30232ae9b22SMarek Lindner 	struct hard_iface *primary_if;
3037aadf889SMarek Lindner 	struct hlist_node *node;
304c6c8fea2SSven Eckelmann 	struct hlist_head *head;
305c6c8fea2SSven Eckelmann 	size_t buf_size, pos;
306c6c8fea2SSven Eckelmann 	char *buff;
30732ae9b22SMarek Lindner 	int i, ret = 0;
308c6c8fea2SSven Eckelmann 
30932ae9b22SMarek Lindner 	primary_if = primary_if_get_selected(bat_priv);
31032ae9b22SMarek Lindner 	if (!primary_if) {
31132ae9b22SMarek Lindner 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
312c6c8fea2SSven Eckelmann 				 "please specify interfaces to enable it\n",
313c6c8fea2SSven Eckelmann 				 net_dev->name);
31432ae9b22SMarek Lindner 		goto out;
31532ae9b22SMarek Lindner 	}
31632ae9b22SMarek Lindner 
31732ae9b22SMarek Lindner 	if (primary_if->if_status != IF_ACTIVE) {
31832ae9b22SMarek Lindner 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
31932ae9b22SMarek Lindner 				 "primary interface not active\n",
32032ae9b22SMarek Lindner 				 net_dev->name);
32132ae9b22SMarek Lindner 		goto out;
322c6c8fea2SSven Eckelmann 	}
323c6c8fea2SSven Eckelmann 
324c6c8fea2SSven Eckelmann 	seq_printf(seq, "Locally retrieved addresses (from %s) "
325a73105b8SAntonio Quartulli 		   "announced via TT (TTVN: %u):\n",
326a73105b8SAntonio Quartulli 		   net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
327c6c8fea2SSven Eckelmann 
328c6c8fea2SSven Eckelmann 	buf_size = 1;
329c6c8fea2SSven Eckelmann 	/* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
330c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
331c6c8fea2SSven Eckelmann 		head = &hash->table[i];
332c6c8fea2SSven Eckelmann 
3337aadf889SMarek Lindner 		rcu_read_lock();
3347aadf889SMarek Lindner 		__hlist_for_each_rcu(node, head)
335c6c8fea2SSven Eckelmann 			buf_size += 21;
3367aadf889SMarek Lindner 		rcu_read_unlock();
337c6c8fea2SSven Eckelmann 	}
338c6c8fea2SSven Eckelmann 
339c6c8fea2SSven Eckelmann 	buff = kmalloc(buf_size, GFP_ATOMIC);
340c6c8fea2SSven Eckelmann 	if (!buff) {
34132ae9b22SMarek Lindner 		ret = -ENOMEM;
34232ae9b22SMarek Lindner 		goto out;
343c6c8fea2SSven Eckelmann 	}
3447aadf889SMarek Lindner 
345c6c8fea2SSven Eckelmann 	buff[0] = '\0';
346c6c8fea2SSven Eckelmann 	pos = 0;
347c6c8fea2SSven Eckelmann 
348c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
349c6c8fea2SSven Eckelmann 		head = &hash->table[i];
350c6c8fea2SSven Eckelmann 
3517aadf889SMarek Lindner 		rcu_read_lock();
3522dafb49dSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_local_entry, node,
3537aadf889SMarek Lindner 					 head, hash_entry) {
354c6c8fea2SSven Eckelmann 			pos += snprintf(buff + pos, 22, " * %pM\n",
3552dafb49dSAntonio Quartulli 					tt_local_entry->addr);
356c6c8fea2SSven Eckelmann 		}
3577aadf889SMarek Lindner 		rcu_read_unlock();
358c6c8fea2SSven Eckelmann 	}
359c6c8fea2SSven Eckelmann 
360c6c8fea2SSven Eckelmann 	seq_printf(seq, "%s", buff);
361c6c8fea2SSven Eckelmann 	kfree(buff);
36232ae9b22SMarek Lindner out:
36332ae9b22SMarek Lindner 	if (primary_if)
36432ae9b22SMarek Lindner 		hardif_free_ref(primary_if);
36532ae9b22SMarek Lindner 	return ret;
366c6c8fea2SSven Eckelmann }
367c6c8fea2SSven Eckelmann 
368058d0e26SAntonio Quartulli static void tt_local_set_pending(struct bat_priv *bat_priv,
3692dafb49dSAntonio Quartulli 				 struct tt_local_entry *tt_local_entry,
370058d0e26SAntonio Quartulli 				 uint16_t flags)
371c6c8fea2SSven Eckelmann {
372058d0e26SAntonio Quartulli 	tt_local_event(bat_priv, tt_local_entry->addr,
373058d0e26SAntonio Quartulli 		       tt_local_entry->flags | flags);
374c6c8fea2SSven Eckelmann 
375015758d0SAntonio Quartulli 	/* The local client has to be marked as "pending to be removed" but has
376015758d0SAntonio Quartulli 	 * to be kept in the table in order to send it in a full table
377058d0e26SAntonio Quartulli 	 * response issued before the net ttvn increment (consistency check) */
378058d0e26SAntonio Quartulli 	tt_local_entry->flags |= TT_CLIENT_PENDING;
379c6c8fea2SSven Eckelmann }
380c6c8fea2SSven Eckelmann 
381a73105b8SAntonio Quartulli void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
382cc47f66eSAntonio Quartulli 		     const char *message, bool roaming)
383c6c8fea2SSven Eckelmann {
3847683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
385c6c8fea2SSven Eckelmann 
3862dafb49dSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
3877683fdc1SAntonio Quartulli 	if (!tt_local_entry)
3887683fdc1SAntonio Quartulli 		goto out;
3897683fdc1SAntonio Quartulli 
390058d0e26SAntonio Quartulli 	tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
391ff66c975SAntonio Quartulli 			     (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
392058d0e26SAntonio Quartulli 
393058d0e26SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
394058d0e26SAntonio Quartulli 		"%s\n", tt_local_entry->addr, message);
3957683fdc1SAntonio Quartulli out:
3967683fdc1SAntonio Quartulli 	if (tt_local_entry)
3977683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
398c6c8fea2SSven Eckelmann }
399c6c8fea2SSven Eckelmann 
400a73105b8SAntonio Quartulli static void tt_local_purge(struct bat_priv *bat_priv)
401c6c8fea2SSven Eckelmann {
4022dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
4032dafb49dSAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
4047aadf889SMarek Lindner 	struct hlist_node *node, *node_tmp;
405c6c8fea2SSven Eckelmann 	struct hlist_head *head;
4067683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
4077aadf889SMarek Lindner 	int i;
408c6c8fea2SSven Eckelmann 
409c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
410c6c8fea2SSven Eckelmann 		head = &hash->table[i];
4117683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
412c6c8fea2SSven Eckelmann 
4137683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
4142dafb49dSAntonio Quartulli 		hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
4157aadf889SMarek Lindner 					  head, hash_entry) {
4165fbc1598SAntonio Quartulli 			if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
4177aadf889SMarek Lindner 				continue;
418c6c8fea2SSven Eckelmann 
419058d0e26SAntonio Quartulli 			/* entry already marked for deletion */
420058d0e26SAntonio Quartulli 			if (tt_local_entry->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",
4317683fdc1SAntonio Quartulli 				tt_local_entry->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 */
442a73105b8SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
4437683fdc1SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
4447683fdc1SAntonio Quartulli 	struct hlist_head *head;
4457683fdc1SAntonio Quartulli 	int i;
446a73105b8SAntonio Quartulli 
4472dafb49dSAntonio Quartulli 	if (!bat_priv->tt_local_hash)
448c6c8fea2SSven Eckelmann 		return;
449c6c8fea2SSven Eckelmann 
450a73105b8SAntonio Quartulli 	hash = bat_priv->tt_local_hash;
451a73105b8SAntonio Quartulli 
452a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
453a73105b8SAntonio Quartulli 		head = &hash->table[i];
454a73105b8SAntonio Quartulli 		list_lock = &hash->list_locks[i];
455a73105b8SAntonio Quartulli 
456a73105b8SAntonio Quartulli 		spin_lock_bh(list_lock);
457a73105b8SAntonio Quartulli 		hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
458a73105b8SAntonio Quartulli 					  head, hash_entry) {
459a73105b8SAntonio Quartulli 			hlist_del_rcu(node);
4607683fdc1SAntonio Quartulli 			tt_local_entry_free_ref(tt_local_entry);
461a73105b8SAntonio Quartulli 		}
462a73105b8SAntonio Quartulli 		spin_unlock_bh(list_lock);
463a73105b8SAntonio Quartulli 	}
464a73105b8SAntonio Quartulli 
465a73105b8SAntonio Quartulli 	hash_destroy(hash);
466a73105b8SAntonio Quartulli 
4672dafb49dSAntonio Quartulli 	bat_priv->tt_local_hash = NULL;
468c6c8fea2SSven Eckelmann }
469c6c8fea2SSven Eckelmann 
470a73105b8SAntonio Quartulli static int tt_global_init(struct bat_priv *bat_priv)
471c6c8fea2SSven Eckelmann {
4722dafb49dSAntonio Quartulli 	if (bat_priv->tt_global_hash)
473c6c8fea2SSven Eckelmann 		return 1;
474c6c8fea2SSven Eckelmann 
4752dafb49dSAntonio Quartulli 	bat_priv->tt_global_hash = hash_new(1024);
476c6c8fea2SSven Eckelmann 
4772dafb49dSAntonio Quartulli 	if (!bat_priv->tt_global_hash)
478c6c8fea2SSven Eckelmann 		return 0;
479c6c8fea2SSven Eckelmann 
480c6c8fea2SSven Eckelmann 	return 1;
481c6c8fea2SSven Eckelmann }
482c6c8fea2SSven Eckelmann 
483a73105b8SAntonio Quartulli static void tt_changes_list_free(struct bat_priv *bat_priv)
484a73105b8SAntonio Quartulli {
485a73105b8SAntonio Quartulli 	struct tt_change_node *entry, *safe;
486a73105b8SAntonio Quartulli 
487a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
488a73105b8SAntonio Quartulli 
489a73105b8SAntonio Quartulli 	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
490a73105b8SAntonio Quartulli 				 list) {
491a73105b8SAntonio Quartulli 		list_del(&entry->list);
492a73105b8SAntonio Quartulli 		kfree(entry);
493a73105b8SAntonio Quartulli 	}
494a73105b8SAntonio Quartulli 
495a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_local_changes, 0);
496a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
497a73105b8SAntonio Quartulli }
498a73105b8SAntonio Quartulli 
499a73105b8SAntonio Quartulli /* caller must hold orig_node refcount */
500a73105b8SAntonio Quartulli int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
501bc279080SAntonio Quartulli 		  const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
502bc279080SAntonio Quartulli 		  bool wifi)
503c6c8fea2SSven Eckelmann {
5042dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
505a73105b8SAntonio Quartulli 	struct orig_node *orig_node_tmp;
5067683fdc1SAntonio Quartulli 	int ret = 0;
507c6c8fea2SSven Eckelmann 
508a73105b8SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
509c6c8fea2SSven Eckelmann 
5102dafb49dSAntonio Quartulli 	if (!tt_global_entry) {
511a73105b8SAntonio Quartulli 		tt_global_entry =
512a73105b8SAntonio Quartulli 			kmalloc(sizeof(*tt_global_entry),
513c6c8fea2SSven Eckelmann 				GFP_ATOMIC);
5142dafb49dSAntonio Quartulli 		if (!tt_global_entry)
5157683fdc1SAntonio Quartulli 			goto out;
5167683fdc1SAntonio Quartulli 
517a73105b8SAntonio Quartulli 		memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN);
518a73105b8SAntonio Quartulli 		/* Assign the new orig_node */
519a73105b8SAntonio Quartulli 		atomic_inc(&orig_node->refcount);
520a73105b8SAntonio Quartulli 		tt_global_entry->orig_node = orig_node;
521a73105b8SAntonio Quartulli 		tt_global_entry->ttvn = ttvn;
522cc47f66eSAntonio Quartulli 		tt_global_entry->flags = NO_FLAGS;
523cc47f66eSAntonio Quartulli 		tt_global_entry->roam_at = 0;
5247683fdc1SAntonio Quartulli 		atomic_set(&tt_global_entry->refcount, 2);
5257683fdc1SAntonio Quartulli 
5262dafb49dSAntonio Quartulli 		hash_add(bat_priv->tt_global_hash, compare_gtt,
5272dafb49dSAntonio Quartulli 			 choose_orig, tt_global_entry,
5282dafb49dSAntonio Quartulli 			 &tt_global_entry->hash_entry);
5297683fdc1SAntonio Quartulli 		atomic_inc(&orig_node->tt_size);
530a73105b8SAntonio Quartulli 	} else {
531a73105b8SAntonio Quartulli 		if (tt_global_entry->orig_node != orig_node) {
532a73105b8SAntonio Quartulli 			atomic_dec(&tt_global_entry->orig_node->tt_size);
533a73105b8SAntonio Quartulli 			orig_node_tmp = tt_global_entry->orig_node;
534a73105b8SAntonio Quartulli 			atomic_inc(&orig_node->refcount);
535a73105b8SAntonio Quartulli 			tt_global_entry->orig_node = orig_node;
536a73105b8SAntonio Quartulli 			orig_node_free_ref(orig_node_tmp);
537a73105b8SAntonio Quartulli 			atomic_inc(&orig_node->tt_size);
538a73105b8SAntonio Quartulli 		}
539cc47f66eSAntonio Quartulli 		tt_global_entry->ttvn = ttvn;
540cc47f66eSAntonio Quartulli 		tt_global_entry->flags = NO_FLAGS;
541cc47f66eSAntonio Quartulli 		tt_global_entry->roam_at = 0;
542c6c8fea2SSven Eckelmann 	}
543c6c8fea2SSven Eckelmann 
544bc279080SAntonio Quartulli 	if (wifi)
545bc279080SAntonio Quartulli 		tt_global_entry->flags |= TT_CLIENT_WIFI;
546bc279080SAntonio Quartulli 
547a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
548a73105b8SAntonio Quartulli 		"Creating new global tt entry: %pM (via %pM)\n",
549a73105b8SAntonio Quartulli 		tt_global_entry->addr, orig_node->orig);
550a73105b8SAntonio Quartulli 
551c6c8fea2SSven Eckelmann 	/* remove address from local hash if present */
552cc47f66eSAntonio Quartulli 	tt_local_remove(bat_priv, tt_global_entry->addr,
553cc47f66eSAntonio Quartulli 			"global tt received", roaming);
5547683fdc1SAntonio Quartulli 	ret = 1;
5557683fdc1SAntonio Quartulli out:
5567683fdc1SAntonio Quartulli 	if (tt_global_entry)
5577683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
5587683fdc1SAntonio Quartulli 	return ret;
559c6c8fea2SSven Eckelmann }
560c6c8fea2SSven Eckelmann 
5612dafb49dSAntonio Quartulli int tt_global_seq_print_text(struct seq_file *seq, void *offset)
562c6c8fea2SSven Eckelmann {
563c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
564c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(net_dev);
5652dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
5662dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
56732ae9b22SMarek Lindner 	struct hard_iface *primary_if;
5687aadf889SMarek Lindner 	struct hlist_node *node;
569c6c8fea2SSven Eckelmann 	struct hlist_head *head;
570c6c8fea2SSven Eckelmann 	size_t buf_size, pos;
571c6c8fea2SSven Eckelmann 	char *buff;
57232ae9b22SMarek Lindner 	int i, ret = 0;
573c6c8fea2SSven Eckelmann 
57432ae9b22SMarek Lindner 	primary_if = primary_if_get_selected(bat_priv);
57532ae9b22SMarek Lindner 	if (!primary_if) {
57632ae9b22SMarek Lindner 		ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
57732ae9b22SMarek Lindner 				 "specify interfaces to enable it\n",
578c6c8fea2SSven Eckelmann 				 net_dev->name);
57932ae9b22SMarek Lindner 		goto out;
58032ae9b22SMarek Lindner 	}
58132ae9b22SMarek Lindner 
58232ae9b22SMarek Lindner 	if (primary_if->if_status != IF_ACTIVE) {
58332ae9b22SMarek Lindner 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
58432ae9b22SMarek Lindner 				 "primary interface not active\n",
58532ae9b22SMarek Lindner 				 net_dev->name);
58632ae9b22SMarek Lindner 		goto out;
587c6c8fea2SSven Eckelmann 	}
588c6c8fea2SSven Eckelmann 
5892dafb49dSAntonio Quartulli 	seq_printf(seq,
5902dafb49dSAntonio Quartulli 		   "Globally announced TT entries received via the mesh %s\n",
591c6c8fea2SSven Eckelmann 		   net_dev->name);
592a73105b8SAntonio Quartulli 	seq_printf(seq, "       %-13s %s       %-15s %s\n",
593a73105b8SAntonio Quartulli 		   "Client", "(TTVN)", "Originator", "(Curr TTVN)");
594c6c8fea2SSven Eckelmann 
595c6c8fea2SSven Eckelmann 	buf_size = 1;
596a73105b8SAntonio Quartulli 	/* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via
597a73105b8SAntonio Quartulli 	 * xx:xx:xx:xx:xx:xx (cur_ttvn)\n"*/
598c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
599c6c8fea2SSven Eckelmann 		head = &hash->table[i];
600c6c8fea2SSven Eckelmann 
6017aadf889SMarek Lindner 		rcu_read_lock();
6027aadf889SMarek Lindner 		__hlist_for_each_rcu(node, head)
603a73105b8SAntonio Quartulli 			buf_size += 59;
6047aadf889SMarek Lindner 		rcu_read_unlock();
605c6c8fea2SSven Eckelmann 	}
606c6c8fea2SSven Eckelmann 
607c6c8fea2SSven Eckelmann 	buff = kmalloc(buf_size, GFP_ATOMIC);
608c6c8fea2SSven Eckelmann 	if (!buff) {
60932ae9b22SMarek Lindner 		ret = -ENOMEM;
61032ae9b22SMarek Lindner 		goto out;
611c6c8fea2SSven Eckelmann 	}
6127683fdc1SAntonio Quartulli 
613c6c8fea2SSven Eckelmann 	buff[0] = '\0';
614c6c8fea2SSven Eckelmann 	pos = 0;
615c6c8fea2SSven Eckelmann 
616c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
617c6c8fea2SSven Eckelmann 		head = &hash->table[i];
618c6c8fea2SSven Eckelmann 
6197aadf889SMarek Lindner 		rcu_read_lock();
6202dafb49dSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_global_entry, node,
6217aadf889SMarek Lindner 					 head, hash_entry) {
622a73105b8SAntonio Quartulli 			pos += snprintf(buff + pos, 61,
623a73105b8SAntonio Quartulli 					" * %pM  (%3u) via %pM     (%3u)\n",
6242dafb49dSAntonio Quartulli 					tt_global_entry->addr,
625a73105b8SAntonio Quartulli 					tt_global_entry->ttvn,
626a73105b8SAntonio Quartulli 					tt_global_entry->orig_node->orig,
627a73105b8SAntonio Quartulli 					(uint8_t) atomic_read(
628a73105b8SAntonio Quartulli 						&tt_global_entry->orig_node->
629a73105b8SAntonio Quartulli 						last_ttvn));
630c6c8fea2SSven Eckelmann 		}
6317aadf889SMarek Lindner 		rcu_read_unlock();
632c6c8fea2SSven Eckelmann 	}
633c6c8fea2SSven Eckelmann 
634c6c8fea2SSven Eckelmann 	seq_printf(seq, "%s", buff);
635c6c8fea2SSven Eckelmann 	kfree(buff);
63632ae9b22SMarek Lindner out:
63732ae9b22SMarek Lindner 	if (primary_if)
63832ae9b22SMarek Lindner 		hardif_free_ref(primary_if);
63932ae9b22SMarek Lindner 	return ret;
640c6c8fea2SSven Eckelmann }
641c6c8fea2SSven Eckelmann 
642a73105b8SAntonio Quartulli static void _tt_global_del(struct bat_priv *bat_priv,
6432dafb49dSAntonio Quartulli 			   struct tt_global_entry *tt_global_entry,
644747e4221SSven Eckelmann 			   const char *message)
645c6c8fea2SSven Eckelmann {
646a73105b8SAntonio Quartulli 	if (!tt_global_entry)
6477683fdc1SAntonio Quartulli 		goto out;
648a73105b8SAntonio Quartulli 
649a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
6502dafb49dSAntonio Quartulli 		"Deleting global tt entry %pM (via %pM): %s\n",
6512dafb49dSAntonio Quartulli 		tt_global_entry->addr, tt_global_entry->orig_node->orig,
652c6c8fea2SSven Eckelmann 		message);
653c6c8fea2SSven Eckelmann 
654a73105b8SAntonio Quartulli 	atomic_dec(&tt_global_entry->orig_node->tt_size);
6557683fdc1SAntonio Quartulli 
6562dafb49dSAntonio Quartulli 	hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig,
6572dafb49dSAntonio Quartulli 		    tt_global_entry->addr);
6587683fdc1SAntonio Quartulli out:
6597683fdc1SAntonio Quartulli 	if (tt_global_entry)
6607683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
661c6c8fea2SSven Eckelmann }
662c6c8fea2SSven Eckelmann 
663a73105b8SAntonio Quartulli void tt_global_del(struct bat_priv *bat_priv,
664a73105b8SAntonio Quartulli 		   struct orig_node *orig_node, const unsigned char *addr,
665cc47f66eSAntonio Quartulli 		   const char *message, bool roaming)
666a73105b8SAntonio Quartulli {
6677683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
668a73105b8SAntonio Quartulli 
669a73105b8SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
6707683fdc1SAntonio Quartulli 	if (!tt_global_entry)
6717683fdc1SAntonio Quartulli 		goto out;
672a73105b8SAntonio Quartulli 
6737683fdc1SAntonio Quartulli 	if (tt_global_entry->orig_node == orig_node) {
674cc47f66eSAntonio Quartulli 		if (roaming) {
675cc47f66eSAntonio Quartulli 			tt_global_entry->flags |= TT_CLIENT_ROAM;
676cc47f66eSAntonio Quartulli 			tt_global_entry->roam_at = jiffies;
677cc47f66eSAntonio Quartulli 			goto out;
678cc47f66eSAntonio Quartulli 		}
679a73105b8SAntonio Quartulli 		_tt_global_del(bat_priv, tt_global_entry, message);
680a73105b8SAntonio Quartulli 	}
681cc47f66eSAntonio Quartulli out:
6827683fdc1SAntonio Quartulli 	if (tt_global_entry)
6837683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
684a73105b8SAntonio Quartulli }
685a73105b8SAntonio Quartulli 
6862dafb49dSAntonio Quartulli void tt_global_del_orig(struct bat_priv *bat_priv,
687747e4221SSven Eckelmann 			struct orig_node *orig_node, const char *message)
688c6c8fea2SSven Eckelmann {
6892dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
690a73105b8SAntonio Quartulli 	int i;
691a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
692a73105b8SAntonio Quartulli 	struct hlist_node *node, *safe;
693a73105b8SAntonio Quartulli 	struct hlist_head *head;
6947683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
695c6c8fea2SSven Eckelmann 
696a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
697a73105b8SAntonio Quartulli 		head = &hash->table[i];
6987683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
699c6c8fea2SSven Eckelmann 
7007683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
701a73105b8SAntonio Quartulli 		hlist_for_each_entry_safe(tt_global_entry, node, safe,
702a73105b8SAntonio Quartulli 					 head, hash_entry) {
7037683fdc1SAntonio Quartulli 			if (tt_global_entry->orig_node == orig_node) {
7047683fdc1SAntonio Quartulli 				bat_dbg(DBG_TT, bat_priv,
7057683fdc1SAntonio Quartulli 					"Deleting global tt entry %pM "
7067683fdc1SAntonio Quartulli 					"(via %pM): originator time out\n",
7077683fdc1SAntonio Quartulli 					tt_global_entry->addr,
7087683fdc1SAntonio Quartulli 					tt_global_entry->orig_node->orig);
7097683fdc1SAntonio Quartulli 				hlist_del_rcu(node);
7107683fdc1SAntonio Quartulli 				tt_global_entry_free_ref(tt_global_entry);
711c6c8fea2SSven Eckelmann 			}
712a73105b8SAntonio Quartulli 		}
7137683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
7147683fdc1SAntonio Quartulli 	}
715a73105b8SAntonio Quartulli 	atomic_set(&orig_node->tt_size, 0);
716c6c8fea2SSven Eckelmann }
717c6c8fea2SSven Eckelmann 
718cc47f66eSAntonio Quartulli static void tt_global_roam_purge(struct bat_priv *bat_priv)
719cc47f66eSAntonio Quartulli {
720cc47f66eSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
721cc47f66eSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
722cc47f66eSAntonio Quartulli 	struct hlist_node *node, *node_tmp;
723cc47f66eSAntonio Quartulli 	struct hlist_head *head;
7247683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
725cc47f66eSAntonio Quartulli 	int i;
726cc47f66eSAntonio Quartulli 
727cc47f66eSAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
728cc47f66eSAntonio Quartulli 		head = &hash->table[i];
7297683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
730cc47f66eSAntonio Quartulli 
7317683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
732cc47f66eSAntonio Quartulli 		hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
733cc47f66eSAntonio Quartulli 					  head, hash_entry) {
734cc47f66eSAntonio Quartulli 			if (!(tt_global_entry->flags & TT_CLIENT_ROAM))
735cc47f66eSAntonio Quartulli 				continue;
736cc47f66eSAntonio Quartulli 			if (!is_out_of_time(tt_global_entry->roam_at,
737cc47f66eSAntonio Quartulli 					    TT_CLIENT_ROAM_TIMEOUT * 1000))
738cc47f66eSAntonio Quartulli 				continue;
739cc47f66eSAntonio Quartulli 
7407683fdc1SAntonio Quartulli 			bat_dbg(DBG_TT, bat_priv, "Deleting global "
7417683fdc1SAntonio Quartulli 				"tt entry (%pM): Roaming timeout\n",
7427683fdc1SAntonio Quartulli 				tt_global_entry->addr);
7437683fdc1SAntonio Quartulli 			atomic_dec(&tt_global_entry->orig_node->tt_size);
7447683fdc1SAntonio Quartulli 			hlist_del_rcu(node);
7457683fdc1SAntonio Quartulli 			tt_global_entry_free_ref(tt_global_entry);
746cc47f66eSAntonio Quartulli 		}
7477683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
748cc47f66eSAntonio Quartulli 	}
749cc47f66eSAntonio Quartulli 
750cc47f66eSAntonio Quartulli }
751cc47f66eSAntonio Quartulli 
752a73105b8SAntonio Quartulli static void tt_global_table_free(struct bat_priv *bat_priv)
753c6c8fea2SSven Eckelmann {
7547683fdc1SAntonio Quartulli 	struct hashtable_t *hash;
7557683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
7567683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
7577683fdc1SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
7587683fdc1SAntonio Quartulli 	struct hlist_head *head;
7597683fdc1SAntonio Quartulli 	int i;
7607683fdc1SAntonio Quartulli 
7612dafb49dSAntonio Quartulli 	if (!bat_priv->tt_global_hash)
762c6c8fea2SSven Eckelmann 		return;
763c6c8fea2SSven Eckelmann 
7647683fdc1SAntonio Quartulli 	hash = bat_priv->tt_global_hash;
7657683fdc1SAntonio Quartulli 
7667683fdc1SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
7677683fdc1SAntonio Quartulli 		head = &hash->table[i];
7687683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
7697683fdc1SAntonio Quartulli 
7707683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
7717683fdc1SAntonio Quartulli 		hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
7727683fdc1SAntonio Quartulli 					  head, hash_entry) {
7737683fdc1SAntonio Quartulli 			hlist_del_rcu(node);
7747683fdc1SAntonio Quartulli 			tt_global_entry_free_ref(tt_global_entry);
7757683fdc1SAntonio Quartulli 		}
7767683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
7777683fdc1SAntonio Quartulli 	}
7787683fdc1SAntonio Quartulli 
7797683fdc1SAntonio Quartulli 	hash_destroy(hash);
7807683fdc1SAntonio Quartulli 
7812dafb49dSAntonio Quartulli 	bat_priv->tt_global_hash = NULL;
782c6c8fea2SSven Eckelmann }
783c6c8fea2SSven Eckelmann 
78459b699cdSAntonio Quartulli static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
78559b699cdSAntonio Quartulli 			    struct tt_global_entry *tt_global_entry)
78659b699cdSAntonio Quartulli {
78759b699cdSAntonio Quartulli 	bool ret = false;
78859b699cdSAntonio Quartulli 
78959b699cdSAntonio Quartulli 	if (tt_local_entry->flags & TT_CLIENT_WIFI &&
79059b699cdSAntonio Quartulli 	    tt_global_entry->flags & TT_CLIENT_WIFI)
79159b699cdSAntonio Quartulli 		ret = true;
79259b699cdSAntonio Quartulli 
79359b699cdSAntonio Quartulli 	return ret;
79459b699cdSAntonio Quartulli }
79559b699cdSAntonio Quartulli 
796747e4221SSven Eckelmann struct orig_node *transtable_search(struct bat_priv *bat_priv,
7973d393e47SAntonio Quartulli 				    const uint8_t *src, const uint8_t *addr)
798c6c8fea2SSven Eckelmann {
7993d393e47SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
8003d393e47SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
8017b36e8eeSMarek Lindner 	struct orig_node *orig_node = NULL;
802c6c8fea2SSven Eckelmann 
8033d393e47SAntonio Quartulli 	if (src && atomic_read(&bat_priv->ap_isolation)) {
8043d393e47SAntonio Quartulli 		tt_local_entry = tt_local_hash_find(bat_priv, src);
8053d393e47SAntonio Quartulli 		if (!tt_local_entry)
8063d393e47SAntonio Quartulli 			goto out;
8073d393e47SAntonio Quartulli 	}
8087aadf889SMarek Lindner 
8093d393e47SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
8102dafb49dSAntonio Quartulli 	if (!tt_global_entry)
8117b36e8eeSMarek Lindner 		goto out;
812c6c8fea2SSven Eckelmann 
8133d393e47SAntonio Quartulli 	/* check whether the clients should not communicate due to AP
8143d393e47SAntonio Quartulli 	 * isolation */
8153d393e47SAntonio Quartulli 	if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
8163d393e47SAntonio Quartulli 		goto out;
8173d393e47SAntonio Quartulli 
8182dafb49dSAntonio Quartulli 	if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
8193d393e47SAntonio Quartulli 		goto out;
8207b36e8eeSMarek Lindner 
821980d55b2SAntonio Quartulli 	/* A global client marked as PENDING has already moved from that
822980d55b2SAntonio Quartulli 	 * originator */
823980d55b2SAntonio Quartulli 	if (tt_global_entry->flags & TT_CLIENT_PENDING)
8243d393e47SAntonio Quartulli 		goto out;
825980d55b2SAntonio Quartulli 
8262dafb49dSAntonio Quartulli 	orig_node = tt_global_entry->orig_node;
8277b36e8eeSMarek Lindner 
8287b36e8eeSMarek Lindner out:
8293d393e47SAntonio Quartulli 	if (tt_global_entry)
8303d393e47SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
8313d393e47SAntonio Quartulli 	if (tt_local_entry)
8323d393e47SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
8333d393e47SAntonio Quartulli 
8347b36e8eeSMarek Lindner 	return orig_node;
835c6c8fea2SSven Eckelmann }
836a73105b8SAntonio Quartulli 
837a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */
838a73105b8SAntonio Quartulli uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
839a73105b8SAntonio Quartulli {
840a73105b8SAntonio Quartulli 	uint16_t total = 0, total_one;
841a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
842a73105b8SAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
843a73105b8SAntonio Quartulli 	struct hlist_node *node;
844a73105b8SAntonio Quartulli 	struct hlist_head *head;
845a73105b8SAntonio Quartulli 	int i, j;
846a73105b8SAntonio Quartulli 
847a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
848a73105b8SAntonio Quartulli 		head = &hash->table[i];
849a73105b8SAntonio Quartulli 
850a73105b8SAntonio Quartulli 		rcu_read_lock();
851a73105b8SAntonio Quartulli 		hlist_for_each_entry_rcu(tt_global_entry, node,
852a73105b8SAntonio Quartulli 					 head, hash_entry) {
853a73105b8SAntonio Quartulli 			if (compare_eth(tt_global_entry->orig_node,
854a73105b8SAntonio Quartulli 					orig_node)) {
855cc47f66eSAntonio Quartulli 				/* Roaming clients are in the global table for
856cc47f66eSAntonio Quartulli 				 * consistency only. They don't have to be
857cc47f66eSAntonio Quartulli 				 * taken into account while computing the
858cc47f66eSAntonio Quartulli 				 * global crc */
859cc47f66eSAntonio Quartulli 				if (tt_global_entry->flags & TT_CLIENT_ROAM)
860cc47f66eSAntonio Quartulli 					continue;
861a73105b8SAntonio Quartulli 				total_one = 0;
862a73105b8SAntonio Quartulli 				for (j = 0; j < ETH_ALEN; j++)
863a73105b8SAntonio Quartulli 					total_one = crc16_byte(total_one,
864a73105b8SAntonio Quartulli 						tt_global_entry->addr[j]);
865a73105b8SAntonio Quartulli 				total ^= total_one;
866a73105b8SAntonio Quartulli 			}
867a73105b8SAntonio Quartulli 		}
868a73105b8SAntonio Quartulli 		rcu_read_unlock();
869a73105b8SAntonio Quartulli 	}
870a73105b8SAntonio Quartulli 
871a73105b8SAntonio Quartulli 	return total;
872a73105b8SAntonio Quartulli }
873a73105b8SAntonio Quartulli 
874a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */
875a73105b8SAntonio Quartulli uint16_t tt_local_crc(struct bat_priv *bat_priv)
876a73105b8SAntonio Quartulli {
877a73105b8SAntonio Quartulli 	uint16_t total = 0, total_one;
878a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
879a73105b8SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
880a73105b8SAntonio Quartulli 	struct hlist_node *node;
881a73105b8SAntonio Quartulli 	struct hlist_head *head;
882a73105b8SAntonio Quartulli 	int i, j;
883a73105b8SAntonio Quartulli 
884a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
885a73105b8SAntonio Quartulli 		head = &hash->table[i];
886a73105b8SAntonio Quartulli 
887a73105b8SAntonio Quartulli 		rcu_read_lock();
888a73105b8SAntonio Quartulli 		hlist_for_each_entry_rcu(tt_local_entry, node,
889a73105b8SAntonio Quartulli 					 head, hash_entry) {
890058d0e26SAntonio Quartulli 			/* not yet committed clients have not to be taken into
891058d0e26SAntonio Quartulli 			 * account while computing the CRC */
892058d0e26SAntonio Quartulli 			if (tt_local_entry->flags & TT_CLIENT_NEW)
893058d0e26SAntonio Quartulli 				continue;
894a73105b8SAntonio Quartulli 			total_one = 0;
895a73105b8SAntonio Quartulli 			for (j = 0; j < ETH_ALEN; j++)
896a73105b8SAntonio Quartulli 				total_one = crc16_byte(total_one,
897a73105b8SAntonio Quartulli 						   tt_local_entry->addr[j]);
898a73105b8SAntonio Quartulli 			total ^= total_one;
899a73105b8SAntonio Quartulli 		}
900a73105b8SAntonio Quartulli 		rcu_read_unlock();
901a73105b8SAntonio Quartulli 	}
902a73105b8SAntonio Quartulli 
903a73105b8SAntonio Quartulli 	return total;
904a73105b8SAntonio Quartulli }
905a73105b8SAntonio Quartulli 
906a73105b8SAntonio Quartulli static void tt_req_list_free(struct bat_priv *bat_priv)
907a73105b8SAntonio Quartulli {
908a73105b8SAntonio Quartulli 	struct tt_req_node *node, *safe;
909a73105b8SAntonio Quartulli 
910a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
911a73105b8SAntonio Quartulli 
912a73105b8SAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
913a73105b8SAntonio Quartulli 		list_del(&node->list);
914a73105b8SAntonio Quartulli 		kfree(node);
915a73105b8SAntonio Quartulli 	}
916a73105b8SAntonio Quartulli 
917a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
918a73105b8SAntonio Quartulli }
919a73105b8SAntonio Quartulli 
920a73105b8SAntonio Quartulli void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
921a73105b8SAntonio Quartulli 			 const unsigned char *tt_buff, uint8_t tt_num_changes)
922a73105b8SAntonio Quartulli {
923a73105b8SAntonio Quartulli 	uint16_t tt_buff_len = tt_len(tt_num_changes);
924a73105b8SAntonio Quartulli 
925a73105b8SAntonio Quartulli 	/* Replace the old buffer only if I received something in the
926a73105b8SAntonio Quartulli 	 * last OGM (the OGM could carry no changes) */
927a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
928a73105b8SAntonio Quartulli 	if (tt_buff_len > 0) {
929a73105b8SAntonio Quartulli 		kfree(orig_node->tt_buff);
930a73105b8SAntonio Quartulli 		orig_node->tt_buff_len = 0;
931a73105b8SAntonio Quartulli 		orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
932a73105b8SAntonio Quartulli 		if (orig_node->tt_buff) {
933a73105b8SAntonio Quartulli 			memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
934a73105b8SAntonio Quartulli 			orig_node->tt_buff_len = tt_buff_len;
935a73105b8SAntonio Quartulli 		}
936a73105b8SAntonio Quartulli 	}
937a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
938a73105b8SAntonio Quartulli }
939a73105b8SAntonio Quartulli 
940a73105b8SAntonio Quartulli static void tt_req_purge(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 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
946a73105b8SAntonio Quartulli 		if (is_out_of_time(node->issued_at,
947a73105b8SAntonio Quartulli 		    TT_REQUEST_TIMEOUT * 1000)) {
948a73105b8SAntonio Quartulli 			list_del(&node->list);
949a73105b8SAntonio Quartulli 			kfree(node);
950a73105b8SAntonio Quartulli 		}
951a73105b8SAntonio Quartulli 	}
952a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
953a73105b8SAntonio Quartulli }
954a73105b8SAntonio Quartulli 
955a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request
956a73105b8SAntonio Quartulli  * has already been issued for this orig_node, NULL otherwise */
957a73105b8SAntonio Quartulli static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
958a73105b8SAntonio Quartulli 					  struct orig_node *orig_node)
959a73105b8SAntonio Quartulli {
960a73105b8SAntonio Quartulli 	struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
961a73105b8SAntonio Quartulli 
962a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
963a73105b8SAntonio Quartulli 	list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
964a73105b8SAntonio Quartulli 		if (compare_eth(tt_req_node_tmp, orig_node) &&
965a73105b8SAntonio Quartulli 		    !is_out_of_time(tt_req_node_tmp->issued_at,
966a73105b8SAntonio Quartulli 				    TT_REQUEST_TIMEOUT * 1000))
967a73105b8SAntonio Quartulli 			goto unlock;
968a73105b8SAntonio Quartulli 	}
969a73105b8SAntonio Quartulli 
970a73105b8SAntonio Quartulli 	tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
971a73105b8SAntonio Quartulli 	if (!tt_req_node)
972a73105b8SAntonio Quartulli 		goto unlock;
973a73105b8SAntonio Quartulli 
974a73105b8SAntonio Quartulli 	memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
975a73105b8SAntonio Quartulli 	tt_req_node->issued_at = jiffies;
976a73105b8SAntonio Quartulli 
977a73105b8SAntonio Quartulli 	list_add(&tt_req_node->list, &bat_priv->tt_req_list);
978a73105b8SAntonio Quartulli unlock:
979a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
980a73105b8SAntonio Quartulli 	return tt_req_node;
981a73105b8SAntonio Quartulli }
982a73105b8SAntonio Quartulli 
983058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */
984058d0e26SAntonio Quartulli static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
985058d0e26SAntonio Quartulli {
986058d0e26SAntonio Quartulli 	const struct tt_local_entry *tt_local_entry = entry_ptr;
987058d0e26SAntonio Quartulli 
988058d0e26SAntonio Quartulli 	if (tt_local_entry->flags & TT_CLIENT_NEW)
989058d0e26SAntonio Quartulli 		return 0;
990058d0e26SAntonio Quartulli 	return 1;
991058d0e26SAntonio Quartulli }
992058d0e26SAntonio Quartulli 
993a73105b8SAntonio Quartulli static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
994a73105b8SAntonio Quartulli {
995a73105b8SAntonio Quartulli 	const struct tt_global_entry *tt_global_entry = entry_ptr;
996a73105b8SAntonio Quartulli 	const struct orig_node *orig_node = data_ptr;
997a73105b8SAntonio Quartulli 
998cc47f66eSAntonio Quartulli 	if (tt_global_entry->flags & TT_CLIENT_ROAM)
999cc47f66eSAntonio Quartulli 		return 0;
1000cc47f66eSAntonio Quartulli 
1001a73105b8SAntonio Quartulli 	return (tt_global_entry->orig_node == orig_node);
1002a73105b8SAntonio Quartulli }
1003a73105b8SAntonio Quartulli 
1004a73105b8SAntonio Quartulli static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
1005a73105b8SAntonio Quartulli 					      struct hashtable_t *hash,
1006a73105b8SAntonio Quartulli 					      struct hard_iface *primary_if,
1007a73105b8SAntonio Quartulli 					      int (*valid_cb)(const void *,
1008a73105b8SAntonio Quartulli 							      const void *),
1009a73105b8SAntonio Quartulli 					      void *cb_data)
1010a73105b8SAntonio Quartulli {
1011a73105b8SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
1012a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1013a73105b8SAntonio Quartulli 	struct tt_change *tt_change;
1014a73105b8SAntonio Quartulli 	struct hlist_node *node;
1015a73105b8SAntonio Quartulli 	struct hlist_head *head;
1016a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1017a73105b8SAntonio Quartulli 	uint16_t tt_tot, tt_count;
1018a73105b8SAntonio Quartulli 	ssize_t tt_query_size = sizeof(struct tt_query_packet);
1019a73105b8SAntonio Quartulli 	int i;
1020a73105b8SAntonio Quartulli 
1021a73105b8SAntonio Quartulli 	if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
1022a73105b8SAntonio Quartulli 		tt_len = primary_if->soft_iface->mtu - tt_query_size;
1023a73105b8SAntonio Quartulli 		tt_len -= tt_len % sizeof(struct tt_change);
1024a73105b8SAntonio Quartulli 	}
1025a73105b8SAntonio Quartulli 	tt_tot = tt_len / sizeof(struct tt_change);
1026a73105b8SAntonio Quartulli 
1027a73105b8SAntonio Quartulli 	skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
1028a73105b8SAntonio Quartulli 	if (!skb)
1029a73105b8SAntonio Quartulli 		goto out;
1030a73105b8SAntonio Quartulli 
1031a73105b8SAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1032a73105b8SAntonio Quartulli 	tt_response = (struct tt_query_packet *)skb_put(skb,
1033a73105b8SAntonio Quartulli 						     tt_query_size + tt_len);
1034a73105b8SAntonio Quartulli 	tt_response->ttvn = ttvn;
1035a73105b8SAntonio Quartulli 	tt_response->tt_data = htons(tt_tot);
1036a73105b8SAntonio Quartulli 
1037a73105b8SAntonio Quartulli 	tt_change = (struct tt_change *)(skb->data + tt_query_size);
1038a73105b8SAntonio Quartulli 	tt_count = 0;
1039a73105b8SAntonio Quartulli 
1040a73105b8SAntonio Quartulli 	rcu_read_lock();
1041a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1042a73105b8SAntonio Quartulli 		head = &hash->table[i];
1043a73105b8SAntonio Quartulli 
1044a73105b8SAntonio Quartulli 		hlist_for_each_entry_rcu(tt_local_entry, node,
1045a73105b8SAntonio Quartulli 					 head, hash_entry) {
1046a73105b8SAntonio Quartulli 			if (tt_count == tt_tot)
1047a73105b8SAntonio Quartulli 				break;
1048a73105b8SAntonio Quartulli 
1049a73105b8SAntonio Quartulli 			if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data)))
1050a73105b8SAntonio Quartulli 				continue;
1051a73105b8SAntonio Quartulli 
1052a73105b8SAntonio Quartulli 			memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN);
1053a73105b8SAntonio Quartulli 			tt_change->flags = NO_FLAGS;
1054a73105b8SAntonio Quartulli 
1055a73105b8SAntonio Quartulli 			tt_count++;
1056a73105b8SAntonio Quartulli 			tt_change++;
1057a73105b8SAntonio Quartulli 		}
1058a73105b8SAntonio Quartulli 	}
1059a73105b8SAntonio Quartulli 	rcu_read_unlock();
1060a73105b8SAntonio Quartulli 
1061a73105b8SAntonio Quartulli out:
1062a73105b8SAntonio Quartulli 	return skb;
1063a73105b8SAntonio Quartulli }
1064a73105b8SAntonio Quartulli 
1065a73105b8SAntonio Quartulli int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_orig_node,
1066a73105b8SAntonio Quartulli 		    uint8_t ttvn, uint16_t tt_crc, bool full_table)
1067a73105b8SAntonio Quartulli {
1068a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1069a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_request;
1070a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1071a73105b8SAntonio Quartulli 	struct hard_iface *primary_if;
1072a73105b8SAntonio Quartulli 	struct tt_req_node *tt_req_node = NULL;
1073a73105b8SAntonio Quartulli 	int ret = 1;
1074a73105b8SAntonio Quartulli 
1075a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1076a73105b8SAntonio Quartulli 	if (!primary_if)
1077a73105b8SAntonio Quartulli 		goto out;
1078a73105b8SAntonio Quartulli 
1079a73105b8SAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
1080a73105b8SAntonio Quartulli 	 * reply from the same orig_node yet */
1081a73105b8SAntonio Quartulli 	tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
1082a73105b8SAntonio Quartulli 	if (!tt_req_node)
1083a73105b8SAntonio Quartulli 		goto out;
1084a73105b8SAntonio Quartulli 
1085a73105b8SAntonio Quartulli 	skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
1086a73105b8SAntonio Quartulli 	if (!skb)
1087a73105b8SAntonio Quartulli 		goto out;
1088a73105b8SAntonio Quartulli 
1089a73105b8SAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1090a73105b8SAntonio Quartulli 
1091a73105b8SAntonio Quartulli 	tt_request = (struct tt_query_packet *)skb_put(skb,
1092a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet));
1093a73105b8SAntonio Quartulli 
1094a73105b8SAntonio Quartulli 	tt_request->packet_type = BAT_TT_QUERY;
1095a73105b8SAntonio Quartulli 	tt_request->version = COMPAT_VERSION;
1096a73105b8SAntonio Quartulli 	memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1097a73105b8SAntonio Quartulli 	memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
1098a73105b8SAntonio Quartulli 	tt_request->ttl = TTL;
1099a73105b8SAntonio Quartulli 	tt_request->ttvn = ttvn;
1100a73105b8SAntonio Quartulli 	tt_request->tt_data = tt_crc;
1101a73105b8SAntonio Quartulli 	tt_request->flags = TT_REQUEST;
1102a73105b8SAntonio Quartulli 
1103a73105b8SAntonio Quartulli 	if (full_table)
1104a73105b8SAntonio Quartulli 		tt_request->flags |= TT_FULL_TABLE;
1105a73105b8SAntonio Quartulli 
1106a73105b8SAntonio Quartulli 	neigh_node = orig_node_get_router(dst_orig_node);
1107a73105b8SAntonio Quartulli 	if (!neigh_node)
1108a73105b8SAntonio Quartulli 		goto out;
1109a73105b8SAntonio Quartulli 
1110a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
1111a73105b8SAntonio Quartulli 		"[%c]\n", dst_orig_node->orig, neigh_node->addr,
1112a73105b8SAntonio Quartulli 		(full_table ? 'F' : '.'));
1113a73105b8SAntonio Quartulli 
1114a73105b8SAntonio Quartulli 	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1115a73105b8SAntonio Quartulli 	ret = 0;
1116a73105b8SAntonio Quartulli 
1117a73105b8SAntonio Quartulli out:
1118a73105b8SAntonio Quartulli 	if (neigh_node)
1119a73105b8SAntonio Quartulli 		neigh_node_free_ref(neigh_node);
1120a73105b8SAntonio Quartulli 	if (primary_if)
1121a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1122a73105b8SAntonio Quartulli 	if (ret)
1123a73105b8SAntonio Quartulli 		kfree_skb(skb);
1124a73105b8SAntonio Quartulli 	if (ret && tt_req_node) {
1125a73105b8SAntonio Quartulli 		spin_lock_bh(&bat_priv->tt_req_list_lock);
1126a73105b8SAntonio Quartulli 		list_del(&tt_req_node->list);
1127a73105b8SAntonio Quartulli 		spin_unlock_bh(&bat_priv->tt_req_list_lock);
1128a73105b8SAntonio Quartulli 		kfree(tt_req_node);
1129a73105b8SAntonio Quartulli 	}
1130a73105b8SAntonio Quartulli 	return ret;
1131a73105b8SAntonio Quartulli }
1132a73105b8SAntonio Quartulli 
1133a73105b8SAntonio Quartulli static bool send_other_tt_response(struct bat_priv *bat_priv,
1134a73105b8SAntonio Quartulli 				   struct tt_query_packet *tt_request)
1135a73105b8SAntonio Quartulli {
1136a73105b8SAntonio Quartulli 	struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
1137a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1138a73105b8SAntonio Quartulli 	struct hard_iface *primary_if = NULL;
1139a73105b8SAntonio Quartulli 	uint8_t orig_ttvn, req_ttvn, ttvn;
1140a73105b8SAntonio Quartulli 	int ret = false;
1141a73105b8SAntonio Quartulli 	unsigned char *tt_buff;
1142a73105b8SAntonio Quartulli 	bool full_table;
1143a73105b8SAntonio Quartulli 	uint16_t tt_len, tt_tot;
1144a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1145a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1146a73105b8SAntonio Quartulli 
1147a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1148a73105b8SAntonio Quartulli 		"Received TT_REQUEST from %pM for "
1149a73105b8SAntonio Quartulli 		"ttvn: %u (%pM) [%c]\n", tt_request->src,
1150a73105b8SAntonio Quartulli 		tt_request->ttvn, tt_request->dst,
1151a73105b8SAntonio Quartulli 		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1152a73105b8SAntonio Quartulli 
1153a73105b8SAntonio Quartulli 	/* Let's get the orig node of the REAL destination */
1154a73105b8SAntonio Quartulli 	req_dst_orig_node = get_orig_node(bat_priv, tt_request->dst);
1155a73105b8SAntonio Quartulli 	if (!req_dst_orig_node)
1156a73105b8SAntonio Quartulli 		goto out;
1157a73105b8SAntonio Quartulli 
1158a73105b8SAntonio Quartulli 	res_dst_orig_node = get_orig_node(bat_priv, tt_request->src);
1159a73105b8SAntonio Quartulli 	if (!res_dst_orig_node)
1160a73105b8SAntonio Quartulli 		goto out;
1161a73105b8SAntonio Quartulli 
1162a73105b8SAntonio Quartulli 	neigh_node = orig_node_get_router(res_dst_orig_node);
1163a73105b8SAntonio Quartulli 	if (!neigh_node)
1164a73105b8SAntonio Quartulli 		goto out;
1165a73105b8SAntonio Quartulli 
1166a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1167a73105b8SAntonio Quartulli 	if (!primary_if)
1168a73105b8SAntonio Quartulli 		goto out;
1169a73105b8SAntonio Quartulli 
1170a73105b8SAntonio Quartulli 	orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1171a73105b8SAntonio Quartulli 	req_ttvn = tt_request->ttvn;
1172a73105b8SAntonio Quartulli 
1173015758d0SAntonio Quartulli 	/* I don't have the requested data */
1174a73105b8SAntonio Quartulli 	if (orig_ttvn != req_ttvn ||
1175a73105b8SAntonio Quartulli 	    tt_request->tt_data != req_dst_orig_node->tt_crc)
1176a73105b8SAntonio Quartulli 		goto out;
1177a73105b8SAntonio Quartulli 
1178015758d0SAntonio Quartulli 	/* If the full table has been explicitly requested */
1179a73105b8SAntonio Quartulli 	if (tt_request->flags & TT_FULL_TABLE ||
1180a73105b8SAntonio Quartulli 	    !req_dst_orig_node->tt_buff)
1181a73105b8SAntonio Quartulli 		full_table = true;
1182a73105b8SAntonio Quartulli 	else
1183a73105b8SAntonio Quartulli 		full_table = false;
1184a73105b8SAntonio Quartulli 
1185a73105b8SAntonio Quartulli 	/* In this version, fragmentation is not implemented, then
1186a73105b8SAntonio Quartulli 	 * I'll send only one packet with as much TT entries as I can */
1187a73105b8SAntonio Quartulli 	if (!full_table) {
1188a73105b8SAntonio Quartulli 		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1189a73105b8SAntonio Quartulli 		tt_len = req_dst_orig_node->tt_buff_len;
1190a73105b8SAntonio Quartulli 		tt_tot = tt_len / sizeof(struct tt_change);
1191a73105b8SAntonio Quartulli 
1192a73105b8SAntonio Quartulli 		skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1193a73105b8SAntonio Quartulli 				    tt_len + ETH_HLEN);
1194a73105b8SAntonio Quartulli 		if (!skb)
1195a73105b8SAntonio Quartulli 			goto unlock;
1196a73105b8SAntonio Quartulli 
1197a73105b8SAntonio Quartulli 		skb_reserve(skb, ETH_HLEN);
1198a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb_put(skb,
1199a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet) + tt_len);
1200a73105b8SAntonio Quartulli 		tt_response->ttvn = req_ttvn;
1201a73105b8SAntonio Quartulli 		tt_response->tt_data = htons(tt_tot);
1202a73105b8SAntonio Quartulli 
1203a73105b8SAntonio Quartulli 		tt_buff = skb->data + sizeof(struct tt_query_packet);
1204a73105b8SAntonio Quartulli 		/* Copy the last orig_node's OGM buffer */
1205a73105b8SAntonio Quartulli 		memcpy(tt_buff, req_dst_orig_node->tt_buff,
1206a73105b8SAntonio Quartulli 		       req_dst_orig_node->tt_buff_len);
1207a73105b8SAntonio Quartulli 
1208a73105b8SAntonio Quartulli 		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1209a73105b8SAntonio Quartulli 	} else {
1210a73105b8SAntonio Quartulli 		tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
1211a73105b8SAntonio Quartulli 						sizeof(struct tt_change);
1212a73105b8SAntonio Quartulli 		ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1213a73105b8SAntonio Quartulli 
1214a73105b8SAntonio Quartulli 		skb = tt_response_fill_table(tt_len, ttvn,
1215a73105b8SAntonio Quartulli 					     bat_priv->tt_global_hash,
1216a73105b8SAntonio Quartulli 					     primary_if, tt_global_valid_entry,
1217a73105b8SAntonio Quartulli 					     req_dst_orig_node);
1218a73105b8SAntonio Quartulli 		if (!skb)
1219a73105b8SAntonio Quartulli 			goto out;
1220a73105b8SAntonio Quartulli 
1221a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb->data;
1222a73105b8SAntonio Quartulli 	}
1223a73105b8SAntonio Quartulli 
1224a73105b8SAntonio Quartulli 	tt_response->packet_type = BAT_TT_QUERY;
1225a73105b8SAntonio Quartulli 	tt_response->version = COMPAT_VERSION;
1226a73105b8SAntonio Quartulli 	tt_response->ttl = TTL;
1227a73105b8SAntonio Quartulli 	memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
1228a73105b8SAntonio Quartulli 	memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1229a73105b8SAntonio Quartulli 	tt_response->flags = TT_RESPONSE;
1230a73105b8SAntonio Quartulli 
1231a73105b8SAntonio Quartulli 	if (full_table)
1232a73105b8SAntonio Quartulli 		tt_response->flags |= TT_FULL_TABLE;
1233a73105b8SAntonio Quartulli 
1234a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1235a73105b8SAntonio Quartulli 		"Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
1236a73105b8SAntonio Quartulli 		res_dst_orig_node->orig, neigh_node->addr,
1237a73105b8SAntonio Quartulli 		req_dst_orig_node->orig, req_ttvn);
1238a73105b8SAntonio Quartulli 
1239a73105b8SAntonio Quartulli 	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1240a73105b8SAntonio Quartulli 	ret = true;
1241a73105b8SAntonio Quartulli 	goto out;
1242a73105b8SAntonio Quartulli 
1243a73105b8SAntonio Quartulli unlock:
1244a73105b8SAntonio Quartulli 	spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1245a73105b8SAntonio Quartulli 
1246a73105b8SAntonio Quartulli out:
1247a73105b8SAntonio Quartulli 	if (res_dst_orig_node)
1248a73105b8SAntonio Quartulli 		orig_node_free_ref(res_dst_orig_node);
1249a73105b8SAntonio Quartulli 	if (req_dst_orig_node)
1250a73105b8SAntonio Quartulli 		orig_node_free_ref(req_dst_orig_node);
1251a73105b8SAntonio Quartulli 	if (neigh_node)
1252a73105b8SAntonio Quartulli 		neigh_node_free_ref(neigh_node);
1253a73105b8SAntonio Quartulli 	if (primary_if)
1254a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1255a73105b8SAntonio Quartulli 	if (!ret)
1256a73105b8SAntonio Quartulli 		kfree_skb(skb);
1257a73105b8SAntonio Quartulli 	return ret;
1258a73105b8SAntonio Quartulli 
1259a73105b8SAntonio Quartulli }
1260a73105b8SAntonio Quartulli static bool send_my_tt_response(struct bat_priv *bat_priv,
1261a73105b8SAntonio Quartulli 				struct tt_query_packet *tt_request)
1262a73105b8SAntonio Quartulli {
1263a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1264a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1265a73105b8SAntonio Quartulli 	struct hard_iface *primary_if = NULL;
1266a73105b8SAntonio Quartulli 	uint8_t my_ttvn, req_ttvn, ttvn;
1267a73105b8SAntonio Quartulli 	int ret = false;
1268a73105b8SAntonio Quartulli 	unsigned char *tt_buff;
1269a73105b8SAntonio Quartulli 	bool full_table;
1270a73105b8SAntonio Quartulli 	uint16_t tt_len, tt_tot;
1271a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1272a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1273a73105b8SAntonio Quartulli 
1274a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1275a73105b8SAntonio Quartulli 		"Received TT_REQUEST from %pM for "
1276a73105b8SAntonio Quartulli 		"ttvn: %u (me) [%c]\n", tt_request->src,
1277a73105b8SAntonio Quartulli 		tt_request->ttvn,
1278a73105b8SAntonio Quartulli 		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1279a73105b8SAntonio Quartulli 
1280a73105b8SAntonio Quartulli 
1281a73105b8SAntonio Quartulli 	my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1282a73105b8SAntonio Quartulli 	req_ttvn = tt_request->ttvn;
1283a73105b8SAntonio Quartulli 
1284a73105b8SAntonio Quartulli 	orig_node = get_orig_node(bat_priv, tt_request->src);
1285a73105b8SAntonio Quartulli 	if (!orig_node)
1286a73105b8SAntonio Quartulli 		goto out;
1287a73105b8SAntonio Quartulli 
1288a73105b8SAntonio Quartulli 	neigh_node = orig_node_get_router(orig_node);
1289a73105b8SAntonio Quartulli 	if (!neigh_node)
1290a73105b8SAntonio Quartulli 		goto out;
1291a73105b8SAntonio Quartulli 
1292a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1293a73105b8SAntonio Quartulli 	if (!primary_if)
1294a73105b8SAntonio Quartulli 		goto out;
1295a73105b8SAntonio Quartulli 
1296a73105b8SAntonio Quartulli 	/* If the full table has been explicitly requested or the gap
1297a73105b8SAntonio Quartulli 	 * is too big send the whole local translation table */
1298a73105b8SAntonio Quartulli 	if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
1299a73105b8SAntonio Quartulli 	    !bat_priv->tt_buff)
1300a73105b8SAntonio Quartulli 		full_table = true;
1301a73105b8SAntonio Quartulli 	else
1302a73105b8SAntonio Quartulli 		full_table = false;
1303a73105b8SAntonio Quartulli 
1304a73105b8SAntonio Quartulli 	/* In this version, fragmentation is not implemented, then
1305a73105b8SAntonio Quartulli 	 * I'll send only one packet with as much TT entries as I can */
1306a73105b8SAntonio Quartulli 	if (!full_table) {
1307a73105b8SAntonio Quartulli 		spin_lock_bh(&bat_priv->tt_buff_lock);
1308a73105b8SAntonio Quartulli 		tt_len = bat_priv->tt_buff_len;
1309a73105b8SAntonio Quartulli 		tt_tot = tt_len / sizeof(struct tt_change);
1310a73105b8SAntonio Quartulli 
1311a73105b8SAntonio Quartulli 		skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1312a73105b8SAntonio Quartulli 				    tt_len + ETH_HLEN);
1313a73105b8SAntonio Quartulli 		if (!skb)
1314a73105b8SAntonio Quartulli 			goto unlock;
1315a73105b8SAntonio Quartulli 
1316a73105b8SAntonio Quartulli 		skb_reserve(skb, ETH_HLEN);
1317a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb_put(skb,
1318a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet) + tt_len);
1319a73105b8SAntonio Quartulli 		tt_response->ttvn = req_ttvn;
1320a73105b8SAntonio Quartulli 		tt_response->tt_data = htons(tt_tot);
1321a73105b8SAntonio Quartulli 
1322a73105b8SAntonio Quartulli 		tt_buff = skb->data + sizeof(struct tt_query_packet);
1323a73105b8SAntonio Quartulli 		memcpy(tt_buff, bat_priv->tt_buff,
1324a73105b8SAntonio Quartulli 		       bat_priv->tt_buff_len);
1325a73105b8SAntonio Quartulli 		spin_unlock_bh(&bat_priv->tt_buff_lock);
1326a73105b8SAntonio Quartulli 	} else {
1327a73105b8SAntonio Quartulli 		tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
1328a73105b8SAntonio Quartulli 						sizeof(struct tt_change);
1329a73105b8SAntonio Quartulli 		ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1330a73105b8SAntonio Quartulli 
1331a73105b8SAntonio Quartulli 		skb = tt_response_fill_table(tt_len, ttvn,
1332a73105b8SAntonio Quartulli 					     bat_priv->tt_local_hash,
1333058d0e26SAntonio Quartulli 					     primary_if, tt_local_valid_entry,
1334058d0e26SAntonio Quartulli 					     NULL);
1335a73105b8SAntonio Quartulli 		if (!skb)
1336a73105b8SAntonio Quartulli 			goto out;
1337a73105b8SAntonio Quartulli 
1338a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb->data;
1339a73105b8SAntonio Quartulli 	}
1340a73105b8SAntonio Quartulli 
1341a73105b8SAntonio Quartulli 	tt_response->packet_type = BAT_TT_QUERY;
1342a73105b8SAntonio Quartulli 	tt_response->version = COMPAT_VERSION;
1343a73105b8SAntonio Quartulli 	tt_response->ttl = TTL;
1344a73105b8SAntonio Quartulli 	memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1345a73105b8SAntonio Quartulli 	memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1346a73105b8SAntonio Quartulli 	tt_response->flags = TT_RESPONSE;
1347a73105b8SAntonio Quartulli 
1348a73105b8SAntonio Quartulli 	if (full_table)
1349a73105b8SAntonio Quartulli 		tt_response->flags |= TT_FULL_TABLE;
1350a73105b8SAntonio Quartulli 
1351a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1352a73105b8SAntonio Quartulli 		"Sending TT_RESPONSE to %pM via %pM [%c]\n",
1353a73105b8SAntonio Quartulli 		orig_node->orig, neigh_node->addr,
1354a73105b8SAntonio Quartulli 		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1355a73105b8SAntonio Quartulli 
1356a73105b8SAntonio Quartulli 	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1357a73105b8SAntonio Quartulli 	ret = true;
1358a73105b8SAntonio Quartulli 	goto out;
1359a73105b8SAntonio Quartulli 
1360a73105b8SAntonio Quartulli unlock:
1361a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_buff_lock);
1362a73105b8SAntonio Quartulli out:
1363a73105b8SAntonio Quartulli 	if (orig_node)
1364a73105b8SAntonio Quartulli 		orig_node_free_ref(orig_node);
1365a73105b8SAntonio Quartulli 	if (neigh_node)
1366a73105b8SAntonio Quartulli 		neigh_node_free_ref(neigh_node);
1367a73105b8SAntonio Quartulli 	if (primary_if)
1368a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1369a73105b8SAntonio Quartulli 	if (!ret)
1370a73105b8SAntonio Quartulli 		kfree_skb(skb);
1371a73105b8SAntonio Quartulli 	/* This packet was for me, so it doesn't need to be re-routed */
1372a73105b8SAntonio Quartulli 	return true;
1373a73105b8SAntonio Quartulli }
1374a73105b8SAntonio Quartulli 
1375a73105b8SAntonio Quartulli bool send_tt_response(struct bat_priv *bat_priv,
1376a73105b8SAntonio Quartulli 		      struct tt_query_packet *tt_request)
1377a73105b8SAntonio Quartulli {
1378a73105b8SAntonio Quartulli 	if (is_my_mac(tt_request->dst))
1379a73105b8SAntonio Quartulli 		return send_my_tt_response(bat_priv, tt_request);
1380a73105b8SAntonio Quartulli 	else
1381a73105b8SAntonio Quartulli 		return send_other_tt_response(bat_priv, tt_request);
1382a73105b8SAntonio Quartulli }
1383a73105b8SAntonio Quartulli 
1384a73105b8SAntonio Quartulli static void _tt_update_changes(struct bat_priv *bat_priv,
1385a73105b8SAntonio Quartulli 			       struct orig_node *orig_node,
1386a73105b8SAntonio Quartulli 			       struct tt_change *tt_change,
1387a73105b8SAntonio Quartulli 			       uint16_t tt_num_changes, uint8_t ttvn)
1388a73105b8SAntonio Quartulli {
1389a73105b8SAntonio Quartulli 	int i;
1390a73105b8SAntonio Quartulli 
1391a73105b8SAntonio Quartulli 	for (i = 0; i < tt_num_changes; i++) {
13925fbc1598SAntonio Quartulli 		if ((tt_change + i)->flags & TT_CLIENT_DEL)
1393a73105b8SAntonio Quartulli 			tt_global_del(bat_priv, orig_node,
1394a73105b8SAntonio Quartulli 				      (tt_change + i)->addr,
1395cc47f66eSAntonio Quartulli 				      "tt removed by changes",
1396cc47f66eSAntonio Quartulli 				      (tt_change + i)->flags & TT_CLIENT_ROAM);
1397a73105b8SAntonio Quartulli 		else
1398a73105b8SAntonio Quartulli 			if (!tt_global_add(bat_priv, orig_node,
1399bc279080SAntonio Quartulli 					   (tt_change + i)->addr, ttvn, false,
1400bc279080SAntonio Quartulli 					   (tt_change + i)->flags &
1401bc279080SAntonio Quartulli 							TT_CLIENT_WIFI))
1402a73105b8SAntonio Quartulli 				/* In case of problem while storing a
1403a73105b8SAntonio Quartulli 				 * global_entry, we stop the updating
1404a73105b8SAntonio Quartulli 				 * procedure without committing the
1405a73105b8SAntonio Quartulli 				 * ttvn change. This will avoid to send
1406a73105b8SAntonio Quartulli 				 * corrupted data on tt_request
1407a73105b8SAntonio Quartulli 				 */
1408a73105b8SAntonio Quartulli 				return;
1409a73105b8SAntonio Quartulli 	}
1410a73105b8SAntonio Quartulli }
1411a73105b8SAntonio Quartulli 
1412a73105b8SAntonio Quartulli static void tt_fill_gtable(struct bat_priv *bat_priv,
1413a73105b8SAntonio Quartulli 			   struct tt_query_packet *tt_response)
1414a73105b8SAntonio Quartulli {
1415a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1416a73105b8SAntonio Quartulli 
1417a73105b8SAntonio Quartulli 	orig_node = orig_hash_find(bat_priv, tt_response->src);
1418a73105b8SAntonio Quartulli 	if (!orig_node)
1419a73105b8SAntonio Quartulli 		goto out;
1420a73105b8SAntonio Quartulli 
1421a73105b8SAntonio Quartulli 	/* Purge the old table first.. */
1422a73105b8SAntonio Quartulli 	tt_global_del_orig(bat_priv, orig_node, "Received full table");
1423a73105b8SAntonio Quartulli 
1424a73105b8SAntonio Quartulli 	_tt_update_changes(bat_priv, orig_node,
1425a73105b8SAntonio Quartulli 			   (struct tt_change *)(tt_response + 1),
1426a73105b8SAntonio Quartulli 			   tt_response->tt_data, tt_response->ttvn);
1427a73105b8SAntonio Quartulli 
1428a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
1429a73105b8SAntonio Quartulli 	kfree(orig_node->tt_buff);
1430a73105b8SAntonio Quartulli 	orig_node->tt_buff_len = 0;
1431a73105b8SAntonio Quartulli 	orig_node->tt_buff = NULL;
1432a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
1433a73105b8SAntonio Quartulli 
1434a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
1435a73105b8SAntonio Quartulli 
1436a73105b8SAntonio Quartulli out:
1437a73105b8SAntonio Quartulli 	if (orig_node)
1438a73105b8SAntonio Quartulli 		orig_node_free_ref(orig_node);
1439a73105b8SAntonio Quartulli }
1440a73105b8SAntonio Quartulli 
1441a73105b8SAntonio Quartulli void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
1442a73105b8SAntonio Quartulli 		       uint16_t tt_num_changes, uint8_t ttvn,
1443a73105b8SAntonio Quartulli 		       struct tt_change *tt_change)
1444a73105b8SAntonio Quartulli {
1445a73105b8SAntonio Quartulli 	_tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
1446a73105b8SAntonio Quartulli 			   ttvn);
1447a73105b8SAntonio Quartulli 
1448a73105b8SAntonio Quartulli 	tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
1449a73105b8SAntonio Quartulli 			    tt_num_changes);
1450a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, ttvn);
1451a73105b8SAntonio Quartulli }
1452a73105b8SAntonio Quartulli 
1453a73105b8SAntonio Quartulli bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
1454a73105b8SAntonio Quartulli {
14557683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
14567683fdc1SAntonio Quartulli 	bool ret = false;
1457a73105b8SAntonio Quartulli 
1458a73105b8SAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
14597683fdc1SAntonio Quartulli 	if (!tt_local_entry)
14607683fdc1SAntonio Quartulli 		goto out;
1461058d0e26SAntonio Quartulli 	/* Check if the client has been logically deleted (but is kept for
1462058d0e26SAntonio Quartulli 	 * consistency purpose) */
1463058d0e26SAntonio Quartulli 	if (tt_local_entry->flags & TT_CLIENT_PENDING)
1464058d0e26SAntonio Quartulli 		goto out;
14657683fdc1SAntonio Quartulli 	ret = true;
14667683fdc1SAntonio Quartulli out:
1467a73105b8SAntonio Quartulli 	if (tt_local_entry)
14687683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
14697683fdc1SAntonio Quartulli 	return ret;
1470a73105b8SAntonio Quartulli }
1471a73105b8SAntonio Quartulli 
1472a73105b8SAntonio Quartulli void handle_tt_response(struct bat_priv *bat_priv,
1473a73105b8SAntonio Quartulli 			struct tt_query_packet *tt_response)
1474a73105b8SAntonio Quartulli {
1475a73105b8SAntonio Quartulli 	struct tt_req_node *node, *safe;
1476a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1477a73105b8SAntonio Quartulli 
1478a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
1479a73105b8SAntonio Quartulli 		"ttvn %d t_size: %d [%c]\n",
1480a73105b8SAntonio Quartulli 		tt_response->src, tt_response->ttvn,
1481a73105b8SAntonio Quartulli 		tt_response->tt_data,
1482a73105b8SAntonio Quartulli 		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1483a73105b8SAntonio Quartulli 
1484a73105b8SAntonio Quartulli 	orig_node = orig_hash_find(bat_priv, tt_response->src);
1485a73105b8SAntonio Quartulli 	if (!orig_node)
1486a73105b8SAntonio Quartulli 		goto out;
1487a73105b8SAntonio Quartulli 
1488a73105b8SAntonio Quartulli 	if (tt_response->flags & TT_FULL_TABLE)
1489a73105b8SAntonio Quartulli 		tt_fill_gtable(bat_priv, tt_response);
1490a73105b8SAntonio Quartulli 	else
1491a73105b8SAntonio Quartulli 		tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
1492a73105b8SAntonio Quartulli 				  tt_response->ttvn,
1493a73105b8SAntonio Quartulli 				  (struct tt_change *)(tt_response + 1));
1494a73105b8SAntonio Quartulli 
1495a73105b8SAntonio Quartulli 	/* Delete the tt_req_node from pending tt_requests list */
1496a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
1497a73105b8SAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1498a73105b8SAntonio Quartulli 		if (!compare_eth(node->addr, tt_response->src))
1499a73105b8SAntonio Quartulli 			continue;
1500a73105b8SAntonio Quartulli 		list_del(&node->list);
1501a73105b8SAntonio Quartulli 		kfree(node);
1502a73105b8SAntonio Quartulli 	}
1503a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
1504a73105b8SAntonio Quartulli 
1505a73105b8SAntonio Quartulli 	/* Recalculate the CRC for this orig_node and store it */
1506a73105b8SAntonio Quartulli 	orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1507cc47f66eSAntonio Quartulli 	/* Roaming phase is over: tables are in sync again. I can
1508cc47f66eSAntonio Quartulli 	 * unset the flag */
1509cc47f66eSAntonio Quartulli 	orig_node->tt_poss_change = false;
1510a73105b8SAntonio Quartulli out:
1511a73105b8SAntonio Quartulli 	if (orig_node)
1512a73105b8SAntonio Quartulli 		orig_node_free_ref(orig_node);
1513a73105b8SAntonio Quartulli }
1514a73105b8SAntonio Quartulli 
1515a73105b8SAntonio Quartulli int tt_init(struct bat_priv *bat_priv)
1516a73105b8SAntonio Quartulli {
1517a73105b8SAntonio Quartulli 	if (!tt_local_init(bat_priv))
1518a73105b8SAntonio Quartulli 		return 0;
1519a73105b8SAntonio Quartulli 
1520a73105b8SAntonio Quartulli 	if (!tt_global_init(bat_priv))
1521a73105b8SAntonio Quartulli 		return 0;
1522a73105b8SAntonio Quartulli 
1523a73105b8SAntonio Quartulli 	tt_start_timer(bat_priv);
1524a73105b8SAntonio Quartulli 
1525a73105b8SAntonio Quartulli 	return 1;
1526a73105b8SAntonio Quartulli }
1527a73105b8SAntonio Quartulli 
1528cc47f66eSAntonio Quartulli static void tt_roam_list_free(struct bat_priv *bat_priv)
1529a73105b8SAntonio Quartulli {
1530cc47f66eSAntonio Quartulli 	struct tt_roam_node *node, *safe;
1531a73105b8SAntonio Quartulli 
1532cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1533a73105b8SAntonio Quartulli 
1534cc47f66eSAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1535cc47f66eSAntonio Quartulli 		list_del(&node->list);
1536cc47f66eSAntonio Quartulli 		kfree(node);
1537cc47f66eSAntonio Quartulli 	}
1538cc47f66eSAntonio Quartulli 
1539cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1540cc47f66eSAntonio Quartulli }
1541cc47f66eSAntonio Quartulli 
1542cc47f66eSAntonio Quartulli static void tt_roam_purge(struct bat_priv *bat_priv)
1543cc47f66eSAntonio Quartulli {
1544cc47f66eSAntonio Quartulli 	struct tt_roam_node *node, *safe;
1545cc47f66eSAntonio Quartulli 
1546cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1547cc47f66eSAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1548cc47f66eSAntonio Quartulli 		if (!is_out_of_time(node->first_time,
1549cc47f66eSAntonio Quartulli 				    ROAMING_MAX_TIME * 1000))
1550cc47f66eSAntonio Quartulli 			continue;
1551cc47f66eSAntonio Quartulli 
1552cc47f66eSAntonio Quartulli 		list_del(&node->list);
1553cc47f66eSAntonio Quartulli 		kfree(node);
1554cc47f66eSAntonio Quartulli 	}
1555cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1556cc47f66eSAntonio Quartulli }
1557cc47f66eSAntonio Quartulli 
1558cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the
1559cc47f66eSAntonio Quartulli  * maximum number of possible roaming phases. In this case the ROAMING_ADV
1560cc47f66eSAntonio Quartulli  * will not be sent.
1561cc47f66eSAntonio Quartulli  *
1562cc47f66eSAntonio Quartulli  * returns true if the ROAMING_ADV can be sent, false otherwise */
1563cc47f66eSAntonio Quartulli static bool tt_check_roam_count(struct bat_priv *bat_priv,
1564cc47f66eSAntonio Quartulli 				uint8_t *client)
1565cc47f66eSAntonio Quartulli {
1566cc47f66eSAntonio Quartulli 	struct tt_roam_node *tt_roam_node;
1567cc47f66eSAntonio Quartulli 	bool ret = false;
1568cc47f66eSAntonio Quartulli 
1569cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1570cc47f66eSAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
1571cc47f66eSAntonio Quartulli 	 * reply from the same orig_node yet */
1572cc47f66eSAntonio Quartulli 	list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
1573cc47f66eSAntonio Quartulli 		if (!compare_eth(tt_roam_node->addr, client))
1574cc47f66eSAntonio Quartulli 			continue;
1575cc47f66eSAntonio Quartulli 
1576cc47f66eSAntonio Quartulli 		if (is_out_of_time(tt_roam_node->first_time,
1577cc47f66eSAntonio Quartulli 				   ROAMING_MAX_TIME * 1000))
1578cc47f66eSAntonio Quartulli 			continue;
1579cc47f66eSAntonio Quartulli 
1580cc47f66eSAntonio Quartulli 		if (!atomic_dec_not_zero(&tt_roam_node->counter))
1581cc47f66eSAntonio Quartulli 			/* Sorry, you roamed too many times! */
1582cc47f66eSAntonio Quartulli 			goto unlock;
1583cc47f66eSAntonio Quartulli 		ret = true;
1584cc47f66eSAntonio Quartulli 		break;
1585cc47f66eSAntonio Quartulli 	}
1586cc47f66eSAntonio Quartulli 
1587cc47f66eSAntonio Quartulli 	if (!ret) {
1588cc47f66eSAntonio Quartulli 		tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
1589cc47f66eSAntonio Quartulli 		if (!tt_roam_node)
1590cc47f66eSAntonio Quartulli 			goto unlock;
1591cc47f66eSAntonio Quartulli 
1592cc47f66eSAntonio Quartulli 		tt_roam_node->first_time = jiffies;
1593cc47f66eSAntonio Quartulli 		atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
1594cc47f66eSAntonio Quartulli 		memcpy(tt_roam_node->addr, client, ETH_ALEN);
1595cc47f66eSAntonio Quartulli 
1596cc47f66eSAntonio Quartulli 		list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
1597cc47f66eSAntonio Quartulli 		ret = true;
1598cc47f66eSAntonio Quartulli 	}
1599cc47f66eSAntonio Quartulli 
1600cc47f66eSAntonio Quartulli unlock:
1601cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1602cc47f66eSAntonio Quartulli 	return ret;
1603cc47f66eSAntonio Quartulli }
1604cc47f66eSAntonio Quartulli 
1605cc47f66eSAntonio Quartulli void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
1606cc47f66eSAntonio Quartulli 		   struct orig_node *orig_node)
1607cc47f66eSAntonio Quartulli {
1608cc47f66eSAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1609cc47f66eSAntonio Quartulli 	struct sk_buff *skb = NULL;
1610cc47f66eSAntonio Quartulli 	struct roam_adv_packet *roam_adv_packet;
1611cc47f66eSAntonio Quartulli 	int ret = 1;
1612cc47f66eSAntonio Quartulli 	struct hard_iface *primary_if;
1613cc47f66eSAntonio Quartulli 
1614cc47f66eSAntonio Quartulli 	/* before going on we have to check whether the client has
1615cc47f66eSAntonio Quartulli 	 * already roamed to us too many times */
1616cc47f66eSAntonio Quartulli 	if (!tt_check_roam_count(bat_priv, client))
1617cc47f66eSAntonio Quartulli 		goto out;
1618cc47f66eSAntonio Quartulli 
1619cc47f66eSAntonio Quartulli 	skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
1620cc47f66eSAntonio Quartulli 	if (!skb)
1621cc47f66eSAntonio Quartulli 		goto out;
1622cc47f66eSAntonio Quartulli 
1623cc47f66eSAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1624cc47f66eSAntonio Quartulli 
1625cc47f66eSAntonio Quartulli 	roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
1626cc47f66eSAntonio Quartulli 					sizeof(struct roam_adv_packet));
1627cc47f66eSAntonio Quartulli 
1628cc47f66eSAntonio Quartulli 	roam_adv_packet->packet_type = BAT_ROAM_ADV;
1629cc47f66eSAntonio Quartulli 	roam_adv_packet->version = COMPAT_VERSION;
1630cc47f66eSAntonio Quartulli 	roam_adv_packet->ttl = TTL;
1631cc47f66eSAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1632cc47f66eSAntonio Quartulli 	if (!primary_if)
1633cc47f66eSAntonio Quartulli 		goto out;
1634cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1635cc47f66eSAntonio Quartulli 	hardif_free_ref(primary_if);
1636cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
1637cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->client, client, ETH_ALEN);
1638cc47f66eSAntonio Quartulli 
1639cc47f66eSAntonio Quartulli 	neigh_node = orig_node_get_router(orig_node);
1640cc47f66eSAntonio Quartulli 	if (!neigh_node)
1641cc47f66eSAntonio Quartulli 		goto out;
1642cc47f66eSAntonio Quartulli 
1643cc47f66eSAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1644cc47f66eSAntonio Quartulli 		"Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
1645cc47f66eSAntonio Quartulli 		orig_node->orig, client, neigh_node->addr);
1646cc47f66eSAntonio Quartulli 
1647cc47f66eSAntonio Quartulli 	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1648cc47f66eSAntonio Quartulli 	ret = 0;
1649cc47f66eSAntonio Quartulli 
1650cc47f66eSAntonio Quartulli out:
1651cc47f66eSAntonio Quartulli 	if (neigh_node)
1652cc47f66eSAntonio Quartulli 		neigh_node_free_ref(neigh_node);
1653cc47f66eSAntonio Quartulli 	if (ret)
1654cc47f66eSAntonio Quartulli 		kfree_skb(skb);
1655cc47f66eSAntonio Quartulli 	return;
1656a73105b8SAntonio Quartulli }
1657a73105b8SAntonio Quartulli 
1658a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work)
1659a73105b8SAntonio Quartulli {
1660a73105b8SAntonio Quartulli 	struct delayed_work *delayed_work =
1661a73105b8SAntonio Quartulli 		container_of(work, struct delayed_work, work);
1662a73105b8SAntonio Quartulli 	struct bat_priv *bat_priv =
1663a73105b8SAntonio Quartulli 		container_of(delayed_work, struct bat_priv, tt_work);
1664a73105b8SAntonio Quartulli 
1665a73105b8SAntonio Quartulli 	tt_local_purge(bat_priv);
1666cc47f66eSAntonio Quartulli 	tt_global_roam_purge(bat_priv);
1667a73105b8SAntonio Quartulli 	tt_req_purge(bat_priv);
1668cc47f66eSAntonio Quartulli 	tt_roam_purge(bat_priv);
1669a73105b8SAntonio Quartulli 
1670a73105b8SAntonio Quartulli 	tt_start_timer(bat_priv);
1671a73105b8SAntonio Quartulli }
1672cc47f66eSAntonio Quartulli 
1673cc47f66eSAntonio Quartulli void tt_free(struct bat_priv *bat_priv)
1674cc47f66eSAntonio Quartulli {
1675cc47f66eSAntonio Quartulli 	cancel_delayed_work_sync(&bat_priv->tt_work);
1676cc47f66eSAntonio Quartulli 
1677cc47f66eSAntonio Quartulli 	tt_local_table_free(bat_priv);
1678cc47f66eSAntonio Quartulli 	tt_global_table_free(bat_priv);
1679cc47f66eSAntonio Quartulli 	tt_req_list_free(bat_priv);
1680cc47f66eSAntonio Quartulli 	tt_changes_list_free(bat_priv);
1681cc47f66eSAntonio Quartulli 	tt_roam_list_free(bat_priv);
1682cc47f66eSAntonio Quartulli 
1683cc47f66eSAntonio Quartulli 	kfree(bat_priv->tt_buff);
1684cc47f66eSAntonio Quartulli }
1685058d0e26SAntonio Quartulli 
1686058d0e26SAntonio Quartulli /* This function will reset the specified flags from all the entries in
1687058d0e26SAntonio Quartulli  * the given hash table and will increment num_local_tt for each involved
1688058d0e26SAntonio Quartulli  * entry */
1689058d0e26SAntonio Quartulli static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
1690058d0e26SAntonio Quartulli {
1691058d0e26SAntonio Quartulli 	int i;
1692058d0e26SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
1693058d0e26SAntonio Quartulli 	struct hlist_head *head;
1694058d0e26SAntonio Quartulli 	struct hlist_node *node;
1695058d0e26SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
1696058d0e26SAntonio Quartulli 
1697058d0e26SAntonio Quartulli 	if (!hash)
1698058d0e26SAntonio Quartulli 		return;
1699058d0e26SAntonio Quartulli 
1700058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1701058d0e26SAntonio Quartulli 		head = &hash->table[i];
1702058d0e26SAntonio Quartulli 
1703058d0e26SAntonio Quartulli 		rcu_read_lock();
1704058d0e26SAntonio Quartulli 		hlist_for_each_entry_rcu(tt_local_entry, node,
1705058d0e26SAntonio Quartulli 					 head, hash_entry) {
1706058d0e26SAntonio Quartulli 			tt_local_entry->flags &= ~flags;
1707058d0e26SAntonio Quartulli 			atomic_inc(&bat_priv->num_local_tt);
1708058d0e26SAntonio Quartulli 		}
1709058d0e26SAntonio Quartulli 		rcu_read_unlock();
1710058d0e26SAntonio Quartulli 	}
1711058d0e26SAntonio Quartulli 
1712058d0e26SAntonio Quartulli }
1713058d0e26SAntonio Quartulli 
1714058d0e26SAntonio Quartulli /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
1715058d0e26SAntonio Quartulli static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
1716058d0e26SAntonio Quartulli {
1717058d0e26SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
1718058d0e26SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
1719058d0e26SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
1720058d0e26SAntonio Quartulli 	struct hlist_head *head;
1721058d0e26SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
1722058d0e26SAntonio Quartulli 	int i;
1723058d0e26SAntonio Quartulli 
1724058d0e26SAntonio Quartulli 	if (!hash)
1725058d0e26SAntonio Quartulli 		return;
1726058d0e26SAntonio Quartulli 
1727058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1728058d0e26SAntonio Quartulli 		head = &hash->table[i];
1729058d0e26SAntonio Quartulli 		list_lock = &hash->list_locks[i];
1730058d0e26SAntonio Quartulli 
1731058d0e26SAntonio Quartulli 		spin_lock_bh(list_lock);
1732058d0e26SAntonio Quartulli 		hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
1733058d0e26SAntonio Quartulli 					  head, hash_entry) {
1734058d0e26SAntonio Quartulli 			if (!(tt_local_entry->flags & TT_CLIENT_PENDING))
1735058d0e26SAntonio Quartulli 				continue;
1736058d0e26SAntonio Quartulli 
1737058d0e26SAntonio Quartulli 			bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
1738058d0e26SAntonio Quartulli 				"(%pM): pending\n", tt_local_entry->addr);
1739058d0e26SAntonio Quartulli 
1740058d0e26SAntonio Quartulli 			atomic_dec(&bat_priv->num_local_tt);
1741058d0e26SAntonio Quartulli 			hlist_del_rcu(node);
1742058d0e26SAntonio Quartulli 			tt_local_entry_free_ref(tt_local_entry);
1743058d0e26SAntonio Quartulli 		}
1744058d0e26SAntonio Quartulli 		spin_unlock_bh(list_lock);
1745058d0e26SAntonio Quartulli 	}
1746058d0e26SAntonio Quartulli 
1747058d0e26SAntonio Quartulli }
1748058d0e26SAntonio Quartulli 
1749058d0e26SAntonio Quartulli void tt_commit_changes(struct bat_priv *bat_priv)
1750058d0e26SAntonio Quartulli {
1751058d0e26SAntonio Quartulli 	tt_local_reset_flags(bat_priv, TT_CLIENT_NEW);
1752058d0e26SAntonio Quartulli 	tt_local_purge_pending_clients(bat_priv);
1753058d0e26SAntonio Quartulli 
1754058d0e26SAntonio Quartulli 	/* Increment the TTVN only once per OGM interval */
1755058d0e26SAntonio Quartulli 	atomic_inc(&bat_priv->ttvn);
1756058d0e26SAntonio Quartulli 	bat_priv->tt_poss_change = false;
1757058d0e26SAntonio Quartulli }
175859b699cdSAntonio Quartulli 
175959b699cdSAntonio Quartulli bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
176059b699cdSAntonio Quartulli {
176159b699cdSAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
176259b699cdSAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
176359b699cdSAntonio Quartulli 	bool ret = true;
176459b699cdSAntonio Quartulli 
176559b699cdSAntonio Quartulli 	if (!atomic_read(&bat_priv->ap_isolation))
176659b699cdSAntonio Quartulli 		return false;
176759b699cdSAntonio Quartulli 
176859b699cdSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, dst);
176959b699cdSAntonio Quartulli 	if (!tt_local_entry)
177059b699cdSAntonio Quartulli 		goto out;
177159b699cdSAntonio Quartulli 
177259b699cdSAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, src);
177359b699cdSAntonio Quartulli 	if (!tt_global_entry)
177459b699cdSAntonio Quartulli 		goto out;
177559b699cdSAntonio Quartulli 
177659b699cdSAntonio Quartulli 	if (_is_ap_isolated(tt_local_entry, tt_global_entry))
177759b699cdSAntonio Quartulli 		goto out;
177859b699cdSAntonio Quartulli 
177959b699cdSAntonio Quartulli 	ret = false;
178059b699cdSAntonio Quartulli 
178159b699cdSAntonio Quartulli out:
178259b699cdSAntonio Quartulli 	if (tt_global_entry)
178359b699cdSAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
178459b699cdSAntonio Quartulli 	if (tt_local_entry)
178559b699cdSAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
178659b699cdSAntonio Quartulli 	return ret;
178759b699cdSAntonio Quartulli }
1788