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