18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (C) 2007-2020  B.A.T.M.A.N. contributors:
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Marek Lindner, Simon Wunderlich, Antonio Quartulli
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "translation-table.h"
88c2ecf20Sopenharmony_ci#include "main.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/atomic.h>
118c2ecf20Sopenharmony_ci#include <linux/bitops.h>
128c2ecf20Sopenharmony_ci#include <linux/build_bug.h>
138c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h>
148c2ecf20Sopenharmony_ci#include <linux/cache.h>
158c2ecf20Sopenharmony_ci#include <linux/compiler.h>
168c2ecf20Sopenharmony_ci#include <linux/crc32c.h>
178c2ecf20Sopenharmony_ci#include <linux/errno.h>
188c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
198c2ecf20Sopenharmony_ci#include <linux/gfp.h>
208c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
218c2ecf20Sopenharmony_ci#include <linux/init.h>
228c2ecf20Sopenharmony_ci#include <linux/jhash.h>
238c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
248c2ecf20Sopenharmony_ci#include <linux/kernel.h>
258c2ecf20Sopenharmony_ci#include <linux/kref.h>
268c2ecf20Sopenharmony_ci#include <linux/list.h>
278c2ecf20Sopenharmony_ci#include <linux/lockdep.h>
288c2ecf20Sopenharmony_ci#include <linux/net.h>
298c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
308c2ecf20Sopenharmony_ci#include <linux/netlink.h>
318c2ecf20Sopenharmony_ci#include <linux/rculist.h>
328c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
338c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
348c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
358c2ecf20Sopenharmony_ci#include <linux/slab.h>
368c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
378c2ecf20Sopenharmony_ci#include <linux/stddef.h>
388c2ecf20Sopenharmony_ci#include <linux/string.h>
398c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
408c2ecf20Sopenharmony_ci#include <net/genetlink.h>
418c2ecf20Sopenharmony_ci#include <net/netlink.h>
428c2ecf20Sopenharmony_ci#include <net/sock.h>
438c2ecf20Sopenharmony_ci#include <uapi/linux/batadv_packet.h>
448c2ecf20Sopenharmony_ci#include <uapi/linux/batman_adv.h>
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#include "bridge_loop_avoidance.h"
478c2ecf20Sopenharmony_ci#include "hard-interface.h"
488c2ecf20Sopenharmony_ci#include "hash.h"
498c2ecf20Sopenharmony_ci#include "log.h"
508c2ecf20Sopenharmony_ci#include "netlink.h"
518c2ecf20Sopenharmony_ci#include "originator.h"
528c2ecf20Sopenharmony_ci#include "soft-interface.h"
538c2ecf20Sopenharmony_ci#include "tvlv.h"
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic struct kmem_cache *batadv_tl_cache __read_mostly;
568c2ecf20Sopenharmony_cistatic struct kmem_cache *batadv_tg_cache __read_mostly;
578c2ecf20Sopenharmony_cistatic struct kmem_cache *batadv_tt_orig_cache __read_mostly;
588c2ecf20Sopenharmony_cistatic struct kmem_cache *batadv_tt_change_cache __read_mostly;
598c2ecf20Sopenharmony_cistatic struct kmem_cache *batadv_tt_req_cache __read_mostly;
608c2ecf20Sopenharmony_cistatic struct kmem_cache *batadv_tt_roam_cache __read_mostly;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* hash class keys */
638c2ecf20Sopenharmony_cistatic struct lock_class_key batadv_tt_local_hash_lock_class_key;
648c2ecf20Sopenharmony_cistatic struct lock_class_key batadv_tt_global_hash_lock_class_key;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
678c2ecf20Sopenharmony_ci				 unsigned short vid,
688c2ecf20Sopenharmony_ci				 struct batadv_orig_node *orig_node);
698c2ecf20Sopenharmony_cistatic void batadv_tt_purge(struct work_struct *work);
708c2ecf20Sopenharmony_cistatic void
718c2ecf20Sopenharmony_cibatadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
728c2ecf20Sopenharmony_cistatic void batadv_tt_global_del(struct batadv_priv *bat_priv,
738c2ecf20Sopenharmony_ci				 struct batadv_orig_node *orig_node,
748c2ecf20Sopenharmony_ci				 const unsigned char *addr,
758c2ecf20Sopenharmony_ci				 unsigned short vid, const char *message,
768c2ecf20Sopenharmony_ci				 bool roaming);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/**
798c2ecf20Sopenharmony_ci * batadv_compare_tt() - check if two TT entries are the same
808c2ecf20Sopenharmony_ci * @node: the list element pointer of the first TT entry
818c2ecf20Sopenharmony_ci * @data2: pointer to the tt_common_entry of the second TT entry
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * Compare the MAC address and the VLAN ID of the two TT entries and check if
848c2ecf20Sopenharmony_ci * they are the same TT client.
858c2ecf20Sopenharmony_ci * Return: true if the two TT clients are the same, false otherwise
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistatic bool batadv_compare_tt(const struct hlist_node *node, const void *data2)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	const void *data1 = container_of(node, struct batadv_tt_common_entry,
908c2ecf20Sopenharmony_ci					 hash_entry);
918c2ecf20Sopenharmony_ci	const struct batadv_tt_common_entry *tt1 = data1;
928c2ecf20Sopenharmony_ci	const struct batadv_tt_common_entry *tt2 = data2;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/**
988c2ecf20Sopenharmony_ci * batadv_choose_tt() - return the index of the tt entry in the hash table
998c2ecf20Sopenharmony_ci * @data: pointer to the tt_common_entry object to map
1008c2ecf20Sopenharmony_ci * @size: the size of the hash table
1018c2ecf20Sopenharmony_ci *
1028c2ecf20Sopenharmony_ci * Return: the hash index where the object represented by 'data' should be
1038c2ecf20Sopenharmony_ci * stored at.
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_cistatic inline u32 batadv_choose_tt(const void *data, u32 size)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt;
1088c2ecf20Sopenharmony_ci	u32 hash = 0;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	tt = (struct batadv_tt_common_entry *)data;
1118c2ecf20Sopenharmony_ci	hash = jhash(&tt->addr, ETH_ALEN, hash);
1128c2ecf20Sopenharmony_ci	hash = jhash(&tt->vid, sizeof(tt->vid), hash);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return hash % size;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/**
1188c2ecf20Sopenharmony_ci * batadv_tt_hash_find() - look for a client in the given hash table
1198c2ecf20Sopenharmony_ci * @hash: the hash table to search
1208c2ecf20Sopenharmony_ci * @addr: the mac address of the client to look for
1218c2ecf20Sopenharmony_ci * @vid: VLAN identifier
1228c2ecf20Sopenharmony_ci *
1238c2ecf20Sopenharmony_ci * Return: a pointer to the tt_common struct belonging to the searched client if
1248c2ecf20Sopenharmony_ci * found, NULL otherwise.
1258c2ecf20Sopenharmony_ci */
1268c2ecf20Sopenharmony_cistatic struct batadv_tt_common_entry *
1278c2ecf20Sopenharmony_cibatadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr,
1288c2ecf20Sopenharmony_ci		    unsigned short vid)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct hlist_head *head;
1318c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL;
1328c2ecf20Sopenharmony_ci	u32 index;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (!hash)
1358c2ecf20Sopenharmony_ci		return NULL;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	ether_addr_copy(to_search.addr, addr);
1388c2ecf20Sopenharmony_ci	to_search.vid = vid;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	index = batadv_choose_tt(&to_search, hash->size);
1418c2ecf20Sopenharmony_ci	head = &hash->table[index];
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	rcu_read_lock();
1448c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tt, head, hash_entry) {
1458c2ecf20Sopenharmony_ci		if (!batadv_compare_eth(tt, addr))
1468c2ecf20Sopenharmony_ci			continue;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci		if (tt->vid != vid)
1498c2ecf20Sopenharmony_ci			continue;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&tt->refcount))
1528c2ecf20Sopenharmony_ci			continue;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		tt_tmp = tt;
1558c2ecf20Sopenharmony_ci		break;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci	rcu_read_unlock();
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	return tt_tmp;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci/**
1638c2ecf20Sopenharmony_ci * batadv_tt_local_hash_find() - search the local table for a given client
1648c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
1658c2ecf20Sopenharmony_ci * @addr: the mac address of the client to look for
1668c2ecf20Sopenharmony_ci * @vid: VLAN identifier
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci * Return: a pointer to the corresponding tt_local_entry struct if the client is
1698c2ecf20Sopenharmony_ci * found, NULL otherwise.
1708c2ecf20Sopenharmony_ci */
1718c2ecf20Sopenharmony_cistatic struct batadv_tt_local_entry *
1728c2ecf20Sopenharmony_cibatadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
1738c2ecf20Sopenharmony_ci			  unsigned short vid)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
1768c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry = NULL;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr,
1798c2ecf20Sopenharmony_ci					      vid);
1808c2ecf20Sopenharmony_ci	if (tt_common_entry)
1818c2ecf20Sopenharmony_ci		tt_local_entry = container_of(tt_common_entry,
1828c2ecf20Sopenharmony_ci					      struct batadv_tt_local_entry,
1838c2ecf20Sopenharmony_ci					      common);
1848c2ecf20Sopenharmony_ci	return tt_local_entry;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci/**
1888c2ecf20Sopenharmony_ci * batadv_tt_global_hash_find() - search the global table for a given client
1898c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
1908c2ecf20Sopenharmony_ci * @addr: the mac address of the client to look for
1918c2ecf20Sopenharmony_ci * @vid: VLAN identifier
1928c2ecf20Sopenharmony_ci *
1938c2ecf20Sopenharmony_ci * Return: a pointer to the corresponding tt_global_entry struct if the client
1948c2ecf20Sopenharmony_ci * is found, NULL otherwise.
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_cistruct batadv_tt_global_entry *
1978c2ecf20Sopenharmony_cibatadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
1988c2ecf20Sopenharmony_ci			   unsigned short vid)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
2018c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry = NULL;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr,
2048c2ecf20Sopenharmony_ci					      vid);
2058c2ecf20Sopenharmony_ci	if (tt_common_entry)
2068c2ecf20Sopenharmony_ci		tt_global_entry = container_of(tt_common_entry,
2078c2ecf20Sopenharmony_ci					       struct batadv_tt_global_entry,
2088c2ecf20Sopenharmony_ci					       common);
2098c2ecf20Sopenharmony_ci	return tt_global_entry;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/**
2138c2ecf20Sopenharmony_ci * batadv_tt_local_entry_free_rcu() - free the tt_local_entry
2148c2ecf20Sopenharmony_ci * @rcu: rcu pointer of the tt_local_entry
2158c2ecf20Sopenharmony_ci */
2168c2ecf20Sopenharmony_cistatic void batadv_tt_local_entry_free_rcu(struct rcu_head *rcu)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	tt_local_entry = container_of(rcu, struct batadv_tt_local_entry,
2218c2ecf20Sopenharmony_ci				      common.rcu);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	kmem_cache_free(batadv_tl_cache, tt_local_entry);
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci/**
2278c2ecf20Sopenharmony_ci * batadv_tt_local_entry_release() - release tt_local_entry from lists and queue
2288c2ecf20Sopenharmony_ci *  for free after rcu grace period
2298c2ecf20Sopenharmony_ci * @ref: kref pointer of the nc_node
2308c2ecf20Sopenharmony_ci */
2318c2ecf20Sopenharmony_cistatic void batadv_tt_local_entry_release(struct kref *ref)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	tt_local_entry = container_of(ref, struct batadv_tt_local_entry,
2368c2ecf20Sopenharmony_ci				      common.refcount);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	batadv_softif_vlan_put(tt_local_entry->vlan);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	call_rcu(&tt_local_entry->common.rcu, batadv_tt_local_entry_free_rcu);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/**
2448c2ecf20Sopenharmony_ci * batadv_tt_local_entry_put() - decrement the tt_local_entry refcounter and
2458c2ecf20Sopenharmony_ci *  possibly release it
2468c2ecf20Sopenharmony_ci * @tt_local_entry: tt_local_entry to be free'd
2478c2ecf20Sopenharmony_ci */
2488c2ecf20Sopenharmony_cistatic void
2498c2ecf20Sopenharmony_cibatadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	if (!tt_local_entry)
2528c2ecf20Sopenharmony_ci		return;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	kref_put(&tt_local_entry->common.refcount,
2558c2ecf20Sopenharmony_ci		 batadv_tt_local_entry_release);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/**
2598c2ecf20Sopenharmony_ci * batadv_tt_global_entry_free_rcu() - free the tt_global_entry
2608c2ecf20Sopenharmony_ci * @rcu: rcu pointer of the tt_global_entry
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_cistatic void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	tt_global_entry = container_of(rcu, struct batadv_tt_global_entry,
2678c2ecf20Sopenharmony_ci				       common.rcu);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	kmem_cache_free(batadv_tg_cache, tt_global_entry);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci/**
2738c2ecf20Sopenharmony_ci * batadv_tt_global_entry_release() - release tt_global_entry from lists and
2748c2ecf20Sopenharmony_ci *  queue for free after rcu grace period
2758c2ecf20Sopenharmony_ci * @ref: kref pointer of the nc_node
2768c2ecf20Sopenharmony_ci */
2778c2ecf20Sopenharmony_civoid batadv_tt_global_entry_release(struct kref *ref)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	tt_global_entry = container_of(ref, struct batadv_tt_global_entry,
2828c2ecf20Sopenharmony_ci				       common.refcount);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	batadv_tt_global_del_orig_list(tt_global_entry);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	call_rcu(&tt_global_entry->common.rcu, batadv_tt_global_entry_free_rcu);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/**
2908c2ecf20Sopenharmony_ci * batadv_tt_global_hash_count() - count the number of orig entries
2918c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
2928c2ecf20Sopenharmony_ci * @addr: the mac address of the client to count entries for
2938c2ecf20Sopenharmony_ci * @vid: VLAN identifier
2948c2ecf20Sopenharmony_ci *
2958c2ecf20Sopenharmony_ci * Return: the number of originators advertising the given address/data
2968c2ecf20Sopenharmony_ci * (excluding our self).
2978c2ecf20Sopenharmony_ci */
2988c2ecf20Sopenharmony_ciint batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
2998c2ecf20Sopenharmony_ci				const u8 *addr, unsigned short vid)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry;
3028c2ecf20Sopenharmony_ci	int count;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
3058c2ecf20Sopenharmony_ci	if (!tt_global_entry)
3068c2ecf20Sopenharmony_ci		return 0;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	count = atomic_read(&tt_global_entry->orig_list_count);
3098c2ecf20Sopenharmony_ci	batadv_tt_global_entry_put(tt_global_entry);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return count;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci/**
3158c2ecf20Sopenharmony_ci * batadv_tt_local_size_mod() - change the size by v of the local table
3168c2ecf20Sopenharmony_ci *  identified by vid
3178c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
3188c2ecf20Sopenharmony_ci * @vid: the VLAN identifier of the sub-table to change
3198c2ecf20Sopenharmony_ci * @v: the amount to sum to the local table size
3208c2ecf20Sopenharmony_ci */
3218c2ecf20Sopenharmony_cistatic void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
3228c2ecf20Sopenharmony_ci				     unsigned short vid, int v)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct batadv_softif_vlan *vlan;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	vlan = batadv_softif_vlan_get(bat_priv, vid);
3278c2ecf20Sopenharmony_ci	if (!vlan)
3288c2ecf20Sopenharmony_ci		return;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	atomic_add(v, &vlan->tt.num_entries);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	batadv_softif_vlan_put(vlan);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci/**
3368c2ecf20Sopenharmony_ci * batadv_tt_local_size_inc() - increase by one the local table size for the
3378c2ecf20Sopenharmony_ci *  given vid
3388c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
3398c2ecf20Sopenharmony_ci * @vid: the VLAN identifier
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_cistatic void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
3428c2ecf20Sopenharmony_ci				     unsigned short vid)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	batadv_tt_local_size_mod(bat_priv, vid, 1);
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci/**
3488c2ecf20Sopenharmony_ci * batadv_tt_local_size_dec() - decrease by one the local table size for the
3498c2ecf20Sopenharmony_ci *  given vid
3508c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
3518c2ecf20Sopenharmony_ci * @vid: the VLAN identifier
3528c2ecf20Sopenharmony_ci */
3538c2ecf20Sopenharmony_cistatic void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
3548c2ecf20Sopenharmony_ci				     unsigned short vid)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	batadv_tt_local_size_mod(bat_priv, vid, -1);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/**
3608c2ecf20Sopenharmony_ci * batadv_tt_global_size_mod() - change the size by v of the global table
3618c2ecf20Sopenharmony_ci *  for orig_node identified by vid
3628c2ecf20Sopenharmony_ci * @orig_node: the originator for which the table has to be modified
3638c2ecf20Sopenharmony_ci * @vid: the VLAN identifier
3648c2ecf20Sopenharmony_ci * @v: the amount to sum to the global table size
3658c2ecf20Sopenharmony_ci */
3668c2ecf20Sopenharmony_cistatic void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node,
3678c2ecf20Sopenharmony_ci				      unsigned short vid, int v)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct batadv_orig_node_vlan *vlan;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	vlan = batadv_orig_node_vlan_new(orig_node, vid);
3728c2ecf20Sopenharmony_ci	if (!vlan)
3738c2ecf20Sopenharmony_ci		return;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (atomic_add_return(v, &vlan->tt.num_entries) == 0) {
3768c2ecf20Sopenharmony_ci		spin_lock_bh(&orig_node->vlan_list_lock);
3778c2ecf20Sopenharmony_ci		if (!hlist_unhashed(&vlan->list)) {
3788c2ecf20Sopenharmony_ci			hlist_del_init_rcu(&vlan->list);
3798c2ecf20Sopenharmony_ci			batadv_orig_node_vlan_put(vlan);
3808c2ecf20Sopenharmony_ci		}
3818c2ecf20Sopenharmony_ci		spin_unlock_bh(&orig_node->vlan_list_lock);
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	batadv_orig_node_vlan_put(vlan);
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci/**
3888c2ecf20Sopenharmony_ci * batadv_tt_global_size_inc() - increase by one the global table size for the
3898c2ecf20Sopenharmony_ci *  given vid
3908c2ecf20Sopenharmony_ci * @orig_node: the originator which global table size has to be decreased
3918c2ecf20Sopenharmony_ci * @vid: the vlan identifier
3928c2ecf20Sopenharmony_ci */
3938c2ecf20Sopenharmony_cistatic void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node,
3948c2ecf20Sopenharmony_ci				      unsigned short vid)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	batadv_tt_global_size_mod(orig_node, vid, 1);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci/**
4008c2ecf20Sopenharmony_ci * batadv_tt_global_size_dec() - decrease by one the global table size for the
4018c2ecf20Sopenharmony_ci *  given vid
4028c2ecf20Sopenharmony_ci * @orig_node: the originator which global table size has to be decreased
4038c2ecf20Sopenharmony_ci * @vid: the vlan identifier
4048c2ecf20Sopenharmony_ci */
4058c2ecf20Sopenharmony_cistatic void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node,
4068c2ecf20Sopenharmony_ci				      unsigned short vid)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	batadv_tt_global_size_mod(orig_node, vid, -1);
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci/**
4128c2ecf20Sopenharmony_ci * batadv_tt_orig_list_entry_free_rcu() - free the orig_entry
4138c2ecf20Sopenharmony_ci * @rcu: rcu pointer of the orig_entry
4148c2ecf20Sopenharmony_ci */
4158c2ecf20Sopenharmony_cistatic void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	kmem_cache_free(batadv_tt_orig_cache, orig_entry);
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci/**
4258c2ecf20Sopenharmony_ci * batadv_tt_orig_list_entry_release() - release tt orig entry from lists and
4268c2ecf20Sopenharmony_ci *  queue for free after rcu grace period
4278c2ecf20Sopenharmony_ci * @ref: kref pointer of the tt orig entry
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_cistatic void batadv_tt_orig_list_entry_release(struct kref *ref)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	orig_entry = container_of(ref, struct batadv_tt_orig_list_entry,
4348c2ecf20Sopenharmony_ci				  refcount);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	batadv_orig_node_put(orig_entry->orig_node);
4378c2ecf20Sopenharmony_ci	call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci/**
4418c2ecf20Sopenharmony_ci * batadv_tt_orig_list_entry_put() - decrement the tt orig entry refcounter and
4428c2ecf20Sopenharmony_ci *  possibly release it
4438c2ecf20Sopenharmony_ci * @orig_entry: tt orig entry to be free'd
4448c2ecf20Sopenharmony_ci */
4458c2ecf20Sopenharmony_cistatic void
4468c2ecf20Sopenharmony_cibatadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	if (!orig_entry)
4498c2ecf20Sopenharmony_ci		return;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release);
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci/**
4558c2ecf20Sopenharmony_ci * batadv_tt_local_event() - store a local TT event (ADD/DEL)
4568c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
4578c2ecf20Sopenharmony_ci * @tt_local_entry: the TT entry involved in the event
4588c2ecf20Sopenharmony_ci * @event_flags: flags to store in the event structure
4598c2ecf20Sopenharmony_ci */
4608c2ecf20Sopenharmony_cistatic void batadv_tt_local_event(struct batadv_priv *bat_priv,
4618c2ecf20Sopenharmony_ci				  struct batadv_tt_local_entry *tt_local_entry,
4628c2ecf20Sopenharmony_ci				  u8 event_flags)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	struct batadv_tt_change_node *tt_change_node, *entry, *safe;
4658c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *common = &tt_local_entry->common;
4668c2ecf20Sopenharmony_ci	u8 flags = common->flags | event_flags;
4678c2ecf20Sopenharmony_ci	bool event_removed = false;
4688c2ecf20Sopenharmony_ci	bool del_op_requested, del_op_entry;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC);
4718c2ecf20Sopenharmony_ci	if (!tt_change_node)
4728c2ecf20Sopenharmony_ci		return;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	tt_change_node->change.flags = flags;
4758c2ecf20Sopenharmony_ci	memset(tt_change_node->change.reserved, 0,
4768c2ecf20Sopenharmony_ci	       sizeof(tt_change_node->change.reserved));
4778c2ecf20Sopenharmony_ci	ether_addr_copy(tt_change_node->change.addr, common->addr);
4788c2ecf20Sopenharmony_ci	tt_change_node->change.vid = htons(common->vid);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	del_op_requested = flags & BATADV_TT_CLIENT_DEL;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	/* check for ADD+DEL or DEL+ADD events */
4838c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.changes_list_lock);
4848c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
4858c2ecf20Sopenharmony_ci				 list) {
4868c2ecf20Sopenharmony_ci		if (!batadv_compare_eth(entry->change.addr, common->addr))
4878c2ecf20Sopenharmony_ci			continue;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci		/* DEL+ADD in the same orig interval have no effect and can be
4908c2ecf20Sopenharmony_ci		 * removed to avoid silly behaviour on the receiver side. The
4918c2ecf20Sopenharmony_ci		 * other way around (ADD+DEL) can happen in case of roaming of
4928c2ecf20Sopenharmony_ci		 * a client still in the NEW state. Roaming of NEW clients is
4938c2ecf20Sopenharmony_ci		 * now possible due to automatically recognition of "temporary"
4948c2ecf20Sopenharmony_ci		 * clients
4958c2ecf20Sopenharmony_ci		 */
4968c2ecf20Sopenharmony_ci		del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
4978c2ecf20Sopenharmony_ci		if (!del_op_requested && del_op_entry)
4988c2ecf20Sopenharmony_ci			goto del;
4998c2ecf20Sopenharmony_ci		if (del_op_requested && !del_op_entry)
5008c2ecf20Sopenharmony_ci			goto del;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci		/* this is a second add in the same originator interval. It
5038c2ecf20Sopenharmony_ci		 * means that flags have been changed: update them!
5048c2ecf20Sopenharmony_ci		 */
5058c2ecf20Sopenharmony_ci		if (!del_op_requested && !del_op_entry)
5068c2ecf20Sopenharmony_ci			entry->change.flags = flags;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		continue;
5098c2ecf20Sopenharmony_cidel:
5108c2ecf20Sopenharmony_ci		list_del(&entry->list);
5118c2ecf20Sopenharmony_ci		kmem_cache_free(batadv_tt_change_cache, entry);
5128c2ecf20Sopenharmony_ci		kmem_cache_free(batadv_tt_change_cache, tt_change_node);
5138c2ecf20Sopenharmony_ci		event_removed = true;
5148c2ecf20Sopenharmony_ci		goto unlock;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* track the change in the OGMinterval list */
5188c2ecf20Sopenharmony_ci	list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ciunlock:
5218c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (event_removed)
5248c2ecf20Sopenharmony_ci		atomic_dec(&bat_priv->tt.local_changes);
5258c2ecf20Sopenharmony_ci	else
5268c2ecf20Sopenharmony_ci		atomic_inc(&bat_priv->tt.local_changes);
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci/**
5308c2ecf20Sopenharmony_ci * batadv_tt_len() - compute length in bytes of given number of tt changes
5318c2ecf20Sopenharmony_ci * @changes_num: number of tt changes
5328c2ecf20Sopenharmony_ci *
5338c2ecf20Sopenharmony_ci * Return: computed length in bytes.
5348c2ecf20Sopenharmony_ci */
5358c2ecf20Sopenharmony_cistatic int batadv_tt_len(int changes_num)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	return changes_num * sizeof(struct batadv_tvlv_tt_change);
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/**
5418c2ecf20Sopenharmony_ci * batadv_tt_entries() - compute the number of entries fitting in tt_len bytes
5428c2ecf20Sopenharmony_ci * @tt_len: available space
5438c2ecf20Sopenharmony_ci *
5448c2ecf20Sopenharmony_ci * Return: the number of entries.
5458c2ecf20Sopenharmony_ci */
5468c2ecf20Sopenharmony_cistatic u16 batadv_tt_entries(u16 tt_len)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	return tt_len / batadv_tt_len(1);
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci/**
5528c2ecf20Sopenharmony_ci * batadv_tt_local_table_transmit_size() - calculates the local translation
5538c2ecf20Sopenharmony_ci *  table size when transmitted over the air
5548c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
5558c2ecf20Sopenharmony_ci *
5568c2ecf20Sopenharmony_ci * Return: local translation table size in bytes.
5578c2ecf20Sopenharmony_ci */
5588c2ecf20Sopenharmony_cistatic int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	u16 num_vlan = 0;
5618c2ecf20Sopenharmony_ci	u16 tt_local_entries = 0;
5628c2ecf20Sopenharmony_ci	struct batadv_softif_vlan *vlan;
5638c2ecf20Sopenharmony_ci	int hdr_size;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	rcu_read_lock();
5668c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
5678c2ecf20Sopenharmony_ci		num_vlan++;
5688c2ecf20Sopenharmony_ci		tt_local_entries += atomic_read(&vlan->tt.num_entries);
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci	rcu_read_unlock();
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/* header size of tvlv encapsulated tt response payload */
5738c2ecf20Sopenharmony_ci	hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
5748c2ecf20Sopenharmony_ci	hdr_size += sizeof(struct batadv_tvlv_hdr);
5758c2ecf20Sopenharmony_ci	hdr_size += sizeof(struct batadv_tvlv_tt_data);
5768c2ecf20Sopenharmony_ci	hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	return hdr_size + batadv_tt_len(tt_local_entries);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic int batadv_tt_local_init(struct batadv_priv *bat_priv)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	if (bat_priv->tt.local_hash)
5848c2ecf20Sopenharmony_ci		return 0;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	bat_priv->tt.local_hash = batadv_hash_new(1024);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (!bat_priv->tt.local_hash)
5898c2ecf20Sopenharmony_ci		return -ENOMEM;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	batadv_hash_set_lock_class(bat_priv->tt.local_hash,
5928c2ecf20Sopenharmony_ci				   &batadv_tt_local_hash_lock_class_key);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	return 0;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic void batadv_tt_global_free(struct batadv_priv *bat_priv,
5988c2ecf20Sopenharmony_ci				  struct batadv_tt_global_entry *tt_global,
5998c2ecf20Sopenharmony_ci				  const char *message)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_removed_entry;
6028c2ecf20Sopenharmony_ci	struct hlist_node *tt_removed_node;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
6058c2ecf20Sopenharmony_ci		   "Deleting global tt entry %pM (vid: %d): %s\n",
6068c2ecf20Sopenharmony_ci		   tt_global->common.addr,
6078c2ecf20Sopenharmony_ci		   batadv_print_vid(tt_global->common.vid), message);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	tt_removed_node = batadv_hash_remove(bat_priv->tt.global_hash,
6108c2ecf20Sopenharmony_ci					     batadv_compare_tt,
6118c2ecf20Sopenharmony_ci					     batadv_choose_tt,
6128c2ecf20Sopenharmony_ci					     &tt_global->common);
6138c2ecf20Sopenharmony_ci	if (!tt_removed_node)
6148c2ecf20Sopenharmony_ci		return;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	/* drop reference of remove hash entry */
6178c2ecf20Sopenharmony_ci	tt_removed_entry = hlist_entry(tt_removed_node,
6188c2ecf20Sopenharmony_ci				       struct batadv_tt_global_entry,
6198c2ecf20Sopenharmony_ci				       common.hash_entry);
6208c2ecf20Sopenharmony_ci	batadv_tt_global_entry_put(tt_removed_entry);
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci/**
6248c2ecf20Sopenharmony_ci * batadv_tt_local_add() - add a new client to the local table or update an
6258c2ecf20Sopenharmony_ci *  existing client
6268c2ecf20Sopenharmony_ci * @soft_iface: netdev struct of the mesh interface
6278c2ecf20Sopenharmony_ci * @addr: the mac address of the client to add
6288c2ecf20Sopenharmony_ci * @vid: VLAN identifier
6298c2ecf20Sopenharmony_ci * @ifindex: index of the interface where the client is connected to (useful to
6308c2ecf20Sopenharmony_ci *  identify wireless clients)
6318c2ecf20Sopenharmony_ci * @mark: the value contained in the skb->mark field of the received packet (if
6328c2ecf20Sopenharmony_ci *  any)
6338c2ecf20Sopenharmony_ci *
6348c2ecf20Sopenharmony_ci * Return: true if the client was successfully added, false otherwise.
6358c2ecf20Sopenharmony_ci */
6368c2ecf20Sopenharmony_cibool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
6378c2ecf20Sopenharmony_ci			 unsigned short vid, int ifindex, u32 mark)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
6408c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local;
6418c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global = NULL;
6428c2ecf20Sopenharmony_ci	struct net *net = dev_net(soft_iface);
6438c2ecf20Sopenharmony_ci	struct batadv_softif_vlan *vlan;
6448c2ecf20Sopenharmony_ci	struct net_device *in_dev = NULL;
6458c2ecf20Sopenharmony_ci	struct batadv_hard_iface *in_hardif = NULL;
6468c2ecf20Sopenharmony_ci	struct hlist_head *head;
6478c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
6488c2ecf20Sopenharmony_ci	int hash_added, table_size, packet_size_max;
6498c2ecf20Sopenharmony_ci	bool ret = false;
6508c2ecf20Sopenharmony_ci	bool roamed_back = false;
6518c2ecf20Sopenharmony_ci	u8 remote_flags;
6528c2ecf20Sopenharmony_ci	u32 match_mark;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	if (ifindex != BATADV_NULL_IFINDEX)
6558c2ecf20Sopenharmony_ci		in_dev = dev_get_by_index(net, ifindex);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (in_dev)
6588c2ecf20Sopenharmony_ci		in_hardif = batadv_hardif_get_by_netdev(in_dev);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	if (!is_multicast_ether_addr(addr))
6638c2ecf20Sopenharmony_ci		tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	if (tt_local) {
6668c2ecf20Sopenharmony_ci		tt_local->last_seen = jiffies;
6678c2ecf20Sopenharmony_ci		if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
6688c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_TT, bat_priv,
6698c2ecf20Sopenharmony_ci				   "Re-adding pending client %pM (vid: %d)\n",
6708c2ecf20Sopenharmony_ci				   addr, batadv_print_vid(vid));
6718c2ecf20Sopenharmony_ci			/* whatever the reason why the PENDING flag was set,
6728c2ecf20Sopenharmony_ci			 * this is a client which was enqueued to be removed in
6738c2ecf20Sopenharmony_ci			 * this orig_interval. Since it popped up again, the
6748c2ecf20Sopenharmony_ci			 * flag can be reset like it was never enqueued
6758c2ecf20Sopenharmony_ci			 */
6768c2ecf20Sopenharmony_ci			tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
6778c2ecf20Sopenharmony_ci			goto add_event;
6788c2ecf20Sopenharmony_ci		}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
6818c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_TT, bat_priv,
6828c2ecf20Sopenharmony_ci				   "Roaming client %pM (vid: %d) came back to its original location\n",
6838c2ecf20Sopenharmony_ci				   addr, batadv_print_vid(vid));
6848c2ecf20Sopenharmony_ci			/* the ROAM flag is set because this client roamed away
6858c2ecf20Sopenharmony_ci			 * and the node got a roaming_advertisement message. Now
6868c2ecf20Sopenharmony_ci			 * that the client popped up again at its original
6878c2ecf20Sopenharmony_ci			 * location such flag can be unset
6888c2ecf20Sopenharmony_ci			 */
6898c2ecf20Sopenharmony_ci			tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
6908c2ecf20Sopenharmony_ci			roamed_back = true;
6918c2ecf20Sopenharmony_ci		}
6928c2ecf20Sopenharmony_ci		goto check_roaming;
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	/* Ignore the client if we cannot send it in a full table response. */
6968c2ecf20Sopenharmony_ci	table_size = batadv_tt_local_table_transmit_size(bat_priv);
6978c2ecf20Sopenharmony_ci	table_size += batadv_tt_len(1);
6988c2ecf20Sopenharmony_ci	packet_size_max = atomic_read(&bat_priv->packet_size_max);
6998c2ecf20Sopenharmony_ci	if (table_size > packet_size_max) {
7008c2ecf20Sopenharmony_ci		net_ratelimited_function(batadv_info, soft_iface,
7018c2ecf20Sopenharmony_ci					 "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
7028c2ecf20Sopenharmony_ci					 table_size, packet_size_max, addr);
7038c2ecf20Sopenharmony_ci		goto out;
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	tt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);
7078c2ecf20Sopenharmony_ci	if (!tt_local)
7088c2ecf20Sopenharmony_ci		goto out;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	/* increase the refcounter of the related vlan */
7118c2ecf20Sopenharmony_ci	vlan = batadv_softif_vlan_get(bat_priv, vid);
7128c2ecf20Sopenharmony_ci	if (!vlan) {
7138c2ecf20Sopenharmony_ci		net_ratelimited_function(batadv_info, soft_iface,
7148c2ecf20Sopenharmony_ci					 "adding TT local entry %pM to non-existent VLAN %d\n",
7158c2ecf20Sopenharmony_ci					 addr, batadv_print_vid(vid));
7168c2ecf20Sopenharmony_ci		kmem_cache_free(batadv_tl_cache, tt_local);
7178c2ecf20Sopenharmony_ci		tt_local = NULL;
7188c2ecf20Sopenharmony_ci		goto out;
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
7228c2ecf20Sopenharmony_ci		   "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
7238c2ecf20Sopenharmony_ci		   addr, batadv_print_vid(vid),
7248c2ecf20Sopenharmony_ci		   (u8)atomic_read(&bat_priv->tt.vn));
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	ether_addr_copy(tt_local->common.addr, addr);
7278c2ecf20Sopenharmony_ci	/* The local entry has to be marked as NEW to avoid to send it in
7288c2ecf20Sopenharmony_ci	 * a full table response going out before the next ttvn increment
7298c2ecf20Sopenharmony_ci	 * (consistency check)
7308c2ecf20Sopenharmony_ci	 */
7318c2ecf20Sopenharmony_ci	tt_local->common.flags = BATADV_TT_CLIENT_NEW;
7328c2ecf20Sopenharmony_ci	tt_local->common.vid = vid;
7338c2ecf20Sopenharmony_ci	if (batadv_is_wifi_hardif(in_hardif))
7348c2ecf20Sopenharmony_ci		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
7358c2ecf20Sopenharmony_ci	kref_init(&tt_local->common.refcount);
7368c2ecf20Sopenharmony_ci	tt_local->last_seen = jiffies;
7378c2ecf20Sopenharmony_ci	tt_local->common.added_at = tt_local->last_seen;
7388c2ecf20Sopenharmony_ci	tt_local->vlan = vlan;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	/* the batman interface mac and multicast addresses should never be
7418c2ecf20Sopenharmony_ci	 * purged
7428c2ecf20Sopenharmony_ci	 */
7438c2ecf20Sopenharmony_ci	if (batadv_compare_eth(addr, soft_iface->dev_addr) ||
7448c2ecf20Sopenharmony_ci	    is_multicast_ether_addr(addr))
7458c2ecf20Sopenharmony_ci		tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	kref_get(&tt_local->common.refcount);
7488c2ecf20Sopenharmony_ci	hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
7498c2ecf20Sopenharmony_ci				     batadv_choose_tt, &tt_local->common,
7508c2ecf20Sopenharmony_ci				     &tt_local->common.hash_entry);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	if (unlikely(hash_added != 0)) {
7538c2ecf20Sopenharmony_ci		/* remove the reference for the hash */
7548c2ecf20Sopenharmony_ci		batadv_tt_local_entry_put(tt_local);
7558c2ecf20Sopenharmony_ci		goto out;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ciadd_event:
7598c2ecf20Sopenharmony_ci	batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cicheck_roaming:
7628c2ecf20Sopenharmony_ci	/* Check whether it is a roaming, but don't do anything if the roaming
7638c2ecf20Sopenharmony_ci	 * process has already been handled
7648c2ecf20Sopenharmony_ci	 */
7658c2ecf20Sopenharmony_ci	if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
7668c2ecf20Sopenharmony_ci		/* These node are probably going to update their tt table */
7678c2ecf20Sopenharmony_ci		head = &tt_global->orig_list;
7688c2ecf20Sopenharmony_ci		rcu_read_lock();
7698c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(orig_entry, head, list) {
7708c2ecf20Sopenharmony_ci			batadv_send_roam_adv(bat_priv, tt_global->common.addr,
7718c2ecf20Sopenharmony_ci					     tt_global->common.vid,
7728c2ecf20Sopenharmony_ci					     orig_entry->orig_node);
7738c2ecf20Sopenharmony_ci		}
7748c2ecf20Sopenharmony_ci		rcu_read_unlock();
7758c2ecf20Sopenharmony_ci		if (roamed_back) {
7768c2ecf20Sopenharmony_ci			batadv_tt_global_free(bat_priv, tt_global,
7778c2ecf20Sopenharmony_ci					      "Roaming canceled");
7788c2ecf20Sopenharmony_ci		} else {
7798c2ecf20Sopenharmony_ci			/* The global entry has to be marked as ROAMING and
7808c2ecf20Sopenharmony_ci			 * has to be kept for consistency purpose
7818c2ecf20Sopenharmony_ci			 */
7828c2ecf20Sopenharmony_ci			tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
7838c2ecf20Sopenharmony_ci			tt_global->roam_at = jiffies;
7848c2ecf20Sopenharmony_ci		}
7858c2ecf20Sopenharmony_ci	}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	/* store the current remote flags before altering them. This helps
7888c2ecf20Sopenharmony_ci	 * understanding is flags are changing or not
7898c2ecf20Sopenharmony_ci	 */
7908c2ecf20Sopenharmony_ci	remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	if (batadv_is_wifi_hardif(in_hardif))
7938c2ecf20Sopenharmony_ci		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
7948c2ecf20Sopenharmony_ci	else
7958c2ecf20Sopenharmony_ci		tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	/* check the mark in the skb: if it's equal to the configured
7988c2ecf20Sopenharmony_ci	 * isolation_mark, it means the packet is coming from an isolated
7998c2ecf20Sopenharmony_ci	 * non-mesh client
8008c2ecf20Sopenharmony_ci	 */
8018c2ecf20Sopenharmony_ci	match_mark = (mark & bat_priv->isolation_mark_mask);
8028c2ecf20Sopenharmony_ci	if (bat_priv->isolation_mark_mask &&
8038c2ecf20Sopenharmony_ci	    match_mark == bat_priv->isolation_mark)
8048c2ecf20Sopenharmony_ci		tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
8058c2ecf20Sopenharmony_ci	else
8068c2ecf20Sopenharmony_ci		tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	/* if any "dynamic" flag has been modified, resend an ADD event for this
8098c2ecf20Sopenharmony_ci	 * entry so that all the nodes can get the new flags
8108c2ecf20Sopenharmony_ci	 */
8118c2ecf20Sopenharmony_ci	if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
8128c2ecf20Sopenharmony_ci		batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	ret = true;
8158c2ecf20Sopenharmony_ciout:
8168c2ecf20Sopenharmony_ci	if (in_hardif)
8178c2ecf20Sopenharmony_ci		batadv_hardif_put(in_hardif);
8188c2ecf20Sopenharmony_ci	if (in_dev)
8198c2ecf20Sopenharmony_ci		dev_put(in_dev);
8208c2ecf20Sopenharmony_ci	if (tt_local)
8218c2ecf20Sopenharmony_ci		batadv_tt_local_entry_put(tt_local);
8228c2ecf20Sopenharmony_ci	if (tt_global)
8238c2ecf20Sopenharmony_ci		batadv_tt_global_entry_put(tt_global);
8248c2ecf20Sopenharmony_ci	return ret;
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci/**
8288c2ecf20Sopenharmony_ci * batadv_tt_prepare_tvlv_global_data() - prepare the TVLV TT header to send
8298c2ecf20Sopenharmony_ci *  within a TT Response directed to another node
8308c2ecf20Sopenharmony_ci * @orig_node: originator for which the TT data has to be prepared
8318c2ecf20Sopenharmony_ci * @tt_data: uninitialised pointer to the address of the TVLV buffer
8328c2ecf20Sopenharmony_ci * @tt_change: uninitialised pointer to the address of the area where the TT
8338c2ecf20Sopenharmony_ci *  changed can be stored
8348c2ecf20Sopenharmony_ci * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
8358c2ecf20Sopenharmony_ci *  function reserves the amount of space needed to send the entire global TT
8368c2ecf20Sopenharmony_ci *  table. In case of success the value is updated with the real amount of
8378c2ecf20Sopenharmony_ci *  reserved bytes
8388c2ecf20Sopenharmony_ci * Allocate the needed amount of memory for the entire TT TVLV and write its
8398c2ecf20Sopenharmony_ci * header made up of one tvlv_tt_data object and a series of tvlv_tt_vlan_data
8408c2ecf20Sopenharmony_ci * objects, one per active VLAN served by the originator node.
8418c2ecf20Sopenharmony_ci *
8428c2ecf20Sopenharmony_ci * Return: the size of the allocated buffer or 0 in case of failure.
8438c2ecf20Sopenharmony_ci */
8448c2ecf20Sopenharmony_cistatic u16
8458c2ecf20Sopenharmony_cibatadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
8468c2ecf20Sopenharmony_ci				   struct batadv_tvlv_tt_data **tt_data,
8478c2ecf20Sopenharmony_ci				   struct batadv_tvlv_tt_change **tt_change,
8488c2ecf20Sopenharmony_ci				   s32 *tt_len)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	u16 num_vlan = 0;
8518c2ecf20Sopenharmony_ci	u16 num_entries = 0;
8528c2ecf20Sopenharmony_ci	u16 change_offset;
8538c2ecf20Sopenharmony_ci	u16 tvlv_len;
8548c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_vlan_data *tt_vlan;
8558c2ecf20Sopenharmony_ci	struct batadv_orig_node_vlan *vlan;
8568c2ecf20Sopenharmony_ci	u8 *tt_change_ptr;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	spin_lock_bh(&orig_node->vlan_list_lock);
8598c2ecf20Sopenharmony_ci	hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
8608c2ecf20Sopenharmony_ci		num_vlan++;
8618c2ecf20Sopenharmony_ci		num_entries += atomic_read(&vlan->tt.num_entries);
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	change_offset = sizeof(**tt_data);
8658c2ecf20Sopenharmony_ci	change_offset += num_vlan * sizeof(*tt_vlan);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	/* if tt_len is negative, allocate the space needed by the full table */
8688c2ecf20Sopenharmony_ci	if (*tt_len < 0)
8698c2ecf20Sopenharmony_ci		*tt_len = batadv_tt_len(num_entries);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	tvlv_len = *tt_len;
8728c2ecf20Sopenharmony_ci	tvlv_len += change_offset;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
8758c2ecf20Sopenharmony_ci	if (!*tt_data) {
8768c2ecf20Sopenharmony_ci		*tt_len = 0;
8778c2ecf20Sopenharmony_ci		goto out;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	(*tt_data)->flags = BATADV_NO_FLAGS;
8818c2ecf20Sopenharmony_ci	(*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn);
8828c2ecf20Sopenharmony_ci	(*tt_data)->num_vlan = htons(num_vlan);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
8858c2ecf20Sopenharmony_ci	hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
8868c2ecf20Sopenharmony_ci		tt_vlan->vid = htons(vlan->vid);
8878c2ecf20Sopenharmony_ci		tt_vlan->crc = htonl(vlan->tt.crc);
8888c2ecf20Sopenharmony_ci		tt_vlan->reserved = 0;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci		tt_vlan++;
8918c2ecf20Sopenharmony_ci	}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	tt_change_ptr = (u8 *)*tt_data + change_offset;
8948c2ecf20Sopenharmony_ci	*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ciout:
8978c2ecf20Sopenharmony_ci	spin_unlock_bh(&orig_node->vlan_list_lock);
8988c2ecf20Sopenharmony_ci	return tvlv_len;
8998c2ecf20Sopenharmony_ci}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci/**
9028c2ecf20Sopenharmony_ci * batadv_tt_prepare_tvlv_local_data() - allocate and prepare the TT TVLV for
9038c2ecf20Sopenharmony_ci *  this node
9048c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
9058c2ecf20Sopenharmony_ci * @tt_data: uninitialised pointer to the address of the TVLV buffer
9068c2ecf20Sopenharmony_ci * @tt_change: uninitialised pointer to the address of the area where the TT
9078c2ecf20Sopenharmony_ci *  changes can be stored
9088c2ecf20Sopenharmony_ci * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
9098c2ecf20Sopenharmony_ci *  function reserves the amount of space needed to send the entire local TT
9108c2ecf20Sopenharmony_ci *  table. In case of success the value is updated with the real amount of
9118c2ecf20Sopenharmony_ci *  reserved bytes
9128c2ecf20Sopenharmony_ci *
9138c2ecf20Sopenharmony_ci * Allocate the needed amount of memory for the entire TT TVLV and write its
9148c2ecf20Sopenharmony_ci * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
9158c2ecf20Sopenharmony_ci * objects, one per active VLAN.
9168c2ecf20Sopenharmony_ci *
9178c2ecf20Sopenharmony_ci * Return: the size of the allocated buffer or 0 in case of failure.
9188c2ecf20Sopenharmony_ci */
9198c2ecf20Sopenharmony_cistatic u16
9208c2ecf20Sopenharmony_cibatadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
9218c2ecf20Sopenharmony_ci				  struct batadv_tvlv_tt_data **tt_data,
9228c2ecf20Sopenharmony_ci				  struct batadv_tvlv_tt_change **tt_change,
9238c2ecf20Sopenharmony_ci				  s32 *tt_len)
9248c2ecf20Sopenharmony_ci{
9258c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_vlan_data *tt_vlan;
9268c2ecf20Sopenharmony_ci	struct batadv_softif_vlan *vlan;
9278c2ecf20Sopenharmony_ci	u16 num_vlan = 0;
9288c2ecf20Sopenharmony_ci	u16 vlan_entries = 0;
9298c2ecf20Sopenharmony_ci	u16 total_entries = 0;
9308c2ecf20Sopenharmony_ci	u16 tvlv_len;
9318c2ecf20Sopenharmony_ci	u8 *tt_change_ptr;
9328c2ecf20Sopenharmony_ci	int change_offset;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->softif_vlan_list_lock);
9358c2ecf20Sopenharmony_ci	hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
9368c2ecf20Sopenharmony_ci		vlan_entries = atomic_read(&vlan->tt.num_entries);
9378c2ecf20Sopenharmony_ci		if (vlan_entries < 1)
9388c2ecf20Sopenharmony_ci			continue;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci		num_vlan++;
9418c2ecf20Sopenharmony_ci		total_entries += vlan_entries;
9428c2ecf20Sopenharmony_ci	}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	change_offset = sizeof(**tt_data);
9458c2ecf20Sopenharmony_ci	change_offset += num_vlan * sizeof(*tt_vlan);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/* if tt_len is negative, allocate the space needed by the full table */
9488c2ecf20Sopenharmony_ci	if (*tt_len < 0)
9498c2ecf20Sopenharmony_ci		*tt_len = batadv_tt_len(total_entries);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	tvlv_len = *tt_len;
9528c2ecf20Sopenharmony_ci	tvlv_len += change_offset;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
9558c2ecf20Sopenharmony_ci	if (!*tt_data) {
9568c2ecf20Sopenharmony_ci		tvlv_len = 0;
9578c2ecf20Sopenharmony_ci		goto out;
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	(*tt_data)->flags = BATADV_NO_FLAGS;
9618c2ecf20Sopenharmony_ci	(*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn);
9628c2ecf20Sopenharmony_ci	(*tt_data)->num_vlan = htons(num_vlan);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
9658c2ecf20Sopenharmony_ci	hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
9668c2ecf20Sopenharmony_ci		vlan_entries = atomic_read(&vlan->tt.num_entries);
9678c2ecf20Sopenharmony_ci		if (vlan_entries < 1)
9688c2ecf20Sopenharmony_ci			continue;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci		tt_vlan->vid = htons(vlan->vid);
9718c2ecf20Sopenharmony_ci		tt_vlan->crc = htonl(vlan->tt.crc);
9728c2ecf20Sopenharmony_ci		tt_vlan->reserved = 0;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci		tt_vlan++;
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	tt_change_ptr = (u8 *)*tt_data + change_offset;
9788c2ecf20Sopenharmony_ci	*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ciout:
9818c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
9828c2ecf20Sopenharmony_ci	return tvlv_len;
9838c2ecf20Sopenharmony_ci}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci/**
9868c2ecf20Sopenharmony_ci * batadv_tt_tvlv_container_update() - update the translation table tvlv
9878c2ecf20Sopenharmony_ci *  container after local tt changes have been committed
9888c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
9898c2ecf20Sopenharmony_ci */
9908c2ecf20Sopenharmony_cistatic void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	struct batadv_tt_change_node *entry, *safe;
9938c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_data *tt_data;
9948c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_change *tt_change;
9958c2ecf20Sopenharmony_ci	int tt_diff_len, tt_change_len = 0;
9968c2ecf20Sopenharmony_ci	int tt_diff_entries_num = 0;
9978c2ecf20Sopenharmony_ci	int tt_diff_entries_count = 0;
9988c2ecf20Sopenharmony_ci	u16 tvlv_len;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes);
10018c2ecf20Sopenharmony_ci	tt_diff_len = batadv_tt_len(tt_diff_entries_num);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	/* if we have too many changes for one packet don't send any
10048c2ecf20Sopenharmony_ci	 * and wait for the tt table request which will be fragmented
10058c2ecf20Sopenharmony_ci	 */
10068c2ecf20Sopenharmony_ci	if (tt_diff_len > bat_priv->soft_iface->mtu)
10078c2ecf20Sopenharmony_ci		tt_diff_len = 0;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
10108c2ecf20Sopenharmony_ci						     &tt_change, &tt_diff_len);
10118c2ecf20Sopenharmony_ci	if (!tvlv_len)
10128c2ecf20Sopenharmony_ci		return;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	tt_data->flags = BATADV_TT_OGM_DIFF;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	if (tt_diff_len == 0)
10178c2ecf20Sopenharmony_ci		goto container_register;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.changes_list_lock);
10208c2ecf20Sopenharmony_ci	atomic_set(&bat_priv->tt.local_changes, 0);
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
10238c2ecf20Sopenharmony_ci				 list) {
10248c2ecf20Sopenharmony_ci		if (tt_diff_entries_count < tt_diff_entries_num) {
10258c2ecf20Sopenharmony_ci			memcpy(tt_change + tt_diff_entries_count,
10268c2ecf20Sopenharmony_ci			       &entry->change,
10278c2ecf20Sopenharmony_ci			       sizeof(struct batadv_tvlv_tt_change));
10288c2ecf20Sopenharmony_ci			tt_diff_entries_count++;
10298c2ecf20Sopenharmony_ci		}
10308c2ecf20Sopenharmony_ci		list_del(&entry->list);
10318c2ecf20Sopenharmony_ci		kmem_cache_free(batadv_tt_change_cache, entry);
10328c2ecf20Sopenharmony_ci	}
10338c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	/* Keep the buffer for possible tt_request */
10368c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.last_changeset_lock);
10378c2ecf20Sopenharmony_ci	kfree(bat_priv->tt.last_changeset);
10388c2ecf20Sopenharmony_ci	bat_priv->tt.last_changeset_len = 0;
10398c2ecf20Sopenharmony_ci	bat_priv->tt.last_changeset = NULL;
10408c2ecf20Sopenharmony_ci	tt_change_len = batadv_tt_len(tt_diff_entries_count);
10418c2ecf20Sopenharmony_ci	/* check whether this new OGM has no changes due to size problems */
10428c2ecf20Sopenharmony_ci	if (tt_diff_entries_count > 0) {
10438c2ecf20Sopenharmony_ci		/* if kmalloc() fails we will reply with the full table
10448c2ecf20Sopenharmony_ci		 * instead of providing the diff
10458c2ecf20Sopenharmony_ci		 */
10468c2ecf20Sopenharmony_ci		bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC);
10478c2ecf20Sopenharmony_ci		if (bat_priv->tt.last_changeset) {
10488c2ecf20Sopenharmony_ci			memcpy(bat_priv->tt.last_changeset,
10498c2ecf20Sopenharmony_ci			       tt_change, tt_change_len);
10508c2ecf20Sopenharmony_ci			bat_priv->tt.last_changeset_len = tt_diff_len;
10518c2ecf20Sopenharmony_ci		}
10528c2ecf20Sopenharmony_ci	}
10538c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cicontainer_register:
10568c2ecf20Sopenharmony_ci	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
10578c2ecf20Sopenharmony_ci				       tvlv_len);
10588c2ecf20Sopenharmony_ci	kfree(tt_data);
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci/**
10648c2ecf20Sopenharmony_ci * batadv_tt_local_seq_print_text() - Print the local tt table in a seq file
10658c2ecf20Sopenharmony_ci * @seq: seq file to print on
10668c2ecf20Sopenharmony_ci * @offset: not used
10678c2ecf20Sopenharmony_ci *
10688c2ecf20Sopenharmony_ci * Return: always 0
10698c2ecf20Sopenharmony_ci */
10708c2ecf20Sopenharmony_ciint batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	struct net_device *net_dev = (struct net_device *)seq->private;
10738c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(net_dev);
10748c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
10758c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
10768c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local;
10778c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
10788c2ecf20Sopenharmony_ci	struct hlist_head *head;
10798c2ecf20Sopenharmony_ci	u32 i;
10808c2ecf20Sopenharmony_ci	int last_seen_secs;
10818c2ecf20Sopenharmony_ci	int last_seen_msecs;
10828c2ecf20Sopenharmony_ci	unsigned long last_seen_jiffies;
10838c2ecf20Sopenharmony_ci	bool no_purge;
10848c2ecf20Sopenharmony_ci	u16 np_flag = BATADV_TT_CLIENT_NOPURGE;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	primary_if = batadv_seq_print_text_primary_if_get(seq);
10878c2ecf20Sopenharmony_ci	if (!primary_if)
10888c2ecf20Sopenharmony_ci		goto out;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	seq_printf(seq,
10918c2ecf20Sopenharmony_ci		   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
10928c2ecf20Sopenharmony_ci		   net_dev->name, (u8)atomic_read(&bat_priv->tt.vn));
10938c2ecf20Sopenharmony_ci	seq_puts(seq,
10948c2ecf20Sopenharmony_ci		 "       Client         VID Flags    Last seen (CRC       )\n");
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
10978c2ecf20Sopenharmony_ci		head = &hash->table[i];
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci		rcu_read_lock();
11008c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(tt_common_entry,
11018c2ecf20Sopenharmony_ci					 head, hash_entry) {
11028c2ecf20Sopenharmony_ci			tt_local = container_of(tt_common_entry,
11038c2ecf20Sopenharmony_ci						struct batadv_tt_local_entry,
11048c2ecf20Sopenharmony_ci						common);
11058c2ecf20Sopenharmony_ci			last_seen_jiffies = jiffies - tt_local->last_seen;
11068c2ecf20Sopenharmony_ci			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
11078c2ecf20Sopenharmony_ci			last_seen_secs = last_seen_msecs / 1000;
11088c2ecf20Sopenharmony_ci			last_seen_msecs = last_seen_msecs % 1000;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci			no_purge = tt_common_entry->flags & np_flag;
11118c2ecf20Sopenharmony_ci			seq_printf(seq,
11128c2ecf20Sopenharmony_ci				   " * %pM %4i [%c%c%c%c%c%c] %3u.%03u   (%#.8x)\n",
11138c2ecf20Sopenharmony_ci				   tt_common_entry->addr,
11148c2ecf20Sopenharmony_ci				   batadv_print_vid(tt_common_entry->vid),
11158c2ecf20Sopenharmony_ci				   ((tt_common_entry->flags &
11168c2ecf20Sopenharmony_ci				     BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
11178c2ecf20Sopenharmony_ci				   no_purge ? 'P' : '.',
11188c2ecf20Sopenharmony_ci				   ((tt_common_entry->flags &
11198c2ecf20Sopenharmony_ci				     BATADV_TT_CLIENT_NEW) ? 'N' : '.'),
11208c2ecf20Sopenharmony_ci				   ((tt_common_entry->flags &
11218c2ecf20Sopenharmony_ci				     BATADV_TT_CLIENT_PENDING) ? 'X' : '.'),
11228c2ecf20Sopenharmony_ci				   ((tt_common_entry->flags &
11238c2ecf20Sopenharmony_ci				     BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
11248c2ecf20Sopenharmony_ci				   ((tt_common_entry->flags &
11258c2ecf20Sopenharmony_ci				     BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
11268c2ecf20Sopenharmony_ci				   no_purge ? 0 : last_seen_secs,
11278c2ecf20Sopenharmony_ci				   no_purge ? 0 : last_seen_msecs,
11288c2ecf20Sopenharmony_ci				   tt_local->vlan->tt.crc);
11298c2ecf20Sopenharmony_ci		}
11308c2ecf20Sopenharmony_ci		rcu_read_unlock();
11318c2ecf20Sopenharmony_ci	}
11328c2ecf20Sopenharmony_ciout:
11338c2ecf20Sopenharmony_ci	if (primary_if)
11348c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
11358c2ecf20Sopenharmony_ci	return 0;
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci#endif
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci/**
11408c2ecf20Sopenharmony_ci * batadv_tt_local_dump_entry() - Dump one TT local entry into a message
11418c2ecf20Sopenharmony_ci * @msg :Netlink message to dump into
11428c2ecf20Sopenharmony_ci * @portid: Port making netlink request
11438c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
11448c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information
11458c2ecf20Sopenharmony_ci * @common: tt local & tt global common data
11468c2ecf20Sopenharmony_ci *
11478c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success
11488c2ecf20Sopenharmony_ci */
11498c2ecf20Sopenharmony_cistatic int
11508c2ecf20Sopenharmony_cibatadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
11518c2ecf20Sopenharmony_ci			   struct netlink_callback *cb,
11528c2ecf20Sopenharmony_ci			   struct batadv_priv *bat_priv,
11538c2ecf20Sopenharmony_ci			   struct batadv_tt_common_entry *common)
11548c2ecf20Sopenharmony_ci{
11558c2ecf20Sopenharmony_ci	void *hdr;
11568c2ecf20Sopenharmony_ci	struct batadv_softif_vlan *vlan;
11578c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *local;
11588c2ecf20Sopenharmony_ci	unsigned int last_seen_msecs;
11598c2ecf20Sopenharmony_ci	u32 crc;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	local = container_of(common, struct batadv_tt_local_entry, common);
11628c2ecf20Sopenharmony_ci	last_seen_msecs = jiffies_to_msecs(jiffies - local->last_seen);
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	vlan = batadv_softif_vlan_get(bat_priv, common->vid);
11658c2ecf20Sopenharmony_ci	if (!vlan)
11668c2ecf20Sopenharmony_ci		return 0;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	crc = vlan->tt.crc;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	batadv_softif_vlan_put(vlan);
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
11738c2ecf20Sopenharmony_ci			  &batadv_netlink_family,  NLM_F_MULTI,
11748c2ecf20Sopenharmony_ci			  BATADV_CMD_GET_TRANSTABLE_LOCAL);
11758c2ecf20Sopenharmony_ci	if (!hdr)
11768c2ecf20Sopenharmony_ci		return -ENOBUFS;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	genl_dump_check_consistent(cb, hdr);
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
11818c2ecf20Sopenharmony_ci	    nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
11828c2ecf20Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
11838c2ecf20Sopenharmony_ci	    nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags))
11848c2ecf20Sopenharmony_ci		goto nla_put_failure;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	if (!(common->flags & BATADV_TT_CLIENT_NOPURGE) &&
11878c2ecf20Sopenharmony_ci	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs))
11888c2ecf20Sopenharmony_ci		goto nla_put_failure;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
11918c2ecf20Sopenharmony_ci	return 0;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci nla_put_failure:
11948c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
11958c2ecf20Sopenharmony_ci	return -EMSGSIZE;
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci/**
11998c2ecf20Sopenharmony_ci * batadv_tt_local_dump_bucket() - Dump one TT local bucket into a message
12008c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into
12018c2ecf20Sopenharmony_ci * @portid: Port making netlink request
12028c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
12038c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information
12048c2ecf20Sopenharmony_ci * @hash: hash to dump
12058c2ecf20Sopenharmony_ci * @bucket: bucket index to dump
12068c2ecf20Sopenharmony_ci * @idx_s: Number of entries to skip
12078c2ecf20Sopenharmony_ci *
12088c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success
12098c2ecf20Sopenharmony_ci */
12108c2ecf20Sopenharmony_cistatic int
12118c2ecf20Sopenharmony_cibatadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid,
12128c2ecf20Sopenharmony_ci			    struct netlink_callback *cb,
12138c2ecf20Sopenharmony_ci			    struct batadv_priv *bat_priv,
12148c2ecf20Sopenharmony_ci			    struct batadv_hashtable *hash, unsigned int bucket,
12158c2ecf20Sopenharmony_ci			    int *idx_s)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *common;
12188c2ecf20Sopenharmony_ci	int idx = 0;
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	spin_lock_bh(&hash->list_locks[bucket]);
12218c2ecf20Sopenharmony_ci	cb->seq = atomic_read(&hash->generation) << 1 | 1;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	hlist_for_each_entry(common, &hash->table[bucket], hash_entry) {
12248c2ecf20Sopenharmony_ci		if (idx++ < *idx_s)
12258c2ecf20Sopenharmony_ci			continue;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci		if (batadv_tt_local_dump_entry(msg, portid, cb, bat_priv,
12288c2ecf20Sopenharmony_ci					       common)) {
12298c2ecf20Sopenharmony_ci			spin_unlock_bh(&hash->list_locks[bucket]);
12308c2ecf20Sopenharmony_ci			*idx_s = idx - 1;
12318c2ecf20Sopenharmony_ci			return -EMSGSIZE;
12328c2ecf20Sopenharmony_ci		}
12338c2ecf20Sopenharmony_ci	}
12348c2ecf20Sopenharmony_ci	spin_unlock_bh(&hash->list_locks[bucket]);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	*idx_s = 0;
12378c2ecf20Sopenharmony_ci	return 0;
12388c2ecf20Sopenharmony_ci}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci/**
12418c2ecf20Sopenharmony_ci * batadv_tt_local_dump() - Dump TT local entries into a message
12428c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into
12438c2ecf20Sopenharmony_ci * @cb: Parameters from query
12448c2ecf20Sopenharmony_ci *
12458c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success
12468c2ecf20Sopenharmony_ci */
12478c2ecf20Sopenharmony_ciint batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	struct net *net = sock_net(cb->skb->sk);
12508c2ecf20Sopenharmony_ci	struct net_device *soft_iface;
12518c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
12528c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
12538c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
12548c2ecf20Sopenharmony_ci	int ret;
12558c2ecf20Sopenharmony_ci	int ifindex;
12568c2ecf20Sopenharmony_ci	int bucket = cb->args[0];
12578c2ecf20Sopenharmony_ci	int idx = cb->args[1];
12588c2ecf20Sopenharmony_ci	int portid = NETLINK_CB(cb->skb).portid;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
12618c2ecf20Sopenharmony_ci	if (!ifindex)
12628c2ecf20Sopenharmony_ci		return -EINVAL;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	soft_iface = dev_get_by_index(net, ifindex);
12658c2ecf20Sopenharmony_ci	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
12668c2ecf20Sopenharmony_ci		ret = -ENODEV;
12678c2ecf20Sopenharmony_ci		goto out;
12688c2ecf20Sopenharmony_ci	}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	bat_priv = netdev_priv(soft_iface);
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
12738c2ecf20Sopenharmony_ci	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
12748c2ecf20Sopenharmony_ci		ret = -ENOENT;
12758c2ecf20Sopenharmony_ci		goto out;
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	hash = bat_priv->tt.local_hash;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	while (bucket < hash->size) {
12818c2ecf20Sopenharmony_ci		if (batadv_tt_local_dump_bucket(msg, portid, cb, bat_priv,
12828c2ecf20Sopenharmony_ci						hash, bucket, &idx))
12838c2ecf20Sopenharmony_ci			break;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci		bucket++;
12868c2ecf20Sopenharmony_ci	}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	ret = msg->len;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci out:
12918c2ecf20Sopenharmony_ci	if (primary_if)
12928c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
12938c2ecf20Sopenharmony_ci	if (soft_iface)
12948c2ecf20Sopenharmony_ci		dev_put(soft_iface);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	cb->args[0] = bucket;
12978c2ecf20Sopenharmony_ci	cb->args[1] = idx;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	return ret;
13008c2ecf20Sopenharmony_ci}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_cistatic void
13038c2ecf20Sopenharmony_cibatadv_tt_local_set_pending(struct batadv_priv *bat_priv,
13048c2ecf20Sopenharmony_ci			    struct batadv_tt_local_entry *tt_local_entry,
13058c2ecf20Sopenharmony_ci			    u16 flags, const char *message)
13068c2ecf20Sopenharmony_ci{
13078c2ecf20Sopenharmony_ci	batadv_tt_local_event(bat_priv, tt_local_entry, flags);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	/* The local client has to be marked as "pending to be removed" but has
13108c2ecf20Sopenharmony_ci	 * to be kept in the table in order to send it in a full table
13118c2ecf20Sopenharmony_ci	 * response issued before the net ttvn increment (consistency check)
13128c2ecf20Sopenharmony_ci	 */
13138c2ecf20Sopenharmony_ci	tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
13168c2ecf20Sopenharmony_ci		   "Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
13178c2ecf20Sopenharmony_ci		   tt_local_entry->common.addr,
13188c2ecf20Sopenharmony_ci		   batadv_print_vid(tt_local_entry->common.vid), message);
13198c2ecf20Sopenharmony_ci}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci/**
13228c2ecf20Sopenharmony_ci * batadv_tt_local_remove() - logically remove an entry from the local table
13238c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
13248c2ecf20Sopenharmony_ci * @addr: the MAC address of the client to remove
13258c2ecf20Sopenharmony_ci * @vid: VLAN identifier
13268c2ecf20Sopenharmony_ci * @message: message to append to the log on deletion
13278c2ecf20Sopenharmony_ci * @roaming: true if the deletion is due to a roaming event
13288c2ecf20Sopenharmony_ci *
13298c2ecf20Sopenharmony_ci * Return: the flags assigned to the local entry before being deleted
13308c2ecf20Sopenharmony_ci */
13318c2ecf20Sopenharmony_ciu16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
13328c2ecf20Sopenharmony_ci			   unsigned short vid, const char *message,
13338c2ecf20Sopenharmony_ci			   bool roaming)
13348c2ecf20Sopenharmony_ci{
13358c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_removed_entry;
13368c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry;
13378c2ecf20Sopenharmony_ci	u16 flags, curr_flags = BATADV_NO_FLAGS;
13388c2ecf20Sopenharmony_ci	struct hlist_node *tt_removed_node;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
13418c2ecf20Sopenharmony_ci	if (!tt_local_entry)
13428c2ecf20Sopenharmony_ci		goto out;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	curr_flags = tt_local_entry->common.flags;
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	flags = BATADV_TT_CLIENT_DEL;
13478c2ecf20Sopenharmony_ci	/* if this global entry addition is due to a roaming, the node has to
13488c2ecf20Sopenharmony_ci	 * mark the local entry as "roamed" in order to correctly reroute
13498c2ecf20Sopenharmony_ci	 * packets later
13508c2ecf20Sopenharmony_ci	 */
13518c2ecf20Sopenharmony_ci	if (roaming) {
13528c2ecf20Sopenharmony_ci		flags |= BATADV_TT_CLIENT_ROAM;
13538c2ecf20Sopenharmony_ci		/* mark the local client as ROAMed */
13548c2ecf20Sopenharmony_ci		tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
13588c2ecf20Sopenharmony_ci		batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
13598c2ecf20Sopenharmony_ci					    message);
13608c2ecf20Sopenharmony_ci		goto out;
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci	/* if this client has been added right now, it is possible to
13638c2ecf20Sopenharmony_ci	 * immediately purge it
13648c2ecf20Sopenharmony_ci	 */
13658c2ecf20Sopenharmony_ci	batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash,
13688c2ecf20Sopenharmony_ci					     batadv_compare_tt,
13698c2ecf20Sopenharmony_ci					     batadv_choose_tt,
13708c2ecf20Sopenharmony_ci					     &tt_local_entry->common);
13718c2ecf20Sopenharmony_ci	if (!tt_removed_node)
13728c2ecf20Sopenharmony_ci		goto out;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	/* drop reference of remove hash entry */
13758c2ecf20Sopenharmony_ci	tt_removed_entry = hlist_entry(tt_removed_node,
13768c2ecf20Sopenharmony_ci				       struct batadv_tt_local_entry,
13778c2ecf20Sopenharmony_ci				       common.hash_entry);
13788c2ecf20Sopenharmony_ci	batadv_tt_local_entry_put(tt_removed_entry);
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ciout:
13818c2ecf20Sopenharmony_ci	if (tt_local_entry)
13828c2ecf20Sopenharmony_ci		batadv_tt_local_entry_put(tt_local_entry);
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	return curr_flags;
13858c2ecf20Sopenharmony_ci}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci/**
13888c2ecf20Sopenharmony_ci * batadv_tt_local_purge_list() - purge inactive tt local entries
13898c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
13908c2ecf20Sopenharmony_ci * @head: pointer to the list containing the local tt entries
13918c2ecf20Sopenharmony_ci * @timeout: parameter deciding whether a given tt local entry is considered
13928c2ecf20Sopenharmony_ci *  inactive or not
13938c2ecf20Sopenharmony_ci */
13948c2ecf20Sopenharmony_cistatic void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
13958c2ecf20Sopenharmony_ci				       struct hlist_head *head,
13968c2ecf20Sopenharmony_ci				       int timeout)
13978c2ecf20Sopenharmony_ci{
13988c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry;
13998c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
14008c2ecf20Sopenharmony_ci	struct hlist_node *node_tmp;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
14038c2ecf20Sopenharmony_ci				  hash_entry) {
14048c2ecf20Sopenharmony_ci		tt_local_entry = container_of(tt_common_entry,
14058c2ecf20Sopenharmony_ci					      struct batadv_tt_local_entry,
14068c2ecf20Sopenharmony_ci					      common);
14078c2ecf20Sopenharmony_ci		if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
14088c2ecf20Sopenharmony_ci			continue;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci		/* entry already marked for deletion */
14118c2ecf20Sopenharmony_ci		if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
14128c2ecf20Sopenharmony_ci			continue;
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci		if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
14158c2ecf20Sopenharmony_ci			continue;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci		batadv_tt_local_set_pending(bat_priv, tt_local_entry,
14188c2ecf20Sopenharmony_ci					    BATADV_TT_CLIENT_DEL, "timed out");
14198c2ecf20Sopenharmony_ci	}
14208c2ecf20Sopenharmony_ci}
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci/**
14238c2ecf20Sopenharmony_ci * batadv_tt_local_purge() - purge inactive tt local entries
14248c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
14258c2ecf20Sopenharmony_ci * @timeout: parameter deciding whether a given tt local entry is considered
14268c2ecf20Sopenharmony_ci *  inactive or not
14278c2ecf20Sopenharmony_ci */
14288c2ecf20Sopenharmony_cistatic void batadv_tt_local_purge(struct batadv_priv *bat_priv,
14298c2ecf20Sopenharmony_ci				  int timeout)
14308c2ecf20Sopenharmony_ci{
14318c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
14328c2ecf20Sopenharmony_ci	struct hlist_head *head;
14338c2ecf20Sopenharmony_ci	spinlock_t *list_lock; /* protects write access to the hash lists */
14348c2ecf20Sopenharmony_ci	u32 i;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
14378c2ecf20Sopenharmony_ci		head = &hash->table[i];
14388c2ecf20Sopenharmony_ci		list_lock = &hash->list_locks[i];
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci		spin_lock_bh(list_lock);
14418c2ecf20Sopenharmony_ci		batadv_tt_local_purge_list(bat_priv, head, timeout);
14428c2ecf20Sopenharmony_ci		spin_unlock_bh(list_lock);
14438c2ecf20Sopenharmony_ci	}
14448c2ecf20Sopenharmony_ci}
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_cistatic void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
14478c2ecf20Sopenharmony_ci{
14488c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
14498c2ecf20Sopenharmony_ci	spinlock_t *list_lock; /* protects write access to the hash lists */
14508c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
14518c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local;
14528c2ecf20Sopenharmony_ci	struct hlist_node *node_tmp;
14538c2ecf20Sopenharmony_ci	struct hlist_head *head;
14548c2ecf20Sopenharmony_ci	u32 i;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	if (!bat_priv->tt.local_hash)
14578c2ecf20Sopenharmony_ci		return;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	hash = bat_priv->tt.local_hash;
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
14628c2ecf20Sopenharmony_ci		head = &hash->table[i];
14638c2ecf20Sopenharmony_ci		list_lock = &hash->list_locks[i];
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci		spin_lock_bh(list_lock);
14668c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(tt_common_entry, node_tmp,
14678c2ecf20Sopenharmony_ci					  head, hash_entry) {
14688c2ecf20Sopenharmony_ci			hlist_del_rcu(&tt_common_entry->hash_entry);
14698c2ecf20Sopenharmony_ci			tt_local = container_of(tt_common_entry,
14708c2ecf20Sopenharmony_ci						struct batadv_tt_local_entry,
14718c2ecf20Sopenharmony_ci						common);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci			batadv_tt_local_entry_put(tt_local);
14748c2ecf20Sopenharmony_ci		}
14758c2ecf20Sopenharmony_ci		spin_unlock_bh(list_lock);
14768c2ecf20Sopenharmony_ci	}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	batadv_hash_destroy(hash);
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	bat_priv->tt.local_hash = NULL;
14818c2ecf20Sopenharmony_ci}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_cistatic int batadv_tt_global_init(struct batadv_priv *bat_priv)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	if (bat_priv->tt.global_hash)
14868c2ecf20Sopenharmony_ci		return 0;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	bat_priv->tt.global_hash = batadv_hash_new(1024);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	if (!bat_priv->tt.global_hash)
14918c2ecf20Sopenharmony_ci		return -ENOMEM;
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	batadv_hash_set_lock_class(bat_priv->tt.global_hash,
14948c2ecf20Sopenharmony_ci				   &batadv_tt_global_hash_lock_class_key);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	return 0;
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_cistatic void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
15008c2ecf20Sopenharmony_ci{
15018c2ecf20Sopenharmony_ci	struct batadv_tt_change_node *entry, *safe;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.changes_list_lock);
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
15068c2ecf20Sopenharmony_ci				 list) {
15078c2ecf20Sopenharmony_ci		list_del(&entry->list);
15088c2ecf20Sopenharmony_ci		kmem_cache_free(batadv_tt_change_cache, entry);
15098c2ecf20Sopenharmony_ci	}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	atomic_set(&bat_priv->tt.local_changes, 0);
15128c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.changes_list_lock);
15138c2ecf20Sopenharmony_ci}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci/**
15168c2ecf20Sopenharmony_ci * batadv_tt_global_orig_entry_find() - find a TT orig_list_entry
15178c2ecf20Sopenharmony_ci * @entry: the TT global entry where the orig_list_entry has to be
15188c2ecf20Sopenharmony_ci *  extracted from
15198c2ecf20Sopenharmony_ci * @orig_node: the originator for which the orig_list_entry has to be found
15208c2ecf20Sopenharmony_ci *
15218c2ecf20Sopenharmony_ci * retrieve the orig_tt_list_entry belonging to orig_node from the
15228c2ecf20Sopenharmony_ci * batadv_tt_global_entry list
15238c2ecf20Sopenharmony_ci *
15248c2ecf20Sopenharmony_ci * Return: it with an increased refcounter, NULL if not found
15258c2ecf20Sopenharmony_ci */
15268c2ecf20Sopenharmony_cistatic struct batadv_tt_orig_list_entry *
15278c2ecf20Sopenharmony_cibatadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
15288c2ecf20Sopenharmony_ci				 const struct batadv_orig_node *orig_node)
15298c2ecf20Sopenharmony_ci{
15308c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
15318c2ecf20Sopenharmony_ci	const struct hlist_head *head;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	rcu_read_lock();
15348c2ecf20Sopenharmony_ci	head = &entry->orig_list;
15358c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tmp_orig_entry, head, list) {
15368c2ecf20Sopenharmony_ci		if (tmp_orig_entry->orig_node != orig_node)
15378c2ecf20Sopenharmony_ci			continue;
15388c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&tmp_orig_entry->refcount))
15398c2ecf20Sopenharmony_ci			continue;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci		orig_entry = tmp_orig_entry;
15428c2ecf20Sopenharmony_ci		break;
15438c2ecf20Sopenharmony_ci	}
15448c2ecf20Sopenharmony_ci	rcu_read_unlock();
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	return orig_entry;
15478c2ecf20Sopenharmony_ci}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci/**
15508c2ecf20Sopenharmony_ci * batadv_tt_global_entry_has_orig() - check if a TT global entry is also
15518c2ecf20Sopenharmony_ci *  handled by a given originator
15528c2ecf20Sopenharmony_ci * @entry: the TT global entry to check
15538c2ecf20Sopenharmony_ci * @orig_node: the originator to search in the list
15548c2ecf20Sopenharmony_ci * @flags: a pointer to store TT flags for the given @entry received
15558c2ecf20Sopenharmony_ci *  from @orig_node
15568c2ecf20Sopenharmony_ci *
15578c2ecf20Sopenharmony_ci * find out if an orig_node is already in the list of a tt_global_entry.
15588c2ecf20Sopenharmony_ci *
15598c2ecf20Sopenharmony_ci * Return: true if found, false otherwise
15608c2ecf20Sopenharmony_ci */
15618c2ecf20Sopenharmony_cistatic bool
15628c2ecf20Sopenharmony_cibatadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
15638c2ecf20Sopenharmony_ci				const struct batadv_orig_node *orig_node,
15648c2ecf20Sopenharmony_ci				u8 *flags)
15658c2ecf20Sopenharmony_ci{
15668c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
15678c2ecf20Sopenharmony_ci	bool found = false;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
15708c2ecf20Sopenharmony_ci	if (orig_entry) {
15718c2ecf20Sopenharmony_ci		found = true;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci		if (flags)
15748c2ecf20Sopenharmony_ci			*flags = orig_entry->flags;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci		batadv_tt_orig_list_entry_put(orig_entry);
15778c2ecf20Sopenharmony_ci	}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	return found;
15808c2ecf20Sopenharmony_ci}
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci/**
15838c2ecf20Sopenharmony_ci * batadv_tt_global_sync_flags() - update TT sync flags
15848c2ecf20Sopenharmony_ci * @tt_global: the TT global entry to update sync flags in
15858c2ecf20Sopenharmony_ci *
15868c2ecf20Sopenharmony_ci * Updates the sync flag bits in the tt_global flag attribute with a logical
15878c2ecf20Sopenharmony_ci * OR of all sync flags from any of its TT orig entries.
15888c2ecf20Sopenharmony_ci */
15898c2ecf20Sopenharmony_cistatic void
15908c2ecf20Sopenharmony_cibatadv_tt_global_sync_flags(struct batadv_tt_global_entry *tt_global)
15918c2ecf20Sopenharmony_ci{
15928c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
15938c2ecf20Sopenharmony_ci	const struct hlist_head *head;
15948c2ecf20Sopenharmony_ci	u16 flags = BATADV_NO_FLAGS;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	rcu_read_lock();
15978c2ecf20Sopenharmony_ci	head = &tt_global->orig_list;
15988c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_entry, head, list)
15998c2ecf20Sopenharmony_ci		flags |= orig_entry->flags;
16008c2ecf20Sopenharmony_ci	rcu_read_unlock();
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
16038c2ecf20Sopenharmony_ci	tt_global->common.flags = flags;
16048c2ecf20Sopenharmony_ci}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci/**
16078c2ecf20Sopenharmony_ci * batadv_tt_global_orig_entry_add() - add or update a TT orig entry
16088c2ecf20Sopenharmony_ci * @tt_global: the TT global entry to add an orig entry in
16098c2ecf20Sopenharmony_ci * @orig_node: the originator to add an orig entry for
16108c2ecf20Sopenharmony_ci * @ttvn: translation table version number of this changeset
16118c2ecf20Sopenharmony_ci * @flags: TT sync flags
16128c2ecf20Sopenharmony_ci */
16138c2ecf20Sopenharmony_cistatic void
16148c2ecf20Sopenharmony_cibatadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
16158c2ecf20Sopenharmony_ci				struct batadv_orig_node *orig_node, int ttvn,
16168c2ecf20Sopenharmony_ci				u8 flags)
16178c2ecf20Sopenharmony_ci{
16188c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	spin_lock_bh(&tt_global->list_lock);
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci	orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
16238c2ecf20Sopenharmony_ci	if (orig_entry) {
16248c2ecf20Sopenharmony_ci		/* refresh the ttvn: the current value could be a bogus one that
16258c2ecf20Sopenharmony_ci		 * was added during a "temporary client detection"
16268c2ecf20Sopenharmony_ci		 */
16278c2ecf20Sopenharmony_ci		orig_entry->ttvn = ttvn;
16288c2ecf20Sopenharmony_ci		orig_entry->flags = flags;
16298c2ecf20Sopenharmony_ci		goto sync_flags;
16308c2ecf20Sopenharmony_ci	}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	orig_entry = kmem_cache_zalloc(batadv_tt_orig_cache, GFP_ATOMIC);
16338c2ecf20Sopenharmony_ci	if (!orig_entry)
16348c2ecf20Sopenharmony_ci		goto out;
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	INIT_HLIST_NODE(&orig_entry->list);
16378c2ecf20Sopenharmony_ci	kref_get(&orig_node->refcount);
16388c2ecf20Sopenharmony_ci	batadv_tt_global_size_inc(orig_node, tt_global->common.vid);
16398c2ecf20Sopenharmony_ci	orig_entry->orig_node = orig_node;
16408c2ecf20Sopenharmony_ci	orig_entry->ttvn = ttvn;
16418c2ecf20Sopenharmony_ci	orig_entry->flags = flags;
16428c2ecf20Sopenharmony_ci	kref_init(&orig_entry->refcount);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	kref_get(&orig_entry->refcount);
16458c2ecf20Sopenharmony_ci	hlist_add_head_rcu(&orig_entry->list,
16468c2ecf20Sopenharmony_ci			   &tt_global->orig_list);
16478c2ecf20Sopenharmony_ci	atomic_inc(&tt_global->orig_list_count);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_cisync_flags:
16508c2ecf20Sopenharmony_ci	batadv_tt_global_sync_flags(tt_global);
16518c2ecf20Sopenharmony_ciout:
16528c2ecf20Sopenharmony_ci	if (orig_entry)
16538c2ecf20Sopenharmony_ci		batadv_tt_orig_list_entry_put(orig_entry);
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	spin_unlock_bh(&tt_global->list_lock);
16568c2ecf20Sopenharmony_ci}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci/**
16598c2ecf20Sopenharmony_ci * batadv_tt_global_add() - add a new TT global entry or update an existing one
16608c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
16618c2ecf20Sopenharmony_ci * @orig_node: the originator announcing the client
16628c2ecf20Sopenharmony_ci * @tt_addr: the mac address of the non-mesh client
16638c2ecf20Sopenharmony_ci * @vid: VLAN identifier
16648c2ecf20Sopenharmony_ci * @flags: TT flags that have to be set for this non-mesh client
16658c2ecf20Sopenharmony_ci * @ttvn: the tt version number ever announcing this non-mesh client
16668c2ecf20Sopenharmony_ci *
16678c2ecf20Sopenharmony_ci * Add a new TT global entry for the given originator. If the entry already
16688c2ecf20Sopenharmony_ci * exists add a new reference to the given originator (a global entry can have
16698c2ecf20Sopenharmony_ci * references to multiple originators) and adjust the flags attribute to reflect
16708c2ecf20Sopenharmony_ci * the function argument.
16718c2ecf20Sopenharmony_ci * If a TT local entry exists for this non-mesh client remove it.
16728c2ecf20Sopenharmony_ci *
16738c2ecf20Sopenharmony_ci * The caller must hold the orig_node refcount.
16748c2ecf20Sopenharmony_ci *
16758c2ecf20Sopenharmony_ci * Return: true if the new entry has been added, false otherwise
16768c2ecf20Sopenharmony_ci */
16778c2ecf20Sopenharmony_cistatic bool batadv_tt_global_add(struct batadv_priv *bat_priv,
16788c2ecf20Sopenharmony_ci				 struct batadv_orig_node *orig_node,
16798c2ecf20Sopenharmony_ci				 const unsigned char *tt_addr,
16808c2ecf20Sopenharmony_ci				 unsigned short vid, u16 flags, u8 ttvn)
16818c2ecf20Sopenharmony_ci{
16828c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry;
16838c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry;
16848c2ecf20Sopenharmony_ci	bool ret = false;
16858c2ecf20Sopenharmony_ci	int hash_added;
16868c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *common;
16878c2ecf20Sopenharmony_ci	u16 local_flags;
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	/* ignore global entries from backbone nodes */
16908c2ecf20Sopenharmony_ci	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
16918c2ecf20Sopenharmony_ci		return true;
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid);
16948c2ecf20Sopenharmony_ci	tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid);
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	/* if the node already has a local client for this entry, it has to wait
16978c2ecf20Sopenharmony_ci	 * for a roaming advertisement instead of manually messing up the global
16988c2ecf20Sopenharmony_ci	 * table
16998c2ecf20Sopenharmony_ci	 */
17008c2ecf20Sopenharmony_ci	if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
17018c2ecf20Sopenharmony_ci	    !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
17028c2ecf20Sopenharmony_ci		goto out;
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	if (!tt_global_entry) {
17058c2ecf20Sopenharmony_ci		tt_global_entry = kmem_cache_zalloc(batadv_tg_cache,
17068c2ecf20Sopenharmony_ci						    GFP_ATOMIC);
17078c2ecf20Sopenharmony_ci		if (!tt_global_entry)
17088c2ecf20Sopenharmony_ci			goto out;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci		common = &tt_global_entry->common;
17118c2ecf20Sopenharmony_ci		ether_addr_copy(common->addr, tt_addr);
17128c2ecf20Sopenharmony_ci		common->vid = vid;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci		if (!is_multicast_ether_addr(common->addr))
17158c2ecf20Sopenharmony_ci			common->flags = flags & (~BATADV_TT_SYNC_MASK);
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci		tt_global_entry->roam_at = 0;
17188c2ecf20Sopenharmony_ci		/* node must store current time in case of roaming. This is
17198c2ecf20Sopenharmony_ci		 * needed to purge this entry out on timeout (if nobody claims
17208c2ecf20Sopenharmony_ci		 * it)
17218c2ecf20Sopenharmony_ci		 */
17228c2ecf20Sopenharmony_ci		if (flags & BATADV_TT_CLIENT_ROAM)
17238c2ecf20Sopenharmony_ci			tt_global_entry->roam_at = jiffies;
17248c2ecf20Sopenharmony_ci		kref_init(&common->refcount);
17258c2ecf20Sopenharmony_ci		common->added_at = jiffies;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci		INIT_HLIST_HEAD(&tt_global_entry->orig_list);
17288c2ecf20Sopenharmony_ci		atomic_set(&tt_global_entry->orig_list_count, 0);
17298c2ecf20Sopenharmony_ci		spin_lock_init(&tt_global_entry->list_lock);
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci		kref_get(&common->refcount);
17328c2ecf20Sopenharmony_ci		hash_added = batadv_hash_add(bat_priv->tt.global_hash,
17338c2ecf20Sopenharmony_ci					     batadv_compare_tt,
17348c2ecf20Sopenharmony_ci					     batadv_choose_tt, common,
17358c2ecf20Sopenharmony_ci					     &common->hash_entry);
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci		if (unlikely(hash_added != 0)) {
17388c2ecf20Sopenharmony_ci			/* remove the reference for the hash */
17398c2ecf20Sopenharmony_ci			batadv_tt_global_entry_put(tt_global_entry);
17408c2ecf20Sopenharmony_ci			goto out_remove;
17418c2ecf20Sopenharmony_ci		}
17428c2ecf20Sopenharmony_ci	} else {
17438c2ecf20Sopenharmony_ci		common = &tt_global_entry->common;
17448c2ecf20Sopenharmony_ci		/* If there is already a global entry, we can use this one for
17458c2ecf20Sopenharmony_ci		 * our processing.
17468c2ecf20Sopenharmony_ci		 * But if we are trying to add a temporary client then here are
17478c2ecf20Sopenharmony_ci		 * two options at this point:
17488c2ecf20Sopenharmony_ci		 * 1) the global client is not a temporary client: the global
17498c2ecf20Sopenharmony_ci		 *    client has to be left as it is, temporary information
17508c2ecf20Sopenharmony_ci		 *    should never override any already known client state
17518c2ecf20Sopenharmony_ci		 * 2) the global client is a temporary client: purge the
17528c2ecf20Sopenharmony_ci		 *    originator list and add the new one orig_entry
17538c2ecf20Sopenharmony_ci		 */
17548c2ecf20Sopenharmony_ci		if (flags & BATADV_TT_CLIENT_TEMP) {
17558c2ecf20Sopenharmony_ci			if (!(common->flags & BATADV_TT_CLIENT_TEMP))
17568c2ecf20Sopenharmony_ci				goto out;
17578c2ecf20Sopenharmony_ci			if (batadv_tt_global_entry_has_orig(tt_global_entry,
17588c2ecf20Sopenharmony_ci							    orig_node, NULL))
17598c2ecf20Sopenharmony_ci				goto out_remove;
17608c2ecf20Sopenharmony_ci			batadv_tt_global_del_orig_list(tt_global_entry);
17618c2ecf20Sopenharmony_ci			goto add_orig_entry;
17628c2ecf20Sopenharmony_ci		}
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci		/* if the client was temporary added before receiving the first
17658c2ecf20Sopenharmony_ci		 * OGM announcing it, we have to clear the TEMP flag. Also,
17668c2ecf20Sopenharmony_ci		 * remove the previous temporary orig node and re-add it
17678c2ecf20Sopenharmony_ci		 * if required. If the orig entry changed, the new one which
17688c2ecf20Sopenharmony_ci		 * is a non-temporary entry is preferred.
17698c2ecf20Sopenharmony_ci		 */
17708c2ecf20Sopenharmony_ci		if (common->flags & BATADV_TT_CLIENT_TEMP) {
17718c2ecf20Sopenharmony_ci			batadv_tt_global_del_orig_list(tt_global_entry);
17728c2ecf20Sopenharmony_ci			common->flags &= ~BATADV_TT_CLIENT_TEMP;
17738c2ecf20Sopenharmony_ci		}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci		/* the change can carry possible "attribute" flags like the
17768c2ecf20Sopenharmony_ci		 * TT_CLIENT_TEMP, therefore they have to be copied in the
17778c2ecf20Sopenharmony_ci		 * client entry
17788c2ecf20Sopenharmony_ci		 */
17798c2ecf20Sopenharmony_ci		if (!is_multicast_ether_addr(common->addr))
17808c2ecf20Sopenharmony_ci			common->flags |= flags & (~BATADV_TT_SYNC_MASK);
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci		/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
17838c2ecf20Sopenharmony_ci		 * one originator left in the list and we previously received a
17848c2ecf20Sopenharmony_ci		 * delete + roaming change for this originator.
17858c2ecf20Sopenharmony_ci		 *
17868c2ecf20Sopenharmony_ci		 * We should first delete the old originator before adding the
17878c2ecf20Sopenharmony_ci		 * new one.
17888c2ecf20Sopenharmony_ci		 */
17898c2ecf20Sopenharmony_ci		if (common->flags & BATADV_TT_CLIENT_ROAM) {
17908c2ecf20Sopenharmony_ci			batadv_tt_global_del_orig_list(tt_global_entry);
17918c2ecf20Sopenharmony_ci			common->flags &= ~BATADV_TT_CLIENT_ROAM;
17928c2ecf20Sopenharmony_ci			tt_global_entry->roam_at = 0;
17938c2ecf20Sopenharmony_ci		}
17948c2ecf20Sopenharmony_ci	}
17958c2ecf20Sopenharmony_ciadd_orig_entry:
17968c2ecf20Sopenharmony_ci	/* add the new orig_entry (if needed) or update it */
17978c2ecf20Sopenharmony_ci	batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn,
17988c2ecf20Sopenharmony_ci					flags & BATADV_TT_SYNC_MASK);
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
18018c2ecf20Sopenharmony_ci		   "Creating new global tt entry: %pM (vid: %d, via %pM)\n",
18028c2ecf20Sopenharmony_ci		   common->addr, batadv_print_vid(common->vid),
18038c2ecf20Sopenharmony_ci		   orig_node->orig);
18048c2ecf20Sopenharmony_ci	ret = true;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ciout_remove:
18078c2ecf20Sopenharmony_ci	/* Do not remove multicast addresses from the local hash on
18088c2ecf20Sopenharmony_ci	 * global additions
18098c2ecf20Sopenharmony_ci	 */
18108c2ecf20Sopenharmony_ci	if (is_multicast_ether_addr(tt_addr))
18118c2ecf20Sopenharmony_ci		goto out;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	/* remove address from local hash if present */
18148c2ecf20Sopenharmony_ci	local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
18158c2ecf20Sopenharmony_ci					     "global tt received",
18168c2ecf20Sopenharmony_ci					     flags & BATADV_TT_CLIENT_ROAM);
18178c2ecf20Sopenharmony_ci	tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	if (!(flags & BATADV_TT_CLIENT_ROAM))
18208c2ecf20Sopenharmony_ci		/* this is a normal global add. Therefore the client is not in a
18218c2ecf20Sopenharmony_ci		 * roaming state anymore.
18228c2ecf20Sopenharmony_ci		 */
18238c2ecf20Sopenharmony_ci		tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ciout:
18268c2ecf20Sopenharmony_ci	if (tt_global_entry)
18278c2ecf20Sopenharmony_ci		batadv_tt_global_entry_put(tt_global_entry);
18288c2ecf20Sopenharmony_ci	if (tt_local_entry)
18298c2ecf20Sopenharmony_ci		batadv_tt_local_entry_put(tt_local_entry);
18308c2ecf20Sopenharmony_ci	return ret;
18318c2ecf20Sopenharmony_ci}
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci/**
18348c2ecf20Sopenharmony_ci * batadv_transtable_best_orig() - Get best originator list entry from tt entry
18358c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
18368c2ecf20Sopenharmony_ci * @tt_global_entry: global translation table entry to be analyzed
18378c2ecf20Sopenharmony_ci *
18388c2ecf20Sopenharmony_ci * This function assumes the caller holds rcu_read_lock().
18398c2ecf20Sopenharmony_ci * Return: best originator list entry or NULL on errors.
18408c2ecf20Sopenharmony_ci */
18418c2ecf20Sopenharmony_cistatic struct batadv_tt_orig_list_entry *
18428c2ecf20Sopenharmony_cibatadv_transtable_best_orig(struct batadv_priv *bat_priv,
18438c2ecf20Sopenharmony_ci			    struct batadv_tt_global_entry *tt_global_entry)
18448c2ecf20Sopenharmony_ci{
18458c2ecf20Sopenharmony_ci	struct batadv_neigh_node *router, *best_router = NULL;
18468c2ecf20Sopenharmony_ci	struct batadv_algo_ops *bao = bat_priv->algo_ops;
18478c2ecf20Sopenharmony_ci	struct hlist_head *head;
18488c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL;
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	head = &tt_global_entry->orig_list;
18518c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_entry, head, list) {
18528c2ecf20Sopenharmony_ci		router = batadv_orig_router_get(orig_entry->orig_node,
18538c2ecf20Sopenharmony_ci						BATADV_IF_DEFAULT);
18548c2ecf20Sopenharmony_ci		if (!router)
18558c2ecf20Sopenharmony_ci			continue;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci		if (best_router &&
18588c2ecf20Sopenharmony_ci		    bao->neigh.cmp(router, BATADV_IF_DEFAULT, best_router,
18598c2ecf20Sopenharmony_ci				   BATADV_IF_DEFAULT) <= 0) {
18608c2ecf20Sopenharmony_ci			batadv_neigh_node_put(router);
18618c2ecf20Sopenharmony_ci			continue;
18628c2ecf20Sopenharmony_ci		}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci		/* release the refcount for the "old" best */
18658c2ecf20Sopenharmony_ci		if (best_router)
18668c2ecf20Sopenharmony_ci			batadv_neigh_node_put(best_router);
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci		best_entry = orig_entry;
18698c2ecf20Sopenharmony_ci		best_router = router;
18708c2ecf20Sopenharmony_ci	}
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci	if (best_router)
18738c2ecf20Sopenharmony_ci		batadv_neigh_node_put(best_router);
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	return best_entry;
18768c2ecf20Sopenharmony_ci}
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS
18798c2ecf20Sopenharmony_ci/**
18808c2ecf20Sopenharmony_ci * batadv_tt_global_print_entry() - print all orig nodes who announce the
18818c2ecf20Sopenharmony_ci *  address for this global entry
18828c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
18838c2ecf20Sopenharmony_ci * @tt_global_entry: global translation table entry to be printed
18848c2ecf20Sopenharmony_ci * @seq: debugfs table seq_file struct
18858c2ecf20Sopenharmony_ci *
18868c2ecf20Sopenharmony_ci * This function assumes the caller holds rcu_read_lock().
18878c2ecf20Sopenharmony_ci */
18888c2ecf20Sopenharmony_cistatic void
18898c2ecf20Sopenharmony_cibatadv_tt_global_print_entry(struct batadv_priv *bat_priv,
18908c2ecf20Sopenharmony_ci			     struct batadv_tt_global_entry *tt_global_entry,
18918c2ecf20Sopenharmony_ci			     struct seq_file *seq)
18928c2ecf20Sopenharmony_ci{
18938c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
18948c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
18958c2ecf20Sopenharmony_ci	struct batadv_orig_node_vlan *vlan;
18968c2ecf20Sopenharmony_ci	struct hlist_head *head;
18978c2ecf20Sopenharmony_ci	u8 last_ttvn;
18988c2ecf20Sopenharmony_ci	u16 flags;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	tt_common_entry = &tt_global_entry->common;
19018c2ecf20Sopenharmony_ci	flags = tt_common_entry->flags;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
19048c2ecf20Sopenharmony_ci	if (best_entry) {
19058c2ecf20Sopenharmony_ci		vlan = batadv_orig_node_vlan_get(best_entry->orig_node,
19068c2ecf20Sopenharmony_ci						 tt_common_entry->vid);
19078c2ecf20Sopenharmony_ci		if (!vlan) {
19088c2ecf20Sopenharmony_ci			seq_printf(seq,
19098c2ecf20Sopenharmony_ci				   " * Cannot retrieve VLAN %d for originator %pM\n",
19108c2ecf20Sopenharmony_ci				   batadv_print_vid(tt_common_entry->vid),
19118c2ecf20Sopenharmony_ci				   best_entry->orig_node->orig);
19128c2ecf20Sopenharmony_ci			goto print_list;
19138c2ecf20Sopenharmony_ci		}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci		last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
19168c2ecf20Sopenharmony_ci		seq_printf(seq,
19178c2ecf20Sopenharmony_ci			   " %c %pM %4i   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c%c]\n",
19188c2ecf20Sopenharmony_ci			   '*', tt_global_entry->common.addr,
19198c2ecf20Sopenharmony_ci			   batadv_print_vid(tt_global_entry->common.vid),
19208c2ecf20Sopenharmony_ci			   best_entry->ttvn, best_entry->orig_node->orig,
19218c2ecf20Sopenharmony_ci			   last_ttvn, vlan->tt.crc,
19228c2ecf20Sopenharmony_ci			   ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
19238c2ecf20Sopenharmony_ci			   ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
19248c2ecf20Sopenharmony_ci			   ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
19258c2ecf20Sopenharmony_ci			   ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci		batadv_orig_node_vlan_put(vlan);
19288c2ecf20Sopenharmony_ci	}
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ciprint_list:
19318c2ecf20Sopenharmony_ci	head = &tt_global_entry->orig_list;
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_entry, head, list) {
19348c2ecf20Sopenharmony_ci		if (best_entry == orig_entry)
19358c2ecf20Sopenharmony_ci			continue;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci		vlan = batadv_orig_node_vlan_get(orig_entry->orig_node,
19388c2ecf20Sopenharmony_ci						 tt_common_entry->vid);
19398c2ecf20Sopenharmony_ci		if (!vlan) {
19408c2ecf20Sopenharmony_ci			seq_printf(seq,
19418c2ecf20Sopenharmony_ci				   " + Cannot retrieve VLAN %d for originator %pM\n",
19428c2ecf20Sopenharmony_ci				   batadv_print_vid(tt_common_entry->vid),
19438c2ecf20Sopenharmony_ci				   orig_entry->orig_node->orig);
19448c2ecf20Sopenharmony_ci			continue;
19458c2ecf20Sopenharmony_ci		}
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci		last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
19488c2ecf20Sopenharmony_ci		seq_printf(seq,
19498c2ecf20Sopenharmony_ci			   " %c %pM %4d   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c%c]\n",
19508c2ecf20Sopenharmony_ci			   '+', tt_global_entry->common.addr,
19518c2ecf20Sopenharmony_ci			   batadv_print_vid(tt_global_entry->common.vid),
19528c2ecf20Sopenharmony_ci			   orig_entry->ttvn, orig_entry->orig_node->orig,
19538c2ecf20Sopenharmony_ci			   last_ttvn, vlan->tt.crc,
19548c2ecf20Sopenharmony_ci			   ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'),
19558c2ecf20Sopenharmony_ci			   ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'),
19568c2ecf20Sopenharmony_ci			   ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
19578c2ecf20Sopenharmony_ci			   ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci		batadv_orig_node_vlan_put(vlan);
19608c2ecf20Sopenharmony_ci	}
19618c2ecf20Sopenharmony_ci}
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci/**
19648c2ecf20Sopenharmony_ci * batadv_tt_global_seq_print_text() - Print the global tt table in a seq file
19658c2ecf20Sopenharmony_ci * @seq: seq file to print on
19668c2ecf20Sopenharmony_ci * @offset: not used
19678c2ecf20Sopenharmony_ci *
19688c2ecf20Sopenharmony_ci * Return: always 0
19698c2ecf20Sopenharmony_ci */
19708c2ecf20Sopenharmony_ciint batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
19718c2ecf20Sopenharmony_ci{
19728c2ecf20Sopenharmony_ci	struct net_device *net_dev = (struct net_device *)seq->private;
19738c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(net_dev);
19748c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
19758c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
19768c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global;
19778c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
19788c2ecf20Sopenharmony_ci	struct hlist_head *head;
19798c2ecf20Sopenharmony_ci	u32 i;
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	primary_if = batadv_seq_print_text_primary_if_get(seq);
19828c2ecf20Sopenharmony_ci	if (!primary_if)
19838c2ecf20Sopenharmony_ci		goto out;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	seq_printf(seq,
19868c2ecf20Sopenharmony_ci		   "Globally announced TT entries received via the mesh %s\n",
19878c2ecf20Sopenharmony_ci		   net_dev->name);
19888c2ecf20Sopenharmony_ci	seq_puts(seq,
19898c2ecf20Sopenharmony_ci		 "       Client         VID  (TTVN)       Originator      (Curr TTVN) (CRC       ) Flags\n");
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
19928c2ecf20Sopenharmony_ci		head = &hash->table[i];
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci		rcu_read_lock();
19958c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(tt_common_entry,
19968c2ecf20Sopenharmony_ci					 head, hash_entry) {
19978c2ecf20Sopenharmony_ci			tt_global = container_of(tt_common_entry,
19988c2ecf20Sopenharmony_ci						 struct batadv_tt_global_entry,
19998c2ecf20Sopenharmony_ci						 common);
20008c2ecf20Sopenharmony_ci			batadv_tt_global_print_entry(bat_priv, tt_global, seq);
20018c2ecf20Sopenharmony_ci		}
20028c2ecf20Sopenharmony_ci		rcu_read_unlock();
20038c2ecf20Sopenharmony_ci	}
20048c2ecf20Sopenharmony_ciout:
20058c2ecf20Sopenharmony_ci	if (primary_if)
20068c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
20078c2ecf20Sopenharmony_ci	return 0;
20088c2ecf20Sopenharmony_ci}
20098c2ecf20Sopenharmony_ci#endif
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci/**
20128c2ecf20Sopenharmony_ci * batadv_tt_global_dump_subentry() - Dump all TT local entries into a message
20138c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into
20148c2ecf20Sopenharmony_ci * @portid: Port making netlink request
20158c2ecf20Sopenharmony_ci * @seq: Sequence number of netlink message
20168c2ecf20Sopenharmony_ci * @common: tt local & tt global common data
20178c2ecf20Sopenharmony_ci * @orig: Originator node announcing a non-mesh client
20188c2ecf20Sopenharmony_ci * @best: Is the best originator for the TT entry
20198c2ecf20Sopenharmony_ci *
20208c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success
20218c2ecf20Sopenharmony_ci */
20228c2ecf20Sopenharmony_cistatic int
20238c2ecf20Sopenharmony_cibatadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
20248c2ecf20Sopenharmony_ci			       struct batadv_tt_common_entry *common,
20258c2ecf20Sopenharmony_ci			       struct batadv_tt_orig_list_entry *orig,
20268c2ecf20Sopenharmony_ci			       bool best)
20278c2ecf20Sopenharmony_ci{
20288c2ecf20Sopenharmony_ci	u16 flags = (common->flags & (~BATADV_TT_SYNC_MASK)) | orig->flags;
20298c2ecf20Sopenharmony_ci	void *hdr;
20308c2ecf20Sopenharmony_ci	struct batadv_orig_node_vlan *vlan;
20318c2ecf20Sopenharmony_ci	u8 last_ttvn;
20328c2ecf20Sopenharmony_ci	u32 crc;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci	vlan = batadv_orig_node_vlan_get(orig->orig_node,
20358c2ecf20Sopenharmony_ci					 common->vid);
20368c2ecf20Sopenharmony_ci	if (!vlan)
20378c2ecf20Sopenharmony_ci		return 0;
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci	crc = vlan->tt.crc;
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	batadv_orig_node_vlan_put(vlan);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
20448c2ecf20Sopenharmony_ci			  NLM_F_MULTI,
20458c2ecf20Sopenharmony_ci			  BATADV_CMD_GET_TRANSTABLE_GLOBAL);
20468c2ecf20Sopenharmony_ci	if (!hdr)
20478c2ecf20Sopenharmony_ci		return -ENOBUFS;
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	last_ttvn = atomic_read(&orig->orig_node->last_ttvn);
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
20528c2ecf20Sopenharmony_ci	    nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
20538c2ecf20Sopenharmony_ci		    orig->orig_node->orig) ||
20548c2ecf20Sopenharmony_ci	    nla_put_u8(msg, BATADV_ATTR_TT_TTVN, orig->ttvn) ||
20558c2ecf20Sopenharmony_ci	    nla_put_u8(msg, BATADV_ATTR_TT_LAST_TTVN, last_ttvn) ||
20568c2ecf20Sopenharmony_ci	    nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
20578c2ecf20Sopenharmony_ci	    nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
20588c2ecf20Sopenharmony_ci	    nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, flags))
20598c2ecf20Sopenharmony_ci		goto nla_put_failure;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
20628c2ecf20Sopenharmony_ci		goto nla_put_failure;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
20658c2ecf20Sopenharmony_ci	return 0;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci nla_put_failure:
20688c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
20698c2ecf20Sopenharmony_ci	return -EMSGSIZE;
20708c2ecf20Sopenharmony_ci}
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci/**
20738c2ecf20Sopenharmony_ci * batadv_tt_global_dump_entry() - Dump one TT global entry into a message
20748c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into
20758c2ecf20Sopenharmony_ci * @portid: Port making netlink request
20768c2ecf20Sopenharmony_ci * @seq: Sequence number of netlink message
20778c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information
20788c2ecf20Sopenharmony_ci * @common: tt local & tt global common data
20798c2ecf20Sopenharmony_ci * @sub_s: Number of entries to skip
20808c2ecf20Sopenharmony_ci *
20818c2ecf20Sopenharmony_ci * This function assumes the caller holds rcu_read_lock().
20828c2ecf20Sopenharmony_ci *
20838c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success
20848c2ecf20Sopenharmony_ci */
20858c2ecf20Sopenharmony_cistatic int
20868c2ecf20Sopenharmony_cibatadv_tt_global_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
20878c2ecf20Sopenharmony_ci			    struct batadv_priv *bat_priv,
20888c2ecf20Sopenharmony_ci			    struct batadv_tt_common_entry *common, int *sub_s)
20898c2ecf20Sopenharmony_ci{
20908c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
20918c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *global;
20928c2ecf20Sopenharmony_ci	struct hlist_head *head;
20938c2ecf20Sopenharmony_ci	int sub = 0;
20948c2ecf20Sopenharmony_ci	bool best;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	global = container_of(common, struct batadv_tt_global_entry, common);
20978c2ecf20Sopenharmony_ci	best_entry = batadv_transtable_best_orig(bat_priv, global);
20988c2ecf20Sopenharmony_ci	head = &global->orig_list;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_entry, head, list) {
21018c2ecf20Sopenharmony_ci		if (sub++ < *sub_s)
21028c2ecf20Sopenharmony_ci			continue;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci		best = (orig_entry == best_entry);
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci		if (batadv_tt_global_dump_subentry(msg, portid, seq, common,
21078c2ecf20Sopenharmony_ci						   orig_entry, best)) {
21088c2ecf20Sopenharmony_ci			*sub_s = sub - 1;
21098c2ecf20Sopenharmony_ci			return -EMSGSIZE;
21108c2ecf20Sopenharmony_ci		}
21118c2ecf20Sopenharmony_ci	}
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	*sub_s = 0;
21148c2ecf20Sopenharmony_ci	return 0;
21158c2ecf20Sopenharmony_ci}
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci/**
21188c2ecf20Sopenharmony_ci * batadv_tt_global_dump_bucket() - Dump one TT local bucket into a message
21198c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into
21208c2ecf20Sopenharmony_ci * @portid: Port making netlink request
21218c2ecf20Sopenharmony_ci * @seq: Sequence number of netlink message
21228c2ecf20Sopenharmony_ci * @bat_priv: The bat priv with all the soft interface information
21238c2ecf20Sopenharmony_ci * @head: Pointer to the list containing the global tt entries
21248c2ecf20Sopenharmony_ci * @idx_s: Number of entries to skip
21258c2ecf20Sopenharmony_ci * @sub: Number of entries to skip
21268c2ecf20Sopenharmony_ci *
21278c2ecf20Sopenharmony_ci * Return: Error code, or 0 on success
21288c2ecf20Sopenharmony_ci */
21298c2ecf20Sopenharmony_cistatic int
21308c2ecf20Sopenharmony_cibatadv_tt_global_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
21318c2ecf20Sopenharmony_ci			     struct batadv_priv *bat_priv,
21328c2ecf20Sopenharmony_ci			     struct hlist_head *head, int *idx_s, int *sub)
21338c2ecf20Sopenharmony_ci{
21348c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *common;
21358c2ecf20Sopenharmony_ci	int idx = 0;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	rcu_read_lock();
21388c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(common, head, hash_entry) {
21398c2ecf20Sopenharmony_ci		if (idx++ < *idx_s)
21408c2ecf20Sopenharmony_ci			continue;
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci		if (batadv_tt_global_dump_entry(msg, portid, seq, bat_priv,
21438c2ecf20Sopenharmony_ci						common, sub)) {
21448c2ecf20Sopenharmony_ci			rcu_read_unlock();
21458c2ecf20Sopenharmony_ci			*idx_s = idx - 1;
21468c2ecf20Sopenharmony_ci			return -EMSGSIZE;
21478c2ecf20Sopenharmony_ci		}
21488c2ecf20Sopenharmony_ci	}
21498c2ecf20Sopenharmony_ci	rcu_read_unlock();
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	*idx_s = 0;
21528c2ecf20Sopenharmony_ci	*sub = 0;
21538c2ecf20Sopenharmony_ci	return 0;
21548c2ecf20Sopenharmony_ci}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci/**
21578c2ecf20Sopenharmony_ci * batadv_tt_global_dump() -  Dump TT global entries into a message
21588c2ecf20Sopenharmony_ci * @msg: Netlink message to dump into
21598c2ecf20Sopenharmony_ci * @cb: Parameters from query
21608c2ecf20Sopenharmony_ci *
21618c2ecf20Sopenharmony_ci * Return: Error code, or length of message on success
21628c2ecf20Sopenharmony_ci */
21638c2ecf20Sopenharmony_ciint batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb)
21648c2ecf20Sopenharmony_ci{
21658c2ecf20Sopenharmony_ci	struct net *net = sock_net(cb->skb->sk);
21668c2ecf20Sopenharmony_ci	struct net_device *soft_iface;
21678c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
21688c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
21698c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
21708c2ecf20Sopenharmony_ci	struct hlist_head *head;
21718c2ecf20Sopenharmony_ci	int ret;
21728c2ecf20Sopenharmony_ci	int ifindex;
21738c2ecf20Sopenharmony_ci	int bucket = cb->args[0];
21748c2ecf20Sopenharmony_ci	int idx = cb->args[1];
21758c2ecf20Sopenharmony_ci	int sub = cb->args[2];
21768c2ecf20Sopenharmony_ci	int portid = NETLINK_CB(cb->skb).portid;
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
21798c2ecf20Sopenharmony_ci	if (!ifindex)
21808c2ecf20Sopenharmony_ci		return -EINVAL;
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	soft_iface = dev_get_by_index(net, ifindex);
21838c2ecf20Sopenharmony_ci	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
21848c2ecf20Sopenharmony_ci		ret = -ENODEV;
21858c2ecf20Sopenharmony_ci		goto out;
21868c2ecf20Sopenharmony_ci	}
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	bat_priv = netdev_priv(soft_iface);
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
21918c2ecf20Sopenharmony_ci	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
21928c2ecf20Sopenharmony_ci		ret = -ENOENT;
21938c2ecf20Sopenharmony_ci		goto out;
21948c2ecf20Sopenharmony_ci	}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	hash = bat_priv->tt.global_hash;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	while (bucket < hash->size) {
21998c2ecf20Sopenharmony_ci		head = &hash->table[bucket];
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci		if (batadv_tt_global_dump_bucket(msg, portid,
22028c2ecf20Sopenharmony_ci						 cb->nlh->nlmsg_seq, bat_priv,
22038c2ecf20Sopenharmony_ci						 head, &idx, &sub))
22048c2ecf20Sopenharmony_ci			break;
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci		bucket++;
22078c2ecf20Sopenharmony_ci	}
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	ret = msg->len;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci out:
22128c2ecf20Sopenharmony_ci	if (primary_if)
22138c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
22148c2ecf20Sopenharmony_ci	if (soft_iface)
22158c2ecf20Sopenharmony_ci		dev_put(soft_iface);
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci	cb->args[0] = bucket;
22188c2ecf20Sopenharmony_ci	cb->args[1] = idx;
22198c2ecf20Sopenharmony_ci	cb->args[2] = sub;
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	return ret;
22228c2ecf20Sopenharmony_ci}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci/**
22258c2ecf20Sopenharmony_ci * _batadv_tt_global_del_orig_entry() - remove and free an orig_entry
22268c2ecf20Sopenharmony_ci * @tt_global_entry: the global entry to remove the orig_entry from
22278c2ecf20Sopenharmony_ci * @orig_entry: the orig entry to remove and free
22288c2ecf20Sopenharmony_ci *
22298c2ecf20Sopenharmony_ci * Remove an orig_entry from its list in the given tt_global_entry and
22308c2ecf20Sopenharmony_ci * free this orig_entry afterwards.
22318c2ecf20Sopenharmony_ci *
22328c2ecf20Sopenharmony_ci * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is
22338c2ecf20Sopenharmony_ci * part of a list.
22348c2ecf20Sopenharmony_ci */
22358c2ecf20Sopenharmony_cistatic void
22368c2ecf20Sopenharmony_ci_batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
22378c2ecf20Sopenharmony_ci				 struct batadv_tt_orig_list_entry *orig_entry)
22388c2ecf20Sopenharmony_ci{
22398c2ecf20Sopenharmony_ci	lockdep_assert_held(&tt_global_entry->list_lock);
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	batadv_tt_global_size_dec(orig_entry->orig_node,
22428c2ecf20Sopenharmony_ci				  tt_global_entry->common.vid);
22438c2ecf20Sopenharmony_ci	atomic_dec(&tt_global_entry->orig_list_count);
22448c2ecf20Sopenharmony_ci	/* requires holding tt_global_entry->list_lock and orig_entry->list
22458c2ecf20Sopenharmony_ci	 * being part of a list
22468c2ecf20Sopenharmony_ci	 */
22478c2ecf20Sopenharmony_ci	hlist_del_rcu(&orig_entry->list);
22488c2ecf20Sopenharmony_ci	batadv_tt_orig_list_entry_put(orig_entry);
22498c2ecf20Sopenharmony_ci}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci/* deletes the orig list of a tt_global_entry */
22528c2ecf20Sopenharmony_cistatic void
22538c2ecf20Sopenharmony_cibatadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
22548c2ecf20Sopenharmony_ci{
22558c2ecf20Sopenharmony_ci	struct hlist_head *head;
22568c2ecf20Sopenharmony_ci	struct hlist_node *safe;
22578c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	spin_lock_bh(&tt_global_entry->list_lock);
22608c2ecf20Sopenharmony_ci	head = &tt_global_entry->orig_list;
22618c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(orig_entry, safe, head, list)
22628c2ecf20Sopenharmony_ci		_batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry);
22638c2ecf20Sopenharmony_ci	spin_unlock_bh(&tt_global_entry->list_lock);
22648c2ecf20Sopenharmony_ci}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci/**
22678c2ecf20Sopenharmony_ci * batadv_tt_global_del_orig_node() - remove orig_node from a global tt entry
22688c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
22698c2ecf20Sopenharmony_ci * @tt_global_entry: the global entry to remove the orig_node from
22708c2ecf20Sopenharmony_ci * @orig_node: the originator announcing the client
22718c2ecf20Sopenharmony_ci * @message: message to append to the log on deletion
22728c2ecf20Sopenharmony_ci *
22738c2ecf20Sopenharmony_ci * Remove the given orig_node and its according orig_entry from the given
22748c2ecf20Sopenharmony_ci * global tt entry.
22758c2ecf20Sopenharmony_ci */
22768c2ecf20Sopenharmony_cistatic void
22778c2ecf20Sopenharmony_cibatadv_tt_global_del_orig_node(struct batadv_priv *bat_priv,
22788c2ecf20Sopenharmony_ci			       struct batadv_tt_global_entry *tt_global_entry,
22798c2ecf20Sopenharmony_ci			       struct batadv_orig_node *orig_node,
22808c2ecf20Sopenharmony_ci			       const char *message)
22818c2ecf20Sopenharmony_ci{
22828c2ecf20Sopenharmony_ci	struct hlist_head *head;
22838c2ecf20Sopenharmony_ci	struct hlist_node *safe;
22848c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
22858c2ecf20Sopenharmony_ci	unsigned short vid;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	spin_lock_bh(&tt_global_entry->list_lock);
22888c2ecf20Sopenharmony_ci	head = &tt_global_entry->orig_list;
22898c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(orig_entry, safe, head, list) {
22908c2ecf20Sopenharmony_ci		if (orig_entry->orig_node == orig_node) {
22918c2ecf20Sopenharmony_ci			vid = tt_global_entry->common.vid;
22928c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_TT, bat_priv,
22938c2ecf20Sopenharmony_ci				   "Deleting %pM from global tt entry %pM (vid: %d): %s\n",
22948c2ecf20Sopenharmony_ci				   orig_node->orig,
22958c2ecf20Sopenharmony_ci				   tt_global_entry->common.addr,
22968c2ecf20Sopenharmony_ci				   batadv_print_vid(vid), message);
22978c2ecf20Sopenharmony_ci			_batadv_tt_global_del_orig_entry(tt_global_entry,
22988c2ecf20Sopenharmony_ci							 orig_entry);
22998c2ecf20Sopenharmony_ci		}
23008c2ecf20Sopenharmony_ci	}
23018c2ecf20Sopenharmony_ci	spin_unlock_bh(&tt_global_entry->list_lock);
23028c2ecf20Sopenharmony_ci}
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci/* If the client is to be deleted, we check if it is the last origantor entry
23058c2ecf20Sopenharmony_ci * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
23068c2ecf20Sopenharmony_ci * timer, otherwise we simply remove the originator scheduled for deletion.
23078c2ecf20Sopenharmony_ci */
23088c2ecf20Sopenharmony_cistatic void
23098c2ecf20Sopenharmony_cibatadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
23108c2ecf20Sopenharmony_ci			     struct batadv_tt_global_entry *tt_global_entry,
23118c2ecf20Sopenharmony_ci			     struct batadv_orig_node *orig_node,
23128c2ecf20Sopenharmony_ci			     const char *message)
23138c2ecf20Sopenharmony_ci{
23148c2ecf20Sopenharmony_ci	bool last_entry = true;
23158c2ecf20Sopenharmony_ci	struct hlist_head *head;
23168c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	/* no local entry exists, case 1:
23198c2ecf20Sopenharmony_ci	 * Check if this is the last one or if other entries exist.
23208c2ecf20Sopenharmony_ci	 */
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci	rcu_read_lock();
23238c2ecf20Sopenharmony_ci	head = &tt_global_entry->orig_list;
23248c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_entry, head, list) {
23258c2ecf20Sopenharmony_ci		if (orig_entry->orig_node != orig_node) {
23268c2ecf20Sopenharmony_ci			last_entry = false;
23278c2ecf20Sopenharmony_ci			break;
23288c2ecf20Sopenharmony_ci		}
23298c2ecf20Sopenharmony_ci	}
23308c2ecf20Sopenharmony_ci	rcu_read_unlock();
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	if (last_entry) {
23338c2ecf20Sopenharmony_ci		/* its the last one, mark for roaming. */
23348c2ecf20Sopenharmony_ci		tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
23358c2ecf20Sopenharmony_ci		tt_global_entry->roam_at = jiffies;
23368c2ecf20Sopenharmony_ci	} else {
23378c2ecf20Sopenharmony_ci		/* there is another entry, we can simply delete this
23388c2ecf20Sopenharmony_ci		 * one and can still use the other one.
23398c2ecf20Sopenharmony_ci		 */
23408c2ecf20Sopenharmony_ci		batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
23418c2ecf20Sopenharmony_ci					       orig_node, message);
23428c2ecf20Sopenharmony_ci	}
23438c2ecf20Sopenharmony_ci}
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci/**
23468c2ecf20Sopenharmony_ci * batadv_tt_global_del() - remove a client from the global table
23478c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
23488c2ecf20Sopenharmony_ci * @orig_node: an originator serving this client
23498c2ecf20Sopenharmony_ci * @addr: the mac address of the client
23508c2ecf20Sopenharmony_ci * @vid: VLAN identifier
23518c2ecf20Sopenharmony_ci * @message: a message explaining the reason for deleting the client to print
23528c2ecf20Sopenharmony_ci *  for debugging purpose
23538c2ecf20Sopenharmony_ci * @roaming: true if the deletion has been triggered by a roaming event
23548c2ecf20Sopenharmony_ci */
23558c2ecf20Sopenharmony_cistatic void batadv_tt_global_del(struct batadv_priv *bat_priv,
23568c2ecf20Sopenharmony_ci				 struct batadv_orig_node *orig_node,
23578c2ecf20Sopenharmony_ci				 const unsigned char *addr, unsigned short vid,
23588c2ecf20Sopenharmony_ci				 const char *message, bool roaming)
23598c2ecf20Sopenharmony_ci{
23608c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry;
23618c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *local_entry = NULL;
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
23648c2ecf20Sopenharmony_ci	if (!tt_global_entry)
23658c2ecf20Sopenharmony_ci		goto out;
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	if (!roaming) {
23688c2ecf20Sopenharmony_ci		batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
23698c2ecf20Sopenharmony_ci					       orig_node, message);
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci		if (hlist_empty(&tt_global_entry->orig_list))
23728c2ecf20Sopenharmony_ci			batadv_tt_global_free(bat_priv, tt_global_entry,
23738c2ecf20Sopenharmony_ci					      message);
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci		goto out;
23768c2ecf20Sopenharmony_ci	}
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci	/* if we are deleting a global entry due to a roam
23798c2ecf20Sopenharmony_ci	 * event, there are two possibilities:
23808c2ecf20Sopenharmony_ci	 * 1) the client roamed from node A to node B => if there
23818c2ecf20Sopenharmony_ci	 *    is only one originator left for this client, we mark
23828c2ecf20Sopenharmony_ci	 *    it with BATADV_TT_CLIENT_ROAM, we start a timer and we
23838c2ecf20Sopenharmony_ci	 *    wait for node B to claim it. In case of timeout
23848c2ecf20Sopenharmony_ci	 *    the entry is purged.
23858c2ecf20Sopenharmony_ci	 *
23868c2ecf20Sopenharmony_ci	 *    If there are other originators left, we directly delete
23878c2ecf20Sopenharmony_ci	 *    the originator.
23888c2ecf20Sopenharmony_ci	 * 2) the client roamed to us => we can directly delete
23898c2ecf20Sopenharmony_ci	 *    the global entry, since it is useless now.
23908c2ecf20Sopenharmony_ci	 */
23918c2ecf20Sopenharmony_ci	local_entry = batadv_tt_local_hash_find(bat_priv,
23928c2ecf20Sopenharmony_ci						tt_global_entry->common.addr,
23938c2ecf20Sopenharmony_ci						vid);
23948c2ecf20Sopenharmony_ci	if (local_entry) {
23958c2ecf20Sopenharmony_ci		/* local entry exists, case 2: client roamed to us. */
23968c2ecf20Sopenharmony_ci		batadv_tt_global_del_orig_list(tt_global_entry);
23978c2ecf20Sopenharmony_ci		batadv_tt_global_free(bat_priv, tt_global_entry, message);
23988c2ecf20Sopenharmony_ci	} else {
23998c2ecf20Sopenharmony_ci		/* no local entry exists, case 1: check for roaming */
24008c2ecf20Sopenharmony_ci		batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
24018c2ecf20Sopenharmony_ci					     orig_node, message);
24028c2ecf20Sopenharmony_ci	}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ciout:
24058c2ecf20Sopenharmony_ci	if (tt_global_entry)
24068c2ecf20Sopenharmony_ci		batadv_tt_global_entry_put(tt_global_entry);
24078c2ecf20Sopenharmony_ci	if (local_entry)
24088c2ecf20Sopenharmony_ci		batadv_tt_local_entry_put(local_entry);
24098c2ecf20Sopenharmony_ci}
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci/**
24128c2ecf20Sopenharmony_ci * batadv_tt_global_del_orig() - remove all the TT global entries belonging to
24138c2ecf20Sopenharmony_ci *  the given originator matching the provided vid
24148c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
24158c2ecf20Sopenharmony_ci * @orig_node: the originator owning the entries to remove
24168c2ecf20Sopenharmony_ci * @match_vid: the VLAN identifier to match. If negative all the entries will be
24178c2ecf20Sopenharmony_ci *  removed
24188c2ecf20Sopenharmony_ci * @message: debug message to print as "reason"
24198c2ecf20Sopenharmony_ci */
24208c2ecf20Sopenharmony_civoid batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
24218c2ecf20Sopenharmony_ci			       struct batadv_orig_node *orig_node,
24228c2ecf20Sopenharmony_ci			       s32 match_vid,
24238c2ecf20Sopenharmony_ci			       const char *message)
24248c2ecf20Sopenharmony_ci{
24258c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global;
24268c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
24278c2ecf20Sopenharmony_ci	u32 i;
24288c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
24298c2ecf20Sopenharmony_ci	struct hlist_node *safe;
24308c2ecf20Sopenharmony_ci	struct hlist_head *head;
24318c2ecf20Sopenharmony_ci	spinlock_t *list_lock; /* protects write access to the hash lists */
24328c2ecf20Sopenharmony_ci	unsigned short vid;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	if (!hash)
24358c2ecf20Sopenharmony_ci		return;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
24388c2ecf20Sopenharmony_ci		head = &hash->table[i];
24398c2ecf20Sopenharmony_ci		list_lock = &hash->list_locks[i];
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci		spin_lock_bh(list_lock);
24428c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(tt_common_entry, safe,
24438c2ecf20Sopenharmony_ci					  head, hash_entry) {
24448c2ecf20Sopenharmony_ci			/* remove only matching entries */
24458c2ecf20Sopenharmony_ci			if (match_vid >= 0 && tt_common_entry->vid != match_vid)
24468c2ecf20Sopenharmony_ci				continue;
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci			tt_global = container_of(tt_common_entry,
24498c2ecf20Sopenharmony_ci						 struct batadv_tt_global_entry,
24508c2ecf20Sopenharmony_ci						 common);
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci			batadv_tt_global_del_orig_node(bat_priv, tt_global,
24538c2ecf20Sopenharmony_ci						       orig_node, message);
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci			if (hlist_empty(&tt_global->orig_list)) {
24568c2ecf20Sopenharmony_ci				vid = tt_global->common.vid;
24578c2ecf20Sopenharmony_ci				batadv_dbg(BATADV_DBG_TT, bat_priv,
24588c2ecf20Sopenharmony_ci					   "Deleting global tt entry %pM (vid: %d): %s\n",
24598c2ecf20Sopenharmony_ci					   tt_global->common.addr,
24608c2ecf20Sopenharmony_ci					   batadv_print_vid(vid), message);
24618c2ecf20Sopenharmony_ci				hlist_del_rcu(&tt_common_entry->hash_entry);
24628c2ecf20Sopenharmony_ci				batadv_tt_global_entry_put(tt_global);
24638c2ecf20Sopenharmony_ci			}
24648c2ecf20Sopenharmony_ci		}
24658c2ecf20Sopenharmony_ci		spin_unlock_bh(list_lock);
24668c2ecf20Sopenharmony_ci	}
24678c2ecf20Sopenharmony_ci	clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
24688c2ecf20Sopenharmony_ci}
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_cistatic bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
24718c2ecf20Sopenharmony_ci				      char **msg)
24728c2ecf20Sopenharmony_ci{
24738c2ecf20Sopenharmony_ci	bool purge = false;
24748c2ecf20Sopenharmony_ci	unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT;
24758c2ecf20Sopenharmony_ci	unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_ci	if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
24788c2ecf20Sopenharmony_ci	    batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
24798c2ecf20Sopenharmony_ci		purge = true;
24808c2ecf20Sopenharmony_ci		*msg = "Roaming timeout\n";
24818c2ecf20Sopenharmony_ci	}
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci	if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
24848c2ecf20Sopenharmony_ci	    batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
24858c2ecf20Sopenharmony_ci		purge = true;
24868c2ecf20Sopenharmony_ci		*msg = "Temporary client timeout\n";
24878c2ecf20Sopenharmony_ci	}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	return purge;
24908c2ecf20Sopenharmony_ci}
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_cistatic void batadv_tt_global_purge(struct batadv_priv *bat_priv)
24938c2ecf20Sopenharmony_ci{
24948c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
24958c2ecf20Sopenharmony_ci	struct hlist_head *head;
24968c2ecf20Sopenharmony_ci	struct hlist_node *node_tmp;
24978c2ecf20Sopenharmony_ci	spinlock_t *list_lock; /* protects write access to the hash lists */
24988c2ecf20Sopenharmony_ci	u32 i;
24998c2ecf20Sopenharmony_ci	char *msg = NULL;
25008c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common;
25018c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global;
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
25048c2ecf20Sopenharmony_ci		head = &hash->table[i];
25058c2ecf20Sopenharmony_ci		list_lock = &hash->list_locks[i];
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci		spin_lock_bh(list_lock);
25088c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(tt_common, node_tmp, head,
25098c2ecf20Sopenharmony_ci					  hash_entry) {
25108c2ecf20Sopenharmony_ci			tt_global = container_of(tt_common,
25118c2ecf20Sopenharmony_ci						 struct batadv_tt_global_entry,
25128c2ecf20Sopenharmony_ci						 common);
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci			if (!batadv_tt_global_to_purge(tt_global, &msg))
25158c2ecf20Sopenharmony_ci				continue;
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_TT, bat_priv,
25188c2ecf20Sopenharmony_ci				   "Deleting global tt entry %pM (vid: %d): %s\n",
25198c2ecf20Sopenharmony_ci				   tt_global->common.addr,
25208c2ecf20Sopenharmony_ci				   batadv_print_vid(tt_global->common.vid),
25218c2ecf20Sopenharmony_ci				   msg);
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci			hlist_del_rcu(&tt_common->hash_entry);
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci			batadv_tt_global_entry_put(tt_global);
25268c2ecf20Sopenharmony_ci		}
25278c2ecf20Sopenharmony_ci		spin_unlock_bh(list_lock);
25288c2ecf20Sopenharmony_ci	}
25298c2ecf20Sopenharmony_ci}
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_cistatic void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
25328c2ecf20Sopenharmony_ci{
25338c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash;
25348c2ecf20Sopenharmony_ci	spinlock_t *list_lock; /* protects write access to the hash lists */
25358c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
25368c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global;
25378c2ecf20Sopenharmony_ci	struct hlist_node *node_tmp;
25388c2ecf20Sopenharmony_ci	struct hlist_head *head;
25398c2ecf20Sopenharmony_ci	u32 i;
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	if (!bat_priv->tt.global_hash)
25428c2ecf20Sopenharmony_ci		return;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	hash = bat_priv->tt.global_hash;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
25478c2ecf20Sopenharmony_ci		head = &hash->table[i];
25488c2ecf20Sopenharmony_ci		list_lock = &hash->list_locks[i];
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci		spin_lock_bh(list_lock);
25518c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(tt_common_entry, node_tmp,
25528c2ecf20Sopenharmony_ci					  head, hash_entry) {
25538c2ecf20Sopenharmony_ci			hlist_del_rcu(&tt_common_entry->hash_entry);
25548c2ecf20Sopenharmony_ci			tt_global = container_of(tt_common_entry,
25558c2ecf20Sopenharmony_ci						 struct batadv_tt_global_entry,
25568c2ecf20Sopenharmony_ci						 common);
25578c2ecf20Sopenharmony_ci			batadv_tt_global_entry_put(tt_global);
25588c2ecf20Sopenharmony_ci		}
25598c2ecf20Sopenharmony_ci		spin_unlock_bh(list_lock);
25608c2ecf20Sopenharmony_ci	}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	batadv_hash_destroy(hash);
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	bat_priv->tt.global_hash = NULL;
25658c2ecf20Sopenharmony_ci}
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_cistatic bool
25688c2ecf20Sopenharmony_ci_batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
25698c2ecf20Sopenharmony_ci		       struct batadv_tt_global_entry *tt_global_entry)
25708c2ecf20Sopenharmony_ci{
25718c2ecf20Sopenharmony_ci	if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
25728c2ecf20Sopenharmony_ci	    tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
25738c2ecf20Sopenharmony_ci		return true;
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	/* check if the two clients are marked as isolated */
25768c2ecf20Sopenharmony_ci	if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
25778c2ecf20Sopenharmony_ci	    tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
25788c2ecf20Sopenharmony_ci		return true;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	return false;
25818c2ecf20Sopenharmony_ci}
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci/**
25848c2ecf20Sopenharmony_ci * batadv_transtable_search() - get the mesh destination for a given client
25858c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
25868c2ecf20Sopenharmony_ci * @src: mac address of the source client
25878c2ecf20Sopenharmony_ci * @addr: mac address of the destination client
25888c2ecf20Sopenharmony_ci * @vid: VLAN identifier
25898c2ecf20Sopenharmony_ci *
25908c2ecf20Sopenharmony_ci * Return: a pointer to the originator that was selected as destination in the
25918c2ecf20Sopenharmony_ci * mesh for contacting the client 'addr', NULL otherwise.
25928c2ecf20Sopenharmony_ci * In case of multiple originators serving the same client, the function returns
25938c2ecf20Sopenharmony_ci * the best one (best in terms of metric towards the destination node).
25948c2ecf20Sopenharmony_ci *
25958c2ecf20Sopenharmony_ci * If the two clients are AP isolated the function returns NULL.
25968c2ecf20Sopenharmony_ci */
25978c2ecf20Sopenharmony_cistruct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
25988c2ecf20Sopenharmony_ci						  const u8 *src,
25998c2ecf20Sopenharmony_ci						  const u8 *addr,
26008c2ecf20Sopenharmony_ci						  unsigned short vid)
26018c2ecf20Sopenharmony_ci{
26028c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry = NULL;
26038c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry = NULL;
26048c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node = NULL;
26058c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *best_entry;
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
26088c2ecf20Sopenharmony_ci		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
26098c2ecf20Sopenharmony_ci		if (!tt_local_entry ||
26108c2ecf20Sopenharmony_ci		    (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
26118c2ecf20Sopenharmony_ci			goto out;
26128c2ecf20Sopenharmony_ci	}
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
26158c2ecf20Sopenharmony_ci	if (!tt_global_entry)
26168c2ecf20Sopenharmony_ci		goto out;
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	/* check whether the clients should not communicate due to AP
26198c2ecf20Sopenharmony_ci	 * isolation
26208c2ecf20Sopenharmony_ci	 */
26218c2ecf20Sopenharmony_ci	if (tt_local_entry &&
26228c2ecf20Sopenharmony_ci	    _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
26238c2ecf20Sopenharmony_ci		goto out;
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	rcu_read_lock();
26268c2ecf20Sopenharmony_ci	best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
26278c2ecf20Sopenharmony_ci	/* found anything? */
26288c2ecf20Sopenharmony_ci	if (best_entry)
26298c2ecf20Sopenharmony_ci		orig_node = best_entry->orig_node;
26308c2ecf20Sopenharmony_ci	if (orig_node && !kref_get_unless_zero(&orig_node->refcount))
26318c2ecf20Sopenharmony_ci		orig_node = NULL;
26328c2ecf20Sopenharmony_ci	rcu_read_unlock();
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ciout:
26358c2ecf20Sopenharmony_ci	if (tt_global_entry)
26368c2ecf20Sopenharmony_ci		batadv_tt_global_entry_put(tt_global_entry);
26378c2ecf20Sopenharmony_ci	if (tt_local_entry)
26388c2ecf20Sopenharmony_ci		batadv_tt_local_entry_put(tt_local_entry);
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci	return orig_node;
26418c2ecf20Sopenharmony_ci}
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci/**
26448c2ecf20Sopenharmony_ci * batadv_tt_global_crc() - calculates the checksum of the local table belonging
26458c2ecf20Sopenharmony_ci *  to the given orig_node
26468c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
26478c2ecf20Sopenharmony_ci * @orig_node: originator for which the CRC should be computed
26488c2ecf20Sopenharmony_ci * @vid: VLAN identifier for which the CRC32 has to be computed
26498c2ecf20Sopenharmony_ci *
26508c2ecf20Sopenharmony_ci * This function computes the checksum for the global table corresponding to a
26518c2ecf20Sopenharmony_ci * specific originator. In particular, the checksum is computed as follows: For
26528c2ecf20Sopenharmony_ci * each client connected to the originator the CRC32C of the MAC address and the
26538c2ecf20Sopenharmony_ci * VID is computed and then all the CRC32Cs of the various clients are xor'ed
26548c2ecf20Sopenharmony_ci * together.
26558c2ecf20Sopenharmony_ci *
26568c2ecf20Sopenharmony_ci * The idea behind is that CRC32C should be used as much as possible in order to
26578c2ecf20Sopenharmony_ci * produce a unique hash of the table, but since the order which is used to feed
26588c2ecf20Sopenharmony_ci * the CRC32C function affects the result and since every node in the network
26598c2ecf20Sopenharmony_ci * probably sorts the clients differently, the hash function cannot be directly
26608c2ecf20Sopenharmony_ci * computed over the entire table. Hence the CRC32C is used only on
26618c2ecf20Sopenharmony_ci * the single client entry, while all the results are then xor'ed together
26628c2ecf20Sopenharmony_ci * because the XOR operation can combine them all while trying to reduce the
26638c2ecf20Sopenharmony_ci * noise as much as possible.
26648c2ecf20Sopenharmony_ci *
26658c2ecf20Sopenharmony_ci * Return: the checksum of the global table of a given originator.
26668c2ecf20Sopenharmony_ci */
26678c2ecf20Sopenharmony_cistatic u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
26688c2ecf20Sopenharmony_ci				struct batadv_orig_node *orig_node,
26698c2ecf20Sopenharmony_ci				unsigned short vid)
26708c2ecf20Sopenharmony_ci{
26718c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
26728c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *tt_orig;
26738c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common;
26748c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global;
26758c2ecf20Sopenharmony_ci	struct hlist_head *head;
26768c2ecf20Sopenharmony_ci	u32 i, crc_tmp, crc = 0;
26778c2ecf20Sopenharmony_ci	u8 flags;
26788c2ecf20Sopenharmony_ci	__be16 tmp_vid;
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
26818c2ecf20Sopenharmony_ci		head = &hash->table[i];
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci		rcu_read_lock();
26848c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
26858c2ecf20Sopenharmony_ci			tt_global = container_of(tt_common,
26868c2ecf20Sopenharmony_ci						 struct batadv_tt_global_entry,
26878c2ecf20Sopenharmony_ci						 common);
26888c2ecf20Sopenharmony_ci			/* compute the CRC only for entries belonging to the
26898c2ecf20Sopenharmony_ci			 * VLAN identified by the vid passed as parameter
26908c2ecf20Sopenharmony_ci			 */
26918c2ecf20Sopenharmony_ci			if (tt_common->vid != vid)
26928c2ecf20Sopenharmony_ci				continue;
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci			/* Roaming clients are in the global table for
26958c2ecf20Sopenharmony_ci			 * consistency only. They don't have to be
26968c2ecf20Sopenharmony_ci			 * taken into account while computing the
26978c2ecf20Sopenharmony_ci			 * global crc
26988c2ecf20Sopenharmony_ci			 */
26998c2ecf20Sopenharmony_ci			if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
27008c2ecf20Sopenharmony_ci				continue;
27018c2ecf20Sopenharmony_ci			/* Temporary clients have not been announced yet, so
27028c2ecf20Sopenharmony_ci			 * they have to be skipped while computing the global
27038c2ecf20Sopenharmony_ci			 * crc
27048c2ecf20Sopenharmony_ci			 */
27058c2ecf20Sopenharmony_ci			if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
27068c2ecf20Sopenharmony_ci				continue;
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci			/* find out if this global entry is announced by this
27098c2ecf20Sopenharmony_ci			 * originator
27108c2ecf20Sopenharmony_ci			 */
27118c2ecf20Sopenharmony_ci			tt_orig = batadv_tt_global_orig_entry_find(tt_global,
27128c2ecf20Sopenharmony_ci								   orig_node);
27138c2ecf20Sopenharmony_ci			if (!tt_orig)
27148c2ecf20Sopenharmony_ci				continue;
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci			/* use network order to read the VID: this ensures that
27178c2ecf20Sopenharmony_ci			 * every node reads the bytes in the same order.
27188c2ecf20Sopenharmony_ci			 */
27198c2ecf20Sopenharmony_ci			tmp_vid = htons(tt_common->vid);
27208c2ecf20Sopenharmony_ci			crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci			/* compute the CRC on flags that have to be kept in sync
27238c2ecf20Sopenharmony_ci			 * among nodes
27248c2ecf20Sopenharmony_ci			 */
27258c2ecf20Sopenharmony_ci			flags = tt_orig->flags;
27268c2ecf20Sopenharmony_ci			crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci			crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci			batadv_tt_orig_list_entry_put(tt_orig);
27318c2ecf20Sopenharmony_ci		}
27328c2ecf20Sopenharmony_ci		rcu_read_unlock();
27338c2ecf20Sopenharmony_ci	}
27348c2ecf20Sopenharmony_ci
27358c2ecf20Sopenharmony_ci	return crc;
27368c2ecf20Sopenharmony_ci}
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci/**
27398c2ecf20Sopenharmony_ci * batadv_tt_local_crc() - calculates the checksum of the local table
27408c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
27418c2ecf20Sopenharmony_ci * @vid: VLAN identifier for which the CRC32 has to be computed
27428c2ecf20Sopenharmony_ci *
27438c2ecf20Sopenharmony_ci * For details about the computation, please refer to the documentation for
27448c2ecf20Sopenharmony_ci * batadv_tt_global_crc().
27458c2ecf20Sopenharmony_ci *
27468c2ecf20Sopenharmony_ci * Return: the checksum of the local table
27478c2ecf20Sopenharmony_ci */
27488c2ecf20Sopenharmony_cistatic u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
27498c2ecf20Sopenharmony_ci			       unsigned short vid)
27508c2ecf20Sopenharmony_ci{
27518c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
27528c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common;
27538c2ecf20Sopenharmony_ci	struct hlist_head *head;
27548c2ecf20Sopenharmony_ci	u32 i, crc_tmp, crc = 0;
27558c2ecf20Sopenharmony_ci	u8 flags;
27568c2ecf20Sopenharmony_ci	__be16 tmp_vid;
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
27598c2ecf20Sopenharmony_ci		head = &hash->table[i];
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci		rcu_read_lock();
27628c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
27638c2ecf20Sopenharmony_ci			/* compute the CRC only for entries belonging to the
27648c2ecf20Sopenharmony_ci			 * VLAN identified by vid
27658c2ecf20Sopenharmony_ci			 */
27668c2ecf20Sopenharmony_ci			if (tt_common->vid != vid)
27678c2ecf20Sopenharmony_ci				continue;
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_ci			/* not yet committed clients have not to be taken into
27708c2ecf20Sopenharmony_ci			 * account while computing the CRC
27718c2ecf20Sopenharmony_ci			 */
27728c2ecf20Sopenharmony_ci			if (tt_common->flags & BATADV_TT_CLIENT_NEW)
27738c2ecf20Sopenharmony_ci				continue;
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci			/* use network order to read the VID: this ensures that
27768c2ecf20Sopenharmony_ci			 * every node reads the bytes in the same order.
27778c2ecf20Sopenharmony_ci			 */
27788c2ecf20Sopenharmony_ci			tmp_vid = htons(tt_common->vid);
27798c2ecf20Sopenharmony_ci			crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci			/* compute the CRC on flags that have to be kept in sync
27828c2ecf20Sopenharmony_ci			 * among nodes
27838c2ecf20Sopenharmony_ci			 */
27848c2ecf20Sopenharmony_ci			flags = tt_common->flags & BATADV_TT_SYNC_MASK;
27858c2ecf20Sopenharmony_ci			crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
27868c2ecf20Sopenharmony_ci
27878c2ecf20Sopenharmony_ci			crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
27888c2ecf20Sopenharmony_ci		}
27898c2ecf20Sopenharmony_ci		rcu_read_unlock();
27908c2ecf20Sopenharmony_ci	}
27918c2ecf20Sopenharmony_ci
27928c2ecf20Sopenharmony_ci	return crc;
27938c2ecf20Sopenharmony_ci}
27948c2ecf20Sopenharmony_ci
27958c2ecf20Sopenharmony_ci/**
27968c2ecf20Sopenharmony_ci * batadv_tt_req_node_release() - free tt_req node entry
27978c2ecf20Sopenharmony_ci * @ref: kref pointer of the tt req_node entry
27988c2ecf20Sopenharmony_ci */
27998c2ecf20Sopenharmony_cistatic void batadv_tt_req_node_release(struct kref *ref)
28008c2ecf20Sopenharmony_ci{
28018c2ecf20Sopenharmony_ci	struct batadv_tt_req_node *tt_req_node;
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	tt_req_node = container_of(ref, struct batadv_tt_req_node, refcount);
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci	kmem_cache_free(batadv_tt_req_cache, tt_req_node);
28068c2ecf20Sopenharmony_ci}
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci/**
28098c2ecf20Sopenharmony_ci * batadv_tt_req_node_put() - decrement the tt_req_node refcounter and
28108c2ecf20Sopenharmony_ci *  possibly release it
28118c2ecf20Sopenharmony_ci * @tt_req_node: tt_req_node to be free'd
28128c2ecf20Sopenharmony_ci */
28138c2ecf20Sopenharmony_cistatic void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node)
28148c2ecf20Sopenharmony_ci{
28158c2ecf20Sopenharmony_ci	if (!tt_req_node)
28168c2ecf20Sopenharmony_ci		return;
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci	kref_put(&tt_req_node->refcount, batadv_tt_req_node_release);
28198c2ecf20Sopenharmony_ci}
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_cistatic void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
28228c2ecf20Sopenharmony_ci{
28238c2ecf20Sopenharmony_ci	struct batadv_tt_req_node *node;
28248c2ecf20Sopenharmony_ci	struct hlist_node *safe;
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.req_list_lock);
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
28298c2ecf20Sopenharmony_ci		hlist_del_init(&node->list);
28308c2ecf20Sopenharmony_ci		batadv_tt_req_node_put(node);
28318c2ecf20Sopenharmony_ci	}
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.req_list_lock);
28348c2ecf20Sopenharmony_ci}
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_cistatic void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv,
28378c2ecf20Sopenharmony_ci				       struct batadv_orig_node *orig_node,
28388c2ecf20Sopenharmony_ci				       const void *tt_buff,
28398c2ecf20Sopenharmony_ci				       u16 tt_buff_len)
28408c2ecf20Sopenharmony_ci{
28418c2ecf20Sopenharmony_ci	/* Replace the old buffer only if I received something in the
28428c2ecf20Sopenharmony_ci	 * last OGM (the OGM could carry no changes)
28438c2ecf20Sopenharmony_ci	 */
28448c2ecf20Sopenharmony_ci	spin_lock_bh(&orig_node->tt_buff_lock);
28458c2ecf20Sopenharmony_ci	if (tt_buff_len > 0) {
28468c2ecf20Sopenharmony_ci		kfree(orig_node->tt_buff);
28478c2ecf20Sopenharmony_ci		orig_node->tt_buff_len = 0;
28488c2ecf20Sopenharmony_ci		orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
28498c2ecf20Sopenharmony_ci		if (orig_node->tt_buff) {
28508c2ecf20Sopenharmony_ci			memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
28518c2ecf20Sopenharmony_ci			orig_node->tt_buff_len = tt_buff_len;
28528c2ecf20Sopenharmony_ci		}
28538c2ecf20Sopenharmony_ci	}
28548c2ecf20Sopenharmony_ci	spin_unlock_bh(&orig_node->tt_buff_lock);
28558c2ecf20Sopenharmony_ci}
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_cistatic void batadv_tt_req_purge(struct batadv_priv *bat_priv)
28588c2ecf20Sopenharmony_ci{
28598c2ecf20Sopenharmony_ci	struct batadv_tt_req_node *node;
28608c2ecf20Sopenharmony_ci	struct hlist_node *safe;
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.req_list_lock);
28638c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
28648c2ecf20Sopenharmony_ci		if (batadv_has_timed_out(node->issued_at,
28658c2ecf20Sopenharmony_ci					 BATADV_TT_REQUEST_TIMEOUT)) {
28668c2ecf20Sopenharmony_ci			hlist_del_init(&node->list);
28678c2ecf20Sopenharmony_ci			batadv_tt_req_node_put(node);
28688c2ecf20Sopenharmony_ci		}
28698c2ecf20Sopenharmony_ci	}
28708c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.req_list_lock);
28718c2ecf20Sopenharmony_ci}
28728c2ecf20Sopenharmony_ci
28738c2ecf20Sopenharmony_ci/**
28748c2ecf20Sopenharmony_ci * batadv_tt_req_node_new() - search and possibly create a tt_req_node object
28758c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
28768c2ecf20Sopenharmony_ci * @orig_node: orig node this request is being issued for
28778c2ecf20Sopenharmony_ci *
28788c2ecf20Sopenharmony_ci * Return: the pointer to the new tt_req_node struct if no request
28798c2ecf20Sopenharmony_ci * has already been issued for this orig_node, NULL otherwise.
28808c2ecf20Sopenharmony_ci */
28818c2ecf20Sopenharmony_cistatic struct batadv_tt_req_node *
28828c2ecf20Sopenharmony_cibatadv_tt_req_node_new(struct batadv_priv *bat_priv,
28838c2ecf20Sopenharmony_ci		       struct batadv_orig_node *orig_node)
28848c2ecf20Sopenharmony_ci{
28858c2ecf20Sopenharmony_ci	struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.req_list_lock);
28888c2ecf20Sopenharmony_ci	hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) {
28898c2ecf20Sopenharmony_ci		if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
28908c2ecf20Sopenharmony_ci		    !batadv_has_timed_out(tt_req_node_tmp->issued_at,
28918c2ecf20Sopenharmony_ci					  BATADV_TT_REQUEST_TIMEOUT))
28928c2ecf20Sopenharmony_ci			goto unlock;
28938c2ecf20Sopenharmony_ci	}
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	tt_req_node = kmem_cache_alloc(batadv_tt_req_cache, GFP_ATOMIC);
28968c2ecf20Sopenharmony_ci	if (!tt_req_node)
28978c2ecf20Sopenharmony_ci		goto unlock;
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci	kref_init(&tt_req_node->refcount);
29008c2ecf20Sopenharmony_ci	ether_addr_copy(tt_req_node->addr, orig_node->orig);
29018c2ecf20Sopenharmony_ci	tt_req_node->issued_at = jiffies;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	kref_get(&tt_req_node->refcount);
29048c2ecf20Sopenharmony_ci	hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list);
29058c2ecf20Sopenharmony_ciunlock:
29068c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.req_list_lock);
29078c2ecf20Sopenharmony_ci	return tt_req_node;
29088c2ecf20Sopenharmony_ci}
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci/**
29118c2ecf20Sopenharmony_ci * batadv_tt_local_valid() - verify local tt entry and get flags
29128c2ecf20Sopenharmony_ci * @entry_ptr: to be checked local tt entry
29138c2ecf20Sopenharmony_ci * @data_ptr: not used but definition required to satisfy the callback prototype
29148c2ecf20Sopenharmony_ci * @flags: a pointer to store TT flags for this client to
29158c2ecf20Sopenharmony_ci *
29168c2ecf20Sopenharmony_ci * Checks the validity of the given local TT entry. If it is, then the provided
29178c2ecf20Sopenharmony_ci * flags pointer is updated.
29188c2ecf20Sopenharmony_ci *
29198c2ecf20Sopenharmony_ci * Return: true if the entry is a valid, false otherwise.
29208c2ecf20Sopenharmony_ci */
29218c2ecf20Sopenharmony_cistatic bool batadv_tt_local_valid(const void *entry_ptr,
29228c2ecf20Sopenharmony_ci				  const void *data_ptr,
29238c2ecf20Sopenharmony_ci				  u8 *flags)
29248c2ecf20Sopenharmony_ci{
29258c2ecf20Sopenharmony_ci	const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci	if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
29288c2ecf20Sopenharmony_ci		return false;
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci	if (flags)
29318c2ecf20Sopenharmony_ci		*flags = tt_common_entry->flags;
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci	return true;
29348c2ecf20Sopenharmony_ci}
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci/**
29378c2ecf20Sopenharmony_ci * batadv_tt_global_valid() - verify global tt entry and get flags
29388c2ecf20Sopenharmony_ci * @entry_ptr: to be checked global tt entry
29398c2ecf20Sopenharmony_ci * @data_ptr: an orig_node object (may be NULL)
29408c2ecf20Sopenharmony_ci * @flags: a pointer to store TT flags for this client to
29418c2ecf20Sopenharmony_ci *
29428c2ecf20Sopenharmony_ci * Checks the validity of the given global TT entry. If it is, then the provided
29438c2ecf20Sopenharmony_ci * flags pointer is updated either with the common (summed) TT flags if data_ptr
29448c2ecf20Sopenharmony_ci * is NULL or the specific, per originator TT flags otherwise.
29458c2ecf20Sopenharmony_ci *
29468c2ecf20Sopenharmony_ci * Return: true if the entry is a valid, false otherwise.
29478c2ecf20Sopenharmony_ci */
29488c2ecf20Sopenharmony_cistatic bool batadv_tt_global_valid(const void *entry_ptr,
29498c2ecf20Sopenharmony_ci				   const void *data_ptr,
29508c2ecf20Sopenharmony_ci				   u8 *flags)
29518c2ecf20Sopenharmony_ci{
29528c2ecf20Sopenharmony_ci	const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
29538c2ecf20Sopenharmony_ci	const struct batadv_tt_global_entry *tt_global_entry;
29548c2ecf20Sopenharmony_ci	const struct batadv_orig_node *orig_node = data_ptr;
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci	if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
29578c2ecf20Sopenharmony_ci	    tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
29588c2ecf20Sopenharmony_ci		return false;
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_ci	tt_global_entry = container_of(tt_common_entry,
29618c2ecf20Sopenharmony_ci				       struct batadv_tt_global_entry,
29628c2ecf20Sopenharmony_ci				       common);
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node,
29658c2ecf20Sopenharmony_ci					       flags);
29668c2ecf20Sopenharmony_ci}
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci/**
29698c2ecf20Sopenharmony_ci * batadv_tt_tvlv_generate() - fill the tvlv buff with the tt entries from the
29708c2ecf20Sopenharmony_ci *  specified tt hash
29718c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
29728c2ecf20Sopenharmony_ci * @hash: hash table containing the tt entries
29738c2ecf20Sopenharmony_ci * @tt_len: expected tvlv tt data buffer length in number of bytes
29748c2ecf20Sopenharmony_ci * @tvlv_buff: pointer to the buffer to fill with the TT data
29758c2ecf20Sopenharmony_ci * @valid_cb: function to filter tt change entries and to return TT flags
29768c2ecf20Sopenharmony_ci * @cb_data: data passed to the filter function as argument
29778c2ecf20Sopenharmony_ci *
29788c2ecf20Sopenharmony_ci * Fills the tvlv buff with the tt entries from the specified hash. If valid_cb
29798c2ecf20Sopenharmony_ci * is not provided then this becomes a no-op.
29808c2ecf20Sopenharmony_ci */
29818c2ecf20Sopenharmony_cistatic void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
29828c2ecf20Sopenharmony_ci				    struct batadv_hashtable *hash,
29838c2ecf20Sopenharmony_ci				    void *tvlv_buff, u16 tt_len,
29848c2ecf20Sopenharmony_ci				    bool (*valid_cb)(const void *,
29858c2ecf20Sopenharmony_ci						     const void *,
29868c2ecf20Sopenharmony_ci						     u8 *flags),
29878c2ecf20Sopenharmony_ci				    void *cb_data)
29888c2ecf20Sopenharmony_ci{
29898c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
29908c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_change *tt_change;
29918c2ecf20Sopenharmony_ci	struct hlist_head *head;
29928c2ecf20Sopenharmony_ci	u16 tt_tot, tt_num_entries = 0;
29938c2ecf20Sopenharmony_ci	u8 flags;
29948c2ecf20Sopenharmony_ci	bool ret;
29958c2ecf20Sopenharmony_ci	u32 i;
29968c2ecf20Sopenharmony_ci
29978c2ecf20Sopenharmony_ci	tt_tot = batadv_tt_entries(tt_len);
29988c2ecf20Sopenharmony_ci	tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff;
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci	if (!valid_cb)
30018c2ecf20Sopenharmony_ci		return;
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci	rcu_read_lock();
30048c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
30058c2ecf20Sopenharmony_ci		head = &hash->table[i];
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(tt_common_entry,
30088c2ecf20Sopenharmony_ci					 head, hash_entry) {
30098c2ecf20Sopenharmony_ci			if (tt_tot == tt_num_entries)
30108c2ecf20Sopenharmony_ci				break;
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci			ret = valid_cb(tt_common_entry, cb_data, &flags);
30138c2ecf20Sopenharmony_ci			if (!ret)
30148c2ecf20Sopenharmony_ci				continue;
30158c2ecf20Sopenharmony_ci
30168c2ecf20Sopenharmony_ci			ether_addr_copy(tt_change->addr, tt_common_entry->addr);
30178c2ecf20Sopenharmony_ci			tt_change->flags = flags;
30188c2ecf20Sopenharmony_ci			tt_change->vid = htons(tt_common_entry->vid);
30198c2ecf20Sopenharmony_ci			memset(tt_change->reserved, 0,
30208c2ecf20Sopenharmony_ci			       sizeof(tt_change->reserved));
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci			tt_num_entries++;
30238c2ecf20Sopenharmony_ci			tt_change++;
30248c2ecf20Sopenharmony_ci		}
30258c2ecf20Sopenharmony_ci	}
30268c2ecf20Sopenharmony_ci	rcu_read_unlock();
30278c2ecf20Sopenharmony_ci}
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci/**
30308c2ecf20Sopenharmony_ci * batadv_tt_global_check_crc() - check if all the CRCs are correct
30318c2ecf20Sopenharmony_ci * @orig_node: originator for which the CRCs have to be checked
30328c2ecf20Sopenharmony_ci * @tt_vlan: pointer to the first tvlv VLAN entry
30338c2ecf20Sopenharmony_ci * @num_vlan: number of tvlv VLAN entries
30348c2ecf20Sopenharmony_ci *
30358c2ecf20Sopenharmony_ci * Return: true if all the received CRCs match the locally stored ones, false
30368c2ecf20Sopenharmony_ci * otherwise
30378c2ecf20Sopenharmony_ci */
30388c2ecf20Sopenharmony_cistatic bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
30398c2ecf20Sopenharmony_ci				       struct batadv_tvlv_tt_vlan_data *tt_vlan,
30408c2ecf20Sopenharmony_ci				       u16 num_vlan)
30418c2ecf20Sopenharmony_ci{
30428c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
30438c2ecf20Sopenharmony_ci	struct batadv_orig_node_vlan *vlan;
30448c2ecf20Sopenharmony_ci	int i, orig_num_vlan;
30458c2ecf20Sopenharmony_ci	u32 crc;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci	/* check if each received CRC matches the locally stored one */
30488c2ecf20Sopenharmony_ci	for (i = 0; i < num_vlan; i++) {
30498c2ecf20Sopenharmony_ci		tt_vlan_tmp = tt_vlan + i;
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci		/* if orig_node is a backbone node for this VLAN, don't check
30528c2ecf20Sopenharmony_ci		 * the CRC as we ignore all the global entries over it
30538c2ecf20Sopenharmony_ci		 */
30548c2ecf20Sopenharmony_ci		if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv,
30558c2ecf20Sopenharmony_ci						   orig_node->orig,
30568c2ecf20Sopenharmony_ci						   ntohs(tt_vlan_tmp->vid)))
30578c2ecf20Sopenharmony_ci			continue;
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_ci		vlan = batadv_orig_node_vlan_get(orig_node,
30608c2ecf20Sopenharmony_ci						 ntohs(tt_vlan_tmp->vid));
30618c2ecf20Sopenharmony_ci		if (!vlan)
30628c2ecf20Sopenharmony_ci			return false;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci		crc = vlan->tt.crc;
30658c2ecf20Sopenharmony_ci		batadv_orig_node_vlan_put(vlan);
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci		if (crc != ntohl(tt_vlan_tmp->crc))
30688c2ecf20Sopenharmony_ci			return false;
30698c2ecf20Sopenharmony_ci	}
30708c2ecf20Sopenharmony_ci
30718c2ecf20Sopenharmony_ci	/* check if any excess VLANs exist locally for the originator
30728c2ecf20Sopenharmony_ci	 * which are not mentioned in the TVLV from the originator.
30738c2ecf20Sopenharmony_ci	 */
30748c2ecf20Sopenharmony_ci	rcu_read_lock();
30758c2ecf20Sopenharmony_ci	orig_num_vlan = 0;
30768c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list)
30778c2ecf20Sopenharmony_ci		orig_num_vlan++;
30788c2ecf20Sopenharmony_ci	rcu_read_unlock();
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci	if (orig_num_vlan > num_vlan)
30818c2ecf20Sopenharmony_ci		return false;
30828c2ecf20Sopenharmony_ci
30838c2ecf20Sopenharmony_ci	return true;
30848c2ecf20Sopenharmony_ci}
30858c2ecf20Sopenharmony_ci
30868c2ecf20Sopenharmony_ci/**
30878c2ecf20Sopenharmony_ci * batadv_tt_local_update_crc() - update all the local CRCs
30888c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
30898c2ecf20Sopenharmony_ci */
30908c2ecf20Sopenharmony_cistatic void batadv_tt_local_update_crc(struct batadv_priv *bat_priv)
30918c2ecf20Sopenharmony_ci{
30928c2ecf20Sopenharmony_ci	struct batadv_softif_vlan *vlan;
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci	/* recompute the global CRC for each VLAN */
30958c2ecf20Sopenharmony_ci	rcu_read_lock();
30968c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
30978c2ecf20Sopenharmony_ci		vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid);
30988c2ecf20Sopenharmony_ci	}
30998c2ecf20Sopenharmony_ci	rcu_read_unlock();
31008c2ecf20Sopenharmony_ci}
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci/**
31038c2ecf20Sopenharmony_ci * batadv_tt_global_update_crc() - update all the global CRCs for this orig_node
31048c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
31058c2ecf20Sopenharmony_ci * @orig_node: the orig_node for which the CRCs have to be updated
31068c2ecf20Sopenharmony_ci */
31078c2ecf20Sopenharmony_cistatic void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
31088c2ecf20Sopenharmony_ci					struct batadv_orig_node *orig_node)
31098c2ecf20Sopenharmony_ci{
31108c2ecf20Sopenharmony_ci	struct batadv_orig_node_vlan *vlan;
31118c2ecf20Sopenharmony_ci	u32 crc;
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci	/* recompute the global CRC for each VLAN */
31148c2ecf20Sopenharmony_ci	rcu_read_lock();
31158c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
31168c2ecf20Sopenharmony_ci		/* if orig_node is a backbone node for this VLAN, don't compute
31178c2ecf20Sopenharmony_ci		 * the CRC as we ignore all the global entries over it
31188c2ecf20Sopenharmony_ci		 */
31198c2ecf20Sopenharmony_ci		if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig,
31208c2ecf20Sopenharmony_ci						   vlan->vid))
31218c2ecf20Sopenharmony_ci			continue;
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci		crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid);
31248c2ecf20Sopenharmony_ci		vlan->tt.crc = crc;
31258c2ecf20Sopenharmony_ci	}
31268c2ecf20Sopenharmony_ci	rcu_read_unlock();
31278c2ecf20Sopenharmony_ci}
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci/**
31308c2ecf20Sopenharmony_ci * batadv_send_tt_request() - send a TT Request message to a given node
31318c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
31328c2ecf20Sopenharmony_ci * @dst_orig_node: the destination of the message
31338c2ecf20Sopenharmony_ci * @ttvn: the version number that the source of the message is looking for
31348c2ecf20Sopenharmony_ci * @tt_vlan: pointer to the first tvlv VLAN object to request
31358c2ecf20Sopenharmony_ci * @num_vlan: number of tvlv VLAN entries
31368c2ecf20Sopenharmony_ci * @full_table: ask for the entire translation table if true, while only for the
31378c2ecf20Sopenharmony_ci *  last TT diff otherwise
31388c2ecf20Sopenharmony_ci *
31398c2ecf20Sopenharmony_ci * Return: true if the TT Request was sent, false otherwise
31408c2ecf20Sopenharmony_ci */
31418c2ecf20Sopenharmony_cistatic bool batadv_send_tt_request(struct batadv_priv *bat_priv,
31428c2ecf20Sopenharmony_ci				   struct batadv_orig_node *dst_orig_node,
31438c2ecf20Sopenharmony_ci				   u8 ttvn,
31448c2ecf20Sopenharmony_ci				   struct batadv_tvlv_tt_vlan_data *tt_vlan,
31458c2ecf20Sopenharmony_ci				   u16 num_vlan, bool full_table)
31468c2ecf20Sopenharmony_ci{
31478c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
31488c2ecf20Sopenharmony_ci	struct batadv_tt_req_node *tt_req_node = NULL;
31498c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_vlan_data *tt_vlan_req;
31508c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
31518c2ecf20Sopenharmony_ci	bool ret = false;
31528c2ecf20Sopenharmony_ci	int i, size;
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
31558c2ecf20Sopenharmony_ci	if (!primary_if)
31568c2ecf20Sopenharmony_ci		goto out;
31578c2ecf20Sopenharmony_ci
31588c2ecf20Sopenharmony_ci	/* The new tt_req will be issued only if I'm not waiting for a
31598c2ecf20Sopenharmony_ci	 * reply from the same orig_node yet
31608c2ecf20Sopenharmony_ci	 */
31618c2ecf20Sopenharmony_ci	tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node);
31628c2ecf20Sopenharmony_ci	if (!tt_req_node)
31638c2ecf20Sopenharmony_ci		goto out;
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan;
31668c2ecf20Sopenharmony_ci	tvlv_tt_data = kzalloc(size, GFP_ATOMIC);
31678c2ecf20Sopenharmony_ci	if (!tvlv_tt_data)
31688c2ecf20Sopenharmony_ci		goto out;
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_ci	tvlv_tt_data->flags = BATADV_TT_REQUEST;
31718c2ecf20Sopenharmony_ci	tvlv_tt_data->ttvn = ttvn;
31728c2ecf20Sopenharmony_ci	tvlv_tt_data->num_vlan = htons(num_vlan);
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci	/* send all the CRCs within the request. This is needed by intermediate
31758c2ecf20Sopenharmony_ci	 * nodes to ensure they have the correct table before replying
31768c2ecf20Sopenharmony_ci	 */
31778c2ecf20Sopenharmony_ci	tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1);
31788c2ecf20Sopenharmony_ci	for (i = 0; i < num_vlan; i++) {
31798c2ecf20Sopenharmony_ci		tt_vlan_req->vid = tt_vlan->vid;
31808c2ecf20Sopenharmony_ci		tt_vlan_req->crc = tt_vlan->crc;
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_ci		tt_vlan_req++;
31838c2ecf20Sopenharmony_ci		tt_vlan++;
31848c2ecf20Sopenharmony_ci	}
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ci	if (full_table)
31878c2ecf20Sopenharmony_ci		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n",
31908c2ecf20Sopenharmony_ci		   dst_orig_node->orig, full_table ? 'F' : '.');
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX);
31938c2ecf20Sopenharmony_ci	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
31948c2ecf20Sopenharmony_ci				 dst_orig_node->orig, BATADV_TVLV_TT, 1,
31958c2ecf20Sopenharmony_ci				 tvlv_tt_data, size);
31968c2ecf20Sopenharmony_ci	ret = true;
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ciout:
31998c2ecf20Sopenharmony_ci	if (primary_if)
32008c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci	if (ret && tt_req_node) {
32038c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->tt.req_list_lock);
32048c2ecf20Sopenharmony_ci		if (!hlist_unhashed(&tt_req_node->list)) {
32058c2ecf20Sopenharmony_ci			hlist_del_init(&tt_req_node->list);
32068c2ecf20Sopenharmony_ci			batadv_tt_req_node_put(tt_req_node);
32078c2ecf20Sopenharmony_ci		}
32088c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->tt.req_list_lock);
32098c2ecf20Sopenharmony_ci	}
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci	if (tt_req_node)
32128c2ecf20Sopenharmony_ci		batadv_tt_req_node_put(tt_req_node);
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_ci	kfree(tvlv_tt_data);
32158c2ecf20Sopenharmony_ci	return ret;
32168c2ecf20Sopenharmony_ci}
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_ci/**
32198c2ecf20Sopenharmony_ci * batadv_send_other_tt_response() - send reply to tt request concerning another
32208c2ecf20Sopenharmony_ci *  node's translation table
32218c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
32228c2ecf20Sopenharmony_ci * @tt_data: tt data containing the tt request information
32238c2ecf20Sopenharmony_ci * @req_src: mac address of tt request sender
32248c2ecf20Sopenharmony_ci * @req_dst: mac address of tt request recipient
32258c2ecf20Sopenharmony_ci *
32268c2ecf20Sopenharmony_ci * Return: true if tt request reply was sent, false otherwise.
32278c2ecf20Sopenharmony_ci */
32288c2ecf20Sopenharmony_cistatic bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
32298c2ecf20Sopenharmony_ci					  struct batadv_tvlv_tt_data *tt_data,
32308c2ecf20Sopenharmony_ci					  u8 *req_src, u8 *req_dst)
32318c2ecf20Sopenharmony_ci{
32328c2ecf20Sopenharmony_ci	struct batadv_orig_node *req_dst_orig_node;
32338c2ecf20Sopenharmony_ci	struct batadv_orig_node *res_dst_orig_node = NULL;
32348c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_change *tt_change;
32358c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
32368c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_vlan_data *tt_vlan;
32378c2ecf20Sopenharmony_ci	bool ret = false, full_table;
32388c2ecf20Sopenharmony_ci	u8 orig_ttvn, req_ttvn;
32398c2ecf20Sopenharmony_ci	u16 tvlv_len;
32408c2ecf20Sopenharmony_ci	s32 tt_len;
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
32438c2ecf20Sopenharmony_ci		   "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
32448c2ecf20Sopenharmony_ci		   req_src, tt_data->ttvn, req_dst,
32458c2ecf20Sopenharmony_ci		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
32468c2ecf20Sopenharmony_ci
32478c2ecf20Sopenharmony_ci	/* Let's get the orig node of the REAL destination */
32488c2ecf20Sopenharmony_ci	req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst);
32498c2ecf20Sopenharmony_ci	if (!req_dst_orig_node)
32508c2ecf20Sopenharmony_ci		goto out;
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_ci	res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src);
32538c2ecf20Sopenharmony_ci	if (!res_dst_orig_node)
32548c2ecf20Sopenharmony_ci		goto out;
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci	orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn);
32578c2ecf20Sopenharmony_ci	req_ttvn = tt_data->ttvn;
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
32608c2ecf20Sopenharmony_ci	/* this node doesn't have the requested data */
32618c2ecf20Sopenharmony_ci	if (orig_ttvn != req_ttvn ||
32628c2ecf20Sopenharmony_ci	    !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan,
32638c2ecf20Sopenharmony_ci					ntohs(tt_data->num_vlan)))
32648c2ecf20Sopenharmony_ci		goto out;
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci	/* If the full table has been explicitly requested */
32678c2ecf20Sopenharmony_ci	if (tt_data->flags & BATADV_TT_FULL_TABLE ||
32688c2ecf20Sopenharmony_ci	    !req_dst_orig_node->tt_buff)
32698c2ecf20Sopenharmony_ci		full_table = true;
32708c2ecf20Sopenharmony_ci	else
32718c2ecf20Sopenharmony_ci		full_table = false;
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	/* TT fragmentation hasn't been implemented yet, so send as many
32748c2ecf20Sopenharmony_ci	 * TT entries fit a single packet as possible only
32758c2ecf20Sopenharmony_ci	 */
32768c2ecf20Sopenharmony_ci	if (!full_table) {
32778c2ecf20Sopenharmony_ci		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
32788c2ecf20Sopenharmony_ci		tt_len = req_dst_orig_node->tt_buff_len;
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci		tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
32818c2ecf20Sopenharmony_ci							      &tvlv_tt_data,
32828c2ecf20Sopenharmony_ci							      &tt_change,
32838c2ecf20Sopenharmony_ci							      &tt_len);
32848c2ecf20Sopenharmony_ci		if (!tt_len)
32858c2ecf20Sopenharmony_ci			goto unlock;
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ci		/* Copy the last orig_node's OGM buffer */
32888c2ecf20Sopenharmony_ci		memcpy(tt_change, req_dst_orig_node->tt_buff,
32898c2ecf20Sopenharmony_ci		       req_dst_orig_node->tt_buff_len);
32908c2ecf20Sopenharmony_ci		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
32918c2ecf20Sopenharmony_ci	} else {
32928c2ecf20Sopenharmony_ci		/* allocate the tvlv, put the tt_data and all the tt_vlan_data
32938c2ecf20Sopenharmony_ci		 * in the initial part
32948c2ecf20Sopenharmony_ci		 */
32958c2ecf20Sopenharmony_ci		tt_len = -1;
32968c2ecf20Sopenharmony_ci		tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
32978c2ecf20Sopenharmony_ci							      &tvlv_tt_data,
32988c2ecf20Sopenharmony_ci							      &tt_change,
32998c2ecf20Sopenharmony_ci							      &tt_len);
33008c2ecf20Sopenharmony_ci		if (!tt_len)
33018c2ecf20Sopenharmony_ci			goto out;
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci		/* fill the rest of the tvlv with the real TT entries */
33048c2ecf20Sopenharmony_ci		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash,
33058c2ecf20Sopenharmony_ci					tt_change, tt_len,
33068c2ecf20Sopenharmony_ci					batadv_tt_global_valid,
33078c2ecf20Sopenharmony_ci					req_dst_orig_node);
33088c2ecf20Sopenharmony_ci	}
33098c2ecf20Sopenharmony_ci
33108c2ecf20Sopenharmony_ci	/* Don't send the response, if larger than fragmented packet. */
33118c2ecf20Sopenharmony_ci	tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
33128c2ecf20Sopenharmony_ci	if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
33138c2ecf20Sopenharmony_ci		net_ratelimited_function(batadv_info, bat_priv->soft_iface,
33148c2ecf20Sopenharmony_ci					 "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
33158c2ecf20Sopenharmony_ci					 res_dst_orig_node->orig);
33168c2ecf20Sopenharmony_ci		goto out;
33178c2ecf20Sopenharmony_ci	}
33188c2ecf20Sopenharmony_ci
33198c2ecf20Sopenharmony_ci	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
33208c2ecf20Sopenharmony_ci	tvlv_tt_data->ttvn = req_ttvn;
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_ci	if (full_table)
33238c2ecf20Sopenharmony_ci		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
33268c2ecf20Sopenharmony_ci		   "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n",
33278c2ecf20Sopenharmony_ci		   res_dst_orig_node->orig, req_dst_orig_node->orig,
33288c2ecf20Sopenharmony_ci		   full_table ? 'F' : '.', req_ttvn);
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
33318c2ecf20Sopenharmony_ci
33328c2ecf20Sopenharmony_ci	batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig,
33338c2ecf20Sopenharmony_ci				 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
33348c2ecf20Sopenharmony_ci				 tvlv_len);
33358c2ecf20Sopenharmony_ci
33368c2ecf20Sopenharmony_ci	ret = true;
33378c2ecf20Sopenharmony_ci	goto out;
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ciunlock:
33408c2ecf20Sopenharmony_ci	spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ciout:
33438c2ecf20Sopenharmony_ci	if (res_dst_orig_node)
33448c2ecf20Sopenharmony_ci		batadv_orig_node_put(res_dst_orig_node);
33458c2ecf20Sopenharmony_ci	if (req_dst_orig_node)
33468c2ecf20Sopenharmony_ci		batadv_orig_node_put(req_dst_orig_node);
33478c2ecf20Sopenharmony_ci	kfree(tvlv_tt_data);
33488c2ecf20Sopenharmony_ci	return ret;
33498c2ecf20Sopenharmony_ci}
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci/**
33528c2ecf20Sopenharmony_ci * batadv_send_my_tt_response() - send reply to tt request concerning this
33538c2ecf20Sopenharmony_ci *  node's translation table
33548c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
33558c2ecf20Sopenharmony_ci * @tt_data: tt data containing the tt request information
33568c2ecf20Sopenharmony_ci * @req_src: mac address of tt request sender
33578c2ecf20Sopenharmony_ci *
33588c2ecf20Sopenharmony_ci * Return: true if tt request reply was sent, false otherwise.
33598c2ecf20Sopenharmony_ci */
33608c2ecf20Sopenharmony_cistatic bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
33618c2ecf20Sopenharmony_ci				       struct batadv_tvlv_tt_data *tt_data,
33628c2ecf20Sopenharmony_ci				       u8 *req_src)
33638c2ecf20Sopenharmony_ci{
33648c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
33658c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
33668c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_change *tt_change;
33678c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
33688c2ecf20Sopenharmony_ci	u8 my_ttvn, req_ttvn;
33698c2ecf20Sopenharmony_ci	u16 tvlv_len;
33708c2ecf20Sopenharmony_ci	bool full_table;
33718c2ecf20Sopenharmony_ci	s32 tt_len;
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
33748c2ecf20Sopenharmony_ci		   "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
33758c2ecf20Sopenharmony_ci		   req_src, tt_data->ttvn,
33768c2ecf20Sopenharmony_ci		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.commit_lock);
33798c2ecf20Sopenharmony_ci
33808c2ecf20Sopenharmony_ci	my_ttvn = (u8)atomic_read(&bat_priv->tt.vn);
33818c2ecf20Sopenharmony_ci	req_ttvn = tt_data->ttvn;
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, req_src);
33848c2ecf20Sopenharmony_ci	if (!orig_node)
33858c2ecf20Sopenharmony_ci		goto out;
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
33888c2ecf20Sopenharmony_ci	if (!primary_if)
33898c2ecf20Sopenharmony_ci		goto out;
33908c2ecf20Sopenharmony_ci
33918c2ecf20Sopenharmony_ci	/* If the full table has been explicitly requested or the gap
33928c2ecf20Sopenharmony_ci	 * is too big send the whole local translation table
33938c2ecf20Sopenharmony_ci	 */
33948c2ecf20Sopenharmony_ci	if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn ||
33958c2ecf20Sopenharmony_ci	    !bat_priv->tt.last_changeset)
33968c2ecf20Sopenharmony_ci		full_table = true;
33978c2ecf20Sopenharmony_ci	else
33988c2ecf20Sopenharmony_ci		full_table = false;
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	/* TT fragmentation hasn't been implemented yet, so send as many
34018c2ecf20Sopenharmony_ci	 * TT entries fit a single packet as possible only
34028c2ecf20Sopenharmony_ci	 */
34038c2ecf20Sopenharmony_ci	if (!full_table) {
34048c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->tt.last_changeset_lock);
34058c2ecf20Sopenharmony_ci
34068c2ecf20Sopenharmony_ci		tt_len = bat_priv->tt.last_changeset_len;
34078c2ecf20Sopenharmony_ci		tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
34088c2ecf20Sopenharmony_ci							     &tvlv_tt_data,
34098c2ecf20Sopenharmony_ci							     &tt_change,
34108c2ecf20Sopenharmony_ci							     &tt_len);
34118c2ecf20Sopenharmony_ci		if (!tt_len || !tvlv_len)
34128c2ecf20Sopenharmony_ci			goto unlock;
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci		/* Copy the last orig_node's OGM buffer */
34158c2ecf20Sopenharmony_ci		memcpy(tt_change, bat_priv->tt.last_changeset,
34168c2ecf20Sopenharmony_ci		       bat_priv->tt.last_changeset_len);
34178c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
34188c2ecf20Sopenharmony_ci	} else {
34198c2ecf20Sopenharmony_ci		req_ttvn = (u8)atomic_read(&bat_priv->tt.vn);
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci		/* allocate the tvlv, put the tt_data and all the tt_vlan_data
34228c2ecf20Sopenharmony_ci		 * in the initial part
34238c2ecf20Sopenharmony_ci		 */
34248c2ecf20Sopenharmony_ci		tt_len = -1;
34258c2ecf20Sopenharmony_ci		tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
34268c2ecf20Sopenharmony_ci							     &tvlv_tt_data,
34278c2ecf20Sopenharmony_ci							     &tt_change,
34288c2ecf20Sopenharmony_ci							     &tt_len);
34298c2ecf20Sopenharmony_ci		if (!tt_len || !tvlv_len)
34308c2ecf20Sopenharmony_ci			goto out;
34318c2ecf20Sopenharmony_ci
34328c2ecf20Sopenharmony_ci		/* fill the rest of the tvlv with the real TT entries */
34338c2ecf20Sopenharmony_ci		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash,
34348c2ecf20Sopenharmony_ci					tt_change, tt_len,
34358c2ecf20Sopenharmony_ci					batadv_tt_local_valid, NULL);
34368c2ecf20Sopenharmony_ci	}
34378c2ecf20Sopenharmony_ci
34388c2ecf20Sopenharmony_ci	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
34398c2ecf20Sopenharmony_ci	tvlv_tt_data->ttvn = req_ttvn;
34408c2ecf20Sopenharmony_ci
34418c2ecf20Sopenharmony_ci	if (full_table)
34428c2ecf20Sopenharmony_ci		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
34438c2ecf20Sopenharmony_ci
34448c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
34458c2ecf20Sopenharmony_ci		   "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n",
34468c2ecf20Sopenharmony_ci		   orig_node->orig, full_table ? 'F' : '.', req_ttvn);
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
34498c2ecf20Sopenharmony_ci
34508c2ecf20Sopenharmony_ci	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
34518c2ecf20Sopenharmony_ci				 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
34528c2ecf20Sopenharmony_ci				 tvlv_len);
34538c2ecf20Sopenharmony_ci
34548c2ecf20Sopenharmony_ci	goto out;
34558c2ecf20Sopenharmony_ci
34568c2ecf20Sopenharmony_ciunlock:
34578c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
34588c2ecf20Sopenharmony_ciout:
34598c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.commit_lock);
34608c2ecf20Sopenharmony_ci	if (orig_node)
34618c2ecf20Sopenharmony_ci		batadv_orig_node_put(orig_node);
34628c2ecf20Sopenharmony_ci	if (primary_if)
34638c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
34648c2ecf20Sopenharmony_ci	kfree(tvlv_tt_data);
34658c2ecf20Sopenharmony_ci	/* The packet was for this host, so it doesn't need to be re-routed */
34668c2ecf20Sopenharmony_ci	return true;
34678c2ecf20Sopenharmony_ci}
34688c2ecf20Sopenharmony_ci
34698c2ecf20Sopenharmony_ci/**
34708c2ecf20Sopenharmony_ci * batadv_send_tt_response() - send reply to tt request
34718c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
34728c2ecf20Sopenharmony_ci * @tt_data: tt data containing the tt request information
34738c2ecf20Sopenharmony_ci * @req_src: mac address of tt request sender
34748c2ecf20Sopenharmony_ci * @req_dst: mac address of tt request recipient
34758c2ecf20Sopenharmony_ci *
34768c2ecf20Sopenharmony_ci * Return: true if tt request reply was sent, false otherwise.
34778c2ecf20Sopenharmony_ci */
34788c2ecf20Sopenharmony_cistatic bool batadv_send_tt_response(struct batadv_priv *bat_priv,
34798c2ecf20Sopenharmony_ci				    struct batadv_tvlv_tt_data *tt_data,
34808c2ecf20Sopenharmony_ci				    u8 *req_src, u8 *req_dst)
34818c2ecf20Sopenharmony_ci{
34828c2ecf20Sopenharmony_ci	if (batadv_is_my_mac(bat_priv, req_dst))
34838c2ecf20Sopenharmony_ci		return batadv_send_my_tt_response(bat_priv, tt_data, req_src);
34848c2ecf20Sopenharmony_ci	return batadv_send_other_tt_response(bat_priv, tt_data, req_src,
34858c2ecf20Sopenharmony_ci					     req_dst);
34868c2ecf20Sopenharmony_ci}
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_cistatic void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
34898c2ecf20Sopenharmony_ci				      struct batadv_orig_node *orig_node,
34908c2ecf20Sopenharmony_ci				      struct batadv_tvlv_tt_change *tt_change,
34918c2ecf20Sopenharmony_ci				      u16 tt_num_changes, u8 ttvn)
34928c2ecf20Sopenharmony_ci{
34938c2ecf20Sopenharmony_ci	int i;
34948c2ecf20Sopenharmony_ci	int roams;
34958c2ecf20Sopenharmony_ci
34968c2ecf20Sopenharmony_ci	for (i = 0; i < tt_num_changes; i++) {
34978c2ecf20Sopenharmony_ci		if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
34988c2ecf20Sopenharmony_ci			roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
34998c2ecf20Sopenharmony_ci			batadv_tt_global_del(bat_priv, orig_node,
35008c2ecf20Sopenharmony_ci					     (tt_change + i)->addr,
35018c2ecf20Sopenharmony_ci					     ntohs((tt_change + i)->vid),
35028c2ecf20Sopenharmony_ci					     "tt removed by changes",
35038c2ecf20Sopenharmony_ci					     roams);
35048c2ecf20Sopenharmony_ci		} else {
35058c2ecf20Sopenharmony_ci			if (!batadv_tt_global_add(bat_priv, orig_node,
35068c2ecf20Sopenharmony_ci						  (tt_change + i)->addr,
35078c2ecf20Sopenharmony_ci						  ntohs((tt_change + i)->vid),
35088c2ecf20Sopenharmony_ci						  (tt_change + i)->flags, ttvn))
35098c2ecf20Sopenharmony_ci				/* In case of problem while storing a
35108c2ecf20Sopenharmony_ci				 * global_entry, we stop the updating
35118c2ecf20Sopenharmony_ci				 * procedure without committing the
35128c2ecf20Sopenharmony_ci				 * ttvn change. This will avoid to send
35138c2ecf20Sopenharmony_ci				 * corrupted data on tt_request
35148c2ecf20Sopenharmony_ci				 */
35158c2ecf20Sopenharmony_ci				return;
35168c2ecf20Sopenharmony_ci		}
35178c2ecf20Sopenharmony_ci	}
35188c2ecf20Sopenharmony_ci	set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
35198c2ecf20Sopenharmony_ci}
35208c2ecf20Sopenharmony_ci
35218c2ecf20Sopenharmony_cistatic void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
35228c2ecf20Sopenharmony_ci				  struct batadv_tvlv_tt_change *tt_change,
35238c2ecf20Sopenharmony_ci				  u8 ttvn, u8 *resp_src,
35248c2ecf20Sopenharmony_ci				  u16 num_entries)
35258c2ecf20Sopenharmony_ci{
35268c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
35278c2ecf20Sopenharmony_ci
35288c2ecf20Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
35298c2ecf20Sopenharmony_ci	if (!orig_node)
35308c2ecf20Sopenharmony_ci		goto out;
35318c2ecf20Sopenharmony_ci
35328c2ecf20Sopenharmony_ci	/* Purge the old table first.. */
35338c2ecf20Sopenharmony_ci	batadv_tt_global_del_orig(bat_priv, orig_node, -1,
35348c2ecf20Sopenharmony_ci				  "Received full table");
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci	_batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries,
35378c2ecf20Sopenharmony_ci				  ttvn);
35388c2ecf20Sopenharmony_ci
35398c2ecf20Sopenharmony_ci	spin_lock_bh(&orig_node->tt_buff_lock);
35408c2ecf20Sopenharmony_ci	kfree(orig_node->tt_buff);
35418c2ecf20Sopenharmony_ci	orig_node->tt_buff_len = 0;
35428c2ecf20Sopenharmony_ci	orig_node->tt_buff = NULL;
35438c2ecf20Sopenharmony_ci	spin_unlock_bh(&orig_node->tt_buff_lock);
35448c2ecf20Sopenharmony_ci
35458c2ecf20Sopenharmony_ci	atomic_set(&orig_node->last_ttvn, ttvn);
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_ciout:
35488c2ecf20Sopenharmony_ci	if (orig_node)
35498c2ecf20Sopenharmony_ci		batadv_orig_node_put(orig_node);
35508c2ecf20Sopenharmony_ci}
35518c2ecf20Sopenharmony_ci
35528c2ecf20Sopenharmony_cistatic void batadv_tt_update_changes(struct batadv_priv *bat_priv,
35538c2ecf20Sopenharmony_ci				     struct batadv_orig_node *orig_node,
35548c2ecf20Sopenharmony_ci				     u16 tt_num_changes, u8 ttvn,
35558c2ecf20Sopenharmony_ci				     struct batadv_tvlv_tt_change *tt_change)
35568c2ecf20Sopenharmony_ci{
35578c2ecf20Sopenharmony_ci	_batadv_tt_update_changes(bat_priv, orig_node, tt_change,
35588c2ecf20Sopenharmony_ci				  tt_num_changes, ttvn);
35598c2ecf20Sopenharmony_ci
35608c2ecf20Sopenharmony_ci	batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change,
35618c2ecf20Sopenharmony_ci				   batadv_tt_len(tt_num_changes));
35628c2ecf20Sopenharmony_ci	atomic_set(&orig_node->last_ttvn, ttvn);
35638c2ecf20Sopenharmony_ci}
35648c2ecf20Sopenharmony_ci
35658c2ecf20Sopenharmony_ci/**
35668c2ecf20Sopenharmony_ci * batadv_is_my_client() - check if a client is served by the local node
35678c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
35688c2ecf20Sopenharmony_ci * @addr: the mac address of the client to check
35698c2ecf20Sopenharmony_ci * @vid: VLAN identifier
35708c2ecf20Sopenharmony_ci *
35718c2ecf20Sopenharmony_ci * Return: true if the client is served by this node, false otherwise.
35728c2ecf20Sopenharmony_ci */
35738c2ecf20Sopenharmony_cibool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
35748c2ecf20Sopenharmony_ci			 unsigned short vid)
35758c2ecf20Sopenharmony_ci{
35768c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry;
35778c2ecf20Sopenharmony_ci	bool ret = false;
35788c2ecf20Sopenharmony_ci
35798c2ecf20Sopenharmony_ci	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
35808c2ecf20Sopenharmony_ci	if (!tt_local_entry)
35818c2ecf20Sopenharmony_ci		goto out;
35828c2ecf20Sopenharmony_ci	/* Check if the client has been logically deleted (but is kept for
35838c2ecf20Sopenharmony_ci	 * consistency purpose)
35848c2ecf20Sopenharmony_ci	 */
35858c2ecf20Sopenharmony_ci	if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
35868c2ecf20Sopenharmony_ci	    (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
35878c2ecf20Sopenharmony_ci		goto out;
35888c2ecf20Sopenharmony_ci	ret = true;
35898c2ecf20Sopenharmony_ciout:
35908c2ecf20Sopenharmony_ci	if (tt_local_entry)
35918c2ecf20Sopenharmony_ci		batadv_tt_local_entry_put(tt_local_entry);
35928c2ecf20Sopenharmony_ci	return ret;
35938c2ecf20Sopenharmony_ci}
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci/**
35968c2ecf20Sopenharmony_ci * batadv_handle_tt_response() - process incoming tt reply
35978c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
35988c2ecf20Sopenharmony_ci * @tt_data: tt data containing the tt request information
35998c2ecf20Sopenharmony_ci * @resp_src: mac address of tt reply sender
36008c2ecf20Sopenharmony_ci * @num_entries: number of tt change entries appended to the tt data
36018c2ecf20Sopenharmony_ci */
36028c2ecf20Sopenharmony_cistatic void batadv_handle_tt_response(struct batadv_priv *bat_priv,
36038c2ecf20Sopenharmony_ci				      struct batadv_tvlv_tt_data *tt_data,
36048c2ecf20Sopenharmony_ci				      u8 *resp_src, u16 num_entries)
36058c2ecf20Sopenharmony_ci{
36068c2ecf20Sopenharmony_ci	struct batadv_tt_req_node *node;
36078c2ecf20Sopenharmony_ci	struct hlist_node *safe;
36088c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node = NULL;
36098c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_change *tt_change;
36108c2ecf20Sopenharmony_ci	u8 *tvlv_ptr = (u8 *)tt_data;
36118c2ecf20Sopenharmony_ci	u16 change_offset;
36128c2ecf20Sopenharmony_ci
36138c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
36148c2ecf20Sopenharmony_ci		   "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
36158c2ecf20Sopenharmony_ci		   resp_src, tt_data->ttvn, num_entries,
36168c2ecf20Sopenharmony_ci		   ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.'));
36178c2ecf20Sopenharmony_ci
36188c2ecf20Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
36198c2ecf20Sopenharmony_ci	if (!orig_node)
36208c2ecf20Sopenharmony_ci		goto out;
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci	spin_lock_bh(&orig_node->tt_lock);
36238c2ecf20Sopenharmony_ci
36248c2ecf20Sopenharmony_ci	change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
36258c2ecf20Sopenharmony_ci	change_offset *= ntohs(tt_data->num_vlan);
36268c2ecf20Sopenharmony_ci	change_offset += sizeof(*tt_data);
36278c2ecf20Sopenharmony_ci	tvlv_ptr += change_offset;
36288c2ecf20Sopenharmony_ci
36298c2ecf20Sopenharmony_ci	tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
36308c2ecf20Sopenharmony_ci	if (tt_data->flags & BATADV_TT_FULL_TABLE) {
36318c2ecf20Sopenharmony_ci		batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn,
36328c2ecf20Sopenharmony_ci				      resp_src, num_entries);
36338c2ecf20Sopenharmony_ci	} else {
36348c2ecf20Sopenharmony_ci		batadv_tt_update_changes(bat_priv, orig_node, num_entries,
36358c2ecf20Sopenharmony_ci					 tt_data->ttvn, tt_change);
36368c2ecf20Sopenharmony_ci	}
36378c2ecf20Sopenharmony_ci
36388c2ecf20Sopenharmony_ci	/* Recalculate the CRC for this orig_node and store it */
36398c2ecf20Sopenharmony_ci	batadv_tt_global_update_crc(bat_priv, orig_node);
36408c2ecf20Sopenharmony_ci
36418c2ecf20Sopenharmony_ci	spin_unlock_bh(&orig_node->tt_lock);
36428c2ecf20Sopenharmony_ci
36438c2ecf20Sopenharmony_ci	/* Delete the tt_req_node from pending tt_requests list */
36448c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.req_list_lock);
36458c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
36468c2ecf20Sopenharmony_ci		if (!batadv_compare_eth(node->addr, resp_src))
36478c2ecf20Sopenharmony_ci			continue;
36488c2ecf20Sopenharmony_ci		hlist_del_init(&node->list);
36498c2ecf20Sopenharmony_ci		batadv_tt_req_node_put(node);
36508c2ecf20Sopenharmony_ci	}
36518c2ecf20Sopenharmony_ci
36528c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.req_list_lock);
36538c2ecf20Sopenharmony_ciout:
36548c2ecf20Sopenharmony_ci	if (orig_node)
36558c2ecf20Sopenharmony_ci		batadv_orig_node_put(orig_node);
36568c2ecf20Sopenharmony_ci}
36578c2ecf20Sopenharmony_ci
36588c2ecf20Sopenharmony_cistatic void batadv_tt_roam_list_free(struct batadv_priv *bat_priv)
36598c2ecf20Sopenharmony_ci{
36608c2ecf20Sopenharmony_ci	struct batadv_tt_roam_node *node, *safe;
36618c2ecf20Sopenharmony_ci
36628c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.roam_list_lock);
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci	list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
36658c2ecf20Sopenharmony_ci		list_del(&node->list);
36668c2ecf20Sopenharmony_ci		kmem_cache_free(batadv_tt_roam_cache, node);
36678c2ecf20Sopenharmony_ci	}
36688c2ecf20Sopenharmony_ci
36698c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
36708c2ecf20Sopenharmony_ci}
36718c2ecf20Sopenharmony_ci
36728c2ecf20Sopenharmony_cistatic void batadv_tt_roam_purge(struct batadv_priv *bat_priv)
36738c2ecf20Sopenharmony_ci{
36748c2ecf20Sopenharmony_ci	struct batadv_tt_roam_node *node, *safe;
36758c2ecf20Sopenharmony_ci
36768c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.roam_list_lock);
36778c2ecf20Sopenharmony_ci	list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
36788c2ecf20Sopenharmony_ci		if (!batadv_has_timed_out(node->first_time,
36798c2ecf20Sopenharmony_ci					  BATADV_ROAMING_MAX_TIME))
36808c2ecf20Sopenharmony_ci			continue;
36818c2ecf20Sopenharmony_ci
36828c2ecf20Sopenharmony_ci		list_del(&node->list);
36838c2ecf20Sopenharmony_ci		kmem_cache_free(batadv_tt_roam_cache, node);
36848c2ecf20Sopenharmony_ci	}
36858c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
36868c2ecf20Sopenharmony_ci}
36878c2ecf20Sopenharmony_ci
36888c2ecf20Sopenharmony_ci/**
36898c2ecf20Sopenharmony_ci * batadv_tt_check_roam_count() - check if a client has roamed too frequently
36908c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
36918c2ecf20Sopenharmony_ci * @client: mac address of the roaming client
36928c2ecf20Sopenharmony_ci *
36938c2ecf20Sopenharmony_ci * This function checks whether the client already reached the
36948c2ecf20Sopenharmony_ci * maximum number of possible roaming phases. In this case the ROAMING_ADV
36958c2ecf20Sopenharmony_ci * will not be sent.
36968c2ecf20Sopenharmony_ci *
36978c2ecf20Sopenharmony_ci * Return: true if the ROAMING_ADV can be sent, false otherwise
36988c2ecf20Sopenharmony_ci */
36998c2ecf20Sopenharmony_cistatic bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client)
37008c2ecf20Sopenharmony_ci{
37018c2ecf20Sopenharmony_ci	struct batadv_tt_roam_node *tt_roam_node;
37028c2ecf20Sopenharmony_ci	bool ret = false;
37038c2ecf20Sopenharmony_ci
37048c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.roam_list_lock);
37058c2ecf20Sopenharmony_ci	/* The new tt_req will be issued only if I'm not waiting for a
37068c2ecf20Sopenharmony_ci	 * reply from the same orig_node yet
37078c2ecf20Sopenharmony_ci	 */
37088c2ecf20Sopenharmony_ci	list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) {
37098c2ecf20Sopenharmony_ci		if (!batadv_compare_eth(tt_roam_node->addr, client))
37108c2ecf20Sopenharmony_ci			continue;
37118c2ecf20Sopenharmony_ci
37128c2ecf20Sopenharmony_ci		if (batadv_has_timed_out(tt_roam_node->first_time,
37138c2ecf20Sopenharmony_ci					 BATADV_ROAMING_MAX_TIME))
37148c2ecf20Sopenharmony_ci			continue;
37158c2ecf20Sopenharmony_ci
37168c2ecf20Sopenharmony_ci		if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter))
37178c2ecf20Sopenharmony_ci			/* Sorry, you roamed too many times! */
37188c2ecf20Sopenharmony_ci			goto unlock;
37198c2ecf20Sopenharmony_ci		ret = true;
37208c2ecf20Sopenharmony_ci		break;
37218c2ecf20Sopenharmony_ci	}
37228c2ecf20Sopenharmony_ci
37238c2ecf20Sopenharmony_ci	if (!ret) {
37248c2ecf20Sopenharmony_ci		tt_roam_node = kmem_cache_alloc(batadv_tt_roam_cache,
37258c2ecf20Sopenharmony_ci						GFP_ATOMIC);
37268c2ecf20Sopenharmony_ci		if (!tt_roam_node)
37278c2ecf20Sopenharmony_ci			goto unlock;
37288c2ecf20Sopenharmony_ci
37298c2ecf20Sopenharmony_ci		tt_roam_node->first_time = jiffies;
37308c2ecf20Sopenharmony_ci		atomic_set(&tt_roam_node->counter,
37318c2ecf20Sopenharmony_ci			   BATADV_ROAMING_MAX_COUNT - 1);
37328c2ecf20Sopenharmony_ci		ether_addr_copy(tt_roam_node->addr, client);
37338c2ecf20Sopenharmony_ci
37348c2ecf20Sopenharmony_ci		list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
37358c2ecf20Sopenharmony_ci		ret = true;
37368c2ecf20Sopenharmony_ci	}
37378c2ecf20Sopenharmony_ci
37388c2ecf20Sopenharmony_ciunlock:
37398c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.roam_list_lock);
37408c2ecf20Sopenharmony_ci	return ret;
37418c2ecf20Sopenharmony_ci}
37428c2ecf20Sopenharmony_ci
37438c2ecf20Sopenharmony_ci/**
37448c2ecf20Sopenharmony_ci * batadv_send_roam_adv() - send a roaming advertisement message
37458c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
37468c2ecf20Sopenharmony_ci * @client: mac address of the roaming client
37478c2ecf20Sopenharmony_ci * @vid: VLAN identifier
37488c2ecf20Sopenharmony_ci * @orig_node: message destination
37498c2ecf20Sopenharmony_ci *
37508c2ecf20Sopenharmony_ci * Send a ROAMING_ADV message to the node which was previously serving this
37518c2ecf20Sopenharmony_ci * client. This is done to inform the node that from now on all traffic destined
37528c2ecf20Sopenharmony_ci * for this particular roamed client has to be forwarded to the sender of the
37538c2ecf20Sopenharmony_ci * roaming message.
37548c2ecf20Sopenharmony_ci */
37558c2ecf20Sopenharmony_cistatic void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
37568c2ecf20Sopenharmony_ci				 unsigned short vid,
37578c2ecf20Sopenharmony_ci				 struct batadv_orig_node *orig_node)
37588c2ecf20Sopenharmony_ci{
37598c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
37608c2ecf20Sopenharmony_ci	struct batadv_tvlv_roam_adv tvlv_roam;
37618c2ecf20Sopenharmony_ci
37628c2ecf20Sopenharmony_ci	primary_if = batadv_primary_if_get_selected(bat_priv);
37638c2ecf20Sopenharmony_ci	if (!primary_if)
37648c2ecf20Sopenharmony_ci		goto out;
37658c2ecf20Sopenharmony_ci
37668c2ecf20Sopenharmony_ci	/* before going on we have to check whether the client has
37678c2ecf20Sopenharmony_ci	 * already roamed to us too many times
37688c2ecf20Sopenharmony_ci	 */
37698c2ecf20Sopenharmony_ci	if (!batadv_tt_check_roam_count(bat_priv, client))
37708c2ecf20Sopenharmony_ci		goto out;
37718c2ecf20Sopenharmony_ci
37728c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
37738c2ecf20Sopenharmony_ci		   "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n",
37748c2ecf20Sopenharmony_ci		   orig_node->orig, client, batadv_print_vid(vid));
37758c2ecf20Sopenharmony_ci
37768c2ecf20Sopenharmony_ci	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
37778c2ecf20Sopenharmony_ci
37788c2ecf20Sopenharmony_ci	memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client));
37798c2ecf20Sopenharmony_ci	tvlv_roam.vid = htons(vid);
37808c2ecf20Sopenharmony_ci
37818c2ecf20Sopenharmony_ci	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
37828c2ecf20Sopenharmony_ci				 orig_node->orig, BATADV_TVLV_ROAM, 1,
37838c2ecf20Sopenharmony_ci				 &tvlv_roam, sizeof(tvlv_roam));
37848c2ecf20Sopenharmony_ci
37858c2ecf20Sopenharmony_ciout:
37868c2ecf20Sopenharmony_ci	if (primary_if)
37878c2ecf20Sopenharmony_ci		batadv_hardif_put(primary_if);
37888c2ecf20Sopenharmony_ci}
37898c2ecf20Sopenharmony_ci
37908c2ecf20Sopenharmony_cistatic void batadv_tt_purge(struct work_struct *work)
37918c2ecf20Sopenharmony_ci{
37928c2ecf20Sopenharmony_ci	struct delayed_work *delayed_work;
37938c2ecf20Sopenharmony_ci	struct batadv_priv_tt *priv_tt;
37948c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
37958c2ecf20Sopenharmony_ci
37968c2ecf20Sopenharmony_ci	delayed_work = to_delayed_work(work);
37978c2ecf20Sopenharmony_ci	priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
37988c2ecf20Sopenharmony_ci	bat_priv = container_of(priv_tt, struct batadv_priv, tt);
37998c2ecf20Sopenharmony_ci
38008c2ecf20Sopenharmony_ci	batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
38018c2ecf20Sopenharmony_ci	batadv_tt_global_purge(bat_priv);
38028c2ecf20Sopenharmony_ci	batadv_tt_req_purge(bat_priv);
38038c2ecf20Sopenharmony_ci	batadv_tt_roam_purge(bat_priv);
38048c2ecf20Sopenharmony_ci
38058c2ecf20Sopenharmony_ci	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
38068c2ecf20Sopenharmony_ci			   msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
38078c2ecf20Sopenharmony_ci}
38088c2ecf20Sopenharmony_ci
38098c2ecf20Sopenharmony_ci/**
38108c2ecf20Sopenharmony_ci * batadv_tt_free() - Free translation table of soft interface
38118c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
38128c2ecf20Sopenharmony_ci */
38138c2ecf20Sopenharmony_civoid batadv_tt_free(struct batadv_priv *bat_priv)
38148c2ecf20Sopenharmony_ci{
38158c2ecf20Sopenharmony_ci	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_ROAM, 1);
38168c2ecf20Sopenharmony_ci
38178c2ecf20Sopenharmony_ci	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1);
38188c2ecf20Sopenharmony_ci	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1);
38198c2ecf20Sopenharmony_ci
38208c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&bat_priv->tt.work);
38218c2ecf20Sopenharmony_ci
38228c2ecf20Sopenharmony_ci	batadv_tt_local_table_free(bat_priv);
38238c2ecf20Sopenharmony_ci	batadv_tt_global_table_free(bat_priv);
38248c2ecf20Sopenharmony_ci	batadv_tt_req_list_free(bat_priv);
38258c2ecf20Sopenharmony_ci	batadv_tt_changes_list_free(bat_priv);
38268c2ecf20Sopenharmony_ci	batadv_tt_roam_list_free(bat_priv);
38278c2ecf20Sopenharmony_ci
38288c2ecf20Sopenharmony_ci	kfree(bat_priv->tt.last_changeset);
38298c2ecf20Sopenharmony_ci}
38308c2ecf20Sopenharmony_ci
38318c2ecf20Sopenharmony_ci/**
38328c2ecf20Sopenharmony_ci * batadv_tt_local_set_flags() - set or unset the specified flags on the local
38338c2ecf20Sopenharmony_ci *  table and possibly count them in the TT size
38348c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
38358c2ecf20Sopenharmony_ci * @flags: the flag to switch
38368c2ecf20Sopenharmony_ci * @enable: whether to set or unset the flag
38378c2ecf20Sopenharmony_ci * @count: whether to increase the TT size by the number of changed entries
38388c2ecf20Sopenharmony_ci */
38398c2ecf20Sopenharmony_cistatic void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
38408c2ecf20Sopenharmony_ci				      bool enable, bool count)
38418c2ecf20Sopenharmony_ci{
38428c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
38438c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common_entry;
38448c2ecf20Sopenharmony_ci	struct hlist_head *head;
38458c2ecf20Sopenharmony_ci	u32 i;
38468c2ecf20Sopenharmony_ci
38478c2ecf20Sopenharmony_ci	if (!hash)
38488c2ecf20Sopenharmony_ci		return;
38498c2ecf20Sopenharmony_ci
38508c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
38518c2ecf20Sopenharmony_ci		head = &hash->table[i];
38528c2ecf20Sopenharmony_ci
38538c2ecf20Sopenharmony_ci		rcu_read_lock();
38548c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(tt_common_entry,
38558c2ecf20Sopenharmony_ci					 head, hash_entry) {
38568c2ecf20Sopenharmony_ci			if (enable) {
38578c2ecf20Sopenharmony_ci				if ((tt_common_entry->flags & flags) == flags)
38588c2ecf20Sopenharmony_ci					continue;
38598c2ecf20Sopenharmony_ci				tt_common_entry->flags |= flags;
38608c2ecf20Sopenharmony_ci			} else {
38618c2ecf20Sopenharmony_ci				if (!(tt_common_entry->flags & flags))
38628c2ecf20Sopenharmony_ci					continue;
38638c2ecf20Sopenharmony_ci				tt_common_entry->flags &= ~flags;
38648c2ecf20Sopenharmony_ci			}
38658c2ecf20Sopenharmony_ci
38668c2ecf20Sopenharmony_ci			if (!count)
38678c2ecf20Sopenharmony_ci				continue;
38688c2ecf20Sopenharmony_ci
38698c2ecf20Sopenharmony_ci			batadv_tt_local_size_inc(bat_priv,
38708c2ecf20Sopenharmony_ci						 tt_common_entry->vid);
38718c2ecf20Sopenharmony_ci		}
38728c2ecf20Sopenharmony_ci		rcu_read_unlock();
38738c2ecf20Sopenharmony_ci	}
38748c2ecf20Sopenharmony_ci}
38758c2ecf20Sopenharmony_ci
38768c2ecf20Sopenharmony_ci/* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */
38778c2ecf20Sopenharmony_cistatic void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
38788c2ecf20Sopenharmony_ci{
38798c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
38808c2ecf20Sopenharmony_ci	struct batadv_tt_common_entry *tt_common;
38818c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local;
38828c2ecf20Sopenharmony_ci	struct hlist_node *node_tmp;
38838c2ecf20Sopenharmony_ci	struct hlist_head *head;
38848c2ecf20Sopenharmony_ci	spinlock_t *list_lock; /* protects write access to the hash lists */
38858c2ecf20Sopenharmony_ci	u32 i;
38868c2ecf20Sopenharmony_ci
38878c2ecf20Sopenharmony_ci	if (!hash)
38888c2ecf20Sopenharmony_ci		return;
38898c2ecf20Sopenharmony_ci
38908c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
38918c2ecf20Sopenharmony_ci		head = &hash->table[i];
38928c2ecf20Sopenharmony_ci		list_lock = &hash->list_locks[i];
38938c2ecf20Sopenharmony_ci
38948c2ecf20Sopenharmony_ci		spin_lock_bh(list_lock);
38958c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(tt_common, node_tmp, head,
38968c2ecf20Sopenharmony_ci					  hash_entry) {
38978c2ecf20Sopenharmony_ci			if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
38988c2ecf20Sopenharmony_ci				continue;
38998c2ecf20Sopenharmony_ci
39008c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_TT, bat_priv,
39018c2ecf20Sopenharmony_ci				   "Deleting local tt entry (%pM, vid: %d): pending\n",
39028c2ecf20Sopenharmony_ci				   tt_common->addr,
39038c2ecf20Sopenharmony_ci				   batadv_print_vid(tt_common->vid));
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_ci			batadv_tt_local_size_dec(bat_priv, tt_common->vid);
39068c2ecf20Sopenharmony_ci			hlist_del_rcu(&tt_common->hash_entry);
39078c2ecf20Sopenharmony_ci			tt_local = container_of(tt_common,
39088c2ecf20Sopenharmony_ci						struct batadv_tt_local_entry,
39098c2ecf20Sopenharmony_ci						common);
39108c2ecf20Sopenharmony_ci
39118c2ecf20Sopenharmony_ci			batadv_tt_local_entry_put(tt_local);
39128c2ecf20Sopenharmony_ci		}
39138c2ecf20Sopenharmony_ci		spin_unlock_bh(list_lock);
39148c2ecf20Sopenharmony_ci	}
39158c2ecf20Sopenharmony_ci}
39168c2ecf20Sopenharmony_ci
39178c2ecf20Sopenharmony_ci/**
39188c2ecf20Sopenharmony_ci * batadv_tt_local_commit_changes_nolock() - commit all pending local tt changes
39198c2ecf20Sopenharmony_ci *  which have been queued in the time since the last commit
39208c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
39218c2ecf20Sopenharmony_ci *
39228c2ecf20Sopenharmony_ci * Caller must hold tt->commit_lock.
39238c2ecf20Sopenharmony_ci */
39248c2ecf20Sopenharmony_cistatic void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
39258c2ecf20Sopenharmony_ci{
39268c2ecf20Sopenharmony_ci	lockdep_assert_held(&bat_priv->tt.commit_lock);
39278c2ecf20Sopenharmony_ci
39288c2ecf20Sopenharmony_ci	if (atomic_read(&bat_priv->tt.local_changes) < 1) {
39298c2ecf20Sopenharmony_ci		if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
39308c2ecf20Sopenharmony_ci			batadv_tt_tvlv_container_update(bat_priv);
39318c2ecf20Sopenharmony_ci		return;
39328c2ecf20Sopenharmony_ci	}
39338c2ecf20Sopenharmony_ci
39348c2ecf20Sopenharmony_ci	batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
39358c2ecf20Sopenharmony_ci
39368c2ecf20Sopenharmony_ci	batadv_tt_local_purge_pending_clients(bat_priv);
39378c2ecf20Sopenharmony_ci	batadv_tt_local_update_crc(bat_priv);
39388c2ecf20Sopenharmony_ci
39398c2ecf20Sopenharmony_ci	/* Increment the TTVN only once per OGM interval */
39408c2ecf20Sopenharmony_ci	atomic_inc(&bat_priv->tt.vn);
39418c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
39428c2ecf20Sopenharmony_ci		   "Local changes committed, updating to ttvn %u\n",
39438c2ecf20Sopenharmony_ci		   (u8)atomic_read(&bat_priv->tt.vn));
39448c2ecf20Sopenharmony_ci
39458c2ecf20Sopenharmony_ci	/* reset the sending counter */
39468c2ecf20Sopenharmony_ci	atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
39478c2ecf20Sopenharmony_ci	batadv_tt_tvlv_container_update(bat_priv);
39488c2ecf20Sopenharmony_ci}
39498c2ecf20Sopenharmony_ci
39508c2ecf20Sopenharmony_ci/**
39518c2ecf20Sopenharmony_ci * batadv_tt_local_commit_changes() - commit all pending local tt changes which
39528c2ecf20Sopenharmony_ci *  have been queued in the time since the last commit
39538c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
39548c2ecf20Sopenharmony_ci */
39558c2ecf20Sopenharmony_civoid batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
39568c2ecf20Sopenharmony_ci{
39578c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.commit_lock);
39588c2ecf20Sopenharmony_ci	batadv_tt_local_commit_changes_nolock(bat_priv);
39598c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.commit_lock);
39608c2ecf20Sopenharmony_ci}
39618c2ecf20Sopenharmony_ci
39628c2ecf20Sopenharmony_ci/**
39638c2ecf20Sopenharmony_ci * batadv_is_ap_isolated() - Check if packet from upper layer should be dropped
39648c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
39658c2ecf20Sopenharmony_ci * @src: source mac address of packet
39668c2ecf20Sopenharmony_ci * @dst: destination mac address of packet
39678c2ecf20Sopenharmony_ci * @vid: vlan id of packet
39688c2ecf20Sopenharmony_ci *
39698c2ecf20Sopenharmony_ci * Return: true when src+dst(+vid) pair should be isolated, false otherwise
39708c2ecf20Sopenharmony_ci */
39718c2ecf20Sopenharmony_cibool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst,
39728c2ecf20Sopenharmony_ci			   unsigned short vid)
39738c2ecf20Sopenharmony_ci{
39748c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry;
39758c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry;
39768c2ecf20Sopenharmony_ci	struct batadv_softif_vlan *vlan;
39778c2ecf20Sopenharmony_ci	bool ret = false;
39788c2ecf20Sopenharmony_ci
39798c2ecf20Sopenharmony_ci	vlan = batadv_softif_vlan_get(bat_priv, vid);
39808c2ecf20Sopenharmony_ci	if (!vlan)
39818c2ecf20Sopenharmony_ci		return false;
39828c2ecf20Sopenharmony_ci
39838c2ecf20Sopenharmony_ci	if (!atomic_read(&vlan->ap_isolation))
39848c2ecf20Sopenharmony_ci		goto vlan_put;
39858c2ecf20Sopenharmony_ci
39868c2ecf20Sopenharmony_ci	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid);
39878c2ecf20Sopenharmony_ci	if (!tt_local_entry)
39888c2ecf20Sopenharmony_ci		goto vlan_put;
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_ci	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid);
39918c2ecf20Sopenharmony_ci	if (!tt_global_entry)
39928c2ecf20Sopenharmony_ci		goto local_entry_put;
39938c2ecf20Sopenharmony_ci
39948c2ecf20Sopenharmony_ci	if (_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
39958c2ecf20Sopenharmony_ci		ret = true;
39968c2ecf20Sopenharmony_ci
39978c2ecf20Sopenharmony_ci	batadv_tt_global_entry_put(tt_global_entry);
39988c2ecf20Sopenharmony_cilocal_entry_put:
39998c2ecf20Sopenharmony_ci	batadv_tt_local_entry_put(tt_local_entry);
40008c2ecf20Sopenharmony_civlan_put:
40018c2ecf20Sopenharmony_ci	batadv_softif_vlan_put(vlan);
40028c2ecf20Sopenharmony_ci	return ret;
40038c2ecf20Sopenharmony_ci}
40048c2ecf20Sopenharmony_ci
40058c2ecf20Sopenharmony_ci/**
40068c2ecf20Sopenharmony_ci * batadv_tt_update_orig() - update global translation table with new tt
40078c2ecf20Sopenharmony_ci *  information received via ogms
40088c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
40098c2ecf20Sopenharmony_ci * @orig_node: the orig_node of the ogm
40108c2ecf20Sopenharmony_ci * @tt_buff: pointer to the first tvlv VLAN entry
40118c2ecf20Sopenharmony_ci * @tt_num_vlan: number of tvlv VLAN entries
40128c2ecf20Sopenharmony_ci * @tt_change: pointer to the first entry in the TT buffer
40138c2ecf20Sopenharmony_ci * @tt_num_changes: number of tt changes inside the tt buffer
40148c2ecf20Sopenharmony_ci * @ttvn: translation table version number of this changeset
40158c2ecf20Sopenharmony_ci */
40168c2ecf20Sopenharmony_cistatic void batadv_tt_update_orig(struct batadv_priv *bat_priv,
40178c2ecf20Sopenharmony_ci				  struct batadv_orig_node *orig_node,
40188c2ecf20Sopenharmony_ci				  const void *tt_buff, u16 tt_num_vlan,
40198c2ecf20Sopenharmony_ci				  struct batadv_tvlv_tt_change *tt_change,
40208c2ecf20Sopenharmony_ci				  u16 tt_num_changes, u8 ttvn)
40218c2ecf20Sopenharmony_ci{
40228c2ecf20Sopenharmony_ci	u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn);
40238c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_vlan_data *tt_vlan;
40248c2ecf20Sopenharmony_ci	bool full_table = true;
40258c2ecf20Sopenharmony_ci	bool has_tt_init;
40268c2ecf20Sopenharmony_ci
40278c2ecf20Sopenharmony_ci	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
40288c2ecf20Sopenharmony_ci	has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT,
40298c2ecf20Sopenharmony_ci			       &orig_node->capa_initialized);
40308c2ecf20Sopenharmony_ci
40318c2ecf20Sopenharmony_ci	/* orig table not initialised AND first diff is in the OGM OR the ttvn
40328c2ecf20Sopenharmony_ci	 * increased by one -> we can apply the attached changes
40338c2ecf20Sopenharmony_ci	 */
40348c2ecf20Sopenharmony_ci	if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) {
40358c2ecf20Sopenharmony_ci		/* the OGM could not contain the changes due to their size or
40368c2ecf20Sopenharmony_ci		 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
40378c2ecf20Sopenharmony_ci		 * times.
40388c2ecf20Sopenharmony_ci		 * In this case send a tt request
40398c2ecf20Sopenharmony_ci		 */
40408c2ecf20Sopenharmony_ci		if (!tt_num_changes) {
40418c2ecf20Sopenharmony_ci			full_table = false;
40428c2ecf20Sopenharmony_ci			goto request_table;
40438c2ecf20Sopenharmony_ci		}
40448c2ecf20Sopenharmony_ci
40458c2ecf20Sopenharmony_ci		spin_lock_bh(&orig_node->tt_lock);
40468c2ecf20Sopenharmony_ci
40478c2ecf20Sopenharmony_ci		batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
40488c2ecf20Sopenharmony_ci					 ttvn, tt_change);
40498c2ecf20Sopenharmony_ci
40508c2ecf20Sopenharmony_ci		/* Even if we received the precomputed crc with the OGM, we
40518c2ecf20Sopenharmony_ci		 * prefer to recompute it to spot any possible inconsistency
40528c2ecf20Sopenharmony_ci		 * in the global table
40538c2ecf20Sopenharmony_ci		 */
40548c2ecf20Sopenharmony_ci		batadv_tt_global_update_crc(bat_priv, orig_node);
40558c2ecf20Sopenharmony_ci
40568c2ecf20Sopenharmony_ci		spin_unlock_bh(&orig_node->tt_lock);
40578c2ecf20Sopenharmony_ci
40588c2ecf20Sopenharmony_ci		/* The ttvn alone is not enough to guarantee consistency
40598c2ecf20Sopenharmony_ci		 * because a single value could represent different states
40608c2ecf20Sopenharmony_ci		 * (due to the wrap around). Thus a node has to check whether
40618c2ecf20Sopenharmony_ci		 * the resulting table (after applying the changes) is still
40628c2ecf20Sopenharmony_ci		 * consistent or not. E.g. a node could disconnect while its
40638c2ecf20Sopenharmony_ci		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
40648c2ecf20Sopenharmony_ci		 * checking the CRC value is mandatory to detect the
40658c2ecf20Sopenharmony_ci		 * inconsistency
40668c2ecf20Sopenharmony_ci		 */
40678c2ecf20Sopenharmony_ci		if (!batadv_tt_global_check_crc(orig_node, tt_vlan,
40688c2ecf20Sopenharmony_ci						tt_num_vlan))
40698c2ecf20Sopenharmony_ci			goto request_table;
40708c2ecf20Sopenharmony_ci	} else {
40718c2ecf20Sopenharmony_ci		/* if we missed more than one change or our tables are not
40728c2ecf20Sopenharmony_ci		 * in sync anymore -> request fresh tt data
40738c2ecf20Sopenharmony_ci		 */
40748c2ecf20Sopenharmony_ci		if (!has_tt_init || ttvn != orig_ttvn ||
40758c2ecf20Sopenharmony_ci		    !batadv_tt_global_check_crc(orig_node, tt_vlan,
40768c2ecf20Sopenharmony_ci						tt_num_vlan)) {
40778c2ecf20Sopenharmony_cirequest_table:
40788c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_TT, bat_priv,
40798c2ecf20Sopenharmony_ci				   "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n",
40808c2ecf20Sopenharmony_ci				   orig_node->orig, ttvn, orig_ttvn,
40818c2ecf20Sopenharmony_ci				   tt_num_changes);
40828c2ecf20Sopenharmony_ci			batadv_send_tt_request(bat_priv, orig_node, ttvn,
40838c2ecf20Sopenharmony_ci					       tt_vlan, tt_num_vlan,
40848c2ecf20Sopenharmony_ci					       full_table);
40858c2ecf20Sopenharmony_ci			return;
40868c2ecf20Sopenharmony_ci		}
40878c2ecf20Sopenharmony_ci	}
40888c2ecf20Sopenharmony_ci}
40898c2ecf20Sopenharmony_ci
40908c2ecf20Sopenharmony_ci/**
40918c2ecf20Sopenharmony_ci * batadv_tt_global_client_is_roaming() - check if a client is marked as roaming
40928c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
40938c2ecf20Sopenharmony_ci * @addr: the mac address of the client to check
40948c2ecf20Sopenharmony_ci * @vid: VLAN identifier
40958c2ecf20Sopenharmony_ci *
40968c2ecf20Sopenharmony_ci * Return: true if we know that the client has moved from its old originator
40978c2ecf20Sopenharmony_ci * to another one. This entry is still kept for consistency purposes and will be
40988c2ecf20Sopenharmony_ci * deleted later by a DEL or because of timeout
40998c2ecf20Sopenharmony_ci */
41008c2ecf20Sopenharmony_cibool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
41018c2ecf20Sopenharmony_ci					u8 *addr, unsigned short vid)
41028c2ecf20Sopenharmony_ci{
41038c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global_entry;
41048c2ecf20Sopenharmony_ci	bool ret = false;
41058c2ecf20Sopenharmony_ci
41068c2ecf20Sopenharmony_ci	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
41078c2ecf20Sopenharmony_ci	if (!tt_global_entry)
41088c2ecf20Sopenharmony_ci		goto out;
41098c2ecf20Sopenharmony_ci
41108c2ecf20Sopenharmony_ci	ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
41118c2ecf20Sopenharmony_ci	batadv_tt_global_entry_put(tt_global_entry);
41128c2ecf20Sopenharmony_ciout:
41138c2ecf20Sopenharmony_ci	return ret;
41148c2ecf20Sopenharmony_ci}
41158c2ecf20Sopenharmony_ci
41168c2ecf20Sopenharmony_ci/**
41178c2ecf20Sopenharmony_ci * batadv_tt_local_client_is_roaming() - tells whether the client is roaming
41188c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
41198c2ecf20Sopenharmony_ci * @addr: the mac address of the local client to query
41208c2ecf20Sopenharmony_ci * @vid: VLAN identifier
41218c2ecf20Sopenharmony_ci *
41228c2ecf20Sopenharmony_ci * Return: true if the local client is known to be roaming (it is not served by
41238c2ecf20Sopenharmony_ci * this node anymore) or not. If yes, the client is still present in the table
41248c2ecf20Sopenharmony_ci * to keep the latter consistent with the node TTVN
41258c2ecf20Sopenharmony_ci */
41268c2ecf20Sopenharmony_cibool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
41278c2ecf20Sopenharmony_ci				       u8 *addr, unsigned short vid)
41288c2ecf20Sopenharmony_ci{
41298c2ecf20Sopenharmony_ci	struct batadv_tt_local_entry *tt_local_entry;
41308c2ecf20Sopenharmony_ci	bool ret = false;
41318c2ecf20Sopenharmony_ci
41328c2ecf20Sopenharmony_ci	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
41338c2ecf20Sopenharmony_ci	if (!tt_local_entry)
41348c2ecf20Sopenharmony_ci		goto out;
41358c2ecf20Sopenharmony_ci
41368c2ecf20Sopenharmony_ci	ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
41378c2ecf20Sopenharmony_ci	batadv_tt_local_entry_put(tt_local_entry);
41388c2ecf20Sopenharmony_ciout:
41398c2ecf20Sopenharmony_ci	return ret;
41408c2ecf20Sopenharmony_ci}
41418c2ecf20Sopenharmony_ci
41428c2ecf20Sopenharmony_ci/**
41438c2ecf20Sopenharmony_ci * batadv_tt_add_temporary_global_entry() - Add temporary entry to global TT
41448c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
41458c2ecf20Sopenharmony_ci * @orig_node: orig node which the temporary entry should be associated with
41468c2ecf20Sopenharmony_ci * @addr: mac address of the client
41478c2ecf20Sopenharmony_ci * @vid: VLAN id of the new temporary global translation table
41488c2ecf20Sopenharmony_ci *
41498c2ecf20Sopenharmony_ci * Return: true when temporary tt entry could be added, false otherwise
41508c2ecf20Sopenharmony_ci */
41518c2ecf20Sopenharmony_cibool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
41528c2ecf20Sopenharmony_ci					  struct batadv_orig_node *orig_node,
41538c2ecf20Sopenharmony_ci					  const unsigned char *addr,
41548c2ecf20Sopenharmony_ci					  unsigned short vid)
41558c2ecf20Sopenharmony_ci{
41568c2ecf20Sopenharmony_ci	/* ignore loop detect macs, they are not supposed to be in the tt local
41578c2ecf20Sopenharmony_ci	 * data as well.
41588c2ecf20Sopenharmony_ci	 */
41598c2ecf20Sopenharmony_ci	if (batadv_bla_is_loopdetect_mac(addr))
41608c2ecf20Sopenharmony_ci		return false;
41618c2ecf20Sopenharmony_ci
41628c2ecf20Sopenharmony_ci	if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid,
41638c2ecf20Sopenharmony_ci				  BATADV_TT_CLIENT_TEMP,
41648c2ecf20Sopenharmony_ci				  atomic_read(&orig_node->last_ttvn)))
41658c2ecf20Sopenharmony_ci		return false;
41668c2ecf20Sopenharmony_ci
41678c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
41688c2ecf20Sopenharmony_ci		   "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n",
41698c2ecf20Sopenharmony_ci		   addr, batadv_print_vid(vid), orig_node->orig);
41708c2ecf20Sopenharmony_ci
41718c2ecf20Sopenharmony_ci	return true;
41728c2ecf20Sopenharmony_ci}
41738c2ecf20Sopenharmony_ci
41748c2ecf20Sopenharmony_ci/**
41758c2ecf20Sopenharmony_ci * batadv_tt_local_resize_to_mtu() - resize the local translation table fit the
41768c2ecf20Sopenharmony_ci *  maximum packet size that can be transported through the mesh
41778c2ecf20Sopenharmony_ci * @soft_iface: netdev struct of the mesh interface
41788c2ecf20Sopenharmony_ci *
41798c2ecf20Sopenharmony_ci * Remove entries older than 'timeout' and half timeout if more entries need
41808c2ecf20Sopenharmony_ci * to be removed.
41818c2ecf20Sopenharmony_ci */
41828c2ecf20Sopenharmony_civoid batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
41838c2ecf20Sopenharmony_ci{
41848c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
41858c2ecf20Sopenharmony_ci	int packet_size_max = atomic_read(&bat_priv->packet_size_max);
41868c2ecf20Sopenharmony_ci	int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
41878c2ecf20Sopenharmony_ci	bool reduced = false;
41888c2ecf20Sopenharmony_ci
41898c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tt.commit_lock);
41908c2ecf20Sopenharmony_ci
41918c2ecf20Sopenharmony_ci	while (timeout) {
41928c2ecf20Sopenharmony_ci		table_size = batadv_tt_local_table_transmit_size(bat_priv);
41938c2ecf20Sopenharmony_ci		if (packet_size_max >= table_size)
41948c2ecf20Sopenharmony_ci			break;
41958c2ecf20Sopenharmony_ci
41968c2ecf20Sopenharmony_ci		batadv_tt_local_purge(bat_priv, timeout);
41978c2ecf20Sopenharmony_ci		batadv_tt_local_purge_pending_clients(bat_priv);
41988c2ecf20Sopenharmony_ci
41998c2ecf20Sopenharmony_ci		timeout /= 2;
42008c2ecf20Sopenharmony_ci		reduced = true;
42018c2ecf20Sopenharmony_ci		net_ratelimited_function(batadv_info, soft_iface,
42028c2ecf20Sopenharmony_ci					 "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
42038c2ecf20Sopenharmony_ci					 packet_size_max);
42048c2ecf20Sopenharmony_ci	}
42058c2ecf20Sopenharmony_ci
42068c2ecf20Sopenharmony_ci	/* commit these changes immediately, to avoid synchronization problem
42078c2ecf20Sopenharmony_ci	 * with the TTVN
42088c2ecf20Sopenharmony_ci	 */
42098c2ecf20Sopenharmony_ci	if (reduced)
42108c2ecf20Sopenharmony_ci		batadv_tt_local_commit_changes_nolock(bat_priv);
42118c2ecf20Sopenharmony_ci
42128c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tt.commit_lock);
42138c2ecf20Sopenharmony_ci}
42148c2ecf20Sopenharmony_ci
42158c2ecf20Sopenharmony_ci/**
42168c2ecf20Sopenharmony_ci * batadv_tt_tvlv_ogm_handler_v1() - process incoming tt tvlv container
42178c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
42188c2ecf20Sopenharmony_ci * @orig: the orig_node of the ogm
42198c2ecf20Sopenharmony_ci * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
42208c2ecf20Sopenharmony_ci * @tvlv_value: tvlv buffer containing the gateway data
42218c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv buffer length
42228c2ecf20Sopenharmony_ci */
42238c2ecf20Sopenharmony_cistatic void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
42248c2ecf20Sopenharmony_ci					  struct batadv_orig_node *orig,
42258c2ecf20Sopenharmony_ci					  u8 flags, void *tvlv_value,
42268c2ecf20Sopenharmony_ci					  u16 tvlv_value_len)
42278c2ecf20Sopenharmony_ci{
42288c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_vlan_data *tt_vlan;
42298c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_change *tt_change;
42308c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_data *tt_data;
42318c2ecf20Sopenharmony_ci	u16 num_entries, num_vlan;
42328c2ecf20Sopenharmony_ci
42338c2ecf20Sopenharmony_ci	if (tvlv_value_len < sizeof(*tt_data))
42348c2ecf20Sopenharmony_ci		return;
42358c2ecf20Sopenharmony_ci
42368c2ecf20Sopenharmony_ci	tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
42378c2ecf20Sopenharmony_ci	tvlv_value_len -= sizeof(*tt_data);
42388c2ecf20Sopenharmony_ci
42398c2ecf20Sopenharmony_ci	num_vlan = ntohs(tt_data->num_vlan);
42408c2ecf20Sopenharmony_ci
42418c2ecf20Sopenharmony_ci	if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan)
42428c2ecf20Sopenharmony_ci		return;
42438c2ecf20Sopenharmony_ci
42448c2ecf20Sopenharmony_ci	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
42458c2ecf20Sopenharmony_ci	tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan);
42468c2ecf20Sopenharmony_ci	tvlv_value_len -= sizeof(*tt_vlan) * num_vlan;
42478c2ecf20Sopenharmony_ci
42488c2ecf20Sopenharmony_ci	num_entries = batadv_tt_entries(tvlv_value_len);
42498c2ecf20Sopenharmony_ci
42508c2ecf20Sopenharmony_ci	batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change,
42518c2ecf20Sopenharmony_ci			      num_entries, tt_data->ttvn);
42528c2ecf20Sopenharmony_ci}
42538c2ecf20Sopenharmony_ci
42548c2ecf20Sopenharmony_ci/**
42558c2ecf20Sopenharmony_ci * batadv_tt_tvlv_unicast_handler_v1() - process incoming (unicast) tt tvlv
42568c2ecf20Sopenharmony_ci *  container
42578c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
42588c2ecf20Sopenharmony_ci * @src: mac address of tt tvlv sender
42598c2ecf20Sopenharmony_ci * @dst: mac address of tt tvlv recipient
42608c2ecf20Sopenharmony_ci * @tvlv_value: tvlv buffer containing the tt data
42618c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv buffer length
42628c2ecf20Sopenharmony_ci *
42638c2ecf20Sopenharmony_ci * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS
42648c2ecf20Sopenharmony_ci * otherwise.
42658c2ecf20Sopenharmony_ci */
42668c2ecf20Sopenharmony_cistatic int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
42678c2ecf20Sopenharmony_ci					     u8 *src, u8 *dst,
42688c2ecf20Sopenharmony_ci					     void *tvlv_value,
42698c2ecf20Sopenharmony_ci					     u16 tvlv_value_len)
42708c2ecf20Sopenharmony_ci{
42718c2ecf20Sopenharmony_ci	struct batadv_tvlv_tt_data *tt_data;
42728c2ecf20Sopenharmony_ci	u16 tt_vlan_len, tt_num_entries;
42738c2ecf20Sopenharmony_ci	char tt_flag;
42748c2ecf20Sopenharmony_ci	bool ret;
42758c2ecf20Sopenharmony_ci
42768c2ecf20Sopenharmony_ci	if (tvlv_value_len < sizeof(*tt_data))
42778c2ecf20Sopenharmony_ci		return NET_RX_SUCCESS;
42788c2ecf20Sopenharmony_ci
42798c2ecf20Sopenharmony_ci	tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
42808c2ecf20Sopenharmony_ci	tvlv_value_len -= sizeof(*tt_data);
42818c2ecf20Sopenharmony_ci
42828c2ecf20Sopenharmony_ci	tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data);
42838c2ecf20Sopenharmony_ci	tt_vlan_len *= ntohs(tt_data->num_vlan);
42848c2ecf20Sopenharmony_ci
42858c2ecf20Sopenharmony_ci	if (tvlv_value_len < tt_vlan_len)
42868c2ecf20Sopenharmony_ci		return NET_RX_SUCCESS;
42878c2ecf20Sopenharmony_ci
42888c2ecf20Sopenharmony_ci	tvlv_value_len -= tt_vlan_len;
42898c2ecf20Sopenharmony_ci	tt_num_entries = batadv_tt_entries(tvlv_value_len);
42908c2ecf20Sopenharmony_ci
42918c2ecf20Sopenharmony_ci	switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
42928c2ecf20Sopenharmony_ci	case BATADV_TT_REQUEST:
42938c2ecf20Sopenharmony_ci		batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX);
42948c2ecf20Sopenharmony_ci
42958c2ecf20Sopenharmony_ci		/* If this node cannot provide a TT response the tt_request is
42968c2ecf20Sopenharmony_ci		 * forwarded
42978c2ecf20Sopenharmony_ci		 */
42988c2ecf20Sopenharmony_ci		ret = batadv_send_tt_response(bat_priv, tt_data, src, dst);
42998c2ecf20Sopenharmony_ci		if (!ret) {
43008c2ecf20Sopenharmony_ci			if (tt_data->flags & BATADV_TT_FULL_TABLE)
43018c2ecf20Sopenharmony_ci				tt_flag = 'F';
43028c2ecf20Sopenharmony_ci			else
43038c2ecf20Sopenharmony_ci				tt_flag = '.';
43048c2ecf20Sopenharmony_ci
43058c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_TT, bat_priv,
43068c2ecf20Sopenharmony_ci				   "Routing TT_REQUEST to %pM [%c]\n",
43078c2ecf20Sopenharmony_ci				   dst, tt_flag);
43088c2ecf20Sopenharmony_ci			/* tvlv API will re-route the packet */
43098c2ecf20Sopenharmony_ci			return NET_RX_DROP;
43108c2ecf20Sopenharmony_ci		}
43118c2ecf20Sopenharmony_ci		break;
43128c2ecf20Sopenharmony_ci	case BATADV_TT_RESPONSE:
43138c2ecf20Sopenharmony_ci		batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
43148c2ecf20Sopenharmony_ci
43158c2ecf20Sopenharmony_ci		if (batadv_is_my_mac(bat_priv, dst)) {
43168c2ecf20Sopenharmony_ci			batadv_handle_tt_response(bat_priv, tt_data,
43178c2ecf20Sopenharmony_ci						  src, tt_num_entries);
43188c2ecf20Sopenharmony_ci			return NET_RX_SUCCESS;
43198c2ecf20Sopenharmony_ci		}
43208c2ecf20Sopenharmony_ci
43218c2ecf20Sopenharmony_ci		if (tt_data->flags & BATADV_TT_FULL_TABLE)
43228c2ecf20Sopenharmony_ci			tt_flag =  'F';
43238c2ecf20Sopenharmony_ci		else
43248c2ecf20Sopenharmony_ci			tt_flag = '.';
43258c2ecf20Sopenharmony_ci
43268c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_TT, bat_priv,
43278c2ecf20Sopenharmony_ci			   "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag);
43288c2ecf20Sopenharmony_ci
43298c2ecf20Sopenharmony_ci		/* tvlv API will re-route the packet */
43308c2ecf20Sopenharmony_ci		return NET_RX_DROP;
43318c2ecf20Sopenharmony_ci	}
43328c2ecf20Sopenharmony_ci
43338c2ecf20Sopenharmony_ci	return NET_RX_SUCCESS;
43348c2ecf20Sopenharmony_ci}
43358c2ecf20Sopenharmony_ci
43368c2ecf20Sopenharmony_ci/**
43378c2ecf20Sopenharmony_ci * batadv_roam_tvlv_unicast_handler_v1() - process incoming tt roam tvlv
43388c2ecf20Sopenharmony_ci *  container
43398c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
43408c2ecf20Sopenharmony_ci * @src: mac address of tt tvlv sender
43418c2ecf20Sopenharmony_ci * @dst: mac address of tt tvlv recipient
43428c2ecf20Sopenharmony_ci * @tvlv_value: tvlv buffer containing the tt data
43438c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv buffer length
43448c2ecf20Sopenharmony_ci *
43458c2ecf20Sopenharmony_ci * Return: NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS
43468c2ecf20Sopenharmony_ci * otherwise.
43478c2ecf20Sopenharmony_ci */
43488c2ecf20Sopenharmony_cistatic int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
43498c2ecf20Sopenharmony_ci					       u8 *src, u8 *dst,
43508c2ecf20Sopenharmony_ci					       void *tvlv_value,
43518c2ecf20Sopenharmony_ci					       u16 tvlv_value_len)
43528c2ecf20Sopenharmony_ci{
43538c2ecf20Sopenharmony_ci	struct batadv_tvlv_roam_adv *roaming_adv;
43548c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node = NULL;
43558c2ecf20Sopenharmony_ci
43568c2ecf20Sopenharmony_ci	/* If this node is not the intended recipient of the
43578c2ecf20Sopenharmony_ci	 * roaming advertisement the packet is forwarded
43588c2ecf20Sopenharmony_ci	 * (the tvlv API will re-route the packet).
43598c2ecf20Sopenharmony_ci	 */
43608c2ecf20Sopenharmony_ci	if (!batadv_is_my_mac(bat_priv, dst))
43618c2ecf20Sopenharmony_ci		return NET_RX_DROP;
43628c2ecf20Sopenharmony_ci
43638c2ecf20Sopenharmony_ci	if (tvlv_value_len < sizeof(*roaming_adv))
43648c2ecf20Sopenharmony_ci		goto out;
43658c2ecf20Sopenharmony_ci
43668c2ecf20Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, src);
43678c2ecf20Sopenharmony_ci	if (!orig_node)
43688c2ecf20Sopenharmony_ci		goto out;
43698c2ecf20Sopenharmony_ci
43708c2ecf20Sopenharmony_ci	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
43718c2ecf20Sopenharmony_ci	roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value;
43728c2ecf20Sopenharmony_ci
43738c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_TT, bat_priv,
43748c2ecf20Sopenharmony_ci		   "Received ROAMING_ADV from %pM (client %pM)\n",
43758c2ecf20Sopenharmony_ci		   src, roaming_adv->client);
43768c2ecf20Sopenharmony_ci
43778c2ecf20Sopenharmony_ci	batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client,
43788c2ecf20Sopenharmony_ci			     ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM,
43798c2ecf20Sopenharmony_ci			     atomic_read(&orig_node->last_ttvn) + 1);
43808c2ecf20Sopenharmony_ci
43818c2ecf20Sopenharmony_ciout:
43828c2ecf20Sopenharmony_ci	if (orig_node)
43838c2ecf20Sopenharmony_ci		batadv_orig_node_put(orig_node);
43848c2ecf20Sopenharmony_ci	return NET_RX_SUCCESS;
43858c2ecf20Sopenharmony_ci}
43868c2ecf20Sopenharmony_ci
43878c2ecf20Sopenharmony_ci/**
43888c2ecf20Sopenharmony_ci * batadv_tt_init() - initialise the translation table internals
43898c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
43908c2ecf20Sopenharmony_ci *
43918c2ecf20Sopenharmony_ci * Return: 0 on success or negative error number in case of failure.
43928c2ecf20Sopenharmony_ci */
43938c2ecf20Sopenharmony_ciint batadv_tt_init(struct batadv_priv *bat_priv)
43948c2ecf20Sopenharmony_ci{
43958c2ecf20Sopenharmony_ci	int ret;
43968c2ecf20Sopenharmony_ci
43978c2ecf20Sopenharmony_ci	/* synchronized flags must be remote */
43988c2ecf20Sopenharmony_ci	BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK));
43998c2ecf20Sopenharmony_ci
44008c2ecf20Sopenharmony_ci	ret = batadv_tt_local_init(bat_priv);
44018c2ecf20Sopenharmony_ci	if (ret < 0)
44028c2ecf20Sopenharmony_ci		return ret;
44038c2ecf20Sopenharmony_ci
44048c2ecf20Sopenharmony_ci	ret = batadv_tt_global_init(bat_priv);
44058c2ecf20Sopenharmony_ci	if (ret < 0) {
44068c2ecf20Sopenharmony_ci		batadv_tt_local_table_free(bat_priv);
44078c2ecf20Sopenharmony_ci		return ret;
44088c2ecf20Sopenharmony_ci	}
44098c2ecf20Sopenharmony_ci
44108c2ecf20Sopenharmony_ci	batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1,
44118c2ecf20Sopenharmony_ci				     batadv_tt_tvlv_unicast_handler_v1,
44128c2ecf20Sopenharmony_ci				     BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
44138c2ecf20Sopenharmony_ci
44148c2ecf20Sopenharmony_ci	batadv_tvlv_handler_register(bat_priv, NULL,
44158c2ecf20Sopenharmony_ci				     batadv_roam_tvlv_unicast_handler_v1,
44168c2ecf20Sopenharmony_ci				     BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS);
44178c2ecf20Sopenharmony_ci
44188c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
44198c2ecf20Sopenharmony_ci	queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
44208c2ecf20Sopenharmony_ci			   msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
44218c2ecf20Sopenharmony_ci
44228c2ecf20Sopenharmony_ci	return 1;
44238c2ecf20Sopenharmony_ci}
44248c2ecf20Sopenharmony_ci
44258c2ecf20Sopenharmony_ci/**
44268c2ecf20Sopenharmony_ci * batadv_tt_global_is_isolated() - check if a client is marked as isolated
44278c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
44288c2ecf20Sopenharmony_ci * @addr: the mac address of the client
44298c2ecf20Sopenharmony_ci * @vid: the identifier of the VLAN where this client is connected
44308c2ecf20Sopenharmony_ci *
44318c2ecf20Sopenharmony_ci * Return: true if the client is marked with the TT_CLIENT_ISOLA flag, false
44328c2ecf20Sopenharmony_ci * otherwise
44338c2ecf20Sopenharmony_ci */
44348c2ecf20Sopenharmony_cibool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
44358c2ecf20Sopenharmony_ci				  const u8 *addr, unsigned short vid)
44368c2ecf20Sopenharmony_ci{
44378c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt;
44388c2ecf20Sopenharmony_ci	bool ret;
44398c2ecf20Sopenharmony_ci
44408c2ecf20Sopenharmony_ci	tt = batadv_tt_global_hash_find(bat_priv, addr, vid);
44418c2ecf20Sopenharmony_ci	if (!tt)
44428c2ecf20Sopenharmony_ci		return false;
44438c2ecf20Sopenharmony_ci
44448c2ecf20Sopenharmony_ci	ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
44458c2ecf20Sopenharmony_ci
44468c2ecf20Sopenharmony_ci	batadv_tt_global_entry_put(tt);
44478c2ecf20Sopenharmony_ci
44488c2ecf20Sopenharmony_ci	return ret;
44498c2ecf20Sopenharmony_ci}
44508c2ecf20Sopenharmony_ci
44518c2ecf20Sopenharmony_ci/**
44528c2ecf20Sopenharmony_ci * batadv_tt_cache_init() - Initialize tt memory object cache
44538c2ecf20Sopenharmony_ci *
44548c2ecf20Sopenharmony_ci * Return: 0 on success or negative error number in case of failure.
44558c2ecf20Sopenharmony_ci */
44568c2ecf20Sopenharmony_ciint __init batadv_tt_cache_init(void)
44578c2ecf20Sopenharmony_ci{
44588c2ecf20Sopenharmony_ci	size_t tl_size = sizeof(struct batadv_tt_local_entry);
44598c2ecf20Sopenharmony_ci	size_t tg_size = sizeof(struct batadv_tt_global_entry);
44608c2ecf20Sopenharmony_ci	size_t tt_orig_size = sizeof(struct batadv_tt_orig_list_entry);
44618c2ecf20Sopenharmony_ci	size_t tt_change_size = sizeof(struct batadv_tt_change_node);
44628c2ecf20Sopenharmony_ci	size_t tt_req_size = sizeof(struct batadv_tt_req_node);
44638c2ecf20Sopenharmony_ci	size_t tt_roam_size = sizeof(struct batadv_tt_roam_node);
44648c2ecf20Sopenharmony_ci
44658c2ecf20Sopenharmony_ci	batadv_tl_cache = kmem_cache_create("batadv_tl_cache", tl_size, 0,
44668c2ecf20Sopenharmony_ci					    SLAB_HWCACHE_ALIGN, NULL);
44678c2ecf20Sopenharmony_ci	if (!batadv_tl_cache)
44688c2ecf20Sopenharmony_ci		return -ENOMEM;
44698c2ecf20Sopenharmony_ci
44708c2ecf20Sopenharmony_ci	batadv_tg_cache = kmem_cache_create("batadv_tg_cache", tg_size, 0,
44718c2ecf20Sopenharmony_ci					    SLAB_HWCACHE_ALIGN, NULL);
44728c2ecf20Sopenharmony_ci	if (!batadv_tg_cache)
44738c2ecf20Sopenharmony_ci		goto err_tt_tl_destroy;
44748c2ecf20Sopenharmony_ci
44758c2ecf20Sopenharmony_ci	batadv_tt_orig_cache = kmem_cache_create("batadv_tt_orig_cache",
44768c2ecf20Sopenharmony_ci						 tt_orig_size, 0,
44778c2ecf20Sopenharmony_ci						 SLAB_HWCACHE_ALIGN, NULL);
44788c2ecf20Sopenharmony_ci	if (!batadv_tt_orig_cache)
44798c2ecf20Sopenharmony_ci		goto err_tt_tg_destroy;
44808c2ecf20Sopenharmony_ci
44818c2ecf20Sopenharmony_ci	batadv_tt_change_cache = kmem_cache_create("batadv_tt_change_cache",
44828c2ecf20Sopenharmony_ci						   tt_change_size, 0,
44838c2ecf20Sopenharmony_ci						   SLAB_HWCACHE_ALIGN, NULL);
44848c2ecf20Sopenharmony_ci	if (!batadv_tt_change_cache)
44858c2ecf20Sopenharmony_ci		goto err_tt_orig_destroy;
44868c2ecf20Sopenharmony_ci
44878c2ecf20Sopenharmony_ci	batadv_tt_req_cache = kmem_cache_create("batadv_tt_req_cache",
44888c2ecf20Sopenharmony_ci						tt_req_size, 0,
44898c2ecf20Sopenharmony_ci						SLAB_HWCACHE_ALIGN, NULL);
44908c2ecf20Sopenharmony_ci	if (!batadv_tt_req_cache)
44918c2ecf20Sopenharmony_ci		goto err_tt_change_destroy;
44928c2ecf20Sopenharmony_ci
44938c2ecf20Sopenharmony_ci	batadv_tt_roam_cache = kmem_cache_create("batadv_tt_roam_cache",
44948c2ecf20Sopenharmony_ci						 tt_roam_size, 0,
44958c2ecf20Sopenharmony_ci						 SLAB_HWCACHE_ALIGN, NULL);
44968c2ecf20Sopenharmony_ci	if (!batadv_tt_roam_cache)
44978c2ecf20Sopenharmony_ci		goto err_tt_req_destroy;
44988c2ecf20Sopenharmony_ci
44998c2ecf20Sopenharmony_ci	return 0;
45008c2ecf20Sopenharmony_ci
45018c2ecf20Sopenharmony_cierr_tt_req_destroy:
45028c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tt_req_cache);
45038c2ecf20Sopenharmony_ci	batadv_tt_req_cache = NULL;
45048c2ecf20Sopenharmony_cierr_tt_change_destroy:
45058c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tt_change_cache);
45068c2ecf20Sopenharmony_ci	batadv_tt_change_cache = NULL;
45078c2ecf20Sopenharmony_cierr_tt_orig_destroy:
45088c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tt_orig_cache);
45098c2ecf20Sopenharmony_ci	batadv_tt_orig_cache = NULL;
45108c2ecf20Sopenharmony_cierr_tt_tg_destroy:
45118c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tg_cache);
45128c2ecf20Sopenharmony_ci	batadv_tg_cache = NULL;
45138c2ecf20Sopenharmony_cierr_tt_tl_destroy:
45148c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tl_cache);
45158c2ecf20Sopenharmony_ci	batadv_tl_cache = NULL;
45168c2ecf20Sopenharmony_ci
45178c2ecf20Sopenharmony_ci	return -ENOMEM;
45188c2ecf20Sopenharmony_ci}
45198c2ecf20Sopenharmony_ci
45208c2ecf20Sopenharmony_ci/**
45218c2ecf20Sopenharmony_ci * batadv_tt_cache_destroy() - Destroy tt memory object cache
45228c2ecf20Sopenharmony_ci */
45238c2ecf20Sopenharmony_civoid batadv_tt_cache_destroy(void)
45248c2ecf20Sopenharmony_ci{
45258c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tl_cache);
45268c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tg_cache);
45278c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tt_orig_cache);
45288c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tt_change_cache);
45298c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tt_req_cache);
45308c2ecf20Sopenharmony_ci	kmem_cache_destroy(batadv_tt_roam_cache);
45318c2ecf20Sopenharmony_ci}
4532