1c6c8fea2SSven Eckelmann /*
2567db7b0SSven Eckelmann  * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
3c6c8fea2SSven Eckelmann  *
435c133a0SAntonio Quartulli  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
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"
3020ff9d59SSimon Wunderlich #include "bridge_loop_avoidance.h"
31c6c8fea2SSven Eckelmann 
32a73105b8SAntonio Quartulli #include <linux/crc16.h>
33a73105b8SAntonio Quartulli 
34de7aae65SSven Eckelmann static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
35de7aae65SSven Eckelmann 			  struct orig_node *orig_node);
36a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work);
37db08e6e5SSimon Wunderlich static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry);
38c6c8fea2SSven Eckelmann 
397aadf889SMarek Lindner /* returns 1 if they are the same mac addr */
4048100bacSAntonio Quartulli static int compare_tt(const struct hlist_node *node, const void *data2)
417aadf889SMarek Lindner {
4248100bacSAntonio Quartulli 	const void *data1 = container_of(node, struct tt_common_entry,
43747e4221SSven Eckelmann 					 hash_entry);
447aadf889SMarek Lindner 
457aadf889SMarek Lindner 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
467aadf889SMarek Lindner }
477aadf889SMarek Lindner 
48a73105b8SAntonio Quartulli static void tt_start_timer(struct bat_priv *bat_priv)
49c6c8fea2SSven Eckelmann {
50a73105b8SAntonio Quartulli 	INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
51a73105b8SAntonio Quartulli 	queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
52a73105b8SAntonio Quartulli 			   msecs_to_jiffies(5000));
53c6c8fea2SSven Eckelmann }
54c6c8fea2SSven Eckelmann 
5548100bacSAntonio Quartulli static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash,
56747e4221SSven Eckelmann 					    const void *data)
577aadf889SMarek Lindner {
587aadf889SMarek Lindner 	struct hlist_head *head;
597aadf889SMarek Lindner 	struct hlist_node *node;
6048100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL;
61c90681b8SAntonio Quartulli 	uint32_t index;
627aadf889SMarek Lindner 
637aadf889SMarek Lindner 	if (!hash)
647aadf889SMarek Lindner 		return NULL;
657aadf889SMarek Lindner 
667aadf889SMarek Lindner 	index = choose_orig(data, hash->size);
677aadf889SMarek Lindner 	head = &hash->table[index];
687aadf889SMarek Lindner 
697aadf889SMarek Lindner 	rcu_read_lock();
7048100bacSAntonio Quartulli 	hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) {
7148100bacSAntonio Quartulli 		if (!compare_eth(tt_common_entry, data))
727aadf889SMarek Lindner 			continue;
737aadf889SMarek Lindner 
7448100bacSAntonio Quartulli 		if (!atomic_inc_not_zero(&tt_common_entry->refcount))
757683fdc1SAntonio Quartulli 			continue;
767683fdc1SAntonio Quartulli 
7748100bacSAntonio Quartulli 		tt_common_entry_tmp = tt_common_entry;
787aadf889SMarek Lindner 		break;
797aadf889SMarek Lindner 	}
807aadf889SMarek Lindner 	rcu_read_unlock();
817aadf889SMarek Lindner 
8248100bacSAntonio Quartulli 	return tt_common_entry_tmp;
8348100bacSAntonio Quartulli }
8448100bacSAntonio Quartulli 
8548100bacSAntonio Quartulli static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
8648100bacSAntonio Quartulli 						 const void *data)
8748100bacSAntonio Quartulli {
8848100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
8948100bacSAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
9048100bacSAntonio Quartulli 
9148100bacSAntonio Quartulli 	tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data);
9248100bacSAntonio Quartulli 	if (tt_common_entry)
9348100bacSAntonio Quartulli 		tt_local_entry = container_of(tt_common_entry,
9448100bacSAntonio Quartulli 					      struct tt_local_entry, common);
9548100bacSAntonio Quartulli 	return tt_local_entry;
967aadf889SMarek Lindner }
977aadf889SMarek Lindner 
982dafb49dSAntonio Quartulli static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
99747e4221SSven Eckelmann 						   const void *data)
1007aadf889SMarek Lindner {
10148100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
10248100bacSAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
1037aadf889SMarek Lindner 
10448100bacSAntonio Quartulli 	tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data);
10548100bacSAntonio Quartulli 	if (tt_common_entry)
10648100bacSAntonio Quartulli 		tt_global_entry = container_of(tt_common_entry,
10748100bacSAntonio Quartulli 					       struct tt_global_entry, common);
10848100bacSAntonio Quartulli 	return tt_global_entry;
1097aadf889SMarek Lindner 
1107aadf889SMarek Lindner }
1117aadf889SMarek Lindner 
1127683fdc1SAntonio Quartulli static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
1137683fdc1SAntonio Quartulli {
11448100bacSAntonio Quartulli 	if (atomic_dec_and_test(&tt_local_entry->common.refcount))
11548100bacSAntonio Quartulli 		kfree_rcu(tt_local_entry, common.rcu);
1167683fdc1SAntonio Quartulli }
1177683fdc1SAntonio Quartulli 
118531027fcSSimon Wunderlich static void tt_global_entry_free_rcu(struct rcu_head *rcu)
119531027fcSSimon Wunderlich {
12048100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
121531027fcSSimon Wunderlich 	struct tt_global_entry *tt_global_entry;
122531027fcSSimon Wunderlich 
12348100bacSAntonio Quartulli 	tt_common_entry = container_of(rcu, struct tt_common_entry, rcu);
12448100bacSAntonio Quartulli 	tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
12548100bacSAntonio Quartulli 				       common);
126531027fcSSimon Wunderlich 
127531027fcSSimon Wunderlich 	kfree(tt_global_entry);
128531027fcSSimon Wunderlich }
129531027fcSSimon Wunderlich 
1307683fdc1SAntonio Quartulli static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
1317683fdc1SAntonio Quartulli {
132db08e6e5SSimon Wunderlich 	if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
133db08e6e5SSimon Wunderlich 		tt_global_del_orig_list(tt_global_entry);
13448100bacSAntonio Quartulli 		call_rcu(&tt_global_entry->common.rcu,
13548100bacSAntonio Quartulli 			 tt_global_entry_free_rcu);
1367683fdc1SAntonio Quartulli 	}
137db08e6e5SSimon Wunderlich }
138db08e6e5SSimon Wunderlich 
139db08e6e5SSimon Wunderlich static void tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
140db08e6e5SSimon Wunderlich {
141db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *orig_entry;
142db08e6e5SSimon Wunderlich 
143db08e6e5SSimon Wunderlich 	orig_entry = container_of(rcu, struct tt_orig_list_entry, rcu);
144db08e6e5SSimon Wunderlich 	atomic_dec(&orig_entry->orig_node->tt_size);
1457d211efcSSven Eckelmann 	batadv_orig_node_free_ref(orig_entry->orig_node);
146db08e6e5SSimon Wunderlich 	kfree(orig_entry);
147db08e6e5SSimon Wunderlich }
148db08e6e5SSimon Wunderlich 
149db08e6e5SSimon Wunderlich static void tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry)
150db08e6e5SSimon Wunderlich {
151db08e6e5SSimon Wunderlich 	call_rcu(&orig_entry->rcu, tt_orig_list_entry_free_rcu);
152db08e6e5SSimon Wunderlich }
1537683fdc1SAntonio Quartulli 
154ff66c975SAntonio Quartulli static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
155ff66c975SAntonio Quartulli 			   uint8_t flags)
156a73105b8SAntonio Quartulli {
157a73105b8SAntonio Quartulli 	struct tt_change_node *tt_change_node;
158a73105b8SAntonio Quartulli 
159a73105b8SAntonio Quartulli 	tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
160a73105b8SAntonio Quartulli 
161a73105b8SAntonio Quartulli 	if (!tt_change_node)
162a73105b8SAntonio Quartulli 		return;
163a73105b8SAntonio Quartulli 
164ff66c975SAntonio Quartulli 	tt_change_node->change.flags = flags;
165a73105b8SAntonio Quartulli 	memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
166a73105b8SAntonio Quartulli 
167a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
168a73105b8SAntonio Quartulli 	/* track the change in the OGMinterval list */
169a73105b8SAntonio Quartulli 	list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
170a73105b8SAntonio Quartulli 	atomic_inc(&bat_priv->tt_local_changes);
171a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
172a73105b8SAntonio Quartulli 
173a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
174a73105b8SAntonio Quartulli }
175a73105b8SAntonio Quartulli 
176a73105b8SAntonio Quartulli int tt_len(int changes_num)
177a73105b8SAntonio Quartulli {
178a73105b8SAntonio Quartulli 	return changes_num * sizeof(struct tt_change);
179a73105b8SAntonio Quartulli }
180a73105b8SAntonio Quartulli 
181a73105b8SAntonio Quartulli static int tt_local_init(struct bat_priv *bat_priv)
182c6c8fea2SSven Eckelmann {
1832dafb49dSAntonio Quartulli 	if (bat_priv->tt_local_hash)
1845346c35eSSven Eckelmann 		return 0;
185c6c8fea2SSven Eckelmann 
1861a8eaf07SSven Eckelmann 	bat_priv->tt_local_hash = batadv_hash_new(1024);
187c6c8fea2SSven Eckelmann 
1882dafb49dSAntonio Quartulli 	if (!bat_priv->tt_local_hash)
1895346c35eSSven Eckelmann 		return -ENOMEM;
190c6c8fea2SSven Eckelmann 
1915346c35eSSven Eckelmann 	return 0;
192c6c8fea2SSven Eckelmann }
193c6c8fea2SSven Eckelmann 
194bc279080SAntonio Quartulli void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
195bc279080SAntonio Quartulli 		  int ifindex)
196c6c8fea2SSven Eckelmann {
197c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(soft_iface);
1987683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
1997683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
200db08e6e5SSimon Wunderlich 	struct hlist_head *head;
201db08e6e5SSimon Wunderlich 	struct hlist_node *node;
202db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *orig_entry;
20380b3f58cSSimon Wunderlich 	int hash_added;
204c6c8fea2SSven Eckelmann 
2052dafb49dSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
206c6c8fea2SSven Eckelmann 
2072dafb49dSAntonio Quartulli 	if (tt_local_entry) {
2082dafb49dSAntonio Quartulli 		tt_local_entry->last_seen = jiffies;
209521251f2SAntonio Quartulli 		/* possibly unset the TT_CLIENT_PENDING flag */
210521251f2SAntonio Quartulli 		tt_local_entry->common.flags &= ~TT_CLIENT_PENDING;
2117683fdc1SAntonio Quartulli 		goto out;
212c6c8fea2SSven Eckelmann 	}
213c6c8fea2SSven Eckelmann 
214704509b8SSven Eckelmann 	tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
2152dafb49dSAntonio Quartulli 	if (!tt_local_entry)
2167683fdc1SAntonio Quartulli 		goto out;
217a73105b8SAntonio Quartulli 
218a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
219a73105b8SAntonio Quartulli 		"Creating new local tt entry: %pM (ttvn: %d)\n", addr,
220a73105b8SAntonio Quartulli 		(uint8_t)atomic_read(&bat_priv->ttvn));
221c6c8fea2SSven Eckelmann 
22248100bacSAntonio Quartulli 	memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
22348100bacSAntonio Quartulli 	tt_local_entry->common.flags = NO_FLAGS;
2249563877eSSven Eckelmann 	if (batadv_is_wifi_iface(ifindex))
22548100bacSAntonio Quartulli 		tt_local_entry->common.flags |= TT_CLIENT_WIFI;
22648100bacSAntonio Quartulli 	atomic_set(&tt_local_entry->common.refcount, 2);
22748100bacSAntonio Quartulli 	tt_local_entry->last_seen = jiffies;
228c6c8fea2SSven Eckelmann 
229c6c8fea2SSven Eckelmann 	/* the batman interface mac address should never be purged */
23039901e71SMarek Lindner 	if (compare_eth(addr, soft_iface->dev_addr))
23148100bacSAntonio Quartulli 		tt_local_entry->common.flags |= TT_CLIENT_NOPURGE;
232c6c8fea2SSven Eckelmann 
233c40ed2bfSAntonio Quartulli 	/* The local entry has to be marked as NEW to avoid to send it in
234c40ed2bfSAntonio Quartulli 	 * a full table response going out before the next ttvn increment
235c40ed2bfSAntonio Quartulli 	 * (consistency check) */
236c40ed2bfSAntonio Quartulli 	tt_local_entry->common.flags |= TT_CLIENT_NEW;
237c40ed2bfSAntonio Quartulli 
23880b3f58cSSimon Wunderlich 	hash_added = hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig,
23980b3f58cSSimon Wunderlich 			 &tt_local_entry->common,
24080b3f58cSSimon Wunderlich 			 &tt_local_entry->common.hash_entry);
24180b3f58cSSimon Wunderlich 
24280b3f58cSSimon Wunderlich 	if (unlikely(hash_added != 0)) {
24380b3f58cSSimon Wunderlich 		/* remove the reference for the hash */
24480b3f58cSSimon Wunderlich 		tt_local_entry_free_ref(tt_local_entry);
24580b3f58cSSimon Wunderlich 		goto out;
24680b3f58cSSimon Wunderlich 	}
24780b3f58cSSimon Wunderlich 
24848100bacSAntonio Quartulli 	tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
249ff66c975SAntonio Quartulli 
250c6c8fea2SSven Eckelmann 	/* remove address from global hash if present */
2512dafb49dSAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
252c6c8fea2SSven Eckelmann 
253cc47f66eSAntonio Quartulli 	/* Check whether it is a roaming! */
254cc47f66eSAntonio Quartulli 	if (tt_global_entry) {
255db08e6e5SSimon Wunderlich 		/* These node are probably going to update their tt table */
256db08e6e5SSimon Wunderlich 		head = &tt_global_entry->orig_list;
257db08e6e5SSimon Wunderlich 		rcu_read_lock();
258db08e6e5SSimon Wunderlich 		hlist_for_each_entry_rcu(orig_entry, node, head, list) {
259db08e6e5SSimon Wunderlich 			orig_entry->orig_node->tt_poss_change = true;
260db08e6e5SSimon Wunderlich 
261db08e6e5SSimon Wunderlich 			send_roam_adv(bat_priv, tt_global_entry->common.addr,
262db08e6e5SSimon Wunderlich 				      orig_entry->orig_node);
263db08e6e5SSimon Wunderlich 		}
264db08e6e5SSimon Wunderlich 		rcu_read_unlock();
265db08e6e5SSimon Wunderlich 		/* The global entry has to be marked as ROAMING and
266db08e6e5SSimon Wunderlich 		 * has to be kept for consistency purpose
267db08e6e5SSimon Wunderlich 		 */
268220b07e9SDavid S. Miller 		tt_global_entry->common.flags |= TT_CLIENT_ROAM;
26903fc3070SAntonio Quartulli 		tt_global_entry->roam_at = jiffies;
2707683fdc1SAntonio Quartulli 	}
2717683fdc1SAntonio Quartulli out:
2727683fdc1SAntonio Quartulli 	if (tt_local_entry)
2737683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
2747683fdc1SAntonio Quartulli 	if (tt_global_entry)
2757683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
276c6c8fea2SSven Eckelmann }
277c6c8fea2SSven Eckelmann 
278be9aa4c1SMarek Lindner static void tt_realloc_packet_buff(unsigned char **packet_buff,
279be9aa4c1SMarek Lindner 				   int *packet_buff_len, int min_packet_len,
280be9aa4c1SMarek Lindner 				   int new_packet_len)
281c6c8fea2SSven Eckelmann {
282be9aa4c1SMarek Lindner 	unsigned char *new_buff;
283c6c8fea2SSven Eckelmann 
284be9aa4c1SMarek Lindner 	new_buff = kmalloc(new_packet_len, GFP_ATOMIC);
285be9aa4c1SMarek Lindner 
286be9aa4c1SMarek Lindner 	/* keep old buffer if kmalloc should fail */
287be9aa4c1SMarek Lindner 	if (new_buff) {
288be9aa4c1SMarek Lindner 		memcpy(new_buff, *packet_buff, min_packet_len);
289be9aa4c1SMarek Lindner 		kfree(*packet_buff);
290be9aa4c1SMarek Lindner 		*packet_buff = new_buff;
291be9aa4c1SMarek Lindner 		*packet_buff_len = new_packet_len;
292be9aa4c1SMarek Lindner 	}
293be9aa4c1SMarek Lindner }
294be9aa4c1SMarek Lindner 
295be9aa4c1SMarek Lindner static void tt_prepare_packet_buff(struct bat_priv *bat_priv,
296be9aa4c1SMarek Lindner 				   unsigned char **packet_buff,
297be9aa4c1SMarek Lindner 				   int *packet_buff_len, int min_packet_len)
298be9aa4c1SMarek Lindner {
299be9aa4c1SMarek Lindner 	struct hard_iface *primary_if;
300be9aa4c1SMarek Lindner 	int req_len;
301be9aa4c1SMarek Lindner 
302be9aa4c1SMarek Lindner 	primary_if = primary_if_get_selected(bat_priv);
303be9aa4c1SMarek Lindner 
304be9aa4c1SMarek Lindner 	req_len = min_packet_len;
305be9aa4c1SMarek Lindner 	req_len += tt_len(atomic_read(&bat_priv->tt_local_changes));
306be9aa4c1SMarek Lindner 
307be9aa4c1SMarek Lindner 	/* if we have too many changes for one packet don't send any
308be9aa4c1SMarek Lindner 	 * and wait for the tt table request which will be fragmented
309be9aa4c1SMarek Lindner 	 */
310be9aa4c1SMarek Lindner 	if ((!primary_if) || (req_len > primary_if->soft_iface->mtu))
311be9aa4c1SMarek Lindner 		req_len = min_packet_len;
312be9aa4c1SMarek Lindner 
313be9aa4c1SMarek Lindner 	tt_realloc_packet_buff(packet_buff, packet_buff_len,
314be9aa4c1SMarek Lindner 			       min_packet_len, req_len);
315be9aa4c1SMarek Lindner 
316be9aa4c1SMarek Lindner 	if (primary_if)
317be9aa4c1SMarek Lindner 		hardif_free_ref(primary_if);
318be9aa4c1SMarek Lindner }
319be9aa4c1SMarek Lindner 
320be9aa4c1SMarek Lindner static int tt_changes_fill_buff(struct bat_priv *bat_priv,
321be9aa4c1SMarek Lindner 				unsigned char **packet_buff,
322be9aa4c1SMarek Lindner 				int *packet_buff_len, int min_packet_len)
323be9aa4c1SMarek Lindner {
324be9aa4c1SMarek Lindner 	struct tt_change_node *entry, *safe;
325be9aa4c1SMarek Lindner 	int count = 0, tot_changes = 0, new_len;
326be9aa4c1SMarek Lindner 	unsigned char *tt_buff;
327be9aa4c1SMarek Lindner 
328be9aa4c1SMarek Lindner 	tt_prepare_packet_buff(bat_priv, packet_buff,
329be9aa4c1SMarek Lindner 			       packet_buff_len, min_packet_len);
330be9aa4c1SMarek Lindner 
331be9aa4c1SMarek Lindner 	new_len = *packet_buff_len - min_packet_len;
332be9aa4c1SMarek Lindner 	tt_buff = *packet_buff + min_packet_len;
333be9aa4c1SMarek Lindner 
334be9aa4c1SMarek Lindner 	if (new_len > 0)
335be9aa4c1SMarek Lindner 		tot_changes = new_len / tt_len(1);
336c6c8fea2SSven Eckelmann 
337a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
338a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_local_changes, 0);
339c6c8fea2SSven Eckelmann 
340a73105b8SAntonio Quartulli 	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
341a73105b8SAntonio Quartulli 				 list) {
342a73105b8SAntonio Quartulli 		if (count < tot_changes) {
343be9aa4c1SMarek Lindner 			memcpy(tt_buff + tt_len(count),
344a73105b8SAntonio Quartulli 			       &entry->change, sizeof(struct tt_change));
345c6c8fea2SSven Eckelmann 			count++;
346c6c8fea2SSven Eckelmann 		}
347a73105b8SAntonio Quartulli 		list_del(&entry->list);
348a73105b8SAntonio Quartulli 		kfree(entry);
349c6c8fea2SSven Eckelmann 	}
350a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
351c6c8fea2SSven Eckelmann 
352a73105b8SAntonio Quartulli 	/* Keep the buffer for possible tt_request */
353a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_buff_lock);
354a73105b8SAntonio Quartulli 	kfree(bat_priv->tt_buff);
355a73105b8SAntonio Quartulli 	bat_priv->tt_buff_len = 0;
356a73105b8SAntonio Quartulli 	bat_priv->tt_buff = NULL;
357be9aa4c1SMarek Lindner 	/* check whether this new OGM has no changes due to size problems */
358be9aa4c1SMarek Lindner 	if (new_len > 0) {
359be9aa4c1SMarek Lindner 		/* if kmalloc() fails we will reply with the full table
360a73105b8SAntonio Quartulli 		 * instead of providing the diff
361a73105b8SAntonio Quartulli 		 */
362be9aa4c1SMarek Lindner 		bat_priv->tt_buff = kmalloc(new_len, GFP_ATOMIC);
363a73105b8SAntonio Quartulli 		if (bat_priv->tt_buff) {
364be9aa4c1SMarek Lindner 			memcpy(bat_priv->tt_buff, tt_buff, new_len);
365be9aa4c1SMarek Lindner 			bat_priv->tt_buff_len = new_len;
366a73105b8SAntonio Quartulli 		}
367a73105b8SAntonio Quartulli 	}
368a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_buff_lock);
369c6c8fea2SSven Eckelmann 
37008ad76ecSMarek Lindner 	return count;
371c6c8fea2SSven Eckelmann }
372c6c8fea2SSven Eckelmann 
3732dafb49dSAntonio Quartulli int tt_local_seq_print_text(struct seq_file *seq, void *offset)
374c6c8fea2SSven Eckelmann {
375c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
376c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(net_dev);
3772dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
37848100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
37932ae9b22SMarek Lindner 	struct hard_iface *primary_if;
3807aadf889SMarek Lindner 	struct hlist_node *node;
381c6c8fea2SSven Eckelmann 	struct hlist_head *head;
382c90681b8SAntonio Quartulli 	uint32_t i;
383c90681b8SAntonio Quartulli 	int ret = 0;
384c6c8fea2SSven Eckelmann 
38532ae9b22SMarek Lindner 	primary_if = primary_if_get_selected(bat_priv);
38632ae9b22SMarek Lindner 	if (!primary_if) {
38786ceb360SSven Eckelmann 		ret = seq_printf(seq,
38886ceb360SSven Eckelmann 				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
389c6c8fea2SSven Eckelmann 				 net_dev->name);
39032ae9b22SMarek Lindner 		goto out;
39132ae9b22SMarek Lindner 	}
39232ae9b22SMarek Lindner 
39332ae9b22SMarek Lindner 	if (primary_if->if_status != IF_ACTIVE) {
39486ceb360SSven Eckelmann 		ret = seq_printf(seq,
39586ceb360SSven Eckelmann 				 "BATMAN mesh %s disabled - primary interface not active\n",
39632ae9b22SMarek Lindner 				 net_dev->name);
39732ae9b22SMarek Lindner 		goto out;
398c6c8fea2SSven Eckelmann 	}
399c6c8fea2SSven Eckelmann 
40086ceb360SSven Eckelmann 	seq_printf(seq,
40186ceb360SSven Eckelmann 		   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
402a73105b8SAntonio Quartulli 		   net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
403c6c8fea2SSven Eckelmann 
404c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
405c6c8fea2SSven Eckelmann 		head = &hash->table[i];
406c6c8fea2SSven Eckelmann 
4077aadf889SMarek Lindner 		rcu_read_lock();
40848100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
4097aadf889SMarek Lindner 					 head, hash_entry) {
410d099c2c5SSimon Wunderlich 			seq_printf(seq, " * %pM [%c%c%c%c%c]\n",
41148100bacSAntonio Quartulli 				   tt_common_entry->addr,
41248100bacSAntonio Quartulli 				   (tt_common_entry->flags &
413df6edb9eSAntonio Quartulli 				    TT_CLIENT_ROAM ? 'R' : '.'),
41448100bacSAntonio Quartulli 				   (tt_common_entry->flags &
415df6edb9eSAntonio Quartulli 				    TT_CLIENT_NOPURGE ? 'P' : '.'),
41648100bacSAntonio Quartulli 				   (tt_common_entry->flags &
417df6edb9eSAntonio Quartulli 				    TT_CLIENT_NEW ? 'N' : '.'),
41848100bacSAntonio Quartulli 				   (tt_common_entry->flags &
419df6edb9eSAntonio Quartulli 				    TT_CLIENT_PENDING ? 'X' : '.'),
42048100bacSAntonio Quartulli 				   (tt_common_entry->flags &
421df6edb9eSAntonio Quartulli 				    TT_CLIENT_WIFI ? 'W' : '.'));
422c6c8fea2SSven Eckelmann 		}
4237aadf889SMarek Lindner 		rcu_read_unlock();
424c6c8fea2SSven Eckelmann 	}
42532ae9b22SMarek Lindner out:
42632ae9b22SMarek Lindner 	if (primary_if)
42732ae9b22SMarek Lindner 		hardif_free_ref(primary_if);
42832ae9b22SMarek Lindner 	return ret;
429c6c8fea2SSven Eckelmann }
430c6c8fea2SSven Eckelmann 
431058d0e26SAntonio Quartulli static void tt_local_set_pending(struct bat_priv *bat_priv,
4322dafb49dSAntonio Quartulli 				 struct tt_local_entry *tt_local_entry,
433c566dbbeSAntonio Quartulli 				 uint16_t flags, const char *message)
434c6c8fea2SSven Eckelmann {
43548100bacSAntonio Quartulli 	tt_local_event(bat_priv, tt_local_entry->common.addr,
43648100bacSAntonio Quartulli 		       tt_local_entry->common.flags | flags);
437c6c8fea2SSven Eckelmann 
438015758d0SAntonio Quartulli 	/* The local client has to be marked as "pending to be removed" but has
439015758d0SAntonio Quartulli 	 * to be kept in the table in order to send it in a full table
440058d0e26SAntonio Quartulli 	 * response issued before the net ttvn increment (consistency check) */
44148100bacSAntonio Quartulli 	tt_local_entry->common.flags |= TT_CLIENT_PENDING;
442c566dbbeSAntonio Quartulli 
44386ceb360SSven Eckelmann 	bat_dbg(DBG_TT, bat_priv,
44486ceb360SSven Eckelmann 		"Local tt entry (%pM) pending to be removed: %s\n",
44586ceb360SSven Eckelmann 		tt_local_entry->common.addr, message);
446c6c8fea2SSven Eckelmann }
447c6c8fea2SSven Eckelmann 
448a73105b8SAntonio Quartulli void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
449cc47f66eSAntonio Quartulli 		     const char *message, bool roaming)
450c6c8fea2SSven Eckelmann {
4517683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
452c6c8fea2SSven Eckelmann 
4532dafb49dSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
4547683fdc1SAntonio Quartulli 	if (!tt_local_entry)
4557683fdc1SAntonio Quartulli 		goto out;
4567683fdc1SAntonio Quartulli 
457058d0e26SAntonio Quartulli 	tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
458c566dbbeSAntonio Quartulli 			     (roaming ? TT_CLIENT_ROAM : NO_FLAGS), message);
4597683fdc1SAntonio Quartulli out:
4607683fdc1SAntonio Quartulli 	if (tt_local_entry)
4617683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
462c6c8fea2SSven Eckelmann }
463c6c8fea2SSven Eckelmann 
464a73105b8SAntonio Quartulli static void tt_local_purge(struct bat_priv *bat_priv)
465c6c8fea2SSven Eckelmann {
4662dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
4672dafb49dSAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
46848100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
4697aadf889SMarek Lindner 	struct hlist_node *node, *node_tmp;
470c6c8fea2SSven Eckelmann 	struct hlist_head *head;
4717683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
472c90681b8SAntonio Quartulli 	uint32_t i;
473c6c8fea2SSven Eckelmann 
474c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
475c6c8fea2SSven Eckelmann 		head = &hash->table[i];
4767683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
477c6c8fea2SSven Eckelmann 
4787683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
47948100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
4807aadf889SMarek Lindner 					  head, hash_entry) {
48148100bacSAntonio Quartulli 			tt_local_entry = container_of(tt_common_entry,
48248100bacSAntonio Quartulli 						      struct tt_local_entry,
48348100bacSAntonio Quartulli 						      common);
48448100bacSAntonio Quartulli 			if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE)
4857aadf889SMarek Lindner 				continue;
486c6c8fea2SSven Eckelmann 
487058d0e26SAntonio Quartulli 			/* entry already marked for deletion */
48848100bacSAntonio Quartulli 			if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
489058d0e26SAntonio Quartulli 				continue;
490058d0e26SAntonio Quartulli 
491a04ccd59SMartin Hundebøll 			if (!has_timed_out(tt_local_entry->last_seen,
492032b7969SMarek Lindner 					   TT_LOCAL_TIMEOUT))
4937aadf889SMarek Lindner 				continue;
4947aadf889SMarek Lindner 
495058d0e26SAntonio Quartulli 			tt_local_set_pending(bat_priv, tt_local_entry,
496c566dbbeSAntonio Quartulli 					     TT_CLIENT_DEL, "timed out");
497c6c8fea2SSven Eckelmann 		}
4987683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
499c6c8fea2SSven Eckelmann 	}
500c6c8fea2SSven Eckelmann 
501c6c8fea2SSven Eckelmann }
502c6c8fea2SSven Eckelmann 
503a73105b8SAntonio Quartulli static void tt_local_table_free(struct bat_priv *bat_priv)
504c6c8fea2SSven Eckelmann {
505a73105b8SAntonio Quartulli 	struct hashtable_t *hash;
506a73105b8SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
50748100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
508a73105b8SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
5097683fdc1SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
5107683fdc1SAntonio Quartulli 	struct hlist_head *head;
511c90681b8SAntonio Quartulli 	uint32_t i;
512a73105b8SAntonio Quartulli 
5132dafb49dSAntonio Quartulli 	if (!bat_priv->tt_local_hash)
514c6c8fea2SSven Eckelmann 		return;
515c6c8fea2SSven Eckelmann 
516a73105b8SAntonio Quartulli 	hash = bat_priv->tt_local_hash;
517a73105b8SAntonio Quartulli 
518a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
519a73105b8SAntonio Quartulli 		head = &hash->table[i];
520a73105b8SAntonio Quartulli 		list_lock = &hash->list_locks[i];
521a73105b8SAntonio Quartulli 
522a73105b8SAntonio Quartulli 		spin_lock_bh(list_lock);
52348100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
524a73105b8SAntonio Quartulli 					  head, hash_entry) {
525a73105b8SAntonio Quartulli 			hlist_del_rcu(node);
52648100bacSAntonio Quartulli 			tt_local_entry = container_of(tt_common_entry,
52748100bacSAntonio Quartulli 						      struct tt_local_entry,
52848100bacSAntonio Quartulli 						      common);
5297683fdc1SAntonio Quartulli 			tt_local_entry_free_ref(tt_local_entry);
530a73105b8SAntonio Quartulli 		}
531a73105b8SAntonio Quartulli 		spin_unlock_bh(list_lock);
532a73105b8SAntonio Quartulli 	}
533a73105b8SAntonio Quartulli 
5341a8eaf07SSven Eckelmann 	batadv_hash_destroy(hash);
535a73105b8SAntonio Quartulli 
5362dafb49dSAntonio Quartulli 	bat_priv->tt_local_hash = NULL;
537c6c8fea2SSven Eckelmann }
538c6c8fea2SSven Eckelmann 
539a73105b8SAntonio Quartulli static int tt_global_init(struct bat_priv *bat_priv)
540c6c8fea2SSven Eckelmann {
5412dafb49dSAntonio Quartulli 	if (bat_priv->tt_global_hash)
5425346c35eSSven Eckelmann 		return 0;
543c6c8fea2SSven Eckelmann 
5441a8eaf07SSven Eckelmann 	bat_priv->tt_global_hash = batadv_hash_new(1024);
545c6c8fea2SSven Eckelmann 
5462dafb49dSAntonio Quartulli 	if (!bat_priv->tt_global_hash)
5475346c35eSSven Eckelmann 		return -ENOMEM;
548c6c8fea2SSven Eckelmann 
5495346c35eSSven Eckelmann 	return 0;
550c6c8fea2SSven Eckelmann }
551c6c8fea2SSven Eckelmann 
552a73105b8SAntonio Quartulli static void tt_changes_list_free(struct bat_priv *bat_priv)
553a73105b8SAntonio Quartulli {
554a73105b8SAntonio Quartulli 	struct tt_change_node *entry, *safe;
555a73105b8SAntonio Quartulli 
556a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_changes_list_lock);
557a73105b8SAntonio Quartulli 
558a73105b8SAntonio Quartulli 	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
559a73105b8SAntonio Quartulli 				 list) {
560a73105b8SAntonio Quartulli 		list_del(&entry->list);
561a73105b8SAntonio Quartulli 		kfree(entry);
562a73105b8SAntonio Quartulli 	}
563a73105b8SAntonio Quartulli 
564a73105b8SAntonio Quartulli 	atomic_set(&bat_priv->tt_local_changes, 0);
565a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
566a73105b8SAntonio Quartulli }
567a73105b8SAntonio Quartulli 
568db08e6e5SSimon Wunderlich /* find out if an orig_node is already in the list of a tt_global_entry.
569db08e6e5SSimon Wunderlich  * returns 1 if found, 0 otherwise
570db08e6e5SSimon Wunderlich  */
571db08e6e5SSimon Wunderlich static bool tt_global_entry_has_orig(const struct tt_global_entry *entry,
572db08e6e5SSimon Wunderlich 				     const struct orig_node *orig_node)
573db08e6e5SSimon Wunderlich {
574db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *tmp_orig_entry;
575db08e6e5SSimon Wunderlich 	const struct hlist_head *head;
576db08e6e5SSimon Wunderlich 	struct hlist_node *node;
577db08e6e5SSimon Wunderlich 	bool found = false;
578db08e6e5SSimon Wunderlich 
579db08e6e5SSimon Wunderlich 	rcu_read_lock();
580db08e6e5SSimon Wunderlich 	head = &entry->orig_list;
581db08e6e5SSimon Wunderlich 	hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) {
582db08e6e5SSimon Wunderlich 		if (tmp_orig_entry->orig_node == orig_node) {
583db08e6e5SSimon Wunderlich 			found = true;
584db08e6e5SSimon Wunderlich 			break;
585db08e6e5SSimon Wunderlich 		}
586db08e6e5SSimon Wunderlich 	}
587db08e6e5SSimon Wunderlich 	rcu_read_unlock();
588db08e6e5SSimon Wunderlich 	return found;
589db08e6e5SSimon Wunderlich }
590db08e6e5SSimon Wunderlich 
591db08e6e5SSimon Wunderlich static void tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry,
592db08e6e5SSimon Wunderlich 				     struct orig_node *orig_node,
593db08e6e5SSimon Wunderlich 				     int ttvn)
594db08e6e5SSimon Wunderlich {
595db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *orig_entry;
596db08e6e5SSimon Wunderlich 
597db08e6e5SSimon Wunderlich 	orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
598db08e6e5SSimon Wunderlich 	if (!orig_entry)
599db08e6e5SSimon Wunderlich 		return;
600db08e6e5SSimon Wunderlich 
601db08e6e5SSimon Wunderlich 	INIT_HLIST_NODE(&orig_entry->list);
602db08e6e5SSimon Wunderlich 	atomic_inc(&orig_node->refcount);
603db08e6e5SSimon Wunderlich 	atomic_inc(&orig_node->tt_size);
604db08e6e5SSimon Wunderlich 	orig_entry->orig_node = orig_node;
605db08e6e5SSimon Wunderlich 	orig_entry->ttvn = ttvn;
606db08e6e5SSimon Wunderlich 
607db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
608db08e6e5SSimon Wunderlich 	hlist_add_head_rcu(&orig_entry->list,
609db08e6e5SSimon Wunderlich 			   &tt_global_entry->orig_list);
610db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
611db08e6e5SSimon Wunderlich }
612db08e6e5SSimon Wunderlich 
613a73105b8SAntonio Quartulli /* caller must hold orig_node refcount */
614a73105b8SAntonio Quartulli int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
615bc279080SAntonio Quartulli 		  const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
616bc279080SAntonio Quartulli 		  bool wifi)
617c6c8fea2SSven Eckelmann {
618db08e6e5SSimon Wunderlich 	struct tt_global_entry *tt_global_entry = NULL;
6197683fdc1SAntonio Quartulli 	int ret = 0;
62080b3f58cSSimon Wunderlich 	int hash_added;
621c6c8fea2SSven Eckelmann 
622a73105b8SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
623c6c8fea2SSven Eckelmann 
6242dafb49dSAntonio Quartulli 	if (!tt_global_entry) {
625db08e6e5SSimon Wunderlich 		tt_global_entry = kzalloc(sizeof(*tt_global_entry),
626c6c8fea2SSven Eckelmann 					  GFP_ATOMIC);
6272dafb49dSAntonio Quartulli 		if (!tt_global_entry)
6287683fdc1SAntonio Quartulli 			goto out;
6297683fdc1SAntonio Quartulli 
63048100bacSAntonio Quartulli 		memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
631db08e6e5SSimon Wunderlich 
63248100bacSAntonio Quartulli 		tt_global_entry->common.flags = NO_FLAGS;
633cc47f66eSAntonio Quartulli 		tt_global_entry->roam_at = 0;
634db08e6e5SSimon Wunderlich 		atomic_set(&tt_global_entry->common.refcount, 2);
635db08e6e5SSimon Wunderlich 
636db08e6e5SSimon Wunderlich 		INIT_HLIST_HEAD(&tt_global_entry->orig_list);
637db08e6e5SSimon Wunderlich 		spin_lock_init(&tt_global_entry->list_lock);
6387683fdc1SAntonio Quartulli 
63980b3f58cSSimon Wunderlich 		hash_added = hash_add(bat_priv->tt_global_hash, compare_tt,
64048100bacSAntonio Quartulli 				 choose_orig, &tt_global_entry->common,
64148100bacSAntonio Quartulli 				 &tt_global_entry->common.hash_entry);
64280b3f58cSSimon Wunderlich 
64380b3f58cSSimon Wunderlich 		if (unlikely(hash_added != 0)) {
64480b3f58cSSimon Wunderlich 			/* remove the reference for the hash */
64580b3f58cSSimon Wunderlich 			tt_global_entry_free_ref(tt_global_entry);
64680b3f58cSSimon Wunderlich 			goto out_remove;
64780b3f58cSSimon Wunderlich 		}
648db08e6e5SSimon Wunderlich 
649db08e6e5SSimon Wunderlich 		tt_global_add_orig_entry(tt_global_entry, orig_node, ttvn);
650a73105b8SAntonio Quartulli 	} else {
651db08e6e5SSimon Wunderlich 		/* there is already a global entry, use this one. */
652db08e6e5SSimon Wunderlich 
653db08e6e5SSimon Wunderlich 		/* If there is the TT_CLIENT_ROAM flag set, there is only one
654db08e6e5SSimon Wunderlich 		 * originator left in the list and we previously received a
655db08e6e5SSimon Wunderlich 		 * delete + roaming change for this originator.
656db08e6e5SSimon Wunderlich 		 *
657db08e6e5SSimon Wunderlich 		 * We should first delete the old originator before adding the
658db08e6e5SSimon Wunderlich 		 * new one.
659db08e6e5SSimon Wunderlich 		 */
660db08e6e5SSimon Wunderlich 		if (tt_global_entry->common.flags & TT_CLIENT_ROAM) {
661db08e6e5SSimon Wunderlich 			tt_global_del_orig_list(tt_global_entry);
662db08e6e5SSimon Wunderlich 			tt_global_entry->common.flags &= ~TT_CLIENT_ROAM;
663cc47f66eSAntonio Quartulli 			tt_global_entry->roam_at = 0;
664c6c8fea2SSven Eckelmann 		}
665c6c8fea2SSven Eckelmann 
666db08e6e5SSimon Wunderlich 		if (!tt_global_entry_has_orig(tt_global_entry, orig_node))
667db08e6e5SSimon Wunderlich 			tt_global_add_orig_entry(tt_global_entry, orig_node,
668db08e6e5SSimon Wunderlich 						 ttvn);
669db08e6e5SSimon Wunderlich 	}
670db08e6e5SSimon Wunderlich 
671bc279080SAntonio Quartulli 	if (wifi)
67248100bacSAntonio Quartulli 		tt_global_entry->common.flags |= TT_CLIENT_WIFI;
673bc279080SAntonio Quartulli 
674a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
675a73105b8SAntonio Quartulli 		"Creating new global tt entry: %pM (via %pM)\n",
67648100bacSAntonio Quartulli 		tt_global_entry->common.addr, orig_node->orig);
677a73105b8SAntonio Quartulli 
67880b3f58cSSimon Wunderlich out_remove:
679c6c8fea2SSven Eckelmann 	/* remove address from local hash if present */
68048100bacSAntonio Quartulli 	tt_local_remove(bat_priv, tt_global_entry->common.addr,
681cc47f66eSAntonio Quartulli 			"global tt received", roaming);
6827683fdc1SAntonio Quartulli 	ret = 1;
6837683fdc1SAntonio Quartulli out:
6847683fdc1SAntonio Quartulli 	if (tt_global_entry)
6857683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
6867683fdc1SAntonio Quartulli 	return ret;
687c6c8fea2SSven Eckelmann }
688c6c8fea2SSven Eckelmann 
689db08e6e5SSimon Wunderlich /* print all orig nodes who announce the address for this global entry.
690db08e6e5SSimon Wunderlich  * it is assumed that the caller holds rcu_read_lock();
691db08e6e5SSimon Wunderlich  */
692db08e6e5SSimon Wunderlich static void tt_global_print_entry(struct tt_global_entry *tt_global_entry,
693db08e6e5SSimon Wunderlich 				  struct seq_file *seq)
694db08e6e5SSimon Wunderlich {
695db08e6e5SSimon Wunderlich 	struct hlist_head *head;
696db08e6e5SSimon Wunderlich 	struct hlist_node *node;
697db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *orig_entry;
698db08e6e5SSimon Wunderlich 	struct tt_common_entry *tt_common_entry;
699db08e6e5SSimon Wunderlich 	uint16_t flags;
700db08e6e5SSimon Wunderlich 	uint8_t last_ttvn;
701db08e6e5SSimon Wunderlich 
702db08e6e5SSimon Wunderlich 	tt_common_entry = &tt_global_entry->common;
703db08e6e5SSimon Wunderlich 
704db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
705db08e6e5SSimon Wunderlich 
706db08e6e5SSimon Wunderlich 	hlist_for_each_entry_rcu(orig_entry, node, head, list) {
707db08e6e5SSimon Wunderlich 		flags = tt_common_entry->flags;
708db08e6e5SSimon Wunderlich 		last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
709db08e6e5SSimon Wunderlich 		seq_printf(seq, " * %pM  (%3u) via %pM     (%3u)   [%c%c]\n",
710db08e6e5SSimon Wunderlich 			   tt_global_entry->common.addr, orig_entry->ttvn,
711db08e6e5SSimon Wunderlich 			   orig_entry->orig_node->orig, last_ttvn,
712db08e6e5SSimon Wunderlich 			   (flags & TT_CLIENT_ROAM ? 'R' : '.'),
713db08e6e5SSimon Wunderlich 			   (flags & TT_CLIENT_WIFI ? 'W' : '.'));
714db08e6e5SSimon Wunderlich 	}
715db08e6e5SSimon Wunderlich }
716db08e6e5SSimon Wunderlich 
7172dafb49dSAntonio Quartulli int tt_global_seq_print_text(struct seq_file *seq, void *offset)
718c6c8fea2SSven Eckelmann {
719c6c8fea2SSven Eckelmann 	struct net_device *net_dev = (struct net_device *)seq->private;
720c6c8fea2SSven Eckelmann 	struct bat_priv *bat_priv = netdev_priv(net_dev);
7212dafb49dSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
72248100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
7232dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
72432ae9b22SMarek Lindner 	struct hard_iface *primary_if;
7257aadf889SMarek Lindner 	struct hlist_node *node;
726c6c8fea2SSven Eckelmann 	struct hlist_head *head;
727c90681b8SAntonio Quartulli 	uint32_t i;
728c90681b8SAntonio Quartulli 	int ret = 0;
729c6c8fea2SSven Eckelmann 
73032ae9b22SMarek Lindner 	primary_if = primary_if_get_selected(bat_priv);
73132ae9b22SMarek Lindner 	if (!primary_if) {
73286ceb360SSven Eckelmann 		ret = seq_printf(seq,
73386ceb360SSven Eckelmann 				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
734c6c8fea2SSven Eckelmann 				 net_dev->name);
73532ae9b22SMarek Lindner 		goto out;
73632ae9b22SMarek Lindner 	}
73732ae9b22SMarek Lindner 
73832ae9b22SMarek Lindner 	if (primary_if->if_status != IF_ACTIVE) {
73986ceb360SSven Eckelmann 		ret = seq_printf(seq,
74086ceb360SSven Eckelmann 				 "BATMAN mesh %s disabled - primary interface not active\n",
74132ae9b22SMarek Lindner 				 net_dev->name);
74232ae9b22SMarek Lindner 		goto out;
743c6c8fea2SSven Eckelmann 	}
744c6c8fea2SSven Eckelmann 
7452dafb49dSAntonio Quartulli 	seq_printf(seq,
7462dafb49dSAntonio Quartulli 		   "Globally announced TT entries received via the mesh %s\n",
747c6c8fea2SSven Eckelmann 		   net_dev->name);
748df6edb9eSAntonio Quartulli 	seq_printf(seq, "       %-13s %s       %-15s %s %s\n",
749df6edb9eSAntonio Quartulli 		   "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
750c6c8fea2SSven Eckelmann 
751c6c8fea2SSven Eckelmann 	for (i = 0; i < hash->size; i++) {
752c6c8fea2SSven Eckelmann 		head = &hash->table[i];
753c6c8fea2SSven Eckelmann 
7547aadf889SMarek Lindner 		rcu_read_lock();
75548100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
7567aadf889SMarek Lindner 					 head, hash_entry) {
75748100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
75848100bacSAntonio Quartulli 						       struct tt_global_entry,
75948100bacSAntonio Quartulli 						       common);
760db08e6e5SSimon Wunderlich 			tt_global_print_entry(tt_global_entry, seq);
761c6c8fea2SSven Eckelmann 		}
7627aadf889SMarek Lindner 		rcu_read_unlock();
763c6c8fea2SSven Eckelmann 	}
76432ae9b22SMarek Lindner out:
76532ae9b22SMarek Lindner 	if (primary_if)
76632ae9b22SMarek Lindner 		hardif_free_ref(primary_if);
76732ae9b22SMarek Lindner 	return ret;
768c6c8fea2SSven Eckelmann }
769c6c8fea2SSven Eckelmann 
770db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */
771db08e6e5SSimon Wunderlich static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry)
772db08e6e5SSimon Wunderlich {
773db08e6e5SSimon Wunderlich 	struct hlist_head *head;
774db08e6e5SSimon Wunderlich 	struct hlist_node *node, *safe;
775db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *orig_entry;
776db08e6e5SSimon Wunderlich 
777db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
778db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
779db08e6e5SSimon Wunderlich 	hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
780db08e6e5SSimon Wunderlich 		hlist_del_rcu(node);
781db08e6e5SSimon Wunderlich 		tt_orig_list_entry_free_ref(orig_entry);
782db08e6e5SSimon Wunderlich 	}
783db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
784db08e6e5SSimon Wunderlich 
785db08e6e5SSimon Wunderlich }
786db08e6e5SSimon Wunderlich 
787db08e6e5SSimon Wunderlich static void tt_global_del_orig_entry(struct bat_priv *bat_priv,
788db08e6e5SSimon Wunderlich 				     struct tt_global_entry *tt_global_entry,
789db08e6e5SSimon Wunderlich 				     struct orig_node *orig_node,
790db08e6e5SSimon Wunderlich 				     const char *message)
791db08e6e5SSimon Wunderlich {
792db08e6e5SSimon Wunderlich 	struct hlist_head *head;
793db08e6e5SSimon Wunderlich 	struct hlist_node *node, *safe;
794db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *orig_entry;
795db08e6e5SSimon Wunderlich 
796db08e6e5SSimon Wunderlich 	spin_lock_bh(&tt_global_entry->list_lock);
797db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
798db08e6e5SSimon Wunderlich 	hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
799db08e6e5SSimon Wunderlich 		if (orig_entry->orig_node == orig_node) {
800db08e6e5SSimon Wunderlich 			bat_dbg(DBG_TT, bat_priv,
801db08e6e5SSimon Wunderlich 				"Deleting %pM from global tt entry %pM: %s\n",
802db08e6e5SSimon Wunderlich 				orig_node->orig, tt_global_entry->common.addr,
803db08e6e5SSimon Wunderlich 				message);
804db08e6e5SSimon Wunderlich 			hlist_del_rcu(node);
805db08e6e5SSimon Wunderlich 			tt_orig_list_entry_free_ref(orig_entry);
806db08e6e5SSimon Wunderlich 		}
807db08e6e5SSimon Wunderlich 	}
808db08e6e5SSimon Wunderlich 	spin_unlock_bh(&tt_global_entry->list_lock);
809db08e6e5SSimon Wunderlich }
810db08e6e5SSimon Wunderlich 
811db08e6e5SSimon Wunderlich static void tt_global_del_struct(struct bat_priv *bat_priv,
8122dafb49dSAntonio Quartulli 				 struct tt_global_entry *tt_global_entry,
813747e4221SSven Eckelmann 				 const char *message)
814c6c8fea2SSven Eckelmann {
815a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
816db08e6e5SSimon Wunderlich 		"Deleting global tt entry %pM: %s\n",
817db08e6e5SSimon Wunderlich 		tt_global_entry->common.addr, message);
8187683fdc1SAntonio Quartulli 
81948100bacSAntonio Quartulli 	hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
82048100bacSAntonio Quartulli 		    tt_global_entry->common.addr);
8217683fdc1SAntonio Quartulli 	tt_global_entry_free_ref(tt_global_entry);
822db08e6e5SSimon Wunderlich 
823c6c8fea2SSven Eckelmann }
824c6c8fea2SSven Eckelmann 
825db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry
826db08e6e5SSimon Wunderlich  * within tt_global entry. If yes, we set the TT_CLIENT_ROAM flag and the timer,
827db08e6e5SSimon Wunderlich  * otherwise we simply remove the originator scheduled for deletion.
828db08e6e5SSimon Wunderlich  */
829db08e6e5SSimon Wunderlich static void tt_global_del_roaming(struct bat_priv *bat_priv,
830db08e6e5SSimon Wunderlich 				  struct tt_global_entry *tt_global_entry,
831db08e6e5SSimon Wunderlich 				  struct orig_node *orig_node,
832db08e6e5SSimon Wunderlich 				  const char *message)
833db08e6e5SSimon Wunderlich {
834db08e6e5SSimon Wunderlich 	bool last_entry = true;
835db08e6e5SSimon Wunderlich 	struct hlist_head *head;
836db08e6e5SSimon Wunderlich 	struct hlist_node *node;
837db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *orig_entry;
838db08e6e5SSimon Wunderlich 
839db08e6e5SSimon Wunderlich 	/* no local entry exists, case 1:
840db08e6e5SSimon Wunderlich 	 * Check if this is the last one or if other entries exist.
841db08e6e5SSimon Wunderlich 	 */
842db08e6e5SSimon Wunderlich 
843db08e6e5SSimon Wunderlich 	rcu_read_lock();
844db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
845db08e6e5SSimon Wunderlich 	hlist_for_each_entry_rcu(orig_entry, node, head, list) {
846db08e6e5SSimon Wunderlich 		if (orig_entry->orig_node != orig_node) {
847db08e6e5SSimon Wunderlich 			last_entry = false;
848db08e6e5SSimon Wunderlich 			break;
849db08e6e5SSimon Wunderlich 		}
850db08e6e5SSimon Wunderlich 	}
851db08e6e5SSimon Wunderlich 	rcu_read_unlock();
852db08e6e5SSimon Wunderlich 
853db08e6e5SSimon Wunderlich 	if (last_entry) {
854db08e6e5SSimon Wunderlich 		/* its the last one, mark for roaming. */
855db08e6e5SSimon Wunderlich 		tt_global_entry->common.flags |= TT_CLIENT_ROAM;
856db08e6e5SSimon Wunderlich 		tt_global_entry->roam_at = jiffies;
857db08e6e5SSimon Wunderlich 	} else
858db08e6e5SSimon Wunderlich 		/* there is another entry, we can simply delete this
859db08e6e5SSimon Wunderlich 		 * one and can still use the other one.
860db08e6e5SSimon Wunderlich 		 */
861db08e6e5SSimon Wunderlich 		tt_global_del_orig_entry(bat_priv, tt_global_entry,
862db08e6e5SSimon Wunderlich 					 orig_node, message);
863db08e6e5SSimon Wunderlich }
864db08e6e5SSimon Wunderlich 
865db08e6e5SSimon Wunderlich 
866db08e6e5SSimon Wunderlich 
867de7aae65SSven Eckelmann static void tt_global_del(struct bat_priv *bat_priv,
868de7aae65SSven Eckelmann 			  struct orig_node *orig_node,
869de7aae65SSven Eckelmann 			  const unsigned char *addr,
870cc47f66eSAntonio Quartulli 			  const char *message, bool roaming)
871a73105b8SAntonio Quartulli {
8727683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
873797399b4SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
874a73105b8SAntonio Quartulli 
875a73105b8SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
876db08e6e5SSimon Wunderlich 	if (!tt_global_entry)
8777683fdc1SAntonio Quartulli 		goto out;
878a73105b8SAntonio Quartulli 
879db08e6e5SSimon Wunderlich 	if (!roaming) {
880db08e6e5SSimon Wunderlich 		tt_global_del_orig_entry(bat_priv, tt_global_entry, orig_node,
881db08e6e5SSimon Wunderlich 					 message);
88292f90f56SSven Eckelmann 
883db08e6e5SSimon Wunderlich 		if (hlist_empty(&tt_global_entry->orig_list))
884db08e6e5SSimon Wunderlich 			tt_global_del_struct(bat_priv, tt_global_entry,
885db08e6e5SSimon Wunderlich 					     message);
886db08e6e5SSimon Wunderlich 
887cc47f66eSAntonio Quartulli 		goto out;
888cc47f66eSAntonio Quartulli 	}
88992f90f56SSven Eckelmann 
890db08e6e5SSimon Wunderlich 	/* if we are deleting a global entry due to a roam
891db08e6e5SSimon Wunderlich 	 * event, there are two possibilities:
892db08e6e5SSimon Wunderlich 	 * 1) the client roamed from node A to node B => if there
893db08e6e5SSimon Wunderlich 	 *    is only one originator left for this client, we mark
894db08e6e5SSimon Wunderlich 	 *    it with TT_CLIENT_ROAM, we start a timer and we
895db08e6e5SSimon Wunderlich 	 *    wait for node B to claim it. In case of timeout
896db08e6e5SSimon Wunderlich 	 *    the entry is purged.
897db08e6e5SSimon Wunderlich 	 *
898db08e6e5SSimon Wunderlich 	 *    If there are other originators left, we directly delete
899db08e6e5SSimon Wunderlich 	 *    the originator.
900db08e6e5SSimon Wunderlich 	 * 2) the client roamed to us => we can directly delete
901db08e6e5SSimon Wunderlich 	 *    the global entry, since it is useless now. */
902db08e6e5SSimon Wunderlich 
903db08e6e5SSimon Wunderlich 	tt_local_entry = tt_local_hash_find(bat_priv,
904db08e6e5SSimon Wunderlich 					    tt_global_entry->common.addr);
905db08e6e5SSimon Wunderlich 	if (tt_local_entry) {
906db08e6e5SSimon Wunderlich 		/* local entry exists, case 2: client roamed to us. */
907db08e6e5SSimon Wunderlich 		tt_global_del_orig_list(tt_global_entry);
908db08e6e5SSimon Wunderlich 		tt_global_del_struct(bat_priv, tt_global_entry, message);
909db08e6e5SSimon Wunderlich 	} else
910db08e6e5SSimon Wunderlich 		/* no local entry exists, case 1: check for roaming */
911db08e6e5SSimon Wunderlich 		tt_global_del_roaming(bat_priv, tt_global_entry, orig_node,
912db08e6e5SSimon Wunderlich 				      message);
913db08e6e5SSimon Wunderlich 
91492f90f56SSven Eckelmann 
915cc47f66eSAntonio Quartulli out:
9167683fdc1SAntonio Quartulli 	if (tt_global_entry)
9177683fdc1SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
918797399b4SAntonio Quartulli 	if (tt_local_entry)
919797399b4SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
920a73105b8SAntonio Quartulli }
921a73105b8SAntonio Quartulli 
9222dafb49dSAntonio Quartulli void tt_global_del_orig(struct bat_priv *bat_priv,
923747e4221SSven Eckelmann 			struct orig_node *orig_node, const char *message)
924c6c8fea2SSven Eckelmann {
9252dafb49dSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
92648100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
927c90681b8SAntonio Quartulli 	uint32_t i;
928a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
929a73105b8SAntonio Quartulli 	struct hlist_node *node, *safe;
930a73105b8SAntonio Quartulli 	struct hlist_head *head;
9317683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
932c6c8fea2SSven Eckelmann 
9336e801494SSimon Wunderlich 	if (!hash)
9346e801494SSimon Wunderlich 		return;
9356e801494SSimon Wunderlich 
936a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
937a73105b8SAntonio Quartulli 		head = &hash->table[i];
9387683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
939c6c8fea2SSven Eckelmann 
9407683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
94148100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, safe,
942a73105b8SAntonio Quartulli 					  head, hash_entry) {
94348100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
94448100bacSAntonio Quartulli 						       struct tt_global_entry,
94548100bacSAntonio Quartulli 						       common);
946db08e6e5SSimon Wunderlich 
947db08e6e5SSimon Wunderlich 			tt_global_del_orig_entry(bat_priv, tt_global_entry,
948db08e6e5SSimon Wunderlich 						 orig_node, message);
949db08e6e5SSimon Wunderlich 
950db08e6e5SSimon Wunderlich 			if (hlist_empty(&tt_global_entry->orig_list)) {
9517683fdc1SAntonio Quartulli 				bat_dbg(DBG_TT, bat_priv,
952db08e6e5SSimon Wunderlich 					"Deleting global tt entry %pM: %s\n",
95348100bacSAntonio Quartulli 					tt_global_entry->common.addr,
95487944973SAntonio Quartulli 					message);
9557683fdc1SAntonio Quartulli 				hlist_del_rcu(node);
9567683fdc1SAntonio Quartulli 				tt_global_entry_free_ref(tt_global_entry);
957c6c8fea2SSven Eckelmann 			}
958a73105b8SAntonio Quartulli 		}
9597683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
9607683fdc1SAntonio Quartulli 	}
961a73105b8SAntonio Quartulli 	atomic_set(&orig_node->tt_size, 0);
96217071578SAntonio Quartulli 	orig_node->tt_initialised = false;
963c6c8fea2SSven Eckelmann }
964c6c8fea2SSven Eckelmann 
965cc47f66eSAntonio Quartulli static void tt_global_roam_purge(struct bat_priv *bat_priv)
966cc47f66eSAntonio Quartulli {
967cc47f66eSAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
96848100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
969cc47f66eSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
970cc47f66eSAntonio Quartulli 	struct hlist_node *node, *node_tmp;
971cc47f66eSAntonio Quartulli 	struct hlist_head *head;
9727683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
973c90681b8SAntonio Quartulli 	uint32_t i;
974cc47f66eSAntonio Quartulli 
975cc47f66eSAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
976cc47f66eSAntonio Quartulli 		head = &hash->table[i];
9777683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
978cc47f66eSAntonio Quartulli 
9797683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
98048100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
981cc47f66eSAntonio Quartulli 					  head, hash_entry) {
98248100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
98348100bacSAntonio Quartulli 						       struct tt_global_entry,
98448100bacSAntonio Quartulli 						       common);
98548100bacSAntonio Quartulli 			if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
986cc47f66eSAntonio Quartulli 				continue;
987a04ccd59SMartin Hundebøll 			if (!has_timed_out(tt_global_entry->roam_at,
988032b7969SMarek Lindner 					   TT_CLIENT_ROAM_TIMEOUT))
989cc47f66eSAntonio Quartulli 				continue;
990cc47f66eSAntonio Quartulli 
99186ceb360SSven Eckelmann 			bat_dbg(DBG_TT, bat_priv,
99286ceb360SSven Eckelmann 				"Deleting global tt entry (%pM): Roaming timeout\n",
99348100bacSAntonio Quartulli 				tt_global_entry->common.addr);
994db08e6e5SSimon Wunderlich 
9957683fdc1SAntonio Quartulli 			hlist_del_rcu(node);
9967683fdc1SAntonio Quartulli 			tt_global_entry_free_ref(tt_global_entry);
997cc47f66eSAntonio Quartulli 		}
9987683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
999cc47f66eSAntonio Quartulli 	}
1000cc47f66eSAntonio Quartulli 
1001cc47f66eSAntonio Quartulli }
1002cc47f66eSAntonio Quartulli 
1003a73105b8SAntonio Quartulli static void tt_global_table_free(struct bat_priv *bat_priv)
1004c6c8fea2SSven Eckelmann {
10057683fdc1SAntonio Quartulli 	struct hashtable_t *hash;
10067683fdc1SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
100748100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
10087683fdc1SAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
10097683fdc1SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
10107683fdc1SAntonio Quartulli 	struct hlist_head *head;
1011c90681b8SAntonio Quartulli 	uint32_t i;
10127683fdc1SAntonio Quartulli 
10132dafb49dSAntonio Quartulli 	if (!bat_priv->tt_global_hash)
1014c6c8fea2SSven Eckelmann 		return;
1015c6c8fea2SSven Eckelmann 
10167683fdc1SAntonio Quartulli 	hash = bat_priv->tt_global_hash;
10177683fdc1SAntonio Quartulli 
10187683fdc1SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
10197683fdc1SAntonio Quartulli 		head = &hash->table[i];
10207683fdc1SAntonio Quartulli 		list_lock = &hash->list_locks[i];
10217683fdc1SAntonio Quartulli 
10227683fdc1SAntonio Quartulli 		spin_lock_bh(list_lock);
102348100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
10247683fdc1SAntonio Quartulli 					  head, hash_entry) {
10257683fdc1SAntonio Quartulli 			hlist_del_rcu(node);
102648100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
102748100bacSAntonio Quartulli 						       struct tt_global_entry,
102848100bacSAntonio Quartulli 						       common);
10297683fdc1SAntonio Quartulli 			tt_global_entry_free_ref(tt_global_entry);
10307683fdc1SAntonio Quartulli 		}
10317683fdc1SAntonio Quartulli 		spin_unlock_bh(list_lock);
10327683fdc1SAntonio Quartulli 	}
10337683fdc1SAntonio Quartulli 
10341a8eaf07SSven Eckelmann 	batadv_hash_destroy(hash);
10357683fdc1SAntonio Quartulli 
10362dafb49dSAntonio Quartulli 	bat_priv->tt_global_hash = NULL;
1037c6c8fea2SSven Eckelmann }
1038c6c8fea2SSven Eckelmann 
103959b699cdSAntonio Quartulli static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
104059b699cdSAntonio Quartulli 			    struct tt_global_entry *tt_global_entry)
104159b699cdSAntonio Quartulli {
104259b699cdSAntonio Quartulli 	bool ret = false;
104359b699cdSAntonio Quartulli 
104448100bacSAntonio Quartulli 	if (tt_local_entry->common.flags & TT_CLIENT_WIFI &&
104548100bacSAntonio Quartulli 	    tt_global_entry->common.flags & TT_CLIENT_WIFI)
104659b699cdSAntonio Quartulli 		ret = true;
104759b699cdSAntonio Quartulli 
104859b699cdSAntonio Quartulli 	return ret;
104959b699cdSAntonio Quartulli }
105059b699cdSAntonio Quartulli 
1051747e4221SSven Eckelmann struct orig_node *transtable_search(struct bat_priv *bat_priv,
10523d393e47SAntonio Quartulli 				    const uint8_t *src, const uint8_t *addr)
1053c6c8fea2SSven Eckelmann {
10543d393e47SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
10553d393e47SAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
10567b36e8eeSMarek Lindner 	struct orig_node *orig_node = NULL;
1057db08e6e5SSimon Wunderlich 	struct neigh_node *router = NULL;
1058db08e6e5SSimon Wunderlich 	struct hlist_head *head;
1059db08e6e5SSimon Wunderlich 	struct hlist_node *node;
1060db08e6e5SSimon Wunderlich 	struct tt_orig_list_entry *orig_entry;
1061db08e6e5SSimon Wunderlich 	int best_tq;
1062c6c8fea2SSven Eckelmann 
10633d393e47SAntonio Quartulli 	if (src && atomic_read(&bat_priv->ap_isolation)) {
10643d393e47SAntonio Quartulli 		tt_local_entry = tt_local_hash_find(bat_priv, src);
10653d393e47SAntonio Quartulli 		if (!tt_local_entry)
10663d393e47SAntonio Quartulli 			goto out;
10673d393e47SAntonio Quartulli 	}
10687aadf889SMarek Lindner 
10693d393e47SAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
10702dafb49dSAntonio Quartulli 	if (!tt_global_entry)
10717b36e8eeSMarek Lindner 		goto out;
1072c6c8fea2SSven Eckelmann 
10733d393e47SAntonio Quartulli 	/* check whether the clients should not communicate due to AP
10743d393e47SAntonio Quartulli 	 * isolation */
10753d393e47SAntonio Quartulli 	if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
10763d393e47SAntonio Quartulli 		goto out;
10773d393e47SAntonio Quartulli 
1078db08e6e5SSimon Wunderlich 	best_tq = 0;
10797b36e8eeSMarek Lindner 
1080db08e6e5SSimon Wunderlich 	rcu_read_lock();
1081db08e6e5SSimon Wunderlich 	head = &tt_global_entry->orig_list;
1082db08e6e5SSimon Wunderlich 	hlist_for_each_entry_rcu(orig_entry, node, head, list) {
10837d211efcSSven Eckelmann 		router = batadv_orig_node_get_router(orig_entry->orig_node);
1084db08e6e5SSimon Wunderlich 		if (!router)
1085db08e6e5SSimon Wunderlich 			continue;
10867b36e8eeSMarek Lindner 
1087db08e6e5SSimon Wunderlich 		if (router->tq_avg > best_tq) {
1088db08e6e5SSimon Wunderlich 			orig_node = orig_entry->orig_node;
1089db08e6e5SSimon Wunderlich 			best_tq = router->tq_avg;
1090db08e6e5SSimon Wunderlich 		}
10917d211efcSSven Eckelmann 		batadv_neigh_node_free_ref(router);
1092db08e6e5SSimon Wunderlich 	}
1093db08e6e5SSimon Wunderlich 	/* found anything? */
1094db08e6e5SSimon Wunderlich 	if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
1095db08e6e5SSimon Wunderlich 		orig_node = NULL;
1096db08e6e5SSimon Wunderlich 	rcu_read_unlock();
10977b36e8eeSMarek Lindner out:
10983d393e47SAntonio Quartulli 	if (tt_global_entry)
10993d393e47SAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
11003d393e47SAntonio Quartulli 	if (tt_local_entry)
11013d393e47SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
11023d393e47SAntonio Quartulli 
11037b36e8eeSMarek Lindner 	return orig_node;
1104c6c8fea2SSven Eckelmann }
1105a73105b8SAntonio Quartulli 
1106a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */
1107de7aae65SSven Eckelmann static uint16_t tt_global_crc(struct bat_priv *bat_priv,
1108de7aae65SSven Eckelmann 			      struct orig_node *orig_node)
1109a73105b8SAntonio Quartulli {
1110a73105b8SAntonio Quartulli 	uint16_t total = 0, total_one;
1111a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_global_hash;
111248100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
1113a73105b8SAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
1114a73105b8SAntonio Quartulli 	struct hlist_node *node;
1115a73105b8SAntonio Quartulli 	struct hlist_head *head;
1116c90681b8SAntonio Quartulli 	uint32_t i;
1117c90681b8SAntonio Quartulli 	int j;
1118a73105b8SAntonio Quartulli 
1119a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1120a73105b8SAntonio Quartulli 		head = &hash->table[i];
1121a73105b8SAntonio Quartulli 
1122a73105b8SAntonio Quartulli 		rcu_read_lock();
112348100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
1124a73105b8SAntonio Quartulli 					 head, hash_entry) {
112548100bacSAntonio Quartulli 			tt_global_entry = container_of(tt_common_entry,
112648100bacSAntonio Quartulli 						       struct tt_global_entry,
112748100bacSAntonio Quartulli 						       common);
1128cc47f66eSAntonio Quartulli 			/* Roaming clients are in the global table for
1129cc47f66eSAntonio Quartulli 			 * consistency only. They don't have to be
1130cc47f66eSAntonio Quartulli 			 * taken into account while computing the
1131db08e6e5SSimon Wunderlich 			 * global crc
1132db08e6e5SSimon Wunderlich 			 */
1133db08e6e5SSimon Wunderlich 			if (tt_global_entry->common.flags & TT_CLIENT_ROAM)
1134cc47f66eSAntonio Quartulli 				continue;
1135db08e6e5SSimon Wunderlich 
1136db08e6e5SSimon Wunderlich 			/* find out if this global entry is announced by this
1137db08e6e5SSimon Wunderlich 			 * originator
1138db08e6e5SSimon Wunderlich 			 */
1139db08e6e5SSimon Wunderlich 			if (!tt_global_entry_has_orig(tt_global_entry,
1140db08e6e5SSimon Wunderlich 						      orig_node))
1141db08e6e5SSimon Wunderlich 				continue;
1142db08e6e5SSimon Wunderlich 
1143a73105b8SAntonio Quartulli 			total_one = 0;
1144a73105b8SAntonio Quartulli 			for (j = 0; j < ETH_ALEN; j++)
1145a73105b8SAntonio Quartulli 				total_one = crc16_byte(total_one,
1146db08e6e5SSimon Wunderlich 					tt_global_entry->common.addr[j]);
1147a73105b8SAntonio Quartulli 			total ^= total_one;
1148a73105b8SAntonio Quartulli 		}
1149a73105b8SAntonio Quartulli 		rcu_read_unlock();
1150a73105b8SAntonio Quartulli 	}
1151a73105b8SAntonio Quartulli 
1152a73105b8SAntonio Quartulli 	return total;
1153a73105b8SAntonio Quartulli }
1154a73105b8SAntonio Quartulli 
1155a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */
1156be9aa4c1SMarek Lindner static uint16_t batadv_tt_local_crc(struct bat_priv *bat_priv)
1157a73105b8SAntonio Quartulli {
1158a73105b8SAntonio Quartulli 	uint16_t total = 0, total_one;
1159a73105b8SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
116048100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
1161a73105b8SAntonio Quartulli 	struct hlist_node *node;
1162a73105b8SAntonio Quartulli 	struct hlist_head *head;
1163c90681b8SAntonio Quartulli 	uint32_t i;
1164c90681b8SAntonio Quartulli 	int j;
1165a73105b8SAntonio Quartulli 
1166a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1167a73105b8SAntonio Quartulli 		head = &hash->table[i];
1168a73105b8SAntonio Quartulli 
1169a73105b8SAntonio Quartulli 		rcu_read_lock();
117048100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
1171a73105b8SAntonio Quartulli 					 head, hash_entry) {
1172058d0e26SAntonio Quartulli 			/* not yet committed clients have not to be taken into
1173058d0e26SAntonio Quartulli 			 * account while computing the CRC */
117448100bacSAntonio Quartulli 			if (tt_common_entry->flags & TT_CLIENT_NEW)
1175058d0e26SAntonio Quartulli 				continue;
1176a73105b8SAntonio Quartulli 			total_one = 0;
1177a73105b8SAntonio Quartulli 			for (j = 0; j < ETH_ALEN; j++)
1178a73105b8SAntonio Quartulli 				total_one = crc16_byte(total_one,
117948100bacSAntonio Quartulli 						   tt_common_entry->addr[j]);
1180a73105b8SAntonio Quartulli 			total ^= total_one;
1181a73105b8SAntonio Quartulli 		}
1182a73105b8SAntonio Quartulli 		rcu_read_unlock();
1183a73105b8SAntonio Quartulli 	}
1184a73105b8SAntonio Quartulli 
1185a73105b8SAntonio Quartulli 	return total;
1186a73105b8SAntonio Quartulli }
1187a73105b8SAntonio Quartulli 
1188a73105b8SAntonio Quartulli static void tt_req_list_free(struct bat_priv *bat_priv)
1189a73105b8SAntonio Quartulli {
1190a73105b8SAntonio Quartulli 	struct tt_req_node *node, *safe;
1191a73105b8SAntonio Quartulli 
1192a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
1193a73105b8SAntonio Quartulli 
1194a73105b8SAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1195a73105b8SAntonio Quartulli 		list_del(&node->list);
1196a73105b8SAntonio Quartulli 		kfree(node);
1197a73105b8SAntonio Quartulli 	}
1198a73105b8SAntonio Quartulli 
1199a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
1200a73105b8SAntonio Quartulli }
1201a73105b8SAntonio Quartulli 
1202de7aae65SSven Eckelmann static void tt_save_orig_buffer(struct bat_priv *bat_priv,
1203de7aae65SSven Eckelmann 				struct orig_node *orig_node,
1204de7aae65SSven Eckelmann 				const unsigned char *tt_buff,
1205de7aae65SSven Eckelmann 				uint8_t tt_num_changes)
1206a73105b8SAntonio Quartulli {
1207a73105b8SAntonio Quartulli 	uint16_t tt_buff_len = tt_len(tt_num_changes);
1208a73105b8SAntonio Quartulli 
1209a73105b8SAntonio Quartulli 	/* Replace the old buffer only if I received something in the
1210a73105b8SAntonio Quartulli 	 * last OGM (the OGM could carry no changes) */
1211a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
1212a73105b8SAntonio Quartulli 	if (tt_buff_len > 0) {
1213a73105b8SAntonio Quartulli 		kfree(orig_node->tt_buff);
1214a73105b8SAntonio Quartulli 		orig_node->tt_buff_len = 0;
1215a73105b8SAntonio Quartulli 		orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
1216a73105b8SAntonio Quartulli 		if (orig_node->tt_buff) {
1217a73105b8SAntonio Quartulli 			memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
1218a73105b8SAntonio Quartulli 			orig_node->tt_buff_len = tt_buff_len;
1219a73105b8SAntonio Quartulli 		}
1220a73105b8SAntonio Quartulli 	}
1221a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
1222a73105b8SAntonio Quartulli }
1223a73105b8SAntonio Quartulli 
1224a73105b8SAntonio Quartulli static void tt_req_purge(struct bat_priv *bat_priv)
1225a73105b8SAntonio Quartulli {
1226a73105b8SAntonio Quartulli 	struct tt_req_node *node, *safe;
1227a73105b8SAntonio Quartulli 
1228a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
1229a73105b8SAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1230032b7969SMarek Lindner 		if (has_timed_out(node->issued_at, TT_REQUEST_TIMEOUT)) {
1231a73105b8SAntonio Quartulli 			list_del(&node->list);
1232a73105b8SAntonio Quartulli 			kfree(node);
1233a73105b8SAntonio Quartulli 		}
1234a73105b8SAntonio Quartulli 	}
1235a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
1236a73105b8SAntonio Quartulli }
1237a73105b8SAntonio Quartulli 
1238a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request
1239a73105b8SAntonio Quartulli  * has already been issued for this orig_node, NULL otherwise */
1240a73105b8SAntonio Quartulli static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
1241a73105b8SAntonio Quartulli 					  struct orig_node *orig_node)
1242a73105b8SAntonio Quartulli {
1243a73105b8SAntonio Quartulli 	struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
1244a73105b8SAntonio Quartulli 
1245a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
1246a73105b8SAntonio Quartulli 	list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
1247a73105b8SAntonio Quartulli 		if (compare_eth(tt_req_node_tmp, orig_node) &&
1248a04ccd59SMartin Hundebøll 		    !has_timed_out(tt_req_node_tmp->issued_at,
1249032b7969SMarek Lindner 				   TT_REQUEST_TIMEOUT))
1250a73105b8SAntonio Quartulli 			goto unlock;
1251a73105b8SAntonio Quartulli 	}
1252a73105b8SAntonio Quartulli 
1253a73105b8SAntonio Quartulli 	tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
1254a73105b8SAntonio Quartulli 	if (!tt_req_node)
1255a73105b8SAntonio Quartulli 		goto unlock;
1256a73105b8SAntonio Quartulli 
1257a73105b8SAntonio Quartulli 	memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
1258a73105b8SAntonio Quartulli 	tt_req_node->issued_at = jiffies;
1259a73105b8SAntonio Quartulli 
1260a73105b8SAntonio Quartulli 	list_add(&tt_req_node->list, &bat_priv->tt_req_list);
1261a73105b8SAntonio Quartulli unlock:
1262a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
1263a73105b8SAntonio Quartulli 	return tt_req_node;
1264a73105b8SAntonio Quartulli }
1265a73105b8SAntonio Quartulli 
1266058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */
1267058d0e26SAntonio Quartulli static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
1268058d0e26SAntonio Quartulli {
126948100bacSAntonio Quartulli 	const struct tt_common_entry *tt_common_entry = entry_ptr;
1270058d0e26SAntonio Quartulli 
127148100bacSAntonio Quartulli 	if (tt_common_entry->flags & TT_CLIENT_NEW)
1272058d0e26SAntonio Quartulli 		return 0;
1273058d0e26SAntonio Quartulli 	return 1;
1274058d0e26SAntonio Quartulli }
1275058d0e26SAntonio Quartulli 
1276a73105b8SAntonio Quartulli static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
1277a73105b8SAntonio Quartulli {
127848100bacSAntonio Quartulli 	const struct tt_common_entry *tt_common_entry = entry_ptr;
127948100bacSAntonio Quartulli 	const struct tt_global_entry *tt_global_entry;
1280a73105b8SAntonio Quartulli 	const struct orig_node *orig_node = data_ptr;
1281a73105b8SAntonio Quartulli 
128248100bacSAntonio Quartulli 	if (tt_common_entry->flags & TT_CLIENT_ROAM)
1283cc47f66eSAntonio Quartulli 		return 0;
1284cc47f66eSAntonio Quartulli 
128548100bacSAntonio Quartulli 	tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
128648100bacSAntonio Quartulli 				       common);
128748100bacSAntonio Quartulli 
1288db08e6e5SSimon Wunderlich 	return tt_global_entry_has_orig(tt_global_entry, orig_node);
1289a73105b8SAntonio Quartulli }
1290a73105b8SAntonio Quartulli 
1291a73105b8SAntonio Quartulli static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
1292a73105b8SAntonio Quartulli 					      struct hashtable_t *hash,
1293a73105b8SAntonio Quartulli 					      struct hard_iface *primary_if,
1294a73105b8SAntonio Quartulli 					      int (*valid_cb)(const void *,
1295a73105b8SAntonio Quartulli 							      const void *),
1296a73105b8SAntonio Quartulli 					      void *cb_data)
1297a73105b8SAntonio Quartulli {
129848100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
1299a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1300a73105b8SAntonio Quartulli 	struct tt_change *tt_change;
1301a73105b8SAntonio Quartulli 	struct hlist_node *node;
1302a73105b8SAntonio Quartulli 	struct hlist_head *head;
1303a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1304a73105b8SAntonio Quartulli 	uint16_t tt_tot, tt_count;
1305a73105b8SAntonio Quartulli 	ssize_t tt_query_size = sizeof(struct tt_query_packet);
1306c90681b8SAntonio Quartulli 	uint32_t i;
1307a73105b8SAntonio Quartulli 
1308a73105b8SAntonio Quartulli 	if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
1309a73105b8SAntonio Quartulli 		tt_len = primary_if->soft_iface->mtu - tt_query_size;
1310a73105b8SAntonio Quartulli 		tt_len -= tt_len % sizeof(struct tt_change);
1311a73105b8SAntonio Quartulli 	}
1312a73105b8SAntonio Quartulli 	tt_tot = tt_len / sizeof(struct tt_change);
1313a73105b8SAntonio Quartulli 
1314a73105b8SAntonio Quartulli 	skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
1315a73105b8SAntonio Quartulli 	if (!skb)
1316a73105b8SAntonio Quartulli 		goto out;
1317a73105b8SAntonio Quartulli 
1318a73105b8SAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1319a73105b8SAntonio Quartulli 	tt_response = (struct tt_query_packet *)skb_put(skb,
1320a73105b8SAntonio Quartulli 						     tt_query_size + tt_len);
1321a73105b8SAntonio Quartulli 	tt_response->ttvn = ttvn;
1322a73105b8SAntonio Quartulli 
1323a73105b8SAntonio Quartulli 	tt_change = (struct tt_change *)(skb->data + tt_query_size);
1324a73105b8SAntonio Quartulli 	tt_count = 0;
1325a73105b8SAntonio Quartulli 
1326a73105b8SAntonio Quartulli 	rcu_read_lock();
1327a73105b8SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
1328a73105b8SAntonio Quartulli 		head = &hash->table[i];
1329a73105b8SAntonio Quartulli 
133048100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
1331a73105b8SAntonio Quartulli 					 head, hash_entry) {
1332a73105b8SAntonio Quartulli 			if (tt_count == tt_tot)
1333a73105b8SAntonio Quartulli 				break;
1334a73105b8SAntonio Quartulli 
133548100bacSAntonio Quartulli 			if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
1336a73105b8SAntonio Quartulli 				continue;
1337a73105b8SAntonio Quartulli 
133848100bacSAntonio Quartulli 			memcpy(tt_change->addr, tt_common_entry->addr,
133948100bacSAntonio Quartulli 			       ETH_ALEN);
1340a73105b8SAntonio Quartulli 			tt_change->flags = NO_FLAGS;
1341a73105b8SAntonio Quartulli 
1342a73105b8SAntonio Quartulli 			tt_count++;
1343a73105b8SAntonio Quartulli 			tt_change++;
1344a73105b8SAntonio Quartulli 		}
1345a73105b8SAntonio Quartulli 	}
1346a73105b8SAntonio Quartulli 	rcu_read_unlock();
1347a73105b8SAntonio Quartulli 
13489d852393SAntonio Quartulli 	/* store in the message the number of entries we have successfully
13499d852393SAntonio Quartulli 	 * copied */
13509d852393SAntonio Quartulli 	tt_response->tt_data = htons(tt_count);
13519d852393SAntonio Quartulli 
1352a73105b8SAntonio Quartulli out:
1353a73105b8SAntonio Quartulli 	return skb;
1354a73105b8SAntonio Quartulli }
1355a73105b8SAntonio Quartulli 
1356a943cac1SMarek Lindner static int send_tt_request(struct bat_priv *bat_priv,
1357a943cac1SMarek Lindner 			   struct orig_node *dst_orig_node,
1358a73105b8SAntonio Quartulli 			   uint8_t ttvn, uint16_t tt_crc, bool full_table)
1359a73105b8SAntonio Quartulli {
1360a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1361a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_request;
1362a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1363a73105b8SAntonio Quartulli 	struct hard_iface *primary_if;
1364a73105b8SAntonio Quartulli 	struct tt_req_node *tt_req_node = NULL;
1365a73105b8SAntonio Quartulli 	int ret = 1;
1366a73105b8SAntonio Quartulli 
1367a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1368a73105b8SAntonio Quartulli 	if (!primary_if)
1369a73105b8SAntonio Quartulli 		goto out;
1370a73105b8SAntonio Quartulli 
1371a73105b8SAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
1372a73105b8SAntonio Quartulli 	 * reply from the same orig_node yet */
1373a73105b8SAntonio Quartulli 	tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
1374a73105b8SAntonio Quartulli 	if (!tt_req_node)
1375a73105b8SAntonio Quartulli 		goto out;
1376a73105b8SAntonio Quartulli 
1377a73105b8SAntonio Quartulli 	skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
1378a73105b8SAntonio Quartulli 	if (!skb)
1379a73105b8SAntonio Quartulli 		goto out;
1380a73105b8SAntonio Quartulli 
1381a73105b8SAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1382a73105b8SAntonio Quartulli 
1383a73105b8SAntonio Quartulli 	tt_request = (struct tt_query_packet *)skb_put(skb,
1384a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet));
1385a73105b8SAntonio Quartulli 
138676543d14SSven Eckelmann 	tt_request->header.packet_type = BAT_TT_QUERY;
138776543d14SSven Eckelmann 	tt_request->header.version = COMPAT_VERSION;
1388a73105b8SAntonio Quartulli 	memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1389a73105b8SAntonio Quartulli 	memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
139076543d14SSven Eckelmann 	tt_request->header.ttl = TTL;
1391a73105b8SAntonio Quartulli 	tt_request->ttvn = ttvn;
13926d2003fcSAntonio Quartulli 	tt_request->tt_data = htons(tt_crc);
1393a73105b8SAntonio Quartulli 	tt_request->flags = TT_REQUEST;
1394a73105b8SAntonio Quartulli 
1395a73105b8SAntonio Quartulli 	if (full_table)
1396a73105b8SAntonio Quartulli 		tt_request->flags |= TT_FULL_TABLE;
1397a73105b8SAntonio Quartulli 
13987d211efcSSven Eckelmann 	neigh_node = batadv_orig_node_get_router(dst_orig_node);
1399a73105b8SAntonio Quartulli 	if (!neigh_node)
1400a73105b8SAntonio Quartulli 		goto out;
1401a73105b8SAntonio Quartulli 
140286ceb360SSven Eckelmann 	bat_dbg(DBG_TT, bat_priv,
140386ceb360SSven Eckelmann 		"Sending TT_REQUEST to %pM via %pM [%c]\n",
140486ceb360SSven Eckelmann 		dst_orig_node->orig, neigh_node->addr,
1405a73105b8SAntonio Quartulli 		(full_table ? 'F' : '.'));
1406a73105b8SAntonio Quartulli 
1407f8214865SMartin Hundebøll 	batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_TX);
1408f8214865SMartin Hundebøll 
14099455e34cSSven Eckelmann 	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1410a73105b8SAntonio Quartulli 	ret = 0;
1411a73105b8SAntonio Quartulli 
1412a73105b8SAntonio Quartulli out:
1413a73105b8SAntonio Quartulli 	if (neigh_node)
14147d211efcSSven Eckelmann 		batadv_neigh_node_free_ref(neigh_node);
1415a73105b8SAntonio Quartulli 	if (primary_if)
1416a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1417a73105b8SAntonio Quartulli 	if (ret)
1418a73105b8SAntonio Quartulli 		kfree_skb(skb);
1419a73105b8SAntonio Quartulli 	if (ret && tt_req_node) {
1420a73105b8SAntonio Quartulli 		spin_lock_bh(&bat_priv->tt_req_list_lock);
1421a73105b8SAntonio Quartulli 		list_del(&tt_req_node->list);
1422a73105b8SAntonio Quartulli 		spin_unlock_bh(&bat_priv->tt_req_list_lock);
1423a73105b8SAntonio Quartulli 		kfree(tt_req_node);
1424a73105b8SAntonio Quartulli 	}
1425a73105b8SAntonio Quartulli 	return ret;
1426a73105b8SAntonio Quartulli }
1427a73105b8SAntonio Quartulli 
1428a73105b8SAntonio Quartulli static bool send_other_tt_response(struct bat_priv *bat_priv,
1429a73105b8SAntonio Quartulli 				   struct tt_query_packet *tt_request)
1430a73105b8SAntonio Quartulli {
1431a73105b8SAntonio Quartulli 	struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
1432a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1433a73105b8SAntonio Quartulli 	struct hard_iface *primary_if = NULL;
1434a73105b8SAntonio Quartulli 	uint8_t orig_ttvn, req_ttvn, ttvn;
1435a73105b8SAntonio Quartulli 	int ret = false;
1436a73105b8SAntonio Quartulli 	unsigned char *tt_buff;
1437a73105b8SAntonio Quartulli 	bool full_table;
1438a73105b8SAntonio Quartulli 	uint16_t tt_len, tt_tot;
1439a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1440a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1441a73105b8SAntonio Quartulli 
1442a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
144386ceb360SSven Eckelmann 		"Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
144486ceb360SSven Eckelmann 		tt_request->src, tt_request->ttvn, tt_request->dst,
1445a73105b8SAntonio Quartulli 		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1446a73105b8SAntonio Quartulli 
1447a73105b8SAntonio Quartulli 	/* Let's get the orig node of the REAL destination */
1448eb7e2a1eSAntonio Quartulli 	req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst);
1449a73105b8SAntonio Quartulli 	if (!req_dst_orig_node)
1450a73105b8SAntonio Quartulli 		goto out;
1451a73105b8SAntonio Quartulli 
1452eb7e2a1eSAntonio Quartulli 	res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src);
1453a73105b8SAntonio Quartulli 	if (!res_dst_orig_node)
1454a73105b8SAntonio Quartulli 		goto out;
1455a73105b8SAntonio Quartulli 
14567d211efcSSven Eckelmann 	neigh_node = batadv_orig_node_get_router(res_dst_orig_node);
1457a73105b8SAntonio Quartulli 	if (!neigh_node)
1458a73105b8SAntonio Quartulli 		goto out;
1459a73105b8SAntonio Quartulli 
1460a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1461a73105b8SAntonio Quartulli 	if (!primary_if)
1462a73105b8SAntonio Quartulli 		goto out;
1463a73105b8SAntonio Quartulli 
1464a73105b8SAntonio Quartulli 	orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1465a73105b8SAntonio Quartulli 	req_ttvn = tt_request->ttvn;
1466a73105b8SAntonio Quartulli 
1467015758d0SAntonio Quartulli 	/* I don't have the requested data */
1468a73105b8SAntonio Quartulli 	if (orig_ttvn != req_ttvn ||
1469f25bd58aSAl Viro 	    tt_request->tt_data != htons(req_dst_orig_node->tt_crc))
1470a73105b8SAntonio Quartulli 		goto out;
1471a73105b8SAntonio Quartulli 
1472015758d0SAntonio Quartulli 	/* If the full table has been explicitly requested */
1473a73105b8SAntonio Quartulli 	if (tt_request->flags & TT_FULL_TABLE ||
1474a73105b8SAntonio Quartulli 	    !req_dst_orig_node->tt_buff)
1475a73105b8SAntonio Quartulli 		full_table = true;
1476a73105b8SAntonio Quartulli 	else
1477a73105b8SAntonio Quartulli 		full_table = false;
1478a73105b8SAntonio Quartulli 
1479a73105b8SAntonio Quartulli 	/* In this version, fragmentation is not implemented, then
1480a73105b8SAntonio Quartulli 	 * I'll send only one packet with as much TT entries as I can */
1481a73105b8SAntonio Quartulli 	if (!full_table) {
1482a73105b8SAntonio Quartulli 		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1483a73105b8SAntonio Quartulli 		tt_len = req_dst_orig_node->tt_buff_len;
1484a73105b8SAntonio Quartulli 		tt_tot = tt_len / sizeof(struct tt_change);
1485a73105b8SAntonio Quartulli 
1486a73105b8SAntonio Quartulli 		skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1487a73105b8SAntonio Quartulli 				    tt_len + ETH_HLEN);
1488a73105b8SAntonio Quartulli 		if (!skb)
1489a73105b8SAntonio Quartulli 			goto unlock;
1490a73105b8SAntonio Quartulli 
1491a73105b8SAntonio Quartulli 		skb_reserve(skb, ETH_HLEN);
1492a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb_put(skb,
1493a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet) + tt_len);
1494a73105b8SAntonio Quartulli 		tt_response->ttvn = req_ttvn;
1495a73105b8SAntonio Quartulli 		tt_response->tt_data = htons(tt_tot);
1496a73105b8SAntonio Quartulli 
1497a73105b8SAntonio Quartulli 		tt_buff = skb->data + sizeof(struct tt_query_packet);
1498a73105b8SAntonio Quartulli 		/* Copy the last orig_node's OGM buffer */
1499a73105b8SAntonio Quartulli 		memcpy(tt_buff, req_dst_orig_node->tt_buff,
1500a73105b8SAntonio Quartulli 		       req_dst_orig_node->tt_buff_len);
1501a73105b8SAntonio Quartulli 
1502a73105b8SAntonio Quartulli 		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1503a73105b8SAntonio Quartulli 	} else {
1504a73105b8SAntonio Quartulli 		tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
1505a73105b8SAntonio Quartulli 						sizeof(struct tt_change);
1506a73105b8SAntonio Quartulli 		ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1507a73105b8SAntonio Quartulli 
1508a73105b8SAntonio Quartulli 		skb = tt_response_fill_table(tt_len, ttvn,
1509a73105b8SAntonio Quartulli 					     bat_priv->tt_global_hash,
1510a73105b8SAntonio Quartulli 					     primary_if, tt_global_valid_entry,
1511a73105b8SAntonio Quartulli 					     req_dst_orig_node);
1512a73105b8SAntonio Quartulli 		if (!skb)
1513a73105b8SAntonio Quartulli 			goto out;
1514a73105b8SAntonio Quartulli 
1515a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb->data;
1516a73105b8SAntonio Quartulli 	}
1517a73105b8SAntonio Quartulli 
151876543d14SSven Eckelmann 	tt_response->header.packet_type = BAT_TT_QUERY;
151976543d14SSven Eckelmann 	tt_response->header.version = COMPAT_VERSION;
152076543d14SSven Eckelmann 	tt_response->header.ttl = TTL;
1521a73105b8SAntonio Quartulli 	memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
1522a73105b8SAntonio Quartulli 	memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1523a73105b8SAntonio Quartulli 	tt_response->flags = TT_RESPONSE;
1524a73105b8SAntonio Quartulli 
1525a73105b8SAntonio Quartulli 	if (full_table)
1526a73105b8SAntonio Quartulli 		tt_response->flags |= TT_FULL_TABLE;
1527a73105b8SAntonio Quartulli 
1528a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1529a73105b8SAntonio Quartulli 		"Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
1530a73105b8SAntonio Quartulli 		res_dst_orig_node->orig, neigh_node->addr,
1531a73105b8SAntonio Quartulli 		req_dst_orig_node->orig, req_ttvn);
1532a73105b8SAntonio Quartulli 
1533f8214865SMartin Hundebøll 	batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
1534f8214865SMartin Hundebøll 
15359455e34cSSven Eckelmann 	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1536a73105b8SAntonio Quartulli 	ret = true;
1537a73105b8SAntonio Quartulli 	goto out;
1538a73105b8SAntonio Quartulli 
1539a73105b8SAntonio Quartulli unlock:
1540a73105b8SAntonio Quartulli 	spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1541a73105b8SAntonio Quartulli 
1542a73105b8SAntonio Quartulli out:
1543a73105b8SAntonio Quartulli 	if (res_dst_orig_node)
15447d211efcSSven Eckelmann 		batadv_orig_node_free_ref(res_dst_orig_node);
1545a73105b8SAntonio Quartulli 	if (req_dst_orig_node)
15467d211efcSSven Eckelmann 		batadv_orig_node_free_ref(req_dst_orig_node);
1547a73105b8SAntonio Quartulli 	if (neigh_node)
15487d211efcSSven Eckelmann 		batadv_neigh_node_free_ref(neigh_node);
1549a73105b8SAntonio Quartulli 	if (primary_if)
1550a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1551a73105b8SAntonio Quartulli 	if (!ret)
1552a73105b8SAntonio Quartulli 		kfree_skb(skb);
1553a73105b8SAntonio Quartulli 	return ret;
1554a73105b8SAntonio Quartulli 
1555a73105b8SAntonio Quartulli }
1556a73105b8SAntonio Quartulli static bool send_my_tt_response(struct bat_priv *bat_priv,
1557a73105b8SAntonio Quartulli 				struct tt_query_packet *tt_request)
1558a73105b8SAntonio Quartulli {
1559a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1560a73105b8SAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1561a73105b8SAntonio Quartulli 	struct hard_iface *primary_if = NULL;
1562a73105b8SAntonio Quartulli 	uint8_t my_ttvn, req_ttvn, ttvn;
1563a73105b8SAntonio Quartulli 	int ret = false;
1564a73105b8SAntonio Quartulli 	unsigned char *tt_buff;
1565a73105b8SAntonio Quartulli 	bool full_table;
1566a73105b8SAntonio Quartulli 	uint16_t tt_len, tt_tot;
1567a73105b8SAntonio Quartulli 	struct sk_buff *skb = NULL;
1568a73105b8SAntonio Quartulli 	struct tt_query_packet *tt_response;
1569a73105b8SAntonio Quartulli 
1570a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
157186ceb360SSven Eckelmann 		"Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
157286ceb360SSven Eckelmann 		tt_request->src, tt_request->ttvn,
1573a73105b8SAntonio Quartulli 		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1574a73105b8SAntonio Quartulli 
1575a73105b8SAntonio Quartulli 
1576a73105b8SAntonio Quartulli 	my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1577a73105b8SAntonio Quartulli 	req_ttvn = tt_request->ttvn;
1578a73105b8SAntonio Quartulli 
1579eb7e2a1eSAntonio Quartulli 	orig_node = orig_hash_find(bat_priv, tt_request->src);
1580a73105b8SAntonio Quartulli 	if (!orig_node)
1581a73105b8SAntonio Quartulli 		goto out;
1582a73105b8SAntonio Quartulli 
15837d211efcSSven Eckelmann 	neigh_node = batadv_orig_node_get_router(orig_node);
1584a73105b8SAntonio Quartulli 	if (!neigh_node)
1585a73105b8SAntonio Quartulli 		goto out;
1586a73105b8SAntonio Quartulli 
1587a73105b8SAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1588a73105b8SAntonio Quartulli 	if (!primary_if)
1589a73105b8SAntonio Quartulli 		goto out;
1590a73105b8SAntonio Quartulli 
1591a73105b8SAntonio Quartulli 	/* If the full table has been explicitly requested or the gap
1592a73105b8SAntonio Quartulli 	 * is too big send the whole local translation table */
1593a73105b8SAntonio Quartulli 	if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
1594a73105b8SAntonio Quartulli 	    !bat_priv->tt_buff)
1595a73105b8SAntonio Quartulli 		full_table = true;
1596a73105b8SAntonio Quartulli 	else
1597a73105b8SAntonio Quartulli 		full_table = false;
1598a73105b8SAntonio Quartulli 
1599a73105b8SAntonio Quartulli 	/* In this version, fragmentation is not implemented, then
1600a73105b8SAntonio Quartulli 	 * I'll send only one packet with as much TT entries as I can */
1601a73105b8SAntonio Quartulli 	if (!full_table) {
1602a73105b8SAntonio Quartulli 		spin_lock_bh(&bat_priv->tt_buff_lock);
1603a73105b8SAntonio Quartulli 		tt_len = bat_priv->tt_buff_len;
1604a73105b8SAntonio Quartulli 		tt_tot = tt_len / sizeof(struct tt_change);
1605a73105b8SAntonio Quartulli 
1606a73105b8SAntonio Quartulli 		skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1607a73105b8SAntonio Quartulli 				    tt_len + ETH_HLEN);
1608a73105b8SAntonio Quartulli 		if (!skb)
1609a73105b8SAntonio Quartulli 			goto unlock;
1610a73105b8SAntonio Quartulli 
1611a73105b8SAntonio Quartulli 		skb_reserve(skb, ETH_HLEN);
1612a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb_put(skb,
1613a73105b8SAntonio Quartulli 				sizeof(struct tt_query_packet) + tt_len);
1614a73105b8SAntonio Quartulli 		tt_response->ttvn = req_ttvn;
1615a73105b8SAntonio Quartulli 		tt_response->tt_data = htons(tt_tot);
1616a73105b8SAntonio Quartulli 
1617a73105b8SAntonio Quartulli 		tt_buff = skb->data + sizeof(struct tt_query_packet);
1618a73105b8SAntonio Quartulli 		memcpy(tt_buff, bat_priv->tt_buff,
1619a73105b8SAntonio Quartulli 		       bat_priv->tt_buff_len);
1620a73105b8SAntonio Quartulli 		spin_unlock_bh(&bat_priv->tt_buff_lock);
1621a73105b8SAntonio Quartulli 	} else {
1622a73105b8SAntonio Quartulli 		tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
1623a73105b8SAntonio Quartulli 						sizeof(struct tt_change);
1624a73105b8SAntonio Quartulli 		ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1625a73105b8SAntonio Quartulli 
1626a73105b8SAntonio Quartulli 		skb = tt_response_fill_table(tt_len, ttvn,
1627a73105b8SAntonio Quartulli 					     bat_priv->tt_local_hash,
1628058d0e26SAntonio Quartulli 					     primary_if, tt_local_valid_entry,
1629058d0e26SAntonio Quartulli 					     NULL);
1630a73105b8SAntonio Quartulli 		if (!skb)
1631a73105b8SAntonio Quartulli 			goto out;
1632a73105b8SAntonio Quartulli 
1633a73105b8SAntonio Quartulli 		tt_response = (struct tt_query_packet *)skb->data;
1634a73105b8SAntonio Quartulli 	}
1635a73105b8SAntonio Quartulli 
163676543d14SSven Eckelmann 	tt_response->header.packet_type = BAT_TT_QUERY;
163776543d14SSven Eckelmann 	tt_response->header.version = COMPAT_VERSION;
163876543d14SSven Eckelmann 	tt_response->header.ttl = TTL;
1639a73105b8SAntonio Quartulli 	memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1640a73105b8SAntonio Quartulli 	memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1641a73105b8SAntonio Quartulli 	tt_response->flags = TT_RESPONSE;
1642a73105b8SAntonio Quartulli 
1643a73105b8SAntonio Quartulli 	if (full_table)
1644a73105b8SAntonio Quartulli 		tt_response->flags |= TT_FULL_TABLE;
1645a73105b8SAntonio Quartulli 
1646a73105b8SAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1647a73105b8SAntonio Quartulli 		"Sending TT_RESPONSE to %pM via %pM [%c]\n",
1648a73105b8SAntonio Quartulli 		orig_node->orig, neigh_node->addr,
1649a73105b8SAntonio Quartulli 		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1650a73105b8SAntonio Quartulli 
1651f8214865SMartin Hundebøll 	batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
1652f8214865SMartin Hundebøll 
16539455e34cSSven Eckelmann 	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1654a73105b8SAntonio Quartulli 	ret = true;
1655a73105b8SAntonio Quartulli 	goto out;
1656a73105b8SAntonio Quartulli 
1657a73105b8SAntonio Quartulli unlock:
1658a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_buff_lock);
1659a73105b8SAntonio Quartulli out:
1660a73105b8SAntonio Quartulli 	if (orig_node)
16617d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
1662a73105b8SAntonio Quartulli 	if (neigh_node)
16637d211efcSSven Eckelmann 		batadv_neigh_node_free_ref(neigh_node);
1664a73105b8SAntonio Quartulli 	if (primary_if)
1665a73105b8SAntonio Quartulli 		hardif_free_ref(primary_if);
1666a73105b8SAntonio Quartulli 	if (!ret)
1667a73105b8SAntonio Quartulli 		kfree_skb(skb);
1668a73105b8SAntonio Quartulli 	/* This packet was for me, so it doesn't need to be re-routed */
1669a73105b8SAntonio Quartulli 	return true;
1670a73105b8SAntonio Quartulli }
1671a73105b8SAntonio Quartulli 
1672a73105b8SAntonio Quartulli bool send_tt_response(struct bat_priv *bat_priv,
1673a73105b8SAntonio Quartulli 		      struct tt_query_packet *tt_request)
1674a73105b8SAntonio Quartulli {
167520ff9d59SSimon Wunderlich 	if (is_my_mac(tt_request->dst)) {
167620ff9d59SSimon Wunderlich 		/* don't answer backbone gws! */
167708adf151SSven Eckelmann 		if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src))
167820ff9d59SSimon Wunderlich 			return true;
167920ff9d59SSimon Wunderlich 
1680a73105b8SAntonio Quartulli 		return send_my_tt_response(bat_priv, tt_request);
168120ff9d59SSimon Wunderlich 	} else {
1682a73105b8SAntonio Quartulli 		return send_other_tt_response(bat_priv, tt_request);
1683a73105b8SAntonio Quartulli 	}
168420ff9d59SSimon Wunderlich }
1685a73105b8SAntonio Quartulli 
1686a73105b8SAntonio Quartulli static void _tt_update_changes(struct bat_priv *bat_priv,
1687a73105b8SAntonio Quartulli 			       struct orig_node *orig_node,
1688a73105b8SAntonio Quartulli 			       struct tt_change *tt_change,
1689a73105b8SAntonio Quartulli 			       uint16_t tt_num_changes, uint8_t ttvn)
1690a73105b8SAntonio Quartulli {
1691a73105b8SAntonio Quartulli 	int i;
1692a73105b8SAntonio Quartulli 
1693a73105b8SAntonio Quartulli 	for (i = 0; i < tt_num_changes; i++) {
16945fbc1598SAntonio Quartulli 		if ((tt_change + i)->flags & TT_CLIENT_DEL)
1695a73105b8SAntonio Quartulli 			tt_global_del(bat_priv, orig_node,
1696a73105b8SAntonio Quartulli 				      (tt_change + i)->addr,
1697cc47f66eSAntonio Quartulli 				      "tt removed by changes",
1698cc47f66eSAntonio Quartulli 				      (tt_change + i)->flags & TT_CLIENT_ROAM);
1699a73105b8SAntonio Quartulli 		else
1700a73105b8SAntonio Quartulli 			if (!tt_global_add(bat_priv, orig_node,
1701bc279080SAntonio Quartulli 					   (tt_change + i)->addr, ttvn, false,
1702bc279080SAntonio Quartulli 					   (tt_change + i)->flags &
1703bc279080SAntonio Quartulli 							TT_CLIENT_WIFI))
1704a73105b8SAntonio Quartulli 				/* In case of problem while storing a
1705a73105b8SAntonio Quartulli 				 * global_entry, we stop the updating
1706a73105b8SAntonio Quartulli 				 * procedure without committing the
1707a73105b8SAntonio Quartulli 				 * ttvn change. This will avoid to send
1708a73105b8SAntonio Quartulli 				 * corrupted data on tt_request
1709a73105b8SAntonio Quartulli 				 */
1710a73105b8SAntonio Quartulli 				return;
1711a73105b8SAntonio Quartulli 	}
171217071578SAntonio Quartulli 	orig_node->tt_initialised = true;
1713a73105b8SAntonio Quartulli }
1714a73105b8SAntonio Quartulli 
1715a73105b8SAntonio Quartulli static void tt_fill_gtable(struct bat_priv *bat_priv,
1716a73105b8SAntonio Quartulli 			   struct tt_query_packet *tt_response)
1717a73105b8SAntonio Quartulli {
1718a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1719a73105b8SAntonio Quartulli 
1720a73105b8SAntonio Quartulli 	orig_node = orig_hash_find(bat_priv, tt_response->src);
1721a73105b8SAntonio Quartulli 	if (!orig_node)
1722a73105b8SAntonio Quartulli 		goto out;
1723a73105b8SAntonio Quartulli 
1724a73105b8SAntonio Quartulli 	/* Purge the old table first.. */
1725a73105b8SAntonio Quartulli 	tt_global_del_orig(bat_priv, orig_node, "Received full table");
1726a73105b8SAntonio Quartulli 
1727a73105b8SAntonio Quartulli 	_tt_update_changes(bat_priv, orig_node,
1728a73105b8SAntonio Quartulli 			   (struct tt_change *)(tt_response + 1),
1729f25bd58aSAl Viro 			   ntohs(tt_response->tt_data), tt_response->ttvn);
1730a73105b8SAntonio Quartulli 
1731a73105b8SAntonio Quartulli 	spin_lock_bh(&orig_node->tt_buff_lock);
1732a73105b8SAntonio Quartulli 	kfree(orig_node->tt_buff);
1733a73105b8SAntonio Quartulli 	orig_node->tt_buff_len = 0;
1734a73105b8SAntonio Quartulli 	orig_node->tt_buff = NULL;
1735a73105b8SAntonio Quartulli 	spin_unlock_bh(&orig_node->tt_buff_lock);
1736a73105b8SAntonio Quartulli 
1737a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
1738a73105b8SAntonio Quartulli 
1739a73105b8SAntonio Quartulli out:
1740a73105b8SAntonio Quartulli 	if (orig_node)
17417d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
1742a73105b8SAntonio Quartulli }
1743a73105b8SAntonio Quartulli 
1744a943cac1SMarek Lindner static void tt_update_changes(struct bat_priv *bat_priv,
1745a943cac1SMarek Lindner 			      struct orig_node *orig_node,
1746a73105b8SAntonio Quartulli 			      uint16_t tt_num_changes, uint8_t ttvn,
1747a73105b8SAntonio Quartulli 			      struct tt_change *tt_change)
1748a73105b8SAntonio Quartulli {
1749a73105b8SAntonio Quartulli 	_tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
1750a73105b8SAntonio Quartulli 			   ttvn);
1751a73105b8SAntonio Quartulli 
1752a73105b8SAntonio Quartulli 	tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
1753a73105b8SAntonio Quartulli 			    tt_num_changes);
1754a73105b8SAntonio Quartulli 	atomic_set(&orig_node->last_ttvn, ttvn);
1755a73105b8SAntonio Quartulli }
1756a73105b8SAntonio Quartulli 
1757a73105b8SAntonio Quartulli bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
1758a73105b8SAntonio Quartulli {
17597683fdc1SAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
17607683fdc1SAntonio Quartulli 	bool ret = false;
1761a73105b8SAntonio Quartulli 
1762a73105b8SAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, addr);
17637683fdc1SAntonio Quartulli 	if (!tt_local_entry)
17647683fdc1SAntonio Quartulli 		goto out;
1765058d0e26SAntonio Quartulli 	/* Check if the client has been logically deleted (but is kept for
1766058d0e26SAntonio Quartulli 	 * consistency purpose) */
176748100bacSAntonio Quartulli 	if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
1768058d0e26SAntonio Quartulli 		goto out;
17697683fdc1SAntonio Quartulli 	ret = true;
17707683fdc1SAntonio Quartulli out:
1771a73105b8SAntonio Quartulli 	if (tt_local_entry)
17727683fdc1SAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
17737683fdc1SAntonio Quartulli 	return ret;
1774a73105b8SAntonio Quartulli }
1775a73105b8SAntonio Quartulli 
1776a73105b8SAntonio Quartulli void handle_tt_response(struct bat_priv *bat_priv,
1777a73105b8SAntonio Quartulli 			struct tt_query_packet *tt_response)
1778a73105b8SAntonio Quartulli {
1779a73105b8SAntonio Quartulli 	struct tt_req_node *node, *safe;
1780a73105b8SAntonio Quartulli 	struct orig_node *orig_node = NULL;
1781a73105b8SAntonio Quartulli 
178286ceb360SSven Eckelmann 	bat_dbg(DBG_TT, bat_priv,
178386ceb360SSven Eckelmann 		"Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
1784f25bd58aSAl Viro 		tt_response->src, tt_response->ttvn,
1785f25bd58aSAl Viro 		ntohs(tt_response->tt_data),
1786a73105b8SAntonio Quartulli 		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1787a73105b8SAntonio Quartulli 
178820ff9d59SSimon Wunderlich 	/* we should have never asked a backbone gw */
178908adf151SSven Eckelmann 	if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src))
179020ff9d59SSimon Wunderlich 		goto out;
179120ff9d59SSimon Wunderlich 
1792a73105b8SAntonio Quartulli 	orig_node = orig_hash_find(bat_priv, tt_response->src);
1793a73105b8SAntonio Quartulli 	if (!orig_node)
1794a73105b8SAntonio Quartulli 		goto out;
1795a73105b8SAntonio Quartulli 
1796a73105b8SAntonio Quartulli 	if (tt_response->flags & TT_FULL_TABLE)
1797a73105b8SAntonio Quartulli 		tt_fill_gtable(bat_priv, tt_response);
1798a73105b8SAntonio Quartulli 	else
1799f25bd58aSAl Viro 		tt_update_changes(bat_priv, orig_node,
1800f25bd58aSAl Viro 				  ntohs(tt_response->tt_data),
1801a73105b8SAntonio Quartulli 				  tt_response->ttvn,
1802a73105b8SAntonio Quartulli 				  (struct tt_change *)(tt_response + 1));
1803a73105b8SAntonio Quartulli 
1804a73105b8SAntonio Quartulli 	/* Delete the tt_req_node from pending tt_requests list */
1805a73105b8SAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_req_list_lock);
1806a73105b8SAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1807a73105b8SAntonio Quartulli 		if (!compare_eth(node->addr, tt_response->src))
1808a73105b8SAntonio Quartulli 			continue;
1809a73105b8SAntonio Quartulli 		list_del(&node->list);
1810a73105b8SAntonio Quartulli 		kfree(node);
1811a73105b8SAntonio Quartulli 	}
1812a73105b8SAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_req_list_lock);
1813a73105b8SAntonio Quartulli 
1814a73105b8SAntonio Quartulli 	/* Recalculate the CRC for this orig_node and store it */
1815a73105b8SAntonio Quartulli 	orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1816cc47f66eSAntonio Quartulli 	/* Roaming phase is over: tables are in sync again. I can
1817cc47f66eSAntonio Quartulli 	 * unset the flag */
1818cc47f66eSAntonio Quartulli 	orig_node->tt_poss_change = false;
1819a73105b8SAntonio Quartulli out:
1820a73105b8SAntonio Quartulli 	if (orig_node)
18217d211efcSSven Eckelmann 		batadv_orig_node_free_ref(orig_node);
1822a73105b8SAntonio Quartulli }
1823a73105b8SAntonio Quartulli 
1824a73105b8SAntonio Quartulli int tt_init(struct bat_priv *bat_priv)
1825a73105b8SAntonio Quartulli {
18265346c35eSSven Eckelmann 	int ret;
1827a73105b8SAntonio Quartulli 
18285346c35eSSven Eckelmann 	ret = tt_local_init(bat_priv);
18295346c35eSSven Eckelmann 	if (ret < 0)
18305346c35eSSven Eckelmann 		return ret;
18315346c35eSSven Eckelmann 
18325346c35eSSven Eckelmann 	ret = tt_global_init(bat_priv);
18335346c35eSSven Eckelmann 	if (ret < 0)
18345346c35eSSven Eckelmann 		return ret;
1835a73105b8SAntonio Quartulli 
1836a73105b8SAntonio Quartulli 	tt_start_timer(bat_priv);
1837a73105b8SAntonio Quartulli 
1838a73105b8SAntonio Quartulli 	return 1;
1839a73105b8SAntonio Quartulli }
1840a73105b8SAntonio Quartulli 
1841cc47f66eSAntonio Quartulli static void tt_roam_list_free(struct bat_priv *bat_priv)
1842a73105b8SAntonio Quartulli {
1843cc47f66eSAntonio Quartulli 	struct tt_roam_node *node, *safe;
1844a73105b8SAntonio Quartulli 
1845cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1846a73105b8SAntonio Quartulli 
1847cc47f66eSAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1848cc47f66eSAntonio Quartulli 		list_del(&node->list);
1849cc47f66eSAntonio Quartulli 		kfree(node);
1850cc47f66eSAntonio Quartulli 	}
1851cc47f66eSAntonio Quartulli 
1852cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1853cc47f66eSAntonio Quartulli }
1854cc47f66eSAntonio Quartulli 
1855cc47f66eSAntonio Quartulli static void tt_roam_purge(struct bat_priv *bat_priv)
1856cc47f66eSAntonio Quartulli {
1857cc47f66eSAntonio Quartulli 	struct tt_roam_node *node, *safe;
1858cc47f66eSAntonio Quartulli 
1859cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1860cc47f66eSAntonio Quartulli 	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1861032b7969SMarek Lindner 		if (!has_timed_out(node->first_time, ROAMING_MAX_TIME))
1862cc47f66eSAntonio Quartulli 			continue;
1863cc47f66eSAntonio Quartulli 
1864cc47f66eSAntonio Quartulli 		list_del(&node->list);
1865cc47f66eSAntonio Quartulli 		kfree(node);
1866cc47f66eSAntonio Quartulli 	}
1867cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1868cc47f66eSAntonio Quartulli }
1869cc47f66eSAntonio Quartulli 
1870cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the
1871cc47f66eSAntonio Quartulli  * maximum number of possible roaming phases. In this case the ROAMING_ADV
1872cc47f66eSAntonio Quartulli  * will not be sent.
1873cc47f66eSAntonio Quartulli  *
1874cc47f66eSAntonio Quartulli  * returns true if the ROAMING_ADV can be sent, false otherwise */
1875cc47f66eSAntonio Quartulli static bool tt_check_roam_count(struct bat_priv *bat_priv,
1876cc47f66eSAntonio Quartulli 				uint8_t *client)
1877cc47f66eSAntonio Quartulli {
1878cc47f66eSAntonio Quartulli 	struct tt_roam_node *tt_roam_node;
1879cc47f66eSAntonio Quartulli 	bool ret = false;
1880cc47f66eSAntonio Quartulli 
1881cc47f66eSAntonio Quartulli 	spin_lock_bh(&bat_priv->tt_roam_list_lock);
1882cc47f66eSAntonio Quartulli 	/* The new tt_req will be issued only if I'm not waiting for a
1883cc47f66eSAntonio Quartulli 	 * reply from the same orig_node yet */
1884cc47f66eSAntonio Quartulli 	list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
1885cc47f66eSAntonio Quartulli 		if (!compare_eth(tt_roam_node->addr, client))
1886cc47f66eSAntonio Quartulli 			continue;
1887cc47f66eSAntonio Quartulli 
1888032b7969SMarek Lindner 		if (has_timed_out(tt_roam_node->first_time, ROAMING_MAX_TIME))
1889cc47f66eSAntonio Quartulli 			continue;
1890cc47f66eSAntonio Quartulli 
1891cc47f66eSAntonio Quartulli 		if (!atomic_dec_not_zero(&tt_roam_node->counter))
1892cc47f66eSAntonio Quartulli 			/* Sorry, you roamed too many times! */
1893cc47f66eSAntonio Quartulli 			goto unlock;
1894cc47f66eSAntonio Quartulli 		ret = true;
1895cc47f66eSAntonio Quartulli 		break;
1896cc47f66eSAntonio Quartulli 	}
1897cc47f66eSAntonio Quartulli 
1898cc47f66eSAntonio Quartulli 	if (!ret) {
1899cc47f66eSAntonio Quartulli 		tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
1900cc47f66eSAntonio Quartulli 		if (!tt_roam_node)
1901cc47f66eSAntonio Quartulli 			goto unlock;
1902cc47f66eSAntonio Quartulli 
1903cc47f66eSAntonio Quartulli 		tt_roam_node->first_time = jiffies;
1904cc47f66eSAntonio Quartulli 		atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
1905cc47f66eSAntonio Quartulli 		memcpy(tt_roam_node->addr, client, ETH_ALEN);
1906cc47f66eSAntonio Quartulli 
1907cc47f66eSAntonio Quartulli 		list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
1908cc47f66eSAntonio Quartulli 		ret = true;
1909cc47f66eSAntonio Quartulli 	}
1910cc47f66eSAntonio Quartulli 
1911cc47f66eSAntonio Quartulli unlock:
1912cc47f66eSAntonio Quartulli 	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1913cc47f66eSAntonio Quartulli 	return ret;
1914cc47f66eSAntonio Quartulli }
1915cc47f66eSAntonio Quartulli 
1916de7aae65SSven Eckelmann static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
1917cc47f66eSAntonio Quartulli 			  struct orig_node *orig_node)
1918cc47f66eSAntonio Quartulli {
1919cc47f66eSAntonio Quartulli 	struct neigh_node *neigh_node = NULL;
1920cc47f66eSAntonio Quartulli 	struct sk_buff *skb = NULL;
1921cc47f66eSAntonio Quartulli 	struct roam_adv_packet *roam_adv_packet;
1922cc47f66eSAntonio Quartulli 	int ret = 1;
1923cc47f66eSAntonio Quartulli 	struct hard_iface *primary_if;
1924cc47f66eSAntonio Quartulli 
1925cc47f66eSAntonio Quartulli 	/* before going on we have to check whether the client has
1926cc47f66eSAntonio Quartulli 	 * already roamed to us too many times */
1927cc47f66eSAntonio Quartulli 	if (!tt_check_roam_count(bat_priv, client))
1928cc47f66eSAntonio Quartulli 		goto out;
1929cc47f66eSAntonio Quartulli 
1930cc47f66eSAntonio Quartulli 	skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
1931cc47f66eSAntonio Quartulli 	if (!skb)
1932cc47f66eSAntonio Quartulli 		goto out;
1933cc47f66eSAntonio Quartulli 
1934cc47f66eSAntonio Quartulli 	skb_reserve(skb, ETH_HLEN);
1935cc47f66eSAntonio Quartulli 
1936cc47f66eSAntonio Quartulli 	roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
1937cc47f66eSAntonio Quartulli 					sizeof(struct roam_adv_packet));
1938cc47f66eSAntonio Quartulli 
193976543d14SSven Eckelmann 	roam_adv_packet->header.packet_type = BAT_ROAM_ADV;
194076543d14SSven Eckelmann 	roam_adv_packet->header.version = COMPAT_VERSION;
194176543d14SSven Eckelmann 	roam_adv_packet->header.ttl = TTL;
1942cc47f66eSAntonio Quartulli 	primary_if = primary_if_get_selected(bat_priv);
1943cc47f66eSAntonio Quartulli 	if (!primary_if)
1944cc47f66eSAntonio Quartulli 		goto out;
1945cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1946cc47f66eSAntonio Quartulli 	hardif_free_ref(primary_if);
1947cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
1948cc47f66eSAntonio Quartulli 	memcpy(roam_adv_packet->client, client, ETH_ALEN);
1949cc47f66eSAntonio Quartulli 
19507d211efcSSven Eckelmann 	neigh_node = batadv_orig_node_get_router(orig_node);
1951cc47f66eSAntonio Quartulli 	if (!neigh_node)
1952cc47f66eSAntonio Quartulli 		goto out;
1953cc47f66eSAntonio Quartulli 
1954cc47f66eSAntonio Quartulli 	bat_dbg(DBG_TT, bat_priv,
1955cc47f66eSAntonio Quartulli 		"Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
1956cc47f66eSAntonio Quartulli 		orig_node->orig, client, neigh_node->addr);
1957cc47f66eSAntonio Quartulli 
1958f8214865SMartin Hundebøll 	batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_TX);
1959f8214865SMartin Hundebøll 
19609455e34cSSven Eckelmann 	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1961cc47f66eSAntonio Quartulli 	ret = 0;
1962cc47f66eSAntonio Quartulli 
1963cc47f66eSAntonio Quartulli out:
1964cc47f66eSAntonio Quartulli 	if (neigh_node)
19657d211efcSSven Eckelmann 		batadv_neigh_node_free_ref(neigh_node);
1966cc47f66eSAntonio Quartulli 	if (ret)
1967cc47f66eSAntonio Quartulli 		kfree_skb(skb);
1968cc47f66eSAntonio Quartulli 	return;
1969a73105b8SAntonio Quartulli }
1970a73105b8SAntonio Quartulli 
1971a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work)
1972a73105b8SAntonio Quartulli {
1973a73105b8SAntonio Quartulli 	struct delayed_work *delayed_work =
1974a73105b8SAntonio Quartulli 		container_of(work, struct delayed_work, work);
1975a73105b8SAntonio Quartulli 	struct bat_priv *bat_priv =
1976a73105b8SAntonio Quartulli 		container_of(delayed_work, struct bat_priv, tt_work);
1977a73105b8SAntonio Quartulli 
1978a73105b8SAntonio Quartulli 	tt_local_purge(bat_priv);
1979cc47f66eSAntonio Quartulli 	tt_global_roam_purge(bat_priv);
1980a73105b8SAntonio Quartulli 	tt_req_purge(bat_priv);
1981cc47f66eSAntonio Quartulli 	tt_roam_purge(bat_priv);
1982a73105b8SAntonio Quartulli 
1983a73105b8SAntonio Quartulli 	tt_start_timer(bat_priv);
1984a73105b8SAntonio Quartulli }
1985cc47f66eSAntonio Quartulli 
1986cc47f66eSAntonio Quartulli void tt_free(struct bat_priv *bat_priv)
1987cc47f66eSAntonio Quartulli {
1988cc47f66eSAntonio Quartulli 	cancel_delayed_work_sync(&bat_priv->tt_work);
1989cc47f66eSAntonio Quartulli 
1990cc47f66eSAntonio Quartulli 	tt_local_table_free(bat_priv);
1991cc47f66eSAntonio Quartulli 	tt_global_table_free(bat_priv);
1992cc47f66eSAntonio Quartulli 	tt_req_list_free(bat_priv);
1993cc47f66eSAntonio Quartulli 	tt_changes_list_free(bat_priv);
1994cc47f66eSAntonio Quartulli 	tt_roam_list_free(bat_priv);
1995cc47f66eSAntonio Quartulli 
1996cc47f66eSAntonio Quartulli 	kfree(bat_priv->tt_buff);
1997cc47f66eSAntonio Quartulli }
1998058d0e26SAntonio Quartulli 
1999697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries
2000697f2531SAntonio Quartulli  * in the given hash table and returns the number of modified entries */
2001697f2531SAntonio Quartulli static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags,
2002697f2531SAntonio Quartulli 			     bool enable)
2003058d0e26SAntonio Quartulli {
2004c90681b8SAntonio Quartulli 	uint32_t i;
2005697f2531SAntonio Quartulli 	uint16_t changed_num = 0;
2006058d0e26SAntonio Quartulli 	struct hlist_head *head;
2007058d0e26SAntonio Quartulli 	struct hlist_node *node;
200848100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
2009058d0e26SAntonio Quartulli 
2010058d0e26SAntonio Quartulli 	if (!hash)
2011697f2531SAntonio Quartulli 		goto out;
2012058d0e26SAntonio Quartulli 
2013058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2014058d0e26SAntonio Quartulli 		head = &hash->table[i];
2015058d0e26SAntonio Quartulli 
2016058d0e26SAntonio Quartulli 		rcu_read_lock();
201748100bacSAntonio Quartulli 		hlist_for_each_entry_rcu(tt_common_entry, node,
2018058d0e26SAntonio Quartulli 					 head, hash_entry) {
2019697f2531SAntonio Quartulli 			if (enable) {
2020697f2531SAntonio Quartulli 				if ((tt_common_entry->flags & flags) == flags)
2021697f2531SAntonio Quartulli 					continue;
2022697f2531SAntonio Quartulli 				tt_common_entry->flags |= flags;
2023697f2531SAntonio Quartulli 			} else {
202448100bacSAntonio Quartulli 				if (!(tt_common_entry->flags & flags))
202531901264SAntonio Quartulli 					continue;
202648100bacSAntonio Quartulli 				tt_common_entry->flags &= ~flags;
2027697f2531SAntonio Quartulli 			}
2028697f2531SAntonio Quartulli 			changed_num++;
2029058d0e26SAntonio Quartulli 		}
2030058d0e26SAntonio Quartulli 		rcu_read_unlock();
2031058d0e26SAntonio Quartulli 	}
2032697f2531SAntonio Quartulli out:
2033697f2531SAntonio Quartulli 	return changed_num;
2034058d0e26SAntonio Quartulli }
2035058d0e26SAntonio Quartulli 
2036058d0e26SAntonio Quartulli /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
2037058d0e26SAntonio Quartulli static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
2038058d0e26SAntonio Quartulli {
2039058d0e26SAntonio Quartulli 	struct hashtable_t *hash = bat_priv->tt_local_hash;
204048100bacSAntonio Quartulli 	struct tt_common_entry *tt_common_entry;
2041058d0e26SAntonio Quartulli 	struct tt_local_entry *tt_local_entry;
2042058d0e26SAntonio Quartulli 	struct hlist_node *node, *node_tmp;
2043058d0e26SAntonio Quartulli 	struct hlist_head *head;
2044058d0e26SAntonio Quartulli 	spinlock_t *list_lock; /* protects write access to the hash lists */
2045c90681b8SAntonio Quartulli 	uint32_t i;
2046058d0e26SAntonio Quartulli 
2047058d0e26SAntonio Quartulli 	if (!hash)
2048058d0e26SAntonio Quartulli 		return;
2049058d0e26SAntonio Quartulli 
2050058d0e26SAntonio Quartulli 	for (i = 0; i < hash->size; i++) {
2051058d0e26SAntonio Quartulli 		head = &hash->table[i];
2052058d0e26SAntonio Quartulli 		list_lock = &hash->list_locks[i];
2053058d0e26SAntonio Quartulli 
2054058d0e26SAntonio Quartulli 		spin_lock_bh(list_lock);
205548100bacSAntonio Quartulli 		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
2056058d0e26SAntonio Quartulli 					  head, hash_entry) {
205748100bacSAntonio Quartulli 			if (!(tt_common_entry->flags & TT_CLIENT_PENDING))
2058058d0e26SAntonio Quartulli 				continue;
2059058d0e26SAntonio Quartulli 
206086ceb360SSven Eckelmann 			bat_dbg(DBG_TT, bat_priv,
206186ceb360SSven Eckelmann 				"Deleting local tt entry (%pM): pending\n",
206286ceb360SSven Eckelmann 				tt_common_entry->addr);
2063058d0e26SAntonio Quartulli 
2064058d0e26SAntonio Quartulli 			atomic_dec(&bat_priv->num_local_tt);
2065058d0e26SAntonio Quartulli 			hlist_del_rcu(node);
206648100bacSAntonio Quartulli 			tt_local_entry = container_of(tt_common_entry,
206748100bacSAntonio Quartulli 						      struct tt_local_entry,
206848100bacSAntonio Quartulli 						      common);
2069058d0e26SAntonio Quartulli 			tt_local_entry_free_ref(tt_local_entry);
2070058d0e26SAntonio Quartulli 		}
2071058d0e26SAntonio Quartulli 		spin_unlock_bh(list_lock);
2072058d0e26SAntonio Quartulli 	}
2073058d0e26SAntonio Quartulli 
2074058d0e26SAntonio Quartulli }
2075058d0e26SAntonio Quartulli 
2076be9aa4c1SMarek Lindner static int tt_commit_changes(struct bat_priv *bat_priv,
2077be9aa4c1SMarek Lindner 			     unsigned char **packet_buff, int *packet_buff_len,
2078be9aa4c1SMarek Lindner 			     int packet_min_len)
2079058d0e26SAntonio Quartulli {
2080be9aa4c1SMarek Lindner 	uint16_t changed_num = 0;
2081be9aa4c1SMarek Lindner 
2082be9aa4c1SMarek Lindner 	if (atomic_read(&bat_priv->tt_local_changes) < 1)
2083be9aa4c1SMarek Lindner 		return -ENOENT;
2084be9aa4c1SMarek Lindner 
2085be9aa4c1SMarek Lindner 	changed_num = tt_set_flags(bat_priv->tt_local_hash,
2086697f2531SAntonio Quartulli 				   TT_CLIENT_NEW, false);
2087be9aa4c1SMarek Lindner 
2088be9aa4c1SMarek Lindner 	/* all reset entries have to be counted as local entries */
2089697f2531SAntonio Quartulli 	atomic_add(changed_num, &bat_priv->num_local_tt);
2090058d0e26SAntonio Quartulli 	tt_local_purge_pending_clients(bat_priv);
2091be9aa4c1SMarek Lindner 	bat_priv->tt_crc = batadv_tt_local_crc(bat_priv);
2092058d0e26SAntonio Quartulli 
2093058d0e26SAntonio Quartulli 	/* Increment the TTVN only once per OGM interval */
2094058d0e26SAntonio Quartulli 	atomic_inc(&bat_priv->ttvn);
2095db08e6e5SSimon Wunderlich 	bat_dbg(DBG_TT, bat_priv, "Local changes committed, updating to ttvn %u\n",
2096db08e6e5SSimon Wunderlich 		(uint8_t)atomic_read(&bat_priv->ttvn));
2097058d0e26SAntonio Quartulli 	bat_priv->tt_poss_change = false;
2098be9aa4c1SMarek Lindner 
2099be9aa4c1SMarek Lindner 	/* reset the sending counter */
2100be9aa4c1SMarek Lindner 	atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
2101be9aa4c1SMarek Lindner 
2102be9aa4c1SMarek Lindner 	return tt_changes_fill_buff(bat_priv, packet_buff,
2103be9aa4c1SMarek Lindner 				    packet_buff_len, packet_min_len);
2104be9aa4c1SMarek Lindner }
2105be9aa4c1SMarek Lindner 
2106be9aa4c1SMarek Lindner /* when calling this function (hard_iface == primary_if) has to be true */
2107be9aa4c1SMarek Lindner int batadv_tt_append_diff(struct bat_priv *bat_priv,
2108be9aa4c1SMarek Lindner 			  unsigned char **packet_buff, int *packet_buff_len,
2109be9aa4c1SMarek Lindner 			  int packet_min_len)
2110be9aa4c1SMarek Lindner {
2111be9aa4c1SMarek Lindner 	int tt_num_changes;
2112be9aa4c1SMarek Lindner 
2113be9aa4c1SMarek Lindner 	/* if at least one change happened */
2114be9aa4c1SMarek Lindner 	tt_num_changes = tt_commit_changes(bat_priv, packet_buff,
2115be9aa4c1SMarek Lindner 					   packet_buff_len, packet_min_len);
2116be9aa4c1SMarek Lindner 
2117be9aa4c1SMarek Lindner 	/* if the changes have been sent often enough */
2118be9aa4c1SMarek Lindner 	if ((tt_num_changes < 0) &&
2119be9aa4c1SMarek Lindner 	    (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))) {
2120be9aa4c1SMarek Lindner 		tt_realloc_packet_buff(packet_buff, packet_buff_len,
2121be9aa4c1SMarek Lindner 				       packet_min_len, packet_min_len);
2122be9aa4c1SMarek Lindner 		tt_num_changes = 0;
2123be9aa4c1SMarek Lindner 	}
2124be9aa4c1SMarek Lindner 
2125be9aa4c1SMarek Lindner 	return tt_num_changes;
2126058d0e26SAntonio Quartulli }
212759b699cdSAntonio Quartulli 
212859b699cdSAntonio Quartulli bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
212959b699cdSAntonio Quartulli {
213059b699cdSAntonio Quartulli 	struct tt_local_entry *tt_local_entry = NULL;
213159b699cdSAntonio Quartulli 	struct tt_global_entry *tt_global_entry = NULL;
213259b699cdSAntonio Quartulli 	bool ret = true;
213359b699cdSAntonio Quartulli 
213459b699cdSAntonio Quartulli 	if (!atomic_read(&bat_priv->ap_isolation))
213559b699cdSAntonio Quartulli 		return false;
213659b699cdSAntonio Quartulli 
213759b699cdSAntonio Quartulli 	tt_local_entry = tt_local_hash_find(bat_priv, dst);
213859b699cdSAntonio Quartulli 	if (!tt_local_entry)
213959b699cdSAntonio Quartulli 		goto out;
214059b699cdSAntonio Quartulli 
214159b699cdSAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, src);
214259b699cdSAntonio Quartulli 	if (!tt_global_entry)
214359b699cdSAntonio Quartulli 		goto out;
214459b699cdSAntonio Quartulli 
214559b699cdSAntonio Quartulli 	if (_is_ap_isolated(tt_local_entry, tt_global_entry))
214659b699cdSAntonio Quartulli 		goto out;
214759b699cdSAntonio Quartulli 
214859b699cdSAntonio Quartulli 	ret = false;
214959b699cdSAntonio Quartulli 
215059b699cdSAntonio Quartulli out:
215159b699cdSAntonio Quartulli 	if (tt_global_entry)
215259b699cdSAntonio Quartulli 		tt_global_entry_free_ref(tt_global_entry);
215359b699cdSAntonio Quartulli 	if (tt_local_entry)
215459b699cdSAntonio Quartulli 		tt_local_entry_free_ref(tt_local_entry);
215559b699cdSAntonio Quartulli 	return ret;
215659b699cdSAntonio Quartulli }
2157a943cac1SMarek Lindner 
2158a943cac1SMarek Lindner void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
2159a943cac1SMarek Lindner 		    const unsigned char *tt_buff, uint8_t tt_num_changes,
2160a943cac1SMarek Lindner 		    uint8_t ttvn, uint16_t tt_crc)
2161a943cac1SMarek Lindner {
2162a943cac1SMarek Lindner 	uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
2163a943cac1SMarek Lindner 	bool full_table = true;
2164a943cac1SMarek Lindner 
216520ff9d59SSimon Wunderlich 	/* don't care about a backbone gateways updates. */
216608adf151SSven Eckelmann 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
216720ff9d59SSimon Wunderlich 		return;
216820ff9d59SSimon Wunderlich 
216917071578SAntonio Quartulli 	/* orig table not initialised AND first diff is in the OGM OR the ttvn
217017071578SAntonio Quartulli 	 * increased by one -> we can apply the attached changes */
217117071578SAntonio Quartulli 	if ((!orig_node->tt_initialised && ttvn == 1) ||
217217071578SAntonio Quartulli 	    ttvn - orig_ttvn == 1) {
2173a943cac1SMarek Lindner 		/* the OGM could not contain the changes due to their size or
2174a943cac1SMarek Lindner 		 * because they have already been sent TT_OGM_APPEND_MAX times.
2175a943cac1SMarek Lindner 		 * In this case send a tt request */
2176a943cac1SMarek Lindner 		if (!tt_num_changes) {
2177a943cac1SMarek Lindner 			full_table = false;
2178a943cac1SMarek Lindner 			goto request_table;
2179a943cac1SMarek Lindner 		}
2180a943cac1SMarek Lindner 
2181a943cac1SMarek Lindner 		tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
2182a943cac1SMarek Lindner 				  (struct tt_change *)tt_buff);
2183a943cac1SMarek Lindner 
2184a943cac1SMarek Lindner 		/* Even if we received the precomputed crc with the OGM, we
2185a943cac1SMarek Lindner 		 * prefer to recompute it to spot any possible inconsistency
2186a943cac1SMarek Lindner 		 * in the global table */
2187a943cac1SMarek Lindner 		orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
2188a943cac1SMarek Lindner 
2189a943cac1SMarek Lindner 		/* The ttvn alone is not enough to guarantee consistency
2190a943cac1SMarek Lindner 		 * because a single value could represent different states
2191a943cac1SMarek Lindner 		 * (due to the wrap around). Thus a node has to check whether
2192a943cac1SMarek Lindner 		 * the resulting table (after applying the changes) is still
2193a943cac1SMarek Lindner 		 * consistent or not. E.g. a node could disconnect while its
2194a943cac1SMarek Lindner 		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
2195a943cac1SMarek Lindner 		 * checking the CRC value is mandatory to detect the
2196a943cac1SMarek Lindner 		 * inconsistency */
2197a943cac1SMarek Lindner 		if (orig_node->tt_crc != tt_crc)
2198a943cac1SMarek Lindner 			goto request_table;
2199a943cac1SMarek Lindner 
2200a943cac1SMarek Lindner 		/* Roaming phase is over: tables are in sync again. I can
2201a943cac1SMarek Lindner 		 * unset the flag */
2202a943cac1SMarek Lindner 		orig_node->tt_poss_change = false;
2203a943cac1SMarek Lindner 	} else {
2204a943cac1SMarek Lindner 		/* if we missed more than one change or our tables are not
2205a943cac1SMarek Lindner 		 * in sync anymore -> request fresh tt data */
2206db08e6e5SSimon Wunderlich 
220717071578SAntonio Quartulli 		if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
220817071578SAntonio Quartulli 		    orig_node->tt_crc != tt_crc) {
2209a943cac1SMarek Lindner request_table:
221086ceb360SSven Eckelmann 			bat_dbg(DBG_TT, bat_priv,
221186ceb360SSven Eckelmann 				"TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %u last_crc: %u num_changes: %u)\n",
221286ceb360SSven Eckelmann 				orig_node->orig, ttvn, orig_ttvn, tt_crc,
221386ceb360SSven Eckelmann 				orig_node->tt_crc, tt_num_changes);
2214a943cac1SMarek Lindner 			send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
2215a943cac1SMarek Lindner 					full_table);
2216a943cac1SMarek Lindner 			return;
2217a943cac1SMarek Lindner 		}
2218a943cac1SMarek Lindner 	}
2219a943cac1SMarek Lindner }
22203275e7ccSAntonio Quartulli 
22213275e7ccSAntonio Quartulli /* returns true whether we know that the client has moved from its old
22223275e7ccSAntonio Quartulli  * originator to another one. This entry is kept is still kept for consistency
22233275e7ccSAntonio Quartulli  * purposes
22243275e7ccSAntonio Quartulli  */
22253275e7ccSAntonio Quartulli bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr)
22263275e7ccSAntonio Quartulli {
22273275e7ccSAntonio Quartulli 	struct tt_global_entry *tt_global_entry;
22283275e7ccSAntonio Quartulli 	bool ret = false;
22293275e7ccSAntonio Quartulli 
22303275e7ccSAntonio Quartulli 	tt_global_entry = tt_global_hash_find(bat_priv, addr);
22313275e7ccSAntonio Quartulli 	if (!tt_global_entry)
22323275e7ccSAntonio Quartulli 		goto out;
22333275e7ccSAntonio Quartulli 
22343275e7ccSAntonio Quartulli 	ret = tt_global_entry->common.flags & TT_CLIENT_ROAM;
22353275e7ccSAntonio Quartulli 	tt_global_entry_free_ref(tt_global_entry);
22363275e7ccSAntonio Quartulli out:
22373275e7ccSAntonio Quartulli 	return ret;
22383275e7ccSAntonio Quartulli }
2239