1ac79cbb9SSven Eckelmann /* Copyright (C) 2007-2017 B.A.T.M.A.N. contributors: 2c6c8fea2SSven Eckelmann * 335c133a0SAntonio Quartulli * Marek Lindner, Simon Wunderlich, Antonio Quartulli 4c6c8fea2SSven Eckelmann * 5c6c8fea2SSven Eckelmann * This program is free software; you can redistribute it and/or 6c6c8fea2SSven Eckelmann * modify it under the terms of version 2 of the GNU General Public 7c6c8fea2SSven Eckelmann * License as published by the Free Software Foundation. 8c6c8fea2SSven Eckelmann * 9c6c8fea2SSven Eckelmann * This program is distributed in the hope that it will be useful, but 10c6c8fea2SSven Eckelmann * WITHOUT ANY WARRANTY; without even the implied warranty of 11c6c8fea2SSven Eckelmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12c6c8fea2SSven Eckelmann * General Public License for more details. 13c6c8fea2SSven Eckelmann * 14c6c8fea2SSven Eckelmann * You should have received a copy of the GNU General Public License 15ebf38fb7SAntonio Quartulli * along with this program; if not, see <http://www.gnu.org/licenses/>. 16c6c8fea2SSven Eckelmann */ 17c6c8fea2SSven Eckelmann 18c6c8fea2SSven Eckelmann #include "translation-table.h" 191e2c2a4fSSven Eckelmann #include "main.h" 20c6c8fea2SSven Eckelmann 211e2c2a4fSSven Eckelmann #include <linux/atomic.h> 22ac4eebd4SLinus Lüssing #include <linux/bitops.h> 231e2c2a4fSSven Eckelmann #include <linux/bug.h> 241e2c2a4fSSven Eckelmann #include <linux/byteorder/generic.h> 2586452f81SSven Eckelmann #include <linux/cache.h> 261e2c2a4fSSven Eckelmann #include <linux/compiler.h> 27ced72933SAntonio Quartulli #include <linux/crc32c.h> 281e2c2a4fSSven Eckelmann #include <linux/errno.h> 291e2c2a4fSSven Eckelmann #include <linux/etherdevice.h> 301e2c2a4fSSven Eckelmann #include <linux/fs.h> 311e2c2a4fSSven Eckelmann #include <linux/if_ether.h> 3286452f81SSven Eckelmann #include <linux/init.h> 331e2c2a4fSSven Eckelmann #include <linux/jhash.h> 341e2c2a4fSSven Eckelmann #include <linux/jiffies.h> 351e2c2a4fSSven Eckelmann #include <linux/kernel.h> 366e8ef69dSSven Eckelmann #include <linux/kref.h> 371e2c2a4fSSven Eckelmann #include <linux/list.h> 381e2c2a4fSSven Eckelmann #include <linux/lockdep.h> 391e2c2a4fSSven Eckelmann #include <linux/netdevice.h> 40d34f0550SMatthias Schiffer #include <linux/netlink.h> 411e2c2a4fSSven Eckelmann #include <linux/rculist.h> 421e2c2a4fSSven Eckelmann #include <linux/rcupdate.h> 431e2c2a4fSSven Eckelmann #include <linux/seq_file.h> 44d34f0550SMatthias Schiffer #include <linux/skbuff.h> 451e2c2a4fSSven Eckelmann #include <linux/slab.h> 461e2c2a4fSSven Eckelmann #include <linux/spinlock.h> 471e2c2a4fSSven Eckelmann #include <linux/stddef.h> 481e2c2a4fSSven Eckelmann #include <linux/string.h> 491e2c2a4fSSven Eckelmann #include <linux/workqueue.h> 50d34f0550SMatthias Schiffer #include <net/genetlink.h> 51d34f0550SMatthias Schiffer #include <net/netlink.h> 52d34f0550SMatthias Schiffer #include <net/sock.h> 53d34f0550SMatthias Schiffer #include <uapi/linux/batman_adv.h> 541e2c2a4fSSven Eckelmann 551e2c2a4fSSven Eckelmann #include "bridge_loop_avoidance.h" 561e2c2a4fSSven Eckelmann #include "hard-interface.h" 571e2c2a4fSSven Eckelmann #include "hash.h" 58ba412080SSven Eckelmann #include "log.h" 59d34f0550SMatthias Schiffer #include "netlink.h" 601e2c2a4fSSven Eckelmann #include "originator.h" 611e2c2a4fSSven Eckelmann #include "packet.h" 621e2c2a4fSSven Eckelmann #include "soft-interface.h" 631f8dce49SMarkus Pargmann #include "tvlv.h" 64a73105b8SAntonio Quartulli 6586452f81SSven Eckelmann static struct kmem_cache *batadv_tl_cache __read_mostly; 6686452f81SSven Eckelmann static struct kmem_cache *batadv_tg_cache __read_mostly; 6786452f81SSven Eckelmann static struct kmem_cache *batadv_tt_orig_cache __read_mostly; 6886452f81SSven Eckelmann static struct kmem_cache *batadv_tt_change_cache __read_mostly; 6986452f81SSven Eckelmann static struct kmem_cache *batadv_tt_req_cache __read_mostly; 7086452f81SSven Eckelmann static struct kmem_cache *batadv_tt_roam_cache __read_mostly; 7186452f81SSven Eckelmann 72dec05074SAntonio Quartulli /* hash class keys */ 73dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_local_hash_lock_class_key; 74dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_global_hash_lock_class_key; 75dec05074SAntonio Quartulli 766b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, 77c018ad3dSAntonio Quartulli unsigned short vid, 7856303d34SSven Eckelmann struct batadv_orig_node *orig_node); 79a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work); 80a513088dSSven Eckelmann static void 8156303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); 8230cfd02bSAntonio Quartulli static void batadv_tt_global_del(struct batadv_priv *bat_priv, 8330cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 8430cfd02bSAntonio Quartulli const unsigned char *addr, 85c018ad3dSAntonio Quartulli unsigned short vid, const char *message, 86c018ad3dSAntonio Quartulli bool roaming); 87c6c8fea2SSven Eckelmann 8862fe710fSSven Eckelmann /** 89d15cd622SAntonio Quartulli * batadv_compare_tt - check if two TT entries are the same 90d15cd622SAntonio Quartulli * @node: the list element pointer of the first TT entry 91d15cd622SAntonio Quartulli * @data2: pointer to the tt_common_entry of the second TT entry 9262fe710fSSven Eckelmann * 93d15cd622SAntonio Quartulli * Compare the MAC address and the VLAN ID of the two TT entries and check if 94d15cd622SAntonio Quartulli * they are the same TT client. 954b426b10SSven Eckelmann * Return: true if the two TT clients are the same, false otherwise 9662fe710fSSven Eckelmann */ 974b426b10SSven Eckelmann static bool batadv_compare_tt(const struct hlist_node *node, const void *data2) 987aadf889SMarek Lindner { 9956303d34SSven Eckelmann const void *data1 = container_of(node, struct batadv_tt_common_entry, 100747e4221SSven Eckelmann hash_entry); 1014c718958SMarek Lindner const struct batadv_tt_common_entry *tt1 = data1; 1024c718958SMarek Lindner const struct batadv_tt_common_entry *tt2 = data2; 1037aadf889SMarek Lindner 1044c718958SMarek Lindner return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2); 1057aadf889SMarek Lindner } 1067aadf889SMarek Lindner 107c018ad3dSAntonio Quartulli /** 108c018ad3dSAntonio Quartulli * batadv_choose_tt - return the index of the tt entry in the hash table 109c018ad3dSAntonio Quartulli * @data: pointer to the tt_common_entry object to map 110c018ad3dSAntonio Quartulli * @size: the size of the hash table 111c018ad3dSAntonio Quartulli * 11262fe710fSSven Eckelmann * Return: the hash index where the object represented by 'data' should be 113c018ad3dSAntonio Quartulli * stored at. 114c018ad3dSAntonio Quartulli */ 1156b5e971aSSven Eckelmann static inline u32 batadv_choose_tt(const void *data, u32 size) 116c018ad3dSAntonio Quartulli { 117c018ad3dSAntonio Quartulli struct batadv_tt_common_entry *tt; 1186b5e971aSSven Eckelmann u32 hash = 0; 119c018ad3dSAntonio Quartulli 120c018ad3dSAntonio Quartulli tt = (struct batadv_tt_common_entry *)data; 12136fd61cbSSven Eckelmann hash = jhash(&tt->addr, ETH_ALEN, hash); 12236fd61cbSSven Eckelmann hash = jhash(&tt->vid, sizeof(tt->vid), hash); 123c018ad3dSAntonio Quartulli 124c018ad3dSAntonio Quartulli return hash % size; 125c018ad3dSAntonio Quartulli } 126c018ad3dSAntonio Quartulli 127c018ad3dSAntonio Quartulli /** 128c018ad3dSAntonio Quartulli * batadv_tt_hash_find - look for a client in the given hash table 129c018ad3dSAntonio Quartulli * @hash: the hash table to search 130c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 131c018ad3dSAntonio Quartulli * @vid: VLAN identifier 132c018ad3dSAntonio Quartulli * 13362fe710fSSven Eckelmann * Return: a pointer to the tt_common struct belonging to the searched client if 134c018ad3dSAntonio Quartulli * found, NULL otherwise. 135c018ad3dSAntonio Quartulli */ 13656303d34SSven Eckelmann static struct batadv_tt_common_entry * 1376b5e971aSSven Eckelmann batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr, 138c018ad3dSAntonio Quartulli unsigned short vid) 1397aadf889SMarek Lindner { 1407aadf889SMarek Lindner struct hlist_head *head; 141c018ad3dSAntonio Quartulli struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; 1426b5e971aSSven Eckelmann u32 index; 1437aadf889SMarek Lindner 1447aadf889SMarek Lindner if (!hash) 1457aadf889SMarek Lindner return NULL; 1467aadf889SMarek Lindner 1478fdd0153SAntonio Quartulli ether_addr_copy(to_search.addr, addr); 148c018ad3dSAntonio Quartulli to_search.vid = vid; 149c018ad3dSAntonio Quartulli 150c018ad3dSAntonio Quartulli index = batadv_choose_tt(&to_search, hash->size); 1517aadf889SMarek Lindner head = &hash->table[index]; 1527aadf889SMarek Lindner 1537aadf889SMarek Lindner rcu_read_lock(); 154c018ad3dSAntonio Quartulli hlist_for_each_entry_rcu(tt, head, hash_entry) { 155c018ad3dSAntonio Quartulli if (!batadv_compare_eth(tt, addr)) 1567aadf889SMarek Lindner continue; 1577aadf889SMarek Lindner 158c018ad3dSAntonio Quartulli if (tt->vid != vid) 1597683fdc1SAntonio Quartulli continue; 1607683fdc1SAntonio Quartulli 16192dcdf09SSven Eckelmann if (!kref_get_unless_zero(&tt->refcount)) 162c018ad3dSAntonio Quartulli continue; 163c018ad3dSAntonio Quartulli 164c018ad3dSAntonio Quartulli tt_tmp = tt; 1657aadf889SMarek Lindner break; 1667aadf889SMarek Lindner } 1677aadf889SMarek Lindner rcu_read_unlock(); 1687aadf889SMarek Lindner 169c018ad3dSAntonio Quartulli return tt_tmp; 17048100bacSAntonio Quartulli } 17148100bacSAntonio Quartulli 172c018ad3dSAntonio Quartulli /** 173c018ad3dSAntonio Quartulli * batadv_tt_local_hash_find - search the local table for a given client 174c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 175c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 176c018ad3dSAntonio Quartulli * @vid: VLAN identifier 177c018ad3dSAntonio Quartulli * 17862fe710fSSven Eckelmann * Return: a pointer to the corresponding tt_local_entry struct if the client is 179c018ad3dSAntonio Quartulli * found, NULL otherwise. 180c018ad3dSAntonio Quartulli */ 18156303d34SSven Eckelmann static struct batadv_tt_local_entry * 1826b5e971aSSven Eckelmann batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr, 183c018ad3dSAntonio Quartulli unsigned short vid) 18448100bacSAntonio Quartulli { 18556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 18656303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 18748100bacSAntonio Quartulli 188c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, 189c018ad3dSAntonio Quartulli vid); 19048100bacSAntonio Quartulli if (tt_common_entry) 19148100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 19256303d34SSven Eckelmann struct batadv_tt_local_entry, 19356303d34SSven Eckelmann common); 19448100bacSAntonio Quartulli return tt_local_entry; 1957aadf889SMarek Lindner } 1967aadf889SMarek Lindner 197c018ad3dSAntonio Quartulli /** 198c018ad3dSAntonio Quartulli * batadv_tt_global_hash_find - search the global table for a given client 199c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 200c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 201c018ad3dSAntonio Quartulli * @vid: VLAN identifier 202c018ad3dSAntonio Quartulli * 20362fe710fSSven Eckelmann * Return: a pointer to the corresponding tt_global_entry struct if the client 204c018ad3dSAntonio Quartulli * is found, NULL otherwise. 205c018ad3dSAntonio Quartulli */ 20656303d34SSven Eckelmann static struct batadv_tt_global_entry * 2076b5e971aSSven Eckelmann batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, 208c018ad3dSAntonio Quartulli unsigned short vid) 2097aadf889SMarek Lindner { 21056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 21156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 2127aadf889SMarek Lindner 213c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, 214c018ad3dSAntonio Quartulli vid); 21548100bacSAntonio Quartulli if (tt_common_entry) 21648100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 21756303d34SSven Eckelmann struct batadv_tt_global_entry, 21856303d34SSven Eckelmann common); 21948100bacSAntonio Quartulli return tt_global_entry; 2207aadf889SMarek Lindner } 2217aadf889SMarek Lindner 22292dcdf09SSven Eckelmann /** 22386452f81SSven Eckelmann * batadv_tt_local_entry_free_rcu - free the tt_local_entry 22486452f81SSven Eckelmann * @rcu: rcu pointer of the tt_local_entry 22586452f81SSven Eckelmann */ 22686452f81SSven Eckelmann static void batadv_tt_local_entry_free_rcu(struct rcu_head *rcu) 22786452f81SSven Eckelmann { 22886452f81SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 22986452f81SSven Eckelmann 23086452f81SSven Eckelmann tt_local_entry = container_of(rcu, struct batadv_tt_local_entry, 23186452f81SSven Eckelmann common.rcu); 23286452f81SSven Eckelmann 23386452f81SSven Eckelmann kmem_cache_free(batadv_tl_cache, tt_local_entry); 23486452f81SSven Eckelmann } 23586452f81SSven Eckelmann 23686452f81SSven Eckelmann /** 23792dcdf09SSven Eckelmann * batadv_tt_local_entry_release - release tt_local_entry from lists and queue 23892dcdf09SSven Eckelmann * for free after rcu grace period 23992dcdf09SSven Eckelmann * @ref: kref pointer of the nc_node 24092dcdf09SSven Eckelmann */ 24192dcdf09SSven Eckelmann static void batadv_tt_local_entry_release(struct kref *ref) 2427683fdc1SAntonio Quartulli { 24392dcdf09SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 24492dcdf09SSven Eckelmann 24592dcdf09SSven Eckelmann tt_local_entry = container_of(ref, struct batadv_tt_local_entry, 24692dcdf09SSven Eckelmann common.refcount); 24792dcdf09SSven Eckelmann 248a33d970dSSven Eckelmann batadv_softif_vlan_put(tt_local_entry->vlan); 249a33d970dSSven Eckelmann 25086452f81SSven Eckelmann call_rcu(&tt_local_entry->common.rcu, batadv_tt_local_entry_free_rcu); 2517683fdc1SAntonio Quartulli } 2527683fdc1SAntonio Quartulli 25321026059SAntonio Quartulli /** 25495c0db90SSven Eckelmann * batadv_tt_local_entry_put - decrement the tt_local_entry refcounter and 25592dcdf09SSven Eckelmann * possibly release it 25692dcdf09SSven Eckelmann * @tt_local_entry: tt_local_entry to be free'd 25792dcdf09SSven Eckelmann */ 25892dcdf09SSven Eckelmann static void 25995c0db90SSven Eckelmann batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry) 26092dcdf09SSven Eckelmann { 26192dcdf09SSven Eckelmann kref_put(&tt_local_entry->common.refcount, 26292dcdf09SSven Eckelmann batadv_tt_local_entry_release); 26392dcdf09SSven Eckelmann } 26492dcdf09SSven Eckelmann 26592dcdf09SSven Eckelmann /** 26686452f81SSven Eckelmann * batadv_tt_global_entry_free_rcu - free the tt_global_entry 26786452f81SSven Eckelmann * @rcu: rcu pointer of the tt_global_entry 26886452f81SSven Eckelmann */ 26986452f81SSven Eckelmann static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu) 27086452f81SSven Eckelmann { 27186452f81SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 27286452f81SSven Eckelmann 27386452f81SSven Eckelmann tt_global_entry = container_of(rcu, struct batadv_tt_global_entry, 27486452f81SSven Eckelmann common.rcu); 27586452f81SSven Eckelmann 27686452f81SSven Eckelmann kmem_cache_free(batadv_tg_cache, tt_global_entry); 27786452f81SSven Eckelmann } 27886452f81SSven Eckelmann 27986452f81SSven Eckelmann /** 28092dcdf09SSven Eckelmann * batadv_tt_global_entry_release - release tt_global_entry from lists and queue 28192dcdf09SSven Eckelmann * for free after rcu grace period 28292dcdf09SSven Eckelmann * @ref: kref pointer of the nc_node 28392dcdf09SSven Eckelmann */ 28492dcdf09SSven Eckelmann static void batadv_tt_global_entry_release(struct kref *ref) 28592dcdf09SSven Eckelmann { 28692dcdf09SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 28792dcdf09SSven Eckelmann 28892dcdf09SSven Eckelmann tt_global_entry = container_of(ref, struct batadv_tt_global_entry, 28992dcdf09SSven Eckelmann common.refcount); 29092dcdf09SSven Eckelmann 29192dcdf09SSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 29286452f81SSven Eckelmann 29386452f81SSven Eckelmann call_rcu(&tt_global_entry->common.rcu, batadv_tt_global_entry_free_rcu); 29492dcdf09SSven Eckelmann } 29592dcdf09SSven Eckelmann 29692dcdf09SSven Eckelmann /** 2975dafd8a6SSven Eckelmann * batadv_tt_global_entry_put - decrement the tt_global_entry refcounter and 2985dafd8a6SSven Eckelmann * possibly release it 29992dcdf09SSven Eckelmann * @tt_global_entry: tt_global_entry to be free'd 30021026059SAntonio Quartulli */ 301a513088dSSven Eckelmann static void 3025dafd8a6SSven Eckelmann batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry) 3037683fdc1SAntonio Quartulli { 30492dcdf09SSven Eckelmann kref_put(&tt_global_entry->common.refcount, 30592dcdf09SSven Eckelmann batadv_tt_global_entry_release); 306db08e6e5SSimon Wunderlich } 307db08e6e5SSimon Wunderlich 3081d8ab8d3SLinus Lüssing /** 3091d8ab8d3SLinus Lüssing * batadv_tt_global_hash_count - count the number of orig entries 310d15cd622SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3111d8ab8d3SLinus Lüssing * @addr: the mac address of the client to count entries for 3121d8ab8d3SLinus Lüssing * @vid: VLAN identifier 3131d8ab8d3SLinus Lüssing * 31462fe710fSSven Eckelmann * Return: the number of originators advertising the given address/data 3151d8ab8d3SLinus Lüssing * (excluding ourself). 3161d8ab8d3SLinus Lüssing */ 3171d8ab8d3SLinus Lüssing int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, 3186b5e971aSSven Eckelmann const u8 *addr, unsigned short vid) 3191d8ab8d3SLinus Lüssing { 3201d8ab8d3SLinus Lüssing struct batadv_tt_global_entry *tt_global_entry; 3211d8ab8d3SLinus Lüssing int count; 3221d8ab8d3SLinus Lüssing 3231d8ab8d3SLinus Lüssing tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 3241d8ab8d3SLinus Lüssing if (!tt_global_entry) 3251d8ab8d3SLinus Lüssing return 0; 3261d8ab8d3SLinus Lüssing 3271d8ab8d3SLinus Lüssing count = atomic_read(&tt_global_entry->orig_list_count); 3285dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 3291d8ab8d3SLinus Lüssing 3301d8ab8d3SLinus Lüssing return count; 3311d8ab8d3SLinus Lüssing } 3321d8ab8d3SLinus Lüssing 3337ea7b4a1SAntonio Quartulli /** 3347ea7b4a1SAntonio Quartulli * batadv_tt_local_size_mod - change the size by v of the local table identified 3357ea7b4a1SAntonio Quartulli * by vid 3367ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3377ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier of the sub-table to change 3387ea7b4a1SAntonio Quartulli * @v: the amount to sum to the local table size 3397ea7b4a1SAntonio Quartulli */ 3407ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv, 3417ea7b4a1SAntonio Quartulli unsigned short vid, int v) 3427ea7b4a1SAntonio Quartulli { 3437ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 3447ea7b4a1SAntonio Quartulli 3457ea7b4a1SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 3467ea7b4a1SAntonio Quartulli if (!vlan) 3477ea7b4a1SAntonio Quartulli return; 3487ea7b4a1SAntonio Quartulli 3497ea7b4a1SAntonio Quartulli atomic_add(v, &vlan->tt.num_entries); 3507ea7b4a1SAntonio Quartulli 3519c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 3527ea7b4a1SAntonio Quartulli } 3537ea7b4a1SAntonio Quartulli 3547ea7b4a1SAntonio Quartulli /** 3557ea7b4a1SAntonio Quartulli * batadv_tt_local_size_inc - increase by one the local table size for the given 3567ea7b4a1SAntonio Quartulli * vid 3577ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3587ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3597ea7b4a1SAntonio Quartulli */ 3607ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv, 3617ea7b4a1SAntonio Quartulli unsigned short vid) 3627ea7b4a1SAntonio Quartulli { 3637ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, 1); 3647ea7b4a1SAntonio Quartulli } 3657ea7b4a1SAntonio Quartulli 3667ea7b4a1SAntonio Quartulli /** 3677ea7b4a1SAntonio Quartulli * batadv_tt_local_size_dec - decrease by one the local table size for the given 3687ea7b4a1SAntonio Quartulli * vid 3697ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3707ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3717ea7b4a1SAntonio Quartulli */ 3727ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv, 3737ea7b4a1SAntonio Quartulli unsigned short vid) 3747ea7b4a1SAntonio Quartulli { 3757ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, -1); 3767ea7b4a1SAntonio Quartulli } 3777ea7b4a1SAntonio Quartulli 3787ea7b4a1SAntonio Quartulli /** 379d15cd622SAntonio Quartulli * batadv_tt_global_size_mod - change the size by v of the global table 380d15cd622SAntonio Quartulli * for orig_node identified by vid 381d15cd622SAntonio Quartulli * @orig_node: the originator for which the table has to be modified 3827ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3837ea7b4a1SAntonio Quartulli * @v: the amount to sum to the global table size 3847ea7b4a1SAntonio Quartulli */ 3857ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, 3867ea7b4a1SAntonio Quartulli unsigned short vid, int v) 3877ea7b4a1SAntonio Quartulli { 3887ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 3897ea7b4a1SAntonio Quartulli 3907ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_new(orig_node, vid); 3917ea7b4a1SAntonio Quartulli if (!vlan) 3927ea7b4a1SAntonio Quartulli return; 3937ea7b4a1SAntonio Quartulli 3947ea7b4a1SAntonio Quartulli if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { 3957ea7b4a1SAntonio Quartulli spin_lock_bh(&orig_node->vlan_list_lock); 3963db15209SSven Eckelmann if (!hlist_unhashed(&vlan->list)) { 397a121048aSMarek Lindner hlist_del_init_rcu(&vlan->list); 39821754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 3997ea7b4a1SAntonio Quartulli } 4003db15209SSven Eckelmann spin_unlock_bh(&orig_node->vlan_list_lock); 4013db15209SSven Eckelmann } 4027ea7b4a1SAntonio Quartulli 40321754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 4047ea7b4a1SAntonio Quartulli } 4057ea7b4a1SAntonio Quartulli 4067ea7b4a1SAntonio Quartulli /** 4077ea7b4a1SAntonio Quartulli * batadv_tt_global_size_inc - increase by one the global table size for the 4087ea7b4a1SAntonio Quartulli * given vid 4097ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 4107ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 4117ea7b4a1SAntonio Quartulli */ 4127ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node, 4137ea7b4a1SAntonio Quartulli unsigned short vid) 4147ea7b4a1SAntonio Quartulli { 4157ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, 1); 4167ea7b4a1SAntonio Quartulli } 4177ea7b4a1SAntonio Quartulli 4187ea7b4a1SAntonio Quartulli /** 4197ea7b4a1SAntonio Quartulli * batadv_tt_global_size_dec - decrease by one the global table size for the 4207ea7b4a1SAntonio Quartulli * given vid 4217ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 4227ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 4237ea7b4a1SAntonio Quartulli */ 4247ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, 4257ea7b4a1SAntonio Quartulli unsigned short vid) 4267ea7b4a1SAntonio Quartulli { 4277ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, -1); 4287ea7b4a1SAntonio Quartulli } 4297ea7b4a1SAntonio Quartulli 43042eff6a6SSven Eckelmann /** 43186452f81SSven Eckelmann * batadv_tt_orig_list_entry_free_rcu - free the orig_entry 43286452f81SSven Eckelmann * @rcu: rcu pointer of the orig_entry 43386452f81SSven Eckelmann */ 43486452f81SSven Eckelmann static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) 43586452f81SSven Eckelmann { 43686452f81SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 43786452f81SSven Eckelmann 43886452f81SSven Eckelmann orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu); 43986452f81SSven Eckelmann 44086452f81SSven Eckelmann kmem_cache_free(batadv_tt_orig_cache, orig_entry); 44186452f81SSven Eckelmann } 44286452f81SSven Eckelmann 44386452f81SSven Eckelmann /** 44442eff6a6SSven Eckelmann * batadv_tt_orig_list_entry_release - release tt orig entry from lists and 44542eff6a6SSven Eckelmann * queue for free after rcu grace period 4466e8ef69dSSven Eckelmann * @ref: kref pointer of the tt orig entry 44742eff6a6SSven Eckelmann */ 4486e8ef69dSSven Eckelmann static void batadv_tt_orig_list_entry_release(struct kref *ref) 44942eff6a6SSven Eckelmann { 4506e8ef69dSSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 4516e8ef69dSSven Eckelmann 4526e8ef69dSSven Eckelmann orig_entry = container_of(ref, struct batadv_tt_orig_list_entry, 4536e8ef69dSSven Eckelmann refcount); 4546e8ef69dSSven Eckelmann 4555d967310SSven Eckelmann batadv_orig_node_put(orig_entry->orig_node); 45686452f81SSven Eckelmann call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); 45742eff6a6SSven Eckelmann } 45842eff6a6SSven Eckelmann 4596e8ef69dSSven Eckelmann /** 4607e2366c6SSven Eckelmann * batadv_tt_orig_list_entry_put - decrement the tt orig entry refcounter and 4617e2366c6SSven Eckelmann * possibly release it 4626e8ef69dSSven Eckelmann * @orig_entry: tt orig entry to be free'd 4636e8ef69dSSven Eckelmann */ 464a513088dSSven Eckelmann static void 4657e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry) 466db08e6e5SSimon Wunderlich { 4676e8ef69dSSven Eckelmann kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release); 468db08e6e5SSimon Wunderlich } 4697683fdc1SAntonio Quartulli 4703abe4adbSAntonio Quartulli /** 4713abe4adbSAntonio Quartulli * batadv_tt_local_event - store a local TT event (ADD/DEL) 4723abe4adbSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 4733abe4adbSAntonio Quartulli * @tt_local_entry: the TT entry involved in the event 4743abe4adbSAntonio Quartulli * @event_flags: flags to store in the event structure 4753abe4adbSAntonio Quartulli */ 47656303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv, 4773abe4adbSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry, 4786b5e971aSSven Eckelmann u8 event_flags) 479a73105b8SAntonio Quartulli { 48056303d34SSven Eckelmann struct batadv_tt_change_node *tt_change_node, *entry, *safe; 4813abe4adbSAntonio Quartulli struct batadv_tt_common_entry *common = &tt_local_entry->common; 4826b5e971aSSven Eckelmann u8 flags = common->flags | event_flags; 4833b643de5SAntonio Quartulli bool event_removed = false; 4843b643de5SAntonio Quartulli bool del_op_requested, del_op_entry; 485a73105b8SAntonio Quartulli 48686452f81SSven Eckelmann tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC); 487a73105b8SAntonio Quartulli if (!tt_change_node) 488a73105b8SAntonio Quartulli return; 489a73105b8SAntonio Quartulli 490ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 491ca663046SAntonio Quartulli memset(tt_change_node->change.reserved, 0, 492ca663046SAntonio Quartulli sizeof(tt_change_node->change.reserved)); 4938fdd0153SAntonio Quartulli ether_addr_copy(tt_change_node->change.addr, common->addr); 494c018ad3dSAntonio Quartulli tt_change_node->change.vid = htons(common->vid); 495a73105b8SAntonio Quartulli 496acd34afaSSven Eckelmann del_op_requested = flags & BATADV_TT_CLIENT_DEL; 4973b643de5SAntonio Quartulli 4983b643de5SAntonio Quartulli /* check for ADD+DEL or DEL+ADD events */ 499807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 500807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 5013b643de5SAntonio Quartulli list) { 5023abe4adbSAntonio Quartulli if (!batadv_compare_eth(entry->change.addr, common->addr)) 5033b643de5SAntonio Quartulli continue; 5043b643de5SAntonio Quartulli 5053b643de5SAntonio Quartulli /* DEL+ADD in the same orig interval have no effect and can be 5063b643de5SAntonio Quartulli * removed to avoid silly behaviour on the receiver side. The 5073b643de5SAntonio Quartulli * other way around (ADD+DEL) can happen in case of roaming of 5083b643de5SAntonio Quartulli * a client still in the NEW state. Roaming of NEW clients is 5093b643de5SAntonio Quartulli * now possible due to automatically recognition of "temporary" 5103b643de5SAntonio Quartulli * clients 5113b643de5SAntonio Quartulli */ 512acd34afaSSven Eckelmann del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; 5133b643de5SAntonio Quartulli if (!del_op_requested && del_op_entry) 5143b643de5SAntonio Quartulli goto del; 5153b643de5SAntonio Quartulli if (del_op_requested && !del_op_entry) 5163b643de5SAntonio Quartulli goto del; 5173c4f7ab6SAntonio Quartulli 5183c4f7ab6SAntonio Quartulli /* this is a second add in the same originator interval. It 5193c4f7ab6SAntonio Quartulli * means that flags have been changed: update them! 5203c4f7ab6SAntonio Quartulli */ 5213c4f7ab6SAntonio Quartulli if (!del_op_requested && !del_op_entry) 5223c4f7ab6SAntonio Quartulli entry->change.flags = flags; 5233c4f7ab6SAntonio Quartulli 5243b643de5SAntonio Quartulli continue; 5253b643de5SAntonio Quartulli del: 5263b643de5SAntonio Quartulli list_del(&entry->list); 52786452f81SSven Eckelmann kmem_cache_free(batadv_tt_change_cache, entry); 52886452f81SSven Eckelmann kmem_cache_free(batadv_tt_change_cache, tt_change_node); 5293b643de5SAntonio Quartulli event_removed = true; 5303b643de5SAntonio Quartulli goto unlock; 5313b643de5SAntonio Quartulli } 5323b643de5SAntonio Quartulli 533a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 534807736f6SSven Eckelmann list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list); 5353b643de5SAntonio Quartulli 5363b643de5SAntonio Quartulli unlock: 537807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 538a73105b8SAntonio Quartulli 5393b643de5SAntonio Quartulli if (event_removed) 540807736f6SSven Eckelmann atomic_dec(&bat_priv->tt.local_changes); 5413b643de5SAntonio Quartulli else 542807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.local_changes); 543a73105b8SAntonio Quartulli } 544a73105b8SAntonio Quartulli 545335fbe0fSMarek Lindner /** 546335fbe0fSMarek Lindner * batadv_tt_len - compute length in bytes of given number of tt changes 547335fbe0fSMarek Lindner * @changes_num: number of tt changes 548335fbe0fSMarek Lindner * 54962fe710fSSven Eckelmann * Return: computed length in bytes. 550335fbe0fSMarek Lindner */ 551335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num) 552a73105b8SAntonio Quartulli { 553335fbe0fSMarek Lindner return changes_num * sizeof(struct batadv_tvlv_tt_change); 554a73105b8SAntonio Quartulli } 555a73105b8SAntonio Quartulli 556298e6e68SAntonio Quartulli /** 557298e6e68SAntonio Quartulli * batadv_tt_entries - compute the number of entries fitting in tt_len bytes 558298e6e68SAntonio Quartulli * @tt_len: available space 559298e6e68SAntonio Quartulli * 56062fe710fSSven Eckelmann * Return: the number of entries. 561298e6e68SAntonio Quartulli */ 5626b5e971aSSven Eckelmann static u16 batadv_tt_entries(u16 tt_len) 563298e6e68SAntonio Quartulli { 564298e6e68SAntonio Quartulli return tt_len / batadv_tt_len(1); 565298e6e68SAntonio Quartulli } 566298e6e68SAntonio Quartulli 567a19d3d85SMarek Lindner /** 568a19d3d85SMarek Lindner * batadv_tt_local_table_transmit_size - calculates the local translation table 569a19d3d85SMarek Lindner * size when transmitted over the air 570a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 571a19d3d85SMarek Lindner * 57262fe710fSSven Eckelmann * Return: local translation table size in bytes. 573a19d3d85SMarek Lindner */ 574a19d3d85SMarek Lindner static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) 575a19d3d85SMarek Lindner { 5764f248cffSSven Eckelmann u16 num_vlan = 0; 5774f248cffSSven Eckelmann u16 tt_local_entries = 0; 578a19d3d85SMarek Lindner struct batadv_softif_vlan *vlan; 579a19d3d85SMarek Lindner int hdr_size; 580a19d3d85SMarek Lindner 581a19d3d85SMarek Lindner rcu_read_lock(); 582a19d3d85SMarek Lindner hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 583a19d3d85SMarek Lindner num_vlan++; 584a19d3d85SMarek Lindner tt_local_entries += atomic_read(&vlan->tt.num_entries); 585a19d3d85SMarek Lindner } 586a19d3d85SMarek Lindner rcu_read_unlock(); 587a19d3d85SMarek Lindner 588a19d3d85SMarek Lindner /* header size of tvlv encapsulated tt response payload */ 589a19d3d85SMarek Lindner hdr_size = sizeof(struct batadv_unicast_tvlv_packet); 590a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_hdr); 591a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_tt_data); 592a19d3d85SMarek Lindner hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data); 593a19d3d85SMarek Lindner 594a19d3d85SMarek Lindner return hdr_size + batadv_tt_len(tt_local_entries); 595a19d3d85SMarek Lindner } 596a19d3d85SMarek Lindner 59756303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv) 598c6c8fea2SSven Eckelmann { 599807736f6SSven Eckelmann if (bat_priv->tt.local_hash) 6005346c35eSSven Eckelmann return 0; 601c6c8fea2SSven Eckelmann 602807736f6SSven Eckelmann bat_priv->tt.local_hash = batadv_hash_new(1024); 603c6c8fea2SSven Eckelmann 604807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 6055346c35eSSven Eckelmann return -ENOMEM; 606c6c8fea2SSven Eckelmann 607dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.local_hash, 608dec05074SAntonio Quartulli &batadv_tt_local_hash_lock_class_key); 609dec05074SAntonio Quartulli 6105346c35eSSven Eckelmann return 0; 611c6c8fea2SSven Eckelmann } 612c6c8fea2SSven Eckelmann 613068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv, 614068ee6e2SAntonio Quartulli struct batadv_tt_global_entry *tt_global, 615068ee6e2SAntonio Quartulli const char *message) 616068ee6e2SAntonio Quartulli { 617068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 61816052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 61916052789SAntonio Quartulli tt_global->common.addr, 620f7a2bd65SSven Eckelmann batadv_print_vid(tt_global->common.vid), message); 621068ee6e2SAntonio Quartulli 622068ee6e2SAntonio Quartulli batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, 623c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_global->common); 6245dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 625068ee6e2SAntonio Quartulli } 626068ee6e2SAntonio Quartulli 627c018ad3dSAntonio Quartulli /** 628c018ad3dSAntonio Quartulli * batadv_tt_local_add - add a new client to the local table or update an 629c018ad3dSAntonio Quartulli * existing client 630c018ad3dSAntonio Quartulli * @soft_iface: netdev struct of the mesh interface 631c018ad3dSAntonio Quartulli * @addr: the mac address of the client to add 632c018ad3dSAntonio Quartulli * @vid: VLAN identifier 633c018ad3dSAntonio Quartulli * @ifindex: index of the interface where the client is connected to (useful to 634c018ad3dSAntonio Quartulli * identify wireless clients) 6359464d071SAntonio Quartulli * @mark: the value contained in the skb->mark field of the received packet (if 6369464d071SAntonio Quartulli * any) 637a19d3d85SMarek Lindner * 63862fe710fSSven Eckelmann * Return: true if the client was successfully added, false otherwise. 639c018ad3dSAntonio Quartulli */ 6406b5e971aSSven Eckelmann bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, 6416b5e971aSSven Eckelmann unsigned short vid, int ifindex, u32 mark) 642c6c8fea2SSven Eckelmann { 64356303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(soft_iface); 644170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local; 645c5caf4efSLinus Lüssing struct batadv_tt_global_entry *tt_global = NULL; 6462cd45a06SAndrew Lunn struct net *net = dev_net(soft_iface); 64735df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 6480c69aeccSAntonio Quartulli struct net_device *in_dev = NULL; 64910b1bbb4SSven Eckelmann struct batadv_hard_iface *in_hardif = NULL; 650db08e6e5SSimon Wunderlich struct hlist_head *head; 65156303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 652a19d3d85SMarek Lindner int hash_added, table_size, packet_size_max; 6534f248cffSSven Eckelmann bool ret = false; 6544f248cffSSven Eckelmann bool roamed_back = false; 6556b5e971aSSven Eckelmann u8 remote_flags; 6566b5e971aSSven Eckelmann u32 match_mark; 657c6c8fea2SSven Eckelmann 6580c69aeccSAntonio Quartulli if (ifindex != BATADV_NULL_IFINDEX) 6592cd45a06SAndrew Lunn in_dev = dev_get_by_index(net, ifindex); 6600c69aeccSAntonio Quartulli 66110b1bbb4SSven Eckelmann if (in_dev) 66210b1bbb4SSven Eckelmann in_hardif = batadv_hardif_get_by_netdev(in_dev); 66310b1bbb4SSven Eckelmann 664c018ad3dSAntonio Quartulli tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); 665c5caf4efSLinus Lüssing 666c5caf4efSLinus Lüssing if (!is_multicast_ether_addr(addr)) 667c018ad3dSAntonio Quartulli tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); 668c6c8fea2SSven Eckelmann 66947c94655SAntonio Quartulli if (tt_local) { 67047c94655SAntonio Quartulli tt_local->last_seen = jiffies; 671068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { 672068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 67316052789SAntonio Quartulli "Re-adding pending client %pM (vid: %d)\n", 674f7a2bd65SSven Eckelmann addr, batadv_print_vid(vid)); 675068ee6e2SAntonio Quartulli /* whatever the reason why the PENDING flag was set, 676068ee6e2SAntonio Quartulli * this is a client which was enqueued to be removed in 677068ee6e2SAntonio Quartulli * this orig_interval. Since it popped up again, the 678068ee6e2SAntonio Quartulli * flag can be reset like it was never enqueued 679068ee6e2SAntonio Quartulli */ 68047c94655SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; 681068ee6e2SAntonio Quartulli goto add_event; 682068ee6e2SAntonio Quartulli } 683068ee6e2SAntonio Quartulli 684068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { 685068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 68616052789SAntonio Quartulli "Roaming client %pM (vid: %d) came back to its original location\n", 687f7a2bd65SSven Eckelmann addr, batadv_print_vid(vid)); 688068ee6e2SAntonio Quartulli /* the ROAM flag is set because this client roamed away 689068ee6e2SAntonio Quartulli * and the node got a roaming_advertisement message. Now 690068ee6e2SAntonio Quartulli * that the client popped up again at its original 691068ee6e2SAntonio Quartulli * location such flag can be unset 692068ee6e2SAntonio Quartulli */ 693068ee6e2SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; 694068ee6e2SAntonio Quartulli roamed_back = true; 695068ee6e2SAntonio Quartulli } 696068ee6e2SAntonio Quartulli goto check_roaming; 697c6c8fea2SSven Eckelmann } 698c6c8fea2SSven Eckelmann 699a19d3d85SMarek Lindner /* Ignore the client if we cannot send it in a full table response. */ 700a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 701a19d3d85SMarek Lindner table_size += batadv_tt_len(1); 702a19d3d85SMarek Lindner packet_size_max = atomic_read(&bat_priv->packet_size_max); 703a19d3d85SMarek Lindner if (table_size > packet_size_max) { 704a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 705a19d3d85SMarek Lindner "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n", 706a19d3d85SMarek Lindner table_size, packet_size_max, addr); 707a19d3d85SMarek Lindner goto out; 708a19d3d85SMarek Lindner } 709a19d3d85SMarek Lindner 71086452f81SSven Eckelmann tt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC); 71147c94655SAntonio Quartulli if (!tt_local) 7127683fdc1SAntonio Quartulli goto out; 713a73105b8SAntonio Quartulli 71435df3b29SAntonio Quartulli /* increase the refcounter of the related vlan */ 71535df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 7160b3dd7dfSSimon Wunderlich if (!vlan) { 7170b3dd7dfSSimon Wunderlich net_ratelimited_function(batadv_info, soft_iface, 7180b3dd7dfSSimon Wunderlich "adding TT local entry %pM to non-existent VLAN %d\n", 719f7a2bd65SSven Eckelmann addr, batadv_print_vid(vid)); 72086452f81SSven Eckelmann kmem_cache_free(batadv_tl_cache, tt_local); 721fd7dec25SSven Eckelmann tt_local = NULL; 722354136bcSMarek Lindner goto out; 723fd7dec25SSven Eckelmann } 72435df3b29SAntonio Quartulli 72539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 72616052789SAntonio Quartulli "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", 727f7a2bd65SSven Eckelmann addr, batadv_print_vid(vid), 7286b5e971aSSven Eckelmann (u8)atomic_read(&bat_priv->tt.vn)); 729c6c8fea2SSven Eckelmann 7308fdd0153SAntonio Quartulli ether_addr_copy(tt_local->common.addr, addr); 7318425ec6aSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 7328425ec6aSAntonio Quartulli * a full table response going out before the next ttvn increment 7338425ec6aSAntonio Quartulli * (consistency check) 7348425ec6aSAntonio Quartulli */ 7358425ec6aSAntonio Quartulli tt_local->common.flags = BATADV_TT_CLIENT_NEW; 736c018ad3dSAntonio Quartulli tt_local->common.vid = vid; 73710b1bbb4SSven Eckelmann if (batadv_is_wifi_hardif(in_hardif)) 73847c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 73992dcdf09SSven Eckelmann kref_init(&tt_local->common.refcount); 74047c94655SAntonio Quartulli tt_local->last_seen = jiffies; 74147c94655SAntonio Quartulli tt_local->common.added_at = tt_local->last_seen; 742a33d970dSSven Eckelmann tt_local->vlan = vlan; 743c6c8fea2SSven Eckelmann 744c5caf4efSLinus Lüssing /* the batman interface mac and multicast addresses should never be 745c5caf4efSLinus Lüssing * purged 746c5caf4efSLinus Lüssing */ 747c5caf4efSLinus Lüssing if (batadv_compare_eth(addr, soft_iface->dev_addr) || 748c5caf4efSLinus Lüssing is_multicast_ether_addr(addr)) 74947c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; 750c6c8fea2SSven Eckelmann 751e3387b26SSven Eckelmann kref_get(&tt_local->common.refcount); 752807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, 753c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_local->common, 75447c94655SAntonio Quartulli &tt_local->common.hash_entry); 75580b3f58cSSimon Wunderlich 75680b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 75780b3f58cSSimon Wunderlich /* remove the reference for the hash */ 75895c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local); 75980b3f58cSSimon Wunderlich goto out; 76080b3f58cSSimon Wunderlich } 76180b3f58cSSimon Wunderlich 762068ee6e2SAntonio Quartulli add_event: 7633abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 764ff66c975SAntonio Quartulli 765068ee6e2SAntonio Quartulli check_roaming: 766068ee6e2SAntonio Quartulli /* Check whether it is a roaming, but don't do anything if the roaming 767068ee6e2SAntonio Quartulli * process has already been handled 768068ee6e2SAntonio Quartulli */ 769068ee6e2SAntonio Quartulli if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { 770db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 77147c94655SAntonio Quartulli head = &tt_global->orig_list; 772db08e6e5SSimon Wunderlich rcu_read_lock(); 773b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 77447c94655SAntonio Quartulli batadv_send_roam_adv(bat_priv, tt_global->common.addr, 775c018ad3dSAntonio Quartulli tt_global->common.vid, 776db08e6e5SSimon Wunderlich orig_entry->orig_node); 777db08e6e5SSimon Wunderlich } 778db08e6e5SSimon Wunderlich rcu_read_unlock(); 779068ee6e2SAntonio Quartulli if (roamed_back) { 780068ee6e2SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global, 781068ee6e2SAntonio Quartulli "Roaming canceled"); 782068ee6e2SAntonio Quartulli tt_global = NULL; 783068ee6e2SAntonio Quartulli } else { 784db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 785db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 786db08e6e5SSimon Wunderlich */ 78747c94655SAntonio Quartulli tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; 78847c94655SAntonio Quartulli tt_global->roam_at = jiffies; 7897683fdc1SAntonio Quartulli } 790068ee6e2SAntonio Quartulli } 791068ee6e2SAntonio Quartulli 7923c4f7ab6SAntonio Quartulli /* store the current remote flags before altering them. This helps 7933c4f7ab6SAntonio Quartulli * understanding is flags are changing or not 7943c4f7ab6SAntonio Quartulli */ 7953c4f7ab6SAntonio Quartulli remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK; 796a19d3d85SMarek Lindner 79710b1bbb4SSven Eckelmann if (batadv_is_wifi_hardif(in_hardif)) 7983c4f7ab6SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 7993c4f7ab6SAntonio Quartulli else 8003c4f7ab6SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; 8013c4f7ab6SAntonio Quartulli 8029464d071SAntonio Quartulli /* check the mark in the skb: if it's equal to the configured 8039464d071SAntonio Quartulli * isolation_mark, it means the packet is coming from an isolated 8049464d071SAntonio Quartulli * non-mesh client 8059464d071SAntonio Quartulli */ 8069464d071SAntonio Quartulli match_mark = (mark & bat_priv->isolation_mark_mask); 8079464d071SAntonio Quartulli if (bat_priv->isolation_mark_mask && 8089464d071SAntonio Quartulli match_mark == bat_priv->isolation_mark) 8099464d071SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA; 8109464d071SAntonio Quartulli else 8119464d071SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA; 8129464d071SAntonio Quartulli 8133c4f7ab6SAntonio Quartulli /* if any "dynamic" flag has been modified, resend an ADD event for this 8143c4f7ab6SAntonio Quartulli * entry so that all the nodes can get the new flags 8153c4f7ab6SAntonio Quartulli */ 8163c4f7ab6SAntonio Quartulli if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK)) 8173c4f7ab6SAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 8183c4f7ab6SAntonio Quartulli 8193c4f7ab6SAntonio Quartulli ret = true; 8207683fdc1SAntonio Quartulli out: 82110b1bbb4SSven Eckelmann if (in_hardif) 82210b1bbb4SSven Eckelmann batadv_hardif_put(in_hardif); 8230c69aeccSAntonio Quartulli if (in_dev) 8240c69aeccSAntonio Quartulli dev_put(in_dev); 82547c94655SAntonio Quartulli if (tt_local) 82695c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local); 82747c94655SAntonio Quartulli if (tt_global) 8285dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 829a19d3d85SMarek Lindner return ret; 830c6c8fea2SSven Eckelmann } 831c6c8fea2SSven Eckelmann 832e1bf0c14SMarek Lindner /** 8337ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send 8347ea7b4a1SAntonio Quartulli * within a TT Response directed to another node 8357ea7b4a1SAntonio Quartulli * @orig_node: originator for which the TT data has to be prepared 8367ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 8377ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 8387ea7b4a1SAntonio Quartulli * changed can be stored 8397ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 8407ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire global TT 8417ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 8427ea7b4a1SAntonio Quartulli * reserved bytes 8437ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 8447ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 8457ea7b4a1SAntonio Quartulli * objects, one per active VLAN served by the originator node. 8467ea7b4a1SAntonio Quartulli * 84762fe710fSSven Eckelmann * Return: the size of the allocated buffer or 0 in case of failure. 8487ea7b4a1SAntonio Quartulli */ 8496b5e971aSSven Eckelmann static u16 8507ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, 8517ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 8527ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 8536b5e971aSSven Eckelmann s32 *tt_len) 8547ea7b4a1SAntonio Quartulli { 8554f248cffSSven Eckelmann u16 num_vlan = 0; 8564f248cffSSven Eckelmann u16 num_entries = 0; 8574f248cffSSven Eckelmann u16 change_offset; 8584f248cffSSven Eckelmann u16 tvlv_len; 8597ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 8607ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 8616b5e971aSSven Eckelmann u8 *tt_change_ptr; 8627ea7b4a1SAntonio Quartulli 8637ea7b4a1SAntonio Quartulli rcu_read_lock(); 864d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 8657ea7b4a1SAntonio Quartulli num_vlan++; 8667ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 8677ea7b4a1SAntonio Quartulli } 8687ea7b4a1SAntonio Quartulli 8697ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 8707ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 8717ea7b4a1SAntonio Quartulli 8727ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 8737ea7b4a1SAntonio Quartulli if (*tt_len < 0) 8747ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 8757ea7b4a1SAntonio Quartulli 8767ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 8777ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 8787ea7b4a1SAntonio Quartulli 8797ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 8807ea7b4a1SAntonio Quartulli if (!*tt_data) { 8817ea7b4a1SAntonio Quartulli *tt_len = 0; 8827ea7b4a1SAntonio Quartulli goto out; 8837ea7b4a1SAntonio Quartulli } 8847ea7b4a1SAntonio Quartulli 8857ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 8867ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); 8877ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 8887ea7b4a1SAntonio Quartulli 8897ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 890d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 8917ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 8927ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 8937ea7b4a1SAntonio Quartulli 8947ea7b4a1SAntonio Quartulli tt_vlan++; 8957ea7b4a1SAntonio Quartulli } 8967ea7b4a1SAntonio Quartulli 8976b5e971aSSven Eckelmann tt_change_ptr = (u8 *)*tt_data + change_offset; 8987ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 8997ea7b4a1SAntonio Quartulli 9007ea7b4a1SAntonio Quartulli out: 9017ea7b4a1SAntonio Quartulli rcu_read_unlock(); 9027ea7b4a1SAntonio Quartulli return tvlv_len; 9037ea7b4a1SAntonio Quartulli } 9047ea7b4a1SAntonio Quartulli 9057ea7b4a1SAntonio Quartulli /** 9067ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this 9077ea7b4a1SAntonio Quartulli * node 9087ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 9097ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 9107ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 9117ea7b4a1SAntonio Quartulli * changes can be stored 9127ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 9137ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire local TT 9147ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 9157ea7b4a1SAntonio Quartulli * reserved bytes 9167ea7b4a1SAntonio Quartulli * 9177ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 9187ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 9197ea7b4a1SAntonio Quartulli * objects, one per active VLAN. 9207ea7b4a1SAntonio Quartulli * 92162fe710fSSven Eckelmann * Return: the size of the allocated buffer or 0 in case of failure. 9227ea7b4a1SAntonio Quartulli */ 9236b5e971aSSven Eckelmann static u16 9247ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, 9257ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 9267ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 9276b5e971aSSven Eckelmann s32 *tt_len) 9287ea7b4a1SAntonio Quartulli { 9297ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 9307ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 9314f248cffSSven Eckelmann u16 num_vlan = 0; 9324f248cffSSven Eckelmann u16 num_entries = 0; 9334f248cffSSven Eckelmann u16 tvlv_len; 9346b5e971aSSven Eckelmann u8 *tt_change_ptr; 9357ea7b4a1SAntonio Quartulli int change_offset; 9367ea7b4a1SAntonio Quartulli 9377ea7b4a1SAntonio Quartulli rcu_read_lock(); 9387ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 9397ea7b4a1SAntonio Quartulli num_vlan++; 9407ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 9417ea7b4a1SAntonio Quartulli } 9427ea7b4a1SAntonio Quartulli 9437ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 9447ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 9457ea7b4a1SAntonio Quartulli 9467ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 9477ea7b4a1SAntonio Quartulli if (*tt_len < 0) 9487ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 9497ea7b4a1SAntonio Quartulli 9507ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 9517ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 9527ea7b4a1SAntonio Quartulli 9537ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 9547ea7b4a1SAntonio Quartulli if (!*tt_data) { 9557ea7b4a1SAntonio Quartulli tvlv_len = 0; 9567ea7b4a1SAntonio Quartulli goto out; 9577ea7b4a1SAntonio Quartulli } 9587ea7b4a1SAntonio Quartulli 9597ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 9607ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn); 9617ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 9627ea7b4a1SAntonio Quartulli 9637ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 9647ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 9657ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 9667ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 9677ea7b4a1SAntonio Quartulli 9687ea7b4a1SAntonio Quartulli tt_vlan++; 9697ea7b4a1SAntonio Quartulli } 9707ea7b4a1SAntonio Quartulli 9716b5e971aSSven Eckelmann tt_change_ptr = (u8 *)*tt_data + change_offset; 9727ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 9737ea7b4a1SAntonio Quartulli 9747ea7b4a1SAntonio Quartulli out: 9757ea7b4a1SAntonio Quartulli rcu_read_unlock(); 9767ea7b4a1SAntonio Quartulli return tvlv_len; 9777ea7b4a1SAntonio Quartulli } 9787ea7b4a1SAntonio Quartulli 9797ea7b4a1SAntonio Quartulli /** 980e1bf0c14SMarek Lindner * batadv_tt_tvlv_container_update - update the translation table tvlv container 981e1bf0c14SMarek Lindner * after local tt changes have been committed 982e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 983e1bf0c14SMarek Lindner */ 984e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) 985c6c8fea2SSven Eckelmann { 986e1bf0c14SMarek Lindner struct batadv_tt_change_node *entry, *safe; 987e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 988e1bf0c14SMarek Lindner struct batadv_tvlv_tt_change *tt_change; 9897ea7b4a1SAntonio Quartulli int tt_diff_len, tt_change_len = 0; 9904f248cffSSven Eckelmann int tt_diff_entries_num = 0; 9914f248cffSSven Eckelmann int tt_diff_entries_count = 0; 9926b5e971aSSven Eckelmann u16 tvlv_len; 993c6c8fea2SSven Eckelmann 9947ea7b4a1SAntonio Quartulli tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); 9957ea7b4a1SAntonio Quartulli tt_diff_len = batadv_tt_len(tt_diff_entries_num); 996be9aa4c1SMarek Lindner 997be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 998be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 999be9aa4c1SMarek Lindner */ 1000e1bf0c14SMarek Lindner if (tt_diff_len > bat_priv->soft_iface->mtu) 1001e1bf0c14SMarek Lindner tt_diff_len = 0; 1002be9aa4c1SMarek Lindner 10037ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, 10047ea7b4a1SAntonio Quartulli &tt_change, &tt_diff_len); 10057ea7b4a1SAntonio Quartulli if (!tvlv_len) 1006e1bf0c14SMarek Lindner return; 1007be9aa4c1SMarek Lindner 1008e1bf0c14SMarek Lindner tt_data->flags = BATADV_TT_OGM_DIFF; 1009be9aa4c1SMarek Lindner 1010e1bf0c14SMarek Lindner if (tt_diff_len == 0) 1011e1bf0c14SMarek Lindner goto container_register; 1012be9aa4c1SMarek Lindner 1013807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 1014807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 1015c6c8fea2SSven Eckelmann 1016807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 1017a73105b8SAntonio Quartulli list) { 1018e1bf0c14SMarek Lindner if (tt_diff_entries_count < tt_diff_entries_num) { 1019e1bf0c14SMarek Lindner memcpy(tt_change + tt_diff_entries_count, 1020e1bf0c14SMarek Lindner &entry->change, 1021e1bf0c14SMarek Lindner sizeof(struct batadv_tvlv_tt_change)); 1022e1bf0c14SMarek Lindner tt_diff_entries_count++; 1023c6c8fea2SSven Eckelmann } 1024a73105b8SAntonio Quartulli list_del(&entry->list); 102586452f81SSven Eckelmann kmem_cache_free(batadv_tt_change_cache, entry); 1026c6c8fea2SSven Eckelmann } 1027807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 1028c6c8fea2SSven Eckelmann 1029a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 1030807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 1031807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 1032807736f6SSven Eckelmann bat_priv->tt.last_changeset_len = 0; 1033807736f6SSven Eckelmann bat_priv->tt.last_changeset = NULL; 1034e1bf0c14SMarek Lindner tt_change_len = batadv_tt_len(tt_diff_entries_count); 1035be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 1036e1bf0c14SMarek Lindner if (tt_diff_entries_count > 0) { 1037be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 1038a73105b8SAntonio Quartulli * instead of providing the diff 1039a73105b8SAntonio Quartulli */ 1040e1bf0c14SMarek Lindner bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); 1041807736f6SSven Eckelmann if (bat_priv->tt.last_changeset) { 1042e1bf0c14SMarek Lindner memcpy(bat_priv->tt.last_changeset, 1043e1bf0c14SMarek Lindner tt_change, tt_change_len); 1044e1bf0c14SMarek Lindner bat_priv->tt.last_changeset_len = tt_diff_len; 1045a73105b8SAntonio Quartulli } 1046a73105b8SAntonio Quartulli } 1047807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 1048c6c8fea2SSven Eckelmann 1049e1bf0c14SMarek Lindner container_register: 1050e1bf0c14SMarek Lindner batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, 10517ea7b4a1SAntonio Quartulli tvlv_len); 1052e1bf0c14SMarek Lindner kfree(tt_data); 1053c6c8fea2SSven Eckelmann } 1054c6c8fea2SSven Eckelmann 1055dc1cbd14SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUGFS 105608c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) 1057c6c8fea2SSven Eckelmann { 1058c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 105956303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 1060807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 106156303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 106285766a82SAntonio Quartulli struct batadv_tt_local_entry *tt_local; 106356303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 1064c6c8fea2SSven Eckelmann struct hlist_head *head; 10656b5e971aSSven Eckelmann u32 i; 106685766a82SAntonio Quartulli int last_seen_secs; 106785766a82SAntonio Quartulli int last_seen_msecs; 106885766a82SAntonio Quartulli unsigned long last_seen_jiffies; 106985766a82SAntonio Quartulli bool no_purge; 10706b5e971aSSven Eckelmann u16 np_flag = BATADV_TT_CLIENT_NOPURGE; 1071c6c8fea2SSven Eckelmann 107230da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 107330da63a6SMarek Lindner if (!primary_if) 107432ae9b22SMarek Lindner goto out; 1075c6c8fea2SSven Eckelmann 107686ceb360SSven Eckelmann seq_printf(seq, 10777ea7b4a1SAntonio Quartulli "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", 10786b5e971aSSven Eckelmann net_dev->name, (u8)atomic_read(&bat_priv->tt.vn)); 1079925a6f37SAntonio Quartulli seq_puts(seq, 1080925a6f37SAntonio Quartulli " Client VID Flags Last seen (CRC )\n"); 1081c6c8fea2SSven Eckelmann 1082c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1083c6c8fea2SSven Eckelmann head = &hash->table[i]; 1084c6c8fea2SSven Eckelmann 10857aadf889SMarek Lindner rcu_read_lock(); 1086b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 10877aadf889SMarek Lindner head, hash_entry) { 108885766a82SAntonio Quartulli tt_local = container_of(tt_common_entry, 108985766a82SAntonio Quartulli struct batadv_tt_local_entry, 109085766a82SAntonio Quartulli common); 109185766a82SAntonio Quartulli last_seen_jiffies = jiffies - tt_local->last_seen; 109285766a82SAntonio Quartulli last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 109385766a82SAntonio Quartulli last_seen_secs = last_seen_msecs / 1000; 109485766a82SAntonio Quartulli last_seen_msecs = last_seen_msecs % 1000; 109585766a82SAntonio Quartulli 109685766a82SAntonio Quartulli no_purge = tt_common_entry->flags & np_flag; 10977ea7b4a1SAntonio Quartulli seq_printf(seq, 1098dd24ddb2SAntonio Quartulli " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n", 109948100bacSAntonio Quartulli tt_common_entry->addr, 1100f7a2bd65SSven Eckelmann batadv_print_vid(tt_common_entry->vid), 1101a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1102a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 110385766a82SAntonio Quartulli no_purge ? 'P' : '.', 1104a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1105a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_NEW) ? 'N' : '.'), 1106a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1107a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_PENDING) ? 'X' : '.'), 1108a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1109a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1110a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1111a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1112a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_secs, 11137ea7b4a1SAntonio Quartulli no_purge ? 0 : last_seen_msecs, 1114a33d970dSSven Eckelmann tt_local->vlan->tt.crc); 1115c6c8fea2SSven Eckelmann } 11167aadf889SMarek Lindner rcu_read_unlock(); 1117c6c8fea2SSven Eckelmann } 111832ae9b22SMarek Lindner out: 111932ae9b22SMarek Lindner if (primary_if) 112082047ad7SSven Eckelmann batadv_hardif_put(primary_if); 112130da63a6SMarek Lindner return 0; 1122c6c8fea2SSven Eckelmann } 1123dc1cbd14SSven Eckelmann #endif 1124c6c8fea2SSven Eckelmann 1125d34f0550SMatthias Schiffer /** 1126d34f0550SMatthias Schiffer * batadv_tt_local_dump_entry - Dump one TT local entry into a message 1127d34f0550SMatthias Schiffer * @msg :Netlink message to dump into 1128d34f0550SMatthias Schiffer * @portid: Port making netlink request 1129d34f0550SMatthias Schiffer * @seq: Sequence number of netlink message 1130d34f0550SMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 1131d34f0550SMatthias Schiffer * @common: tt local & tt global common data 1132d34f0550SMatthias Schiffer * 1133d34f0550SMatthias Schiffer * Return: Error code, or 0 on success 1134d34f0550SMatthias Schiffer */ 1135d34f0550SMatthias Schiffer static int 1136d34f0550SMatthias Schiffer batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, 1137d34f0550SMatthias Schiffer struct batadv_priv *bat_priv, 1138d34f0550SMatthias Schiffer struct batadv_tt_common_entry *common) 1139d34f0550SMatthias Schiffer { 1140d34f0550SMatthias Schiffer void *hdr; 1141d34f0550SMatthias Schiffer struct batadv_softif_vlan *vlan; 1142d34f0550SMatthias Schiffer struct batadv_tt_local_entry *local; 1143d34f0550SMatthias Schiffer unsigned int last_seen_msecs; 1144d34f0550SMatthias Schiffer u32 crc; 1145d34f0550SMatthias Schiffer 1146d34f0550SMatthias Schiffer local = container_of(common, struct batadv_tt_local_entry, common); 1147d34f0550SMatthias Schiffer last_seen_msecs = jiffies_to_msecs(jiffies - local->last_seen); 1148d34f0550SMatthias Schiffer 1149d34f0550SMatthias Schiffer vlan = batadv_softif_vlan_get(bat_priv, common->vid); 1150d34f0550SMatthias Schiffer if (!vlan) 1151d34f0550SMatthias Schiffer return 0; 1152d34f0550SMatthias Schiffer 1153d34f0550SMatthias Schiffer crc = vlan->tt.crc; 1154d34f0550SMatthias Schiffer 1155d34f0550SMatthias Schiffer batadv_softif_vlan_put(vlan); 1156d34f0550SMatthias Schiffer 1157d34f0550SMatthias Schiffer hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, 1158d34f0550SMatthias Schiffer NLM_F_MULTI, 1159d34f0550SMatthias Schiffer BATADV_CMD_GET_TRANSTABLE_LOCAL); 1160d34f0550SMatthias Schiffer if (!hdr) 1161d34f0550SMatthias Schiffer return -ENOBUFS; 1162d34f0550SMatthias Schiffer 1163d34f0550SMatthias Schiffer if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) || 1164d34f0550SMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) || 1165d34f0550SMatthias Schiffer nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) || 1166d34f0550SMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags)) 1167d34f0550SMatthias Schiffer goto nla_put_failure; 1168d34f0550SMatthias Schiffer 1169d34f0550SMatthias Schiffer if (!(common->flags & BATADV_TT_CLIENT_NOPURGE) && 1170d34f0550SMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs)) 1171d34f0550SMatthias Schiffer goto nla_put_failure; 1172d34f0550SMatthias Schiffer 1173d34f0550SMatthias Schiffer genlmsg_end(msg, hdr); 1174d34f0550SMatthias Schiffer return 0; 1175d34f0550SMatthias Schiffer 1176d34f0550SMatthias Schiffer nla_put_failure: 1177d34f0550SMatthias Schiffer genlmsg_cancel(msg, hdr); 1178d34f0550SMatthias Schiffer return -EMSGSIZE; 1179d34f0550SMatthias Schiffer } 1180d34f0550SMatthias Schiffer 1181d34f0550SMatthias Schiffer /** 1182d34f0550SMatthias Schiffer * batadv_tt_local_dump_bucket - Dump one TT local bucket into a message 1183d34f0550SMatthias Schiffer * @msg: Netlink message to dump into 1184d34f0550SMatthias Schiffer * @portid: Port making netlink request 1185d34f0550SMatthias Schiffer * @seq: Sequence number of netlink message 1186d34f0550SMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 1187d34f0550SMatthias Schiffer * @head: Pointer to the list containing the local tt entries 1188d34f0550SMatthias Schiffer * @idx_s: Number of entries to skip 1189d34f0550SMatthias Schiffer * 1190d34f0550SMatthias Schiffer * Return: Error code, or 0 on success 1191d34f0550SMatthias Schiffer */ 1192d34f0550SMatthias Schiffer static int 1193d34f0550SMatthias Schiffer batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, 1194d34f0550SMatthias Schiffer struct batadv_priv *bat_priv, 1195d34f0550SMatthias Schiffer struct hlist_head *head, int *idx_s) 1196d34f0550SMatthias Schiffer { 1197d34f0550SMatthias Schiffer struct batadv_tt_common_entry *common; 1198d34f0550SMatthias Schiffer int idx = 0; 1199d34f0550SMatthias Schiffer 1200d34f0550SMatthias Schiffer rcu_read_lock(); 1201d34f0550SMatthias Schiffer hlist_for_each_entry_rcu(common, head, hash_entry) { 1202d34f0550SMatthias Schiffer if (idx++ < *idx_s) 1203d34f0550SMatthias Schiffer continue; 1204d34f0550SMatthias Schiffer 1205d34f0550SMatthias Schiffer if (batadv_tt_local_dump_entry(msg, portid, seq, bat_priv, 1206d34f0550SMatthias Schiffer common)) { 1207d34f0550SMatthias Schiffer rcu_read_unlock(); 1208d34f0550SMatthias Schiffer *idx_s = idx - 1; 1209d34f0550SMatthias Schiffer return -EMSGSIZE; 1210d34f0550SMatthias Schiffer } 1211d34f0550SMatthias Schiffer } 1212d34f0550SMatthias Schiffer rcu_read_unlock(); 1213d34f0550SMatthias Schiffer 1214d34f0550SMatthias Schiffer *idx_s = 0; 1215d34f0550SMatthias Schiffer return 0; 1216d34f0550SMatthias Schiffer } 1217d34f0550SMatthias Schiffer 1218d34f0550SMatthias Schiffer /** 1219d34f0550SMatthias Schiffer * batadv_tt_local_dump - Dump TT local entries into a message 1220d34f0550SMatthias Schiffer * @msg: Netlink message to dump into 1221d34f0550SMatthias Schiffer * @cb: Parameters from query 1222d34f0550SMatthias Schiffer * 1223d34f0550SMatthias Schiffer * Return: Error code, or 0 on success 1224d34f0550SMatthias Schiffer */ 1225d34f0550SMatthias Schiffer int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb) 1226d34f0550SMatthias Schiffer { 1227d34f0550SMatthias Schiffer struct net *net = sock_net(cb->skb->sk); 1228d34f0550SMatthias Schiffer struct net_device *soft_iface; 1229d34f0550SMatthias Schiffer struct batadv_priv *bat_priv; 1230d34f0550SMatthias Schiffer struct batadv_hard_iface *primary_if = NULL; 1231d34f0550SMatthias Schiffer struct batadv_hashtable *hash; 1232d34f0550SMatthias Schiffer struct hlist_head *head; 1233d34f0550SMatthias Schiffer int ret; 1234d34f0550SMatthias Schiffer int ifindex; 1235d34f0550SMatthias Schiffer int bucket = cb->args[0]; 1236d34f0550SMatthias Schiffer int idx = cb->args[1]; 1237d34f0550SMatthias Schiffer int portid = NETLINK_CB(cb->skb).portid; 1238d34f0550SMatthias Schiffer 1239d34f0550SMatthias Schiffer ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); 1240d34f0550SMatthias Schiffer if (!ifindex) 1241d34f0550SMatthias Schiffer return -EINVAL; 1242d34f0550SMatthias Schiffer 1243d34f0550SMatthias Schiffer soft_iface = dev_get_by_index(net, ifindex); 1244d34f0550SMatthias Schiffer if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { 1245d34f0550SMatthias Schiffer ret = -ENODEV; 1246d34f0550SMatthias Schiffer goto out; 1247d34f0550SMatthias Schiffer } 1248d34f0550SMatthias Schiffer 1249d34f0550SMatthias Schiffer bat_priv = netdev_priv(soft_iface); 1250d34f0550SMatthias Schiffer 1251d34f0550SMatthias Schiffer primary_if = batadv_primary_if_get_selected(bat_priv); 1252d34f0550SMatthias Schiffer if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { 1253d34f0550SMatthias Schiffer ret = -ENOENT; 1254d34f0550SMatthias Schiffer goto out; 1255d34f0550SMatthias Schiffer } 1256d34f0550SMatthias Schiffer 1257d34f0550SMatthias Schiffer hash = bat_priv->tt.local_hash; 1258d34f0550SMatthias Schiffer 1259d34f0550SMatthias Schiffer while (bucket < hash->size) { 1260d34f0550SMatthias Schiffer head = &hash->table[bucket]; 1261d34f0550SMatthias Schiffer 1262d34f0550SMatthias Schiffer if (batadv_tt_local_dump_bucket(msg, portid, cb->nlh->nlmsg_seq, 1263d34f0550SMatthias Schiffer bat_priv, head, &idx)) 1264d34f0550SMatthias Schiffer break; 1265d34f0550SMatthias Schiffer 1266d34f0550SMatthias Schiffer bucket++; 1267d34f0550SMatthias Schiffer } 1268d34f0550SMatthias Schiffer 1269d34f0550SMatthias Schiffer ret = msg->len; 1270d34f0550SMatthias Schiffer 1271d34f0550SMatthias Schiffer out: 1272d34f0550SMatthias Schiffer if (primary_if) 1273d34f0550SMatthias Schiffer batadv_hardif_put(primary_if); 1274d34f0550SMatthias Schiffer if (soft_iface) 1275d34f0550SMatthias Schiffer dev_put(soft_iface); 1276d34f0550SMatthias Schiffer 1277d34f0550SMatthias Schiffer cb->args[0] = bucket; 1278d34f0550SMatthias Schiffer cb->args[1] = idx; 1279d34f0550SMatthias Schiffer 1280d34f0550SMatthias Schiffer return ret; 1281d34f0550SMatthias Schiffer } 1282d34f0550SMatthias Schiffer 128356303d34SSven Eckelmann static void 128456303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv, 128556303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry, 12866b5e971aSSven Eckelmann u16 flags, const char *message) 1287c6c8fea2SSven Eckelmann { 12883abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, flags); 1289c6c8fea2SSven Eckelmann 1290015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 1291015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 12929cfc7bd6SSven Eckelmann * response issued before the net ttvn increment (consistency check) 12939cfc7bd6SSven Eckelmann */ 1294acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; 1295c566dbbeSAntonio Quartulli 129639c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 129716052789SAntonio Quartulli "Local tt entry (%pM, vid: %d) pending to be removed: %s\n", 129816052789SAntonio Quartulli tt_local_entry->common.addr, 1299f7a2bd65SSven Eckelmann batadv_print_vid(tt_local_entry->common.vid), message); 1300c6c8fea2SSven Eckelmann } 1301c6c8fea2SSven Eckelmann 13027f91d06cSAntonio Quartulli /** 13037f91d06cSAntonio Quartulli * batadv_tt_local_remove - logically remove an entry from the local table 13047f91d06cSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 13057f91d06cSAntonio Quartulli * @addr: the MAC address of the client to remove 1306c018ad3dSAntonio Quartulli * @vid: VLAN identifier 13077f91d06cSAntonio Quartulli * @message: message to append to the log on deletion 13087f91d06cSAntonio Quartulli * @roaming: true if the deletion is due to a roaming event 13097f91d06cSAntonio Quartulli * 131062fe710fSSven Eckelmann * Return: the flags assigned to the local entry before being deleted 13117f91d06cSAntonio Quartulli */ 13126b5e971aSSven Eckelmann u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, 13136b5e971aSSven Eckelmann unsigned short vid, const char *message, 13146b5e971aSSven Eckelmann bool roaming) 1315c6c8fea2SSven Eckelmann { 1316170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 13176b5e971aSSven Eckelmann u16 flags, curr_flags = BATADV_NO_FLAGS; 1318ef72706aSMarek Lindner void *tt_entry_exists; 1319c6c8fea2SSven Eckelmann 1320c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 13217683fdc1SAntonio Quartulli if (!tt_local_entry) 13227683fdc1SAntonio Quartulli goto out; 13237683fdc1SAntonio Quartulli 13247f91d06cSAntonio Quartulli curr_flags = tt_local_entry->common.flags; 13257f91d06cSAntonio Quartulli 1326acd34afaSSven Eckelmann flags = BATADV_TT_CLIENT_DEL; 1327068ee6e2SAntonio Quartulli /* if this global entry addition is due to a roaming, the node has to 1328068ee6e2SAntonio Quartulli * mark the local entry as "roamed" in order to correctly reroute 1329068ee6e2SAntonio Quartulli * packets later 1330068ee6e2SAntonio Quartulli */ 13317c1fd91dSAntonio Quartulli if (roaming) { 1332acd34afaSSven Eckelmann flags |= BATADV_TT_CLIENT_ROAM; 13337c1fd91dSAntonio Quartulli /* mark the local client as ROAMed */ 13347c1fd91dSAntonio Quartulli tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 13357c1fd91dSAntonio Quartulli } 133642d0b044SSven Eckelmann 1337068ee6e2SAntonio Quartulli if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { 1338068ee6e2SAntonio Quartulli batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, 1339068ee6e2SAntonio Quartulli message); 1340068ee6e2SAntonio Quartulli goto out; 1341068ee6e2SAntonio Quartulli } 1342068ee6e2SAntonio Quartulli /* if this client has been added right now, it is possible to 1343068ee6e2SAntonio Quartulli * immediately purge it 1344068ee6e2SAntonio Quartulli */ 13453abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); 1346ef72706aSMarek Lindner 1347ef72706aSMarek Lindner tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, 1348ef72706aSMarek Lindner batadv_compare_tt, 1349ef72706aSMarek Lindner batadv_choose_tt, 1350ef72706aSMarek Lindner &tt_local_entry->common); 1351ef72706aSMarek Lindner if (!tt_entry_exists) 1352ef72706aSMarek Lindner goto out; 1353ef72706aSMarek Lindner 1354ef72706aSMarek Lindner /* extra call to free the local tt entry */ 135595c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 13567f91d06cSAntonio Quartulli 13577683fdc1SAntonio Quartulli out: 13587683fdc1SAntonio Quartulli if (tt_local_entry) 135995c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 13607f91d06cSAntonio Quartulli 13617f91d06cSAntonio Quartulli return curr_flags; 1362c6c8fea2SSven Eckelmann } 1363c6c8fea2SSven Eckelmann 1364a19d3d85SMarek Lindner /** 1365a19d3d85SMarek Lindner * batadv_tt_local_purge_list - purge inactive tt local entries 1366a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1367a19d3d85SMarek Lindner * @head: pointer to the list containing the local tt entries 1368a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1369a19d3d85SMarek Lindner * inactive or not 1370a19d3d85SMarek Lindner */ 137156303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 1372a19d3d85SMarek Lindner struct hlist_head *head, 1373a19d3d85SMarek Lindner int timeout) 1374c6c8fea2SSven Eckelmann { 137556303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 137656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1377b67bfe0dSSasha Levin struct hlist_node *node_tmp; 1378acd34afaSSven Eckelmann 1379b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, 1380acd34afaSSven Eckelmann hash_entry) { 1381acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common_entry, 138256303d34SSven Eckelmann struct batadv_tt_local_entry, 138356303d34SSven Eckelmann common); 1384acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) 1385acd34afaSSven Eckelmann continue; 1386acd34afaSSven Eckelmann 1387acd34afaSSven Eckelmann /* entry already marked for deletion */ 1388acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 1389acd34afaSSven Eckelmann continue; 1390acd34afaSSven Eckelmann 1391a19d3d85SMarek Lindner if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) 1392acd34afaSSven Eckelmann continue; 1393acd34afaSSven Eckelmann 1394acd34afaSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 1395acd34afaSSven Eckelmann BATADV_TT_CLIENT_DEL, "timed out"); 1396acd34afaSSven Eckelmann } 1397acd34afaSSven Eckelmann } 1398acd34afaSSven Eckelmann 1399a19d3d85SMarek Lindner /** 1400a19d3d85SMarek Lindner * batadv_tt_local_purge - purge inactive tt local entries 1401a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1402a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1403a19d3d85SMarek Lindner * inactive or not 1404a19d3d85SMarek Lindner */ 1405a19d3d85SMarek Lindner static void batadv_tt_local_purge(struct batadv_priv *bat_priv, 1406a19d3d85SMarek Lindner int timeout) 1407acd34afaSSven Eckelmann { 1408807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 1409c6c8fea2SSven Eckelmann struct hlist_head *head; 14107683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 14116b5e971aSSven Eckelmann u32 i; 1412c6c8fea2SSven Eckelmann 1413c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1414c6c8fea2SSven Eckelmann head = &hash->table[i]; 14157683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1416c6c8fea2SSven Eckelmann 14177683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1418a19d3d85SMarek Lindner batadv_tt_local_purge_list(bat_priv, head, timeout); 14197683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1420c6c8fea2SSven Eckelmann } 1421c6c8fea2SSven Eckelmann } 1422c6c8fea2SSven Eckelmann 142356303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) 1424c6c8fea2SSven Eckelmann { 14255bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 1426a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 142756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 142856303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 1429b67bfe0dSSasha Levin struct hlist_node *node_tmp; 14307683fdc1SAntonio Quartulli struct hlist_head *head; 14316b5e971aSSven Eckelmann u32 i; 1432a73105b8SAntonio Quartulli 1433807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 1434c6c8fea2SSven Eckelmann return; 1435c6c8fea2SSven Eckelmann 1436807736f6SSven Eckelmann hash = bat_priv->tt.local_hash; 1437a73105b8SAntonio Quartulli 1438a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1439a73105b8SAntonio Quartulli head = &hash->table[i]; 1440a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 1441a73105b8SAntonio Quartulli 1442a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 1443b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 1444a73105b8SAntonio Quartulli head, hash_entry) { 1445b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 144656303d34SSven Eckelmann tt_local = container_of(tt_common_entry, 144756303d34SSven Eckelmann struct batadv_tt_local_entry, 144848100bacSAntonio Quartulli common); 144935df3b29SAntonio Quartulli 145095c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local); 1451a73105b8SAntonio Quartulli } 1452a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 1453a73105b8SAntonio Quartulli } 1454a73105b8SAntonio Quartulli 14551a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 1456a73105b8SAntonio Quartulli 1457807736f6SSven Eckelmann bat_priv->tt.local_hash = NULL; 1458c6c8fea2SSven Eckelmann } 1459c6c8fea2SSven Eckelmann 146056303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv) 1461c6c8fea2SSven Eckelmann { 1462807736f6SSven Eckelmann if (bat_priv->tt.global_hash) 14635346c35eSSven Eckelmann return 0; 1464c6c8fea2SSven Eckelmann 1465807736f6SSven Eckelmann bat_priv->tt.global_hash = batadv_hash_new(1024); 1466c6c8fea2SSven Eckelmann 1467807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 14685346c35eSSven Eckelmann return -ENOMEM; 1469c6c8fea2SSven Eckelmann 1470dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.global_hash, 1471dec05074SAntonio Quartulli &batadv_tt_global_hash_lock_class_key); 1472dec05074SAntonio Quartulli 14735346c35eSSven Eckelmann return 0; 1474c6c8fea2SSven Eckelmann } 1475c6c8fea2SSven Eckelmann 147656303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) 1477a73105b8SAntonio Quartulli { 147856303d34SSven Eckelmann struct batadv_tt_change_node *entry, *safe; 1479a73105b8SAntonio Quartulli 1480807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 1481a73105b8SAntonio Quartulli 1482807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 1483a73105b8SAntonio Quartulli list) { 1484a73105b8SAntonio Quartulli list_del(&entry->list); 148586452f81SSven Eckelmann kmem_cache_free(batadv_tt_change_cache, entry); 1486a73105b8SAntonio Quartulli } 1487a73105b8SAntonio Quartulli 1488807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 1489807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 1490a73105b8SAntonio Quartulli } 1491a73105b8SAntonio Quartulli 149262fe710fSSven Eckelmann /** 1493d15cd622SAntonio Quartulli * batadv_tt_global_orig_entry_find - find a TT orig_list_entry 1494d15cd622SAntonio Quartulli * @entry: the TT global entry where the orig_list_entry has to be 1495d15cd622SAntonio Quartulli * extracted from 1496d15cd622SAntonio Quartulli * @orig_node: the originator for which the orig_list_entry has to be found 149762fe710fSSven Eckelmann * 1498d15cd622SAntonio Quartulli * retrieve the orig_tt_list_entry belonging to orig_node from the 1499d657e621SAntonio Quartulli * batadv_tt_global_entry list 1500d657e621SAntonio Quartulli * 150162fe710fSSven Eckelmann * Return: it with an increased refcounter, NULL if not found 1502d657e621SAntonio Quartulli */ 1503d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry * 1504d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, 1505d657e621SAntonio Quartulli const struct batadv_orig_node *orig_node) 1506d657e621SAntonio Quartulli { 1507d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; 1508d657e621SAntonio Quartulli const struct hlist_head *head; 1509d657e621SAntonio Quartulli 1510d657e621SAntonio Quartulli rcu_read_lock(); 1511d657e621SAntonio Quartulli head = &entry->orig_list; 1512b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { 1513d657e621SAntonio Quartulli if (tmp_orig_entry->orig_node != orig_node) 1514d657e621SAntonio Quartulli continue; 15156e8ef69dSSven Eckelmann if (!kref_get_unless_zero(&tmp_orig_entry->refcount)) 1516d657e621SAntonio Quartulli continue; 1517d657e621SAntonio Quartulli 1518d657e621SAntonio Quartulli orig_entry = tmp_orig_entry; 1519d657e621SAntonio Quartulli break; 1520d657e621SAntonio Quartulli } 1521d657e621SAntonio Quartulli rcu_read_unlock(); 1522d657e621SAntonio Quartulli 1523d657e621SAntonio Quartulli return orig_entry; 1524d657e621SAntonio Quartulli } 1525d657e621SAntonio Quartulli 152662fe710fSSven Eckelmann /** 1527d15cd622SAntonio Quartulli * batadv_tt_global_entry_has_orig - check if a TT global entry is also handled 1528d15cd622SAntonio Quartulli * by a given originator 1529d15cd622SAntonio Quartulli * @entry: the TT global entry to check 1530d15cd622SAntonio Quartulli * @orig_node: the originator to search in the list 153162fe710fSSven Eckelmann * 153262fe710fSSven Eckelmann * find out if an orig_node is already in the list of a tt_global_entry. 153362fe710fSSven Eckelmann * 153462fe710fSSven Eckelmann * Return: true if found, false otherwise 1535db08e6e5SSimon Wunderlich */ 153656303d34SSven Eckelmann static bool 153756303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, 153856303d34SSven Eckelmann const struct batadv_orig_node *orig_node) 1539db08e6e5SSimon Wunderlich { 1540d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *orig_entry; 1541db08e6e5SSimon Wunderlich bool found = false; 1542db08e6e5SSimon Wunderlich 1543d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); 1544d657e621SAntonio Quartulli if (orig_entry) { 1545db08e6e5SSimon Wunderlich found = true; 15467e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(orig_entry); 1547db08e6e5SSimon Wunderlich } 1548d657e621SAntonio Quartulli 1549db08e6e5SSimon Wunderlich return found; 1550db08e6e5SSimon Wunderlich } 1551db08e6e5SSimon Wunderlich 1552a513088dSSven Eckelmann static void 1553d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, 155456303d34SSven Eckelmann struct batadv_orig_node *orig_node, int ttvn) 1555db08e6e5SSimon Wunderlich { 155656303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1557db08e6e5SSimon Wunderlich 1558d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); 155930cfd02bSAntonio Quartulli if (orig_entry) { 156030cfd02bSAntonio Quartulli /* refresh the ttvn: the current value could be a bogus one that 156130cfd02bSAntonio Quartulli * was added during a "temporary client detection" 156230cfd02bSAntonio Quartulli */ 156330cfd02bSAntonio Quartulli orig_entry->ttvn = ttvn; 1564d657e621SAntonio Quartulli goto out; 156530cfd02bSAntonio Quartulli } 1566d657e621SAntonio Quartulli 156786452f81SSven Eckelmann orig_entry = kmem_cache_zalloc(batadv_tt_orig_cache, GFP_ATOMIC); 1568db08e6e5SSimon Wunderlich if (!orig_entry) 1569d657e621SAntonio Quartulli goto out; 1570db08e6e5SSimon Wunderlich 1571db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 15727c124391SSven Eckelmann kref_get(&orig_node->refcount); 15737ea7b4a1SAntonio Quartulli batadv_tt_global_size_inc(orig_node, tt_global->common.vid); 1574db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 1575db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 15766e8ef69dSSven Eckelmann kref_init(&orig_entry->refcount); 1577db08e6e5SSimon Wunderlich 1578d657e621SAntonio Quartulli spin_lock_bh(&tt_global->list_lock); 157923f55485SSven Eckelmann kref_get(&orig_entry->refcount); 1580db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 1581d657e621SAntonio Quartulli &tt_global->orig_list); 1582d657e621SAntonio Quartulli spin_unlock_bh(&tt_global->list_lock); 15831d8ab8d3SLinus Lüssing atomic_inc(&tt_global->orig_list_count); 15841d8ab8d3SLinus Lüssing 1585d657e621SAntonio Quartulli out: 1586d657e621SAntonio Quartulli if (orig_entry) 15877e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(orig_entry); 1588db08e6e5SSimon Wunderlich } 1589db08e6e5SSimon Wunderlich 1590d4ff40f6SAntonio Quartulli /** 1591d4ff40f6SAntonio Quartulli * batadv_tt_global_add - add a new TT global entry or update an existing one 1592d4ff40f6SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1593d4ff40f6SAntonio Quartulli * @orig_node: the originator announcing the client 1594d4ff40f6SAntonio Quartulli * @tt_addr: the mac address of the non-mesh client 1595c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1596d4ff40f6SAntonio Quartulli * @flags: TT flags that have to be set for this non-mesh client 1597d4ff40f6SAntonio Quartulli * @ttvn: the tt version number ever announcing this non-mesh client 1598d4ff40f6SAntonio Quartulli * 1599d4ff40f6SAntonio Quartulli * Add a new TT global entry for the given originator. If the entry already 1600d4ff40f6SAntonio Quartulli * exists add a new reference to the given originator (a global entry can have 1601d4ff40f6SAntonio Quartulli * references to multiple originators) and adjust the flags attribute to reflect 1602d4ff40f6SAntonio Quartulli * the function argument. 1603d4ff40f6SAntonio Quartulli * If a TT local entry exists for this non-mesh client remove it. 1604d4ff40f6SAntonio Quartulli * 1605d4ff40f6SAntonio Quartulli * The caller must hold orig_node refcount. 16061e5d49fcSAntonio Quartulli * 160762fe710fSSven Eckelmann * Return: true if the new entry has been added, false otherwise 1608d4ff40f6SAntonio Quartulli */ 16091e5d49fcSAntonio Quartulli static bool batadv_tt_global_add(struct batadv_priv *bat_priv, 161056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1611c018ad3dSAntonio Quartulli const unsigned char *tt_addr, 16126b5e971aSSven Eckelmann unsigned short vid, u16 flags, u8 ttvn) 1613c6c8fea2SSven Eckelmann { 1614170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 1615170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 16161e5d49fcSAntonio Quartulli bool ret = false; 161780b3f58cSSimon Wunderlich int hash_added; 161856303d34SSven Eckelmann struct batadv_tt_common_entry *common; 16196b5e971aSSven Eckelmann u16 local_flags; 1620c6c8fea2SSven Eckelmann 1621cfd4f757SAntonio Quartulli /* ignore global entries from backbone nodes */ 1622cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) 1623cfd4f757SAntonio Quartulli return true; 1624cfd4f757SAntonio Quartulli 1625c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); 1626c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid); 1627068ee6e2SAntonio Quartulli 1628068ee6e2SAntonio Quartulli /* if the node already has a local client for this entry, it has to wait 1629068ee6e2SAntonio Quartulli * for a roaming advertisement instead of manually messing up the global 1630068ee6e2SAntonio Quartulli * table 1631068ee6e2SAntonio Quartulli */ 1632068ee6e2SAntonio Quartulli if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && 1633068ee6e2SAntonio Quartulli !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) 1634068ee6e2SAntonio Quartulli goto out; 1635c6c8fea2SSven Eckelmann 16362dafb49dSAntonio Quartulli if (!tt_global_entry) { 163786452f81SSven Eckelmann tt_global_entry = kmem_cache_zalloc(batadv_tg_cache, 163886452f81SSven Eckelmann GFP_ATOMIC); 16392dafb49dSAntonio Quartulli if (!tt_global_entry) 16407683fdc1SAntonio Quartulli goto out; 16417683fdc1SAntonio Quartulli 1642c0a55929SSven Eckelmann common = &tt_global_entry->common; 16438fdd0153SAntonio Quartulli ether_addr_copy(common->addr, tt_addr); 1644c018ad3dSAntonio Quartulli common->vid = vid; 1645db08e6e5SSimon Wunderlich 1646d4f44692SAntonio Quartulli common->flags = flags; 1647cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1648fdf79320SAntonio Quartulli /* node must store current time in case of roaming. This is 1649fdf79320SAntonio Quartulli * needed to purge this entry out on timeout (if nobody claims 1650fdf79320SAntonio Quartulli * it) 1651fdf79320SAntonio Quartulli */ 1652fdf79320SAntonio Quartulli if (flags & BATADV_TT_CLIENT_ROAM) 1653fdf79320SAntonio Quartulli tt_global_entry->roam_at = jiffies; 165492dcdf09SSven Eckelmann kref_init(&common->refcount); 165530cfd02bSAntonio Quartulli common->added_at = jiffies; 1656db08e6e5SSimon Wunderlich 1657db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 16581d8ab8d3SLinus Lüssing atomic_set(&tt_global_entry->orig_list_count, 0); 1659db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 16607683fdc1SAntonio Quartulli 166115d5ffdeSSven Eckelmann kref_get(&common->refcount); 1662807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.global_hash, 1663a513088dSSven Eckelmann batadv_compare_tt, 1664c018ad3dSAntonio Quartulli batadv_choose_tt, common, 1665a513088dSSven Eckelmann &common->hash_entry); 166680b3f58cSSimon Wunderlich 166780b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 166880b3f58cSSimon Wunderlich /* remove the reference for the hash */ 16695dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 167080b3f58cSSimon Wunderlich goto out_remove; 167180b3f58cSSimon Wunderlich } 1672a73105b8SAntonio Quartulli } else { 1673068ee6e2SAntonio Quartulli common = &tt_global_entry->common; 167430cfd02bSAntonio Quartulli /* If there is already a global entry, we can use this one for 167530cfd02bSAntonio Quartulli * our processing. 1676068ee6e2SAntonio Quartulli * But if we are trying to add a temporary client then here are 1677068ee6e2SAntonio Quartulli * two options at this point: 1678068ee6e2SAntonio Quartulli * 1) the global client is not a temporary client: the global 1679068ee6e2SAntonio Quartulli * client has to be left as it is, temporary information 1680068ee6e2SAntonio Quartulli * should never override any already known client state 1681068ee6e2SAntonio Quartulli * 2) the global client is a temporary client: purge the 1682068ee6e2SAntonio Quartulli * originator list and add the new one orig_entry 168330cfd02bSAntonio Quartulli */ 1684068ee6e2SAntonio Quartulli if (flags & BATADV_TT_CLIENT_TEMP) { 1685068ee6e2SAntonio Quartulli if (!(common->flags & BATADV_TT_CLIENT_TEMP)) 168630cfd02bSAntonio Quartulli goto out; 1687068ee6e2SAntonio Quartulli if (batadv_tt_global_entry_has_orig(tt_global_entry, 1688068ee6e2SAntonio Quartulli orig_node)) 1689068ee6e2SAntonio Quartulli goto out_remove; 1690068ee6e2SAntonio Quartulli batadv_tt_global_del_orig_list(tt_global_entry); 1691068ee6e2SAntonio Quartulli goto add_orig_entry; 1692068ee6e2SAntonio Quartulli } 169330cfd02bSAntonio Quartulli 169430cfd02bSAntonio Quartulli /* if the client was temporary added before receiving the first 1695a6cb3909SSimon Wunderlich * OGM announcing it, we have to clear the TEMP flag. Also, 1696a6cb3909SSimon Wunderlich * remove the previous temporary orig node and re-add it 1697a6cb3909SSimon Wunderlich * if required. If the orig entry changed, the new one which 1698a6cb3909SSimon Wunderlich * is a non-temporary entry is preferred. 169930cfd02bSAntonio Quartulli */ 1700a6cb3909SSimon Wunderlich if (common->flags & BATADV_TT_CLIENT_TEMP) { 1701a6cb3909SSimon Wunderlich batadv_tt_global_del_orig_list(tt_global_entry); 1702068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_TEMP; 1703a6cb3909SSimon Wunderlich } 1704db08e6e5SSimon Wunderlich 1705e9c00136SAntonio Quartulli /* the change can carry possible "attribute" flags like the 1706e9c00136SAntonio Quartulli * TT_CLIENT_WIFI, therefore they have to be copied in the 1707e9c00136SAntonio Quartulli * client entry 1708e9c00136SAntonio Quartulli */ 1709ad7e2c46SSimon Wunderlich common->flags |= flags; 1710e9c00136SAntonio Quartulli 1711acd34afaSSven Eckelmann /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 1712acd34afaSSven Eckelmann * one originator left in the list and we previously received a 1713db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 1714db08e6e5SSimon Wunderlich * 1715db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 1716db08e6e5SSimon Wunderlich * new one. 1717db08e6e5SSimon Wunderlich */ 1718068ee6e2SAntonio Quartulli if (common->flags & BATADV_TT_CLIENT_ROAM) { 1719a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1720068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_ROAM; 1721cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1722c6c8fea2SSven Eckelmann } 1723db08e6e5SSimon Wunderlich } 1724068ee6e2SAntonio Quartulli add_orig_entry: 172530cfd02bSAntonio Quartulli /* add the new orig_entry (if needed) or update it */ 1726d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); 1727db08e6e5SSimon Wunderlich 172839c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 172916052789SAntonio Quartulli "Creating new global tt entry: %pM (vid: %d, via %pM)\n", 1730f7a2bd65SSven Eckelmann common->addr, batadv_print_vid(common->vid), 173116052789SAntonio Quartulli orig_node->orig); 17321e5d49fcSAntonio Quartulli ret = true; 1733a73105b8SAntonio Quartulli 173480b3f58cSSimon Wunderlich out_remove: 1735c5caf4efSLinus Lüssing /* Do not remove multicast addresses from the local hash on 1736c5caf4efSLinus Lüssing * global additions 1737c5caf4efSLinus Lüssing */ 1738c5caf4efSLinus Lüssing if (is_multicast_ether_addr(tt_addr)) 1739c5caf4efSLinus Lüssing goto out; 17407f91d06cSAntonio Quartulli 1741c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 1742c018ad3dSAntonio Quartulli local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, 1743acd34afaSSven Eckelmann "global tt received", 1744c1d07431SAntonio Quartulli flags & BATADV_TT_CLIENT_ROAM); 17457f91d06cSAntonio Quartulli tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; 17467f91d06cSAntonio Quartulli 1747068ee6e2SAntonio Quartulli if (!(flags & BATADV_TT_CLIENT_ROAM)) 1748068ee6e2SAntonio Quartulli /* this is a normal global add. Therefore the client is not in a 1749068ee6e2SAntonio Quartulli * roaming state anymore. 1750068ee6e2SAntonio Quartulli */ 1751068ee6e2SAntonio Quartulli tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 1752068ee6e2SAntonio Quartulli 17537683fdc1SAntonio Quartulli out: 17547683fdc1SAntonio Quartulli if (tt_global_entry) 17555dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 1756068ee6e2SAntonio Quartulli if (tt_local_entry) 175795c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 17587683fdc1SAntonio Quartulli return ret; 1759c6c8fea2SSven Eckelmann } 1760c6c8fea2SSven Eckelmann 17611b371d13SSimon Wunderlich /** 17621b371d13SSimon Wunderlich * batadv_transtable_best_orig - Get best originator list entry from tt entry 17634627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1764981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be analyzed 1765981d8900SSven Eckelmann * 1766981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 176762fe710fSSven Eckelmann * Return: best originator list entry or NULL on errors. 1768981d8900SSven Eckelmann */ 1769981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry * 17704627456aSAntonio Quartulli batadv_transtable_best_orig(struct batadv_priv *bat_priv, 17714627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry) 1772981d8900SSven Eckelmann { 17734627456aSAntonio Quartulli struct batadv_neigh_node *router, *best_router = NULL; 177429824a55SAntonio Quartulli struct batadv_algo_ops *bao = bat_priv->algo_ops; 1775981d8900SSven Eckelmann struct hlist_head *head; 1776981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; 1777981d8900SSven Eckelmann 1778981d8900SSven Eckelmann head = &tt_global_entry->orig_list; 1779b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 17807351a482SSimon Wunderlich router = batadv_orig_router_get(orig_entry->orig_node, 17817351a482SSimon Wunderlich BATADV_IF_DEFAULT); 1782981d8900SSven Eckelmann if (!router) 1783981d8900SSven Eckelmann continue; 1784981d8900SSven Eckelmann 17854627456aSAntonio Quartulli if (best_router && 178629824a55SAntonio Quartulli bao->neigh.cmp(router, BATADV_IF_DEFAULT, best_router, 178729824a55SAntonio Quartulli BATADV_IF_DEFAULT) <= 0) { 178825bb2509SSven Eckelmann batadv_neigh_node_put(router); 17894627456aSAntonio Quartulli continue; 1790981d8900SSven Eckelmann } 1791981d8900SSven Eckelmann 17924627456aSAntonio Quartulli /* release the refcount for the "old" best */ 17934627456aSAntonio Quartulli if (best_router) 179425bb2509SSven Eckelmann batadv_neigh_node_put(best_router); 17954627456aSAntonio Quartulli 17964627456aSAntonio Quartulli best_entry = orig_entry; 17974627456aSAntonio Quartulli best_router = router; 1798981d8900SSven Eckelmann } 1799981d8900SSven Eckelmann 18004627456aSAntonio Quartulli if (best_router) 180125bb2509SSven Eckelmann batadv_neigh_node_put(best_router); 18024627456aSAntonio Quartulli 1803981d8900SSven Eckelmann return best_entry; 1804981d8900SSven Eckelmann } 1805981d8900SSven Eckelmann 1806dc1cbd14SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUGFS 18071b371d13SSimon Wunderlich /** 18081b371d13SSimon Wunderlich * batadv_tt_global_print_entry - print all orig nodes who announce the address 1809981d8900SSven Eckelmann * for this global entry 18104627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1811981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be printed 1812981d8900SSven Eckelmann * @seq: debugfs table seq_file struct 1813981d8900SSven Eckelmann * 1814981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 1815db08e6e5SSimon Wunderlich */ 1816a513088dSSven Eckelmann static void 18174627456aSAntonio Quartulli batadv_tt_global_print_entry(struct batadv_priv *bat_priv, 18184627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry, 1819db08e6e5SSimon Wunderlich struct seq_file *seq) 1820db08e6e5SSimon Wunderlich { 1821981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry; 182256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 18237ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 18247ea7b4a1SAntonio Quartulli struct hlist_head *head; 18256b5e971aSSven Eckelmann u8 last_ttvn; 18266b5e971aSSven Eckelmann u16 flags; 1827db08e6e5SSimon Wunderlich 1828db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 1829981d8900SSven Eckelmann flags = tt_common_entry->flags; 1830981d8900SSven Eckelmann 18314627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 1832981d8900SSven Eckelmann if (best_entry) { 18337ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(best_entry->orig_node, 18347ea7b4a1SAntonio Quartulli tt_common_entry->vid); 18357ea7b4a1SAntonio Quartulli if (!vlan) { 18367ea7b4a1SAntonio Quartulli seq_printf(seq, 18377ea7b4a1SAntonio Quartulli " * Cannot retrieve VLAN %d for originator %pM\n", 1838f7a2bd65SSven Eckelmann batadv_print_vid(tt_common_entry->vid), 18397ea7b4a1SAntonio Quartulli best_entry->orig_node->orig); 18407ea7b4a1SAntonio Quartulli goto print_list; 18417ea7b4a1SAntonio Quartulli } 18427ea7b4a1SAntonio Quartulli 1843981d8900SSven Eckelmann last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); 1844f9d8a537SAntonio Quartulli seq_printf(seq, 1845dd24ddb2SAntonio Quartulli " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1846981d8900SSven Eckelmann '*', tt_global_entry->common.addr, 1847f7a2bd65SSven Eckelmann batadv_print_vid(tt_global_entry->common.vid), 1848981d8900SSven Eckelmann best_entry->ttvn, best_entry->orig_node->orig, 18497ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1850a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 1851a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1852a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1853a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.')); 18547ea7b4a1SAntonio Quartulli 185521754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 1856981d8900SSven Eckelmann } 1857db08e6e5SSimon Wunderlich 18587ea7b4a1SAntonio Quartulli print_list: 1859db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1860db08e6e5SSimon Wunderlich 1861b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1862981d8900SSven Eckelmann if (best_entry == orig_entry) 1863981d8900SSven Eckelmann continue; 1864981d8900SSven Eckelmann 18657ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, 18667ea7b4a1SAntonio Quartulli tt_common_entry->vid); 18677ea7b4a1SAntonio Quartulli if (!vlan) { 18687ea7b4a1SAntonio Quartulli seq_printf(seq, 18697ea7b4a1SAntonio Quartulli " + Cannot retrieve VLAN %d for originator %pM\n", 1870f7a2bd65SSven Eckelmann batadv_print_vid(tt_common_entry->vid), 18717ea7b4a1SAntonio Quartulli orig_entry->orig_node->orig); 18727ea7b4a1SAntonio Quartulli continue; 18737ea7b4a1SAntonio Quartulli } 18747ea7b4a1SAntonio Quartulli 1875db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 187616052789SAntonio Quartulli seq_printf(seq, 1877dd24ddb2SAntonio Quartulli " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1878981d8900SSven Eckelmann '+', tt_global_entry->common.addr, 1879f7a2bd65SSven Eckelmann batadv_print_vid(tt_global_entry->common.vid), 1880981d8900SSven Eckelmann orig_entry->ttvn, orig_entry->orig_node->orig, 18817ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1882a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 1883a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1884a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1885a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.')); 18867ea7b4a1SAntonio Quartulli 188721754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 1888db08e6e5SSimon Wunderlich } 1889db08e6e5SSimon Wunderlich } 1890db08e6e5SSimon Wunderlich 189108c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 1892c6c8fea2SSven Eckelmann { 1893c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 189456303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 1895807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 189656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 189756303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 189856303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 1899c6c8fea2SSven Eckelmann struct hlist_head *head; 19006b5e971aSSven Eckelmann u32 i; 1901c6c8fea2SSven Eckelmann 190230da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 190330da63a6SMarek Lindner if (!primary_if) 190432ae9b22SMarek Lindner goto out; 1905c6c8fea2SSven Eckelmann 19062dafb49dSAntonio Quartulli seq_printf(seq, 19072dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 1908c6c8fea2SSven Eckelmann net_dev->name); 1909925a6f37SAntonio Quartulli seq_puts(seq, 1910925a6f37SAntonio Quartulli " Client VID (TTVN) Originator (Curr TTVN) (CRC ) Flags\n"); 1911c6c8fea2SSven Eckelmann 1912c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1913c6c8fea2SSven Eckelmann head = &hash->table[i]; 1914c6c8fea2SSven Eckelmann 19157aadf889SMarek Lindner rcu_read_lock(); 1916b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 19177aadf889SMarek Lindner head, hash_entry) { 191856303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 191956303d34SSven Eckelmann struct batadv_tt_global_entry, 192048100bacSAntonio Quartulli common); 19214627456aSAntonio Quartulli batadv_tt_global_print_entry(bat_priv, tt_global, seq); 1922c6c8fea2SSven Eckelmann } 19237aadf889SMarek Lindner rcu_read_unlock(); 1924c6c8fea2SSven Eckelmann } 192532ae9b22SMarek Lindner out: 192632ae9b22SMarek Lindner if (primary_if) 192782047ad7SSven Eckelmann batadv_hardif_put(primary_if); 192830da63a6SMarek Lindner return 0; 1929c6c8fea2SSven Eckelmann } 1930dc1cbd14SSven Eckelmann #endif 1931c6c8fea2SSven Eckelmann 19321d8ab8d3SLinus Lüssing /** 1933d34f0550SMatthias Schiffer * batadv_tt_global_dump_subentry - Dump all TT local entries into a message 1934d34f0550SMatthias Schiffer * @msg: Netlink message to dump into 1935d34f0550SMatthias Schiffer * @portid: Port making netlink request 1936d34f0550SMatthias Schiffer * @seq: Sequence number of netlink message 1937d34f0550SMatthias Schiffer * @common: tt local & tt global common data 1938d34f0550SMatthias Schiffer * @orig: Originator node announcing a non-mesh client 1939d34f0550SMatthias Schiffer * @best: Is the best originator for the TT entry 1940d34f0550SMatthias Schiffer * 1941d34f0550SMatthias Schiffer * Return: Error code, or 0 on success 1942d34f0550SMatthias Schiffer */ 1943d34f0550SMatthias Schiffer static int 1944d34f0550SMatthias Schiffer batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, 1945d34f0550SMatthias Schiffer struct batadv_tt_common_entry *common, 1946d34f0550SMatthias Schiffer struct batadv_tt_orig_list_entry *orig, 1947d34f0550SMatthias Schiffer bool best) 1948d34f0550SMatthias Schiffer { 1949d34f0550SMatthias Schiffer void *hdr; 1950d34f0550SMatthias Schiffer struct batadv_orig_node_vlan *vlan; 1951d34f0550SMatthias Schiffer u8 last_ttvn; 1952d34f0550SMatthias Schiffer u32 crc; 1953d34f0550SMatthias Schiffer 1954d34f0550SMatthias Schiffer vlan = batadv_orig_node_vlan_get(orig->orig_node, 1955d34f0550SMatthias Schiffer common->vid); 1956d34f0550SMatthias Schiffer if (!vlan) 1957d34f0550SMatthias Schiffer return 0; 1958d34f0550SMatthias Schiffer 1959d34f0550SMatthias Schiffer crc = vlan->tt.crc; 1960d34f0550SMatthias Schiffer 1961d34f0550SMatthias Schiffer batadv_orig_node_vlan_put(vlan); 1962d34f0550SMatthias Schiffer 1963d34f0550SMatthias Schiffer hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, 1964d34f0550SMatthias Schiffer NLM_F_MULTI, 1965d34f0550SMatthias Schiffer BATADV_CMD_GET_TRANSTABLE_GLOBAL); 1966d34f0550SMatthias Schiffer if (!hdr) 1967d34f0550SMatthias Schiffer return -ENOBUFS; 1968d34f0550SMatthias Schiffer 1969d34f0550SMatthias Schiffer last_ttvn = atomic_read(&orig->orig_node->last_ttvn); 1970d34f0550SMatthias Schiffer 1971d34f0550SMatthias Schiffer if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) || 1972d34f0550SMatthias Schiffer nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, 1973d34f0550SMatthias Schiffer orig->orig_node->orig) || 1974d34f0550SMatthias Schiffer nla_put_u8(msg, BATADV_ATTR_TT_TTVN, orig->ttvn) || 1975d34f0550SMatthias Schiffer nla_put_u8(msg, BATADV_ATTR_TT_LAST_TTVN, last_ttvn) || 1976d34f0550SMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) || 1977d34f0550SMatthias Schiffer nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) || 1978d34f0550SMatthias Schiffer nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags)) 1979d34f0550SMatthias Schiffer goto nla_put_failure; 1980d34f0550SMatthias Schiffer 1981d34f0550SMatthias Schiffer if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) 1982d34f0550SMatthias Schiffer goto nla_put_failure; 1983d34f0550SMatthias Schiffer 1984d34f0550SMatthias Schiffer genlmsg_end(msg, hdr); 1985d34f0550SMatthias Schiffer return 0; 1986d34f0550SMatthias Schiffer 1987d34f0550SMatthias Schiffer nla_put_failure: 1988d34f0550SMatthias Schiffer genlmsg_cancel(msg, hdr); 1989d34f0550SMatthias Schiffer return -EMSGSIZE; 1990d34f0550SMatthias Schiffer } 1991d34f0550SMatthias Schiffer 1992d34f0550SMatthias Schiffer /** 1993d34f0550SMatthias Schiffer * batadv_tt_global_dump_entry - Dump one TT global entry into a message 1994d34f0550SMatthias Schiffer * @msg: Netlink message to dump into 1995d34f0550SMatthias Schiffer * @portid: Port making netlink request 1996d34f0550SMatthias Schiffer * @seq: Sequence number of netlink message 1997d34f0550SMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 1998d34f0550SMatthias Schiffer * @common: tt local & tt global common data 1999d34f0550SMatthias Schiffer * @sub_s: Number of entries to skip 2000d34f0550SMatthias Schiffer * 2001d34f0550SMatthias Schiffer * This function assumes the caller holds rcu_read_lock(). 2002d34f0550SMatthias Schiffer * 2003d34f0550SMatthias Schiffer * Return: Error code, or 0 on success 2004d34f0550SMatthias Schiffer */ 2005d34f0550SMatthias Schiffer static int 2006d34f0550SMatthias Schiffer batadv_tt_global_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, 2007d34f0550SMatthias Schiffer struct batadv_priv *bat_priv, 2008d34f0550SMatthias Schiffer struct batadv_tt_common_entry *common, int *sub_s) 2009d34f0550SMatthias Schiffer { 2010d34f0550SMatthias Schiffer struct batadv_tt_orig_list_entry *orig_entry, *best_entry; 2011d34f0550SMatthias Schiffer struct batadv_tt_global_entry *global; 2012d34f0550SMatthias Schiffer struct hlist_head *head; 2013d34f0550SMatthias Schiffer int sub = 0; 2014d34f0550SMatthias Schiffer bool best; 2015d34f0550SMatthias Schiffer 2016d34f0550SMatthias Schiffer global = container_of(common, struct batadv_tt_global_entry, common); 2017d34f0550SMatthias Schiffer best_entry = batadv_transtable_best_orig(bat_priv, global); 2018d34f0550SMatthias Schiffer head = &global->orig_list; 2019d34f0550SMatthias Schiffer 2020d34f0550SMatthias Schiffer hlist_for_each_entry_rcu(orig_entry, head, list) { 2021d34f0550SMatthias Schiffer if (sub++ < *sub_s) 2022d34f0550SMatthias Schiffer continue; 2023d34f0550SMatthias Schiffer 2024d34f0550SMatthias Schiffer best = (orig_entry == best_entry); 2025d34f0550SMatthias Schiffer 2026d34f0550SMatthias Schiffer if (batadv_tt_global_dump_subentry(msg, portid, seq, common, 2027d34f0550SMatthias Schiffer orig_entry, best)) { 2028d34f0550SMatthias Schiffer *sub_s = sub - 1; 2029d34f0550SMatthias Schiffer return -EMSGSIZE; 2030d34f0550SMatthias Schiffer } 2031d34f0550SMatthias Schiffer } 2032d34f0550SMatthias Schiffer 2033d34f0550SMatthias Schiffer *sub_s = 0; 2034d34f0550SMatthias Schiffer return 0; 2035d34f0550SMatthias Schiffer } 2036d34f0550SMatthias Schiffer 2037d34f0550SMatthias Schiffer /** 2038d34f0550SMatthias Schiffer * batadv_tt_global_dump_bucket - Dump one TT local bucket into a message 2039d34f0550SMatthias Schiffer * @msg: Netlink message to dump into 2040d34f0550SMatthias Schiffer * @portid: Port making netlink request 2041d34f0550SMatthias Schiffer * @seq: Sequence number of netlink message 2042d34f0550SMatthias Schiffer * @bat_priv: The bat priv with all the soft interface information 2043d34f0550SMatthias Schiffer * @head: Pointer to the list containing the global tt entries 2044d34f0550SMatthias Schiffer * @idx_s: Number of entries to skip 2045d34f0550SMatthias Schiffer * @sub: Number of entries to skip 2046d34f0550SMatthias Schiffer * 2047d34f0550SMatthias Schiffer * Return: Error code, or 0 on success 2048d34f0550SMatthias Schiffer */ 2049d34f0550SMatthias Schiffer static int 2050d34f0550SMatthias Schiffer batadv_tt_global_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, 2051d34f0550SMatthias Schiffer struct batadv_priv *bat_priv, 2052d34f0550SMatthias Schiffer struct hlist_head *head, int *idx_s, int *sub) 2053d34f0550SMatthias Schiffer { 2054d34f0550SMatthias Schiffer struct batadv_tt_common_entry *common; 2055d34f0550SMatthias Schiffer int idx = 0; 2056d34f0550SMatthias Schiffer 2057d34f0550SMatthias Schiffer rcu_read_lock(); 2058d34f0550SMatthias Schiffer hlist_for_each_entry_rcu(common, head, hash_entry) { 2059d34f0550SMatthias Schiffer if (idx++ < *idx_s) 2060d34f0550SMatthias Schiffer continue; 2061d34f0550SMatthias Schiffer 2062d34f0550SMatthias Schiffer if (batadv_tt_global_dump_entry(msg, portid, seq, bat_priv, 2063d34f0550SMatthias Schiffer common, sub)) { 2064d34f0550SMatthias Schiffer rcu_read_unlock(); 2065d34f0550SMatthias Schiffer *idx_s = idx - 1; 2066d34f0550SMatthias Schiffer return -EMSGSIZE; 2067d34f0550SMatthias Schiffer } 2068d34f0550SMatthias Schiffer } 2069d34f0550SMatthias Schiffer rcu_read_unlock(); 2070d34f0550SMatthias Schiffer 2071d34f0550SMatthias Schiffer *idx_s = 0; 2072d34f0550SMatthias Schiffer *sub = 0; 2073d34f0550SMatthias Schiffer return 0; 2074d34f0550SMatthias Schiffer } 2075d34f0550SMatthias Schiffer 2076d34f0550SMatthias Schiffer /** 2077d34f0550SMatthias Schiffer * batadv_tt_global_dump - Dump TT global entries into a message 2078d34f0550SMatthias Schiffer * @msg: Netlink message to dump into 2079d34f0550SMatthias Schiffer * @cb: Parameters from query 2080d34f0550SMatthias Schiffer * 2081d34f0550SMatthias Schiffer * Return: Error code, or length of message on success 2082d34f0550SMatthias Schiffer */ 2083d34f0550SMatthias Schiffer int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb) 2084d34f0550SMatthias Schiffer { 2085d34f0550SMatthias Schiffer struct net *net = sock_net(cb->skb->sk); 2086d34f0550SMatthias Schiffer struct net_device *soft_iface; 2087d34f0550SMatthias Schiffer struct batadv_priv *bat_priv; 2088d34f0550SMatthias Schiffer struct batadv_hard_iface *primary_if = NULL; 2089d34f0550SMatthias Schiffer struct batadv_hashtable *hash; 2090d34f0550SMatthias Schiffer struct hlist_head *head; 2091d34f0550SMatthias Schiffer int ret; 2092d34f0550SMatthias Schiffer int ifindex; 2093d34f0550SMatthias Schiffer int bucket = cb->args[0]; 2094d34f0550SMatthias Schiffer int idx = cb->args[1]; 2095d34f0550SMatthias Schiffer int sub = cb->args[2]; 2096d34f0550SMatthias Schiffer int portid = NETLINK_CB(cb->skb).portid; 2097d34f0550SMatthias Schiffer 2098d34f0550SMatthias Schiffer ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); 2099d34f0550SMatthias Schiffer if (!ifindex) 2100d34f0550SMatthias Schiffer return -EINVAL; 2101d34f0550SMatthias Schiffer 2102d34f0550SMatthias Schiffer soft_iface = dev_get_by_index(net, ifindex); 2103d34f0550SMatthias Schiffer if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { 2104d34f0550SMatthias Schiffer ret = -ENODEV; 2105d34f0550SMatthias Schiffer goto out; 2106d34f0550SMatthias Schiffer } 2107d34f0550SMatthias Schiffer 2108d34f0550SMatthias Schiffer bat_priv = netdev_priv(soft_iface); 2109d34f0550SMatthias Schiffer 2110d34f0550SMatthias Schiffer primary_if = batadv_primary_if_get_selected(bat_priv); 2111d34f0550SMatthias Schiffer if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { 2112d34f0550SMatthias Schiffer ret = -ENOENT; 2113d34f0550SMatthias Schiffer goto out; 2114d34f0550SMatthias Schiffer } 2115d34f0550SMatthias Schiffer 2116d34f0550SMatthias Schiffer hash = bat_priv->tt.global_hash; 2117d34f0550SMatthias Schiffer 2118d34f0550SMatthias Schiffer while (bucket < hash->size) { 2119d34f0550SMatthias Schiffer head = &hash->table[bucket]; 2120d34f0550SMatthias Schiffer 2121d34f0550SMatthias Schiffer if (batadv_tt_global_dump_bucket(msg, portid, 2122d34f0550SMatthias Schiffer cb->nlh->nlmsg_seq, bat_priv, 2123d34f0550SMatthias Schiffer head, &idx, &sub)) 2124d34f0550SMatthias Schiffer break; 2125d34f0550SMatthias Schiffer 2126d34f0550SMatthias Schiffer bucket++; 2127d34f0550SMatthias Schiffer } 2128d34f0550SMatthias Schiffer 2129d34f0550SMatthias Schiffer ret = msg->len; 2130d34f0550SMatthias Schiffer 2131d34f0550SMatthias Schiffer out: 2132d34f0550SMatthias Schiffer if (primary_if) 2133d34f0550SMatthias Schiffer batadv_hardif_put(primary_if); 2134d34f0550SMatthias Schiffer if (soft_iface) 2135d34f0550SMatthias Schiffer dev_put(soft_iface); 2136d34f0550SMatthias Schiffer 2137d34f0550SMatthias Schiffer cb->args[0] = bucket; 2138d34f0550SMatthias Schiffer cb->args[1] = idx; 2139d34f0550SMatthias Schiffer cb->args[2] = sub; 2140d34f0550SMatthias Schiffer 2141d34f0550SMatthias Schiffer return ret; 2142d34f0550SMatthias Schiffer } 2143d34f0550SMatthias Schiffer 2144d34f0550SMatthias Schiffer /** 2145433ff98fSMarek Lindner * _batadv_tt_global_del_orig_entry - remove and free an orig_entry 21461d8ab8d3SLinus Lüssing * @tt_global_entry: the global entry to remove the orig_entry from 21471d8ab8d3SLinus Lüssing * @orig_entry: the orig entry to remove and free 21481d8ab8d3SLinus Lüssing * 21491d8ab8d3SLinus Lüssing * Remove an orig_entry from its list in the given tt_global_entry and 21501d8ab8d3SLinus Lüssing * free this orig_entry afterwards. 2151433ff98fSMarek Lindner * 2152433ff98fSMarek Lindner * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is 2153433ff98fSMarek Lindner * part of a list. 21541d8ab8d3SLinus Lüssing */ 21551d8ab8d3SLinus Lüssing static void 2156433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, 21571d8ab8d3SLinus Lüssing struct batadv_tt_orig_list_entry *orig_entry) 21581d8ab8d3SLinus Lüssing { 21592c72d655SSven Eckelmann lockdep_assert_held(&tt_global_entry->list_lock); 21602c72d655SSven Eckelmann 21611d8ab8d3SLinus Lüssing batadv_tt_global_size_dec(orig_entry->orig_node, 21621d8ab8d3SLinus Lüssing tt_global_entry->common.vid); 21631d8ab8d3SLinus Lüssing atomic_dec(&tt_global_entry->orig_list_count); 2164433ff98fSMarek Lindner /* requires holding tt_global_entry->list_lock and orig_entry->list 2165433ff98fSMarek Lindner * being part of a list 2166433ff98fSMarek Lindner */ 21671d8ab8d3SLinus Lüssing hlist_del_rcu(&orig_entry->list); 21687e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(orig_entry); 21691d8ab8d3SLinus Lüssing } 21701d8ab8d3SLinus Lüssing 2171db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 2172a513088dSSven Eckelmann static void 217356303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) 2174db08e6e5SSimon Wunderlich { 2175db08e6e5SSimon Wunderlich struct hlist_head *head; 2176b67bfe0dSSasha Levin struct hlist_node *safe; 217756303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 2178db08e6e5SSimon Wunderlich 2179db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 2180db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 21811d8ab8d3SLinus Lüssing hlist_for_each_entry_safe(orig_entry, safe, head, list) 2182433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); 2183db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 2184db08e6e5SSimon Wunderlich } 2185db08e6e5SSimon Wunderlich 21861d8ab8d3SLinus Lüssing /** 21871d8ab8d3SLinus Lüssing * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry 21881d8ab8d3SLinus Lüssing * @bat_priv: the bat priv with all the soft interface information 21891d8ab8d3SLinus Lüssing * @tt_global_entry: the global entry to remove the orig_node from 21901d8ab8d3SLinus Lüssing * @orig_node: the originator announcing the client 21911d8ab8d3SLinus Lüssing * @message: message to append to the log on deletion 21921d8ab8d3SLinus Lüssing * 21931d8ab8d3SLinus Lüssing * Remove the given orig_node and its according orig_entry from the given 21941d8ab8d3SLinus Lüssing * global tt entry. 21951d8ab8d3SLinus Lüssing */ 2196a513088dSSven Eckelmann static void 21971d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, 219856303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 219956303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2200db08e6e5SSimon Wunderlich const char *message) 2201db08e6e5SSimon Wunderlich { 2202db08e6e5SSimon Wunderlich struct hlist_head *head; 2203b67bfe0dSSasha Levin struct hlist_node *safe; 220456303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 220516052789SAntonio Quartulli unsigned short vid; 2206db08e6e5SSimon Wunderlich 2207db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 2208db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 2209b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 2210db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 221116052789SAntonio Quartulli vid = tt_global_entry->common.vid; 221239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 221316052789SAntonio Quartulli "Deleting %pM from global tt entry %pM (vid: %d): %s\n", 22141eda58bfSSven Eckelmann orig_node->orig, 221516052789SAntonio Quartulli tt_global_entry->common.addr, 2216f7a2bd65SSven Eckelmann batadv_print_vid(vid), message); 2217433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(tt_global_entry, 22181d8ab8d3SLinus Lüssing orig_entry); 2219db08e6e5SSimon Wunderlich } 2220db08e6e5SSimon Wunderlich } 2221db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 2222db08e6e5SSimon Wunderlich } 2223db08e6e5SSimon Wunderlich 2224db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 2225acd34afaSSven Eckelmann * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the 2226acd34afaSSven Eckelmann * timer, otherwise we simply remove the originator scheduled for deletion. 2227db08e6e5SSimon Wunderlich */ 2228a513088dSSven Eckelmann static void 222956303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, 223056303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 223156303d34SSven Eckelmann struct batadv_orig_node *orig_node, 223256303d34SSven Eckelmann const char *message) 2233db08e6e5SSimon Wunderlich { 2234db08e6e5SSimon Wunderlich bool last_entry = true; 2235db08e6e5SSimon Wunderlich struct hlist_head *head; 223656303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 2237db08e6e5SSimon Wunderlich 2238db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 2239db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 2240db08e6e5SSimon Wunderlich */ 2241db08e6e5SSimon Wunderlich 2242db08e6e5SSimon Wunderlich rcu_read_lock(); 2243db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 2244b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 2245db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 2246db08e6e5SSimon Wunderlich last_entry = false; 2247db08e6e5SSimon Wunderlich break; 2248db08e6e5SSimon Wunderlich } 2249db08e6e5SSimon Wunderlich } 2250db08e6e5SSimon Wunderlich rcu_read_unlock(); 2251db08e6e5SSimon Wunderlich 2252db08e6e5SSimon Wunderlich if (last_entry) { 2253db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 2254acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 2255db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 22561fda4c0aSSven Eckelmann } else { 2257db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 2258db08e6e5SSimon Wunderlich * one and can still use the other one. 2259db08e6e5SSimon Wunderlich */ 22601d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 2261db08e6e5SSimon Wunderlich orig_node, message); 2262db08e6e5SSimon Wunderlich } 22631fda4c0aSSven Eckelmann } 2264db08e6e5SSimon Wunderlich 2265c018ad3dSAntonio Quartulli /** 2266c018ad3dSAntonio Quartulli * batadv_tt_global_del - remove a client from the global table 2267c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2268c018ad3dSAntonio Quartulli * @orig_node: an originator serving this client 2269c018ad3dSAntonio Quartulli * @addr: the mac address of the client 2270c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2271c018ad3dSAntonio Quartulli * @message: a message explaining the reason for deleting the client to print 2272c018ad3dSAntonio Quartulli * for debugging purpose 2273c018ad3dSAntonio Quartulli * @roaming: true if the deletion has been triggered by a roaming event 2274c018ad3dSAntonio Quartulli */ 227556303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv, 227656303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2277c018ad3dSAntonio Quartulli const unsigned char *addr, unsigned short vid, 2278cc47f66eSAntonio Quartulli const char *message, bool roaming) 2279a73105b8SAntonio Quartulli { 2280170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 228156303d34SSven Eckelmann struct batadv_tt_local_entry *local_entry = NULL; 2282a73105b8SAntonio Quartulli 2283c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 2284db08e6e5SSimon Wunderlich if (!tt_global_entry) 22857683fdc1SAntonio Quartulli goto out; 2286a73105b8SAntonio Quartulli 2287db08e6e5SSimon Wunderlich if (!roaming) { 22881d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 2289a513088dSSven Eckelmann orig_node, message); 229092f90f56SSven Eckelmann 2291db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 2292be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, 2293db08e6e5SSimon Wunderlich message); 2294db08e6e5SSimon Wunderlich 2295cc47f66eSAntonio Quartulli goto out; 2296cc47f66eSAntonio Quartulli } 229792f90f56SSven Eckelmann 2298db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 2299db08e6e5SSimon Wunderlich * event, there are two possibilities: 2300db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 2301db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 2302acd34afaSSven Eckelmann * it with BATADV_TT_CLIENT_ROAM, we start a timer and we 2303db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 2304db08e6e5SSimon Wunderlich * the entry is purged. 2305db08e6e5SSimon Wunderlich * 2306db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 2307db08e6e5SSimon Wunderlich * the originator. 2308db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 23099cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 23109cfc7bd6SSven Eckelmann */ 2311a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 2312c018ad3dSAntonio Quartulli tt_global_entry->common.addr, 2313c018ad3dSAntonio Quartulli vid); 2314a513088dSSven Eckelmann if (local_entry) { 2315db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 2316a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 2317be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, message); 23181fda4c0aSSven Eckelmann } else { 2319db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 2320a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 2321a513088dSSven Eckelmann orig_node, message); 23221fda4c0aSSven Eckelmann } 2323db08e6e5SSimon Wunderlich 2324cc47f66eSAntonio Quartulli out: 23257683fdc1SAntonio Quartulli if (tt_global_entry) 23265dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 2327a513088dSSven Eckelmann if (local_entry) 232895c0db90SSven Eckelmann batadv_tt_local_entry_put(local_entry); 2329a73105b8SAntonio Quartulli } 2330a73105b8SAntonio Quartulli 233195fb130dSAntonio Quartulli /** 233295fb130dSAntonio Quartulli * batadv_tt_global_del_orig - remove all the TT global entries belonging to the 233395fb130dSAntonio Quartulli * given originator matching the provided vid 233495fb130dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 233595fb130dSAntonio Quartulli * @orig_node: the originator owning the entries to remove 233695fb130dSAntonio Quartulli * @match_vid: the VLAN identifier to match. If negative all the entries will be 233795fb130dSAntonio Quartulli * removed 233895fb130dSAntonio Quartulli * @message: debug message to print as "reason" 233995fb130dSAntonio Quartulli */ 234056303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, 234156303d34SSven Eckelmann struct batadv_orig_node *orig_node, 23426b5e971aSSven Eckelmann s32 match_vid, 234356303d34SSven Eckelmann const char *message) 2344c6c8fea2SSven Eckelmann { 234556303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 234656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 23476b5e971aSSven Eckelmann u32 i; 2348807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 2349b67bfe0dSSasha Levin struct hlist_node *safe; 2350a73105b8SAntonio Quartulli struct hlist_head *head; 23517683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 235216052789SAntonio Quartulli unsigned short vid; 2353c6c8fea2SSven Eckelmann 23546e801494SSimon Wunderlich if (!hash) 23556e801494SSimon Wunderlich return; 23566e801494SSimon Wunderlich 2357a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2358a73105b8SAntonio Quartulli head = &hash->table[i]; 23597683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 2360c6c8fea2SSven Eckelmann 23617683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 2362b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, safe, 2363a73105b8SAntonio Quartulli head, hash_entry) { 236495fb130dSAntonio Quartulli /* remove only matching entries */ 236595fb130dSAntonio Quartulli if (match_vid >= 0 && tt_common_entry->vid != match_vid) 236695fb130dSAntonio Quartulli continue; 236795fb130dSAntonio Quartulli 236856303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 236956303d34SSven Eckelmann struct batadv_tt_global_entry, 237048100bacSAntonio Quartulli common); 2371db08e6e5SSimon Wunderlich 23721d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global, 2373db08e6e5SSimon Wunderlich orig_node, message); 2374db08e6e5SSimon Wunderlich 237556303d34SSven Eckelmann if (hlist_empty(&tt_global->orig_list)) { 237616052789SAntonio Quartulli vid = tt_global->common.vid; 237739c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 237816052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 237916052789SAntonio Quartulli tt_global->common.addr, 2380f7a2bd65SSven Eckelmann batadv_print_vid(vid), message); 2381b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 23825dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 2383c6c8fea2SSven Eckelmann } 2384a73105b8SAntonio Quartulli } 23857683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 23867683fdc1SAntonio Quartulli } 2387ac4eebd4SLinus Lüssing clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); 2388c6c8fea2SSven Eckelmann } 2389c6c8fea2SSven Eckelmann 239030cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, 239130cfd02bSAntonio Quartulli char **msg) 2392cc47f66eSAntonio Quartulli { 239330cfd02bSAntonio Quartulli bool purge = false; 239430cfd02bSAntonio Quartulli unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; 239530cfd02bSAntonio Quartulli unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; 2396cc47f66eSAntonio Quartulli 239730cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && 239830cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { 239930cfd02bSAntonio Quartulli purge = true; 240030cfd02bSAntonio Quartulli *msg = "Roaming timeout\n"; 240142d0b044SSven Eckelmann } 240242d0b044SSven Eckelmann 240330cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) && 240430cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) { 240530cfd02bSAntonio Quartulli purge = true; 240630cfd02bSAntonio Quartulli *msg = "Temporary client timeout\n"; 240730cfd02bSAntonio Quartulli } 240830cfd02bSAntonio Quartulli 240930cfd02bSAntonio Quartulli return purge; 241030cfd02bSAntonio Quartulli } 241130cfd02bSAntonio Quartulli 241230cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv) 241342d0b044SSven Eckelmann { 2414807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 241542d0b044SSven Eckelmann struct hlist_head *head; 2416b67bfe0dSSasha Levin struct hlist_node *node_tmp; 241742d0b044SSven Eckelmann spinlock_t *list_lock; /* protects write access to the hash lists */ 24186b5e971aSSven Eckelmann u32 i; 241930cfd02bSAntonio Quartulli char *msg = NULL; 242030cfd02bSAntonio Quartulli struct batadv_tt_common_entry *tt_common; 242130cfd02bSAntonio Quartulli struct batadv_tt_global_entry *tt_global; 242242d0b044SSven Eckelmann 242342d0b044SSven Eckelmann for (i = 0; i < hash->size; i++) { 242442d0b044SSven Eckelmann head = &hash->table[i]; 242542d0b044SSven Eckelmann list_lock = &hash->list_locks[i]; 242642d0b044SSven Eckelmann 242742d0b044SSven Eckelmann spin_lock_bh(list_lock); 2428b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 242930cfd02bSAntonio Quartulli hash_entry) { 243030cfd02bSAntonio Quartulli tt_global = container_of(tt_common, 243130cfd02bSAntonio Quartulli struct batadv_tt_global_entry, 243230cfd02bSAntonio Quartulli common); 243330cfd02bSAntonio Quartulli 243430cfd02bSAntonio Quartulli if (!batadv_tt_global_to_purge(tt_global, &msg)) 243530cfd02bSAntonio Quartulli continue; 243630cfd02bSAntonio Quartulli 243730cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 243816052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 243916052789SAntonio Quartulli tt_global->common.addr, 2440f7a2bd65SSven Eckelmann batadv_print_vid(tt_global->common.vid), 244116052789SAntonio Quartulli msg); 244230cfd02bSAntonio Quartulli 2443b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 244430cfd02bSAntonio Quartulli 24455dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 244630cfd02bSAntonio Quartulli } 24477683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 2448cc47f66eSAntonio Quartulli } 2449cc47f66eSAntonio Quartulli } 2450cc47f66eSAntonio Quartulli 245156303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) 2452c6c8fea2SSven Eckelmann { 24535bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 24547683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 245556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 245656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 2457b67bfe0dSSasha Levin struct hlist_node *node_tmp; 24587683fdc1SAntonio Quartulli struct hlist_head *head; 24596b5e971aSSven Eckelmann u32 i; 24607683fdc1SAntonio Quartulli 2461807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 2462c6c8fea2SSven Eckelmann return; 2463c6c8fea2SSven Eckelmann 2464807736f6SSven Eckelmann hash = bat_priv->tt.global_hash; 24657683fdc1SAntonio Quartulli 24667683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 24677683fdc1SAntonio Quartulli head = &hash->table[i]; 24687683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 24697683fdc1SAntonio Quartulli 24707683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 2471b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 24727683fdc1SAntonio Quartulli head, hash_entry) { 2473b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 247456303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 247556303d34SSven Eckelmann struct batadv_tt_global_entry, 247648100bacSAntonio Quartulli common); 24775dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 24787683fdc1SAntonio Quartulli } 24797683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 24807683fdc1SAntonio Quartulli } 24817683fdc1SAntonio Quartulli 24821a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 24837683fdc1SAntonio Quartulli 2484807736f6SSven Eckelmann bat_priv->tt.global_hash = NULL; 2485c6c8fea2SSven Eckelmann } 2486c6c8fea2SSven Eckelmann 248756303d34SSven Eckelmann static bool 248856303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, 248956303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry) 249059b699cdSAntonio Quartulli { 2491acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && 2492acd34afaSSven Eckelmann tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) 249375ae84a4SSimon Wunderlich return true; 249459b699cdSAntonio Quartulli 24952d2fcc2aSAntonio Quartulli /* check if the two clients are marked as isolated */ 24962d2fcc2aSAntonio Quartulli if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA && 24972d2fcc2aSAntonio Quartulli tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA) 249875ae84a4SSimon Wunderlich return true; 24992d2fcc2aSAntonio Quartulli 250075ae84a4SSimon Wunderlich return false; 250159b699cdSAntonio Quartulli } 250259b699cdSAntonio Quartulli 2503c018ad3dSAntonio Quartulli /** 2504c018ad3dSAntonio Quartulli * batadv_transtable_search - get the mesh destination for a given client 2505c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2506c018ad3dSAntonio Quartulli * @src: mac address of the source client 2507c018ad3dSAntonio Quartulli * @addr: mac address of the destination client 2508c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2509c018ad3dSAntonio Quartulli * 251062fe710fSSven Eckelmann * Return: a pointer to the originator that was selected as destination in the 2511c018ad3dSAntonio Quartulli * mesh for contacting the client 'addr', NULL otherwise. 2512c018ad3dSAntonio Quartulli * In case of multiple originators serving the same client, the function returns 2513c018ad3dSAntonio Quartulli * the best one (best in terms of metric towards the destination node). 2514c018ad3dSAntonio Quartulli * 2515c018ad3dSAntonio Quartulli * If the two clients are AP isolated the function returns NULL. 2516c018ad3dSAntonio Quartulli */ 251756303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, 25186b5e971aSSven Eckelmann const u8 *src, 25196b5e971aSSven Eckelmann const u8 *addr, 2520c018ad3dSAntonio Quartulli unsigned short vid) 2521c6c8fea2SSven Eckelmann { 252256303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 252356303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 252456303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 2525981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *best_entry; 2526c6c8fea2SSven Eckelmann 2527eceb22aeSAntonio Quartulli if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) { 2528c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); 2529068ee6e2SAntonio Quartulli if (!tt_local_entry || 2530068ee6e2SAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) 25313d393e47SAntonio Quartulli goto out; 25323d393e47SAntonio Quartulli } 25337aadf889SMarek Lindner 2534c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 25352dafb49dSAntonio Quartulli if (!tt_global_entry) 25367b36e8eeSMarek Lindner goto out; 2537c6c8fea2SSven Eckelmann 25383d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 25399cfc7bd6SSven Eckelmann * isolation 25409cfc7bd6SSven Eckelmann */ 2541a513088dSSven Eckelmann if (tt_local_entry && 2542a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 25433d393e47SAntonio Quartulli goto out; 25443d393e47SAntonio Quartulli 2545db08e6e5SSimon Wunderlich rcu_read_lock(); 25464627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 2547db08e6e5SSimon Wunderlich /* found anything? */ 2548981d8900SSven Eckelmann if (best_entry) 2549981d8900SSven Eckelmann orig_node = best_entry->orig_node; 25507c124391SSven Eckelmann if (orig_node && !kref_get_unless_zero(&orig_node->refcount)) 2551db08e6e5SSimon Wunderlich orig_node = NULL; 2552db08e6e5SSimon Wunderlich rcu_read_unlock(); 2553981d8900SSven Eckelmann 25547b36e8eeSMarek Lindner out: 25553d393e47SAntonio Quartulli if (tt_global_entry) 25565dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 25573d393e47SAntonio Quartulli if (tt_local_entry) 255895c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 25593d393e47SAntonio Quartulli 25607b36e8eeSMarek Lindner return orig_node; 2561c6c8fea2SSven Eckelmann } 2562a73105b8SAntonio Quartulli 2563ced72933SAntonio Quartulli /** 2564ced72933SAntonio Quartulli * batadv_tt_global_crc - calculates the checksum of the local table belonging 2565ced72933SAntonio Quartulli * to the given orig_node 2566ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 25670ffa9e8dSAntonio Quartulli * @orig_node: originator for which the CRC should be computed 25687ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 25690ffa9e8dSAntonio Quartulli * 25700ffa9e8dSAntonio Quartulli * This function computes the checksum for the global table corresponding to a 25710ffa9e8dSAntonio Quartulli * specific originator. In particular, the checksum is computed as follows: For 25720ffa9e8dSAntonio Quartulli * each client connected to the originator the CRC32C of the MAC address and the 25730ffa9e8dSAntonio Quartulli * VID is computed and then all the CRC32Cs of the various clients are xor'ed 25740ffa9e8dSAntonio Quartulli * together. 25750ffa9e8dSAntonio Quartulli * 25760ffa9e8dSAntonio Quartulli * The idea behind is that CRC32C should be used as much as possible in order to 25770ffa9e8dSAntonio Quartulli * produce a unique hash of the table, but since the order which is used to feed 25780ffa9e8dSAntonio Quartulli * the CRC32C function affects the result and since every node in the network 25790ffa9e8dSAntonio Quartulli * probably sorts the clients differently, the hash function cannot be directly 25800ffa9e8dSAntonio Quartulli * computed over the entire table. Hence the CRC32C is used only on 25810ffa9e8dSAntonio Quartulli * the single client entry, while all the results are then xor'ed together 25820ffa9e8dSAntonio Quartulli * because the XOR operation can combine them all while trying to reduce the 25830ffa9e8dSAntonio Quartulli * noise as much as possible. 25840ffa9e8dSAntonio Quartulli * 258562fe710fSSven Eckelmann * Return: the checksum of the global table of a given originator. 2586ced72933SAntonio Quartulli */ 25876b5e971aSSven Eckelmann static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv, 25887ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node, 25897ea7b4a1SAntonio Quartulli unsigned short vid) 2590a73105b8SAntonio Quartulli { 2591807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 259256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 259356303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 2594a73105b8SAntonio Quartulli struct hlist_head *head; 25956b5e971aSSven Eckelmann u32 i, crc_tmp, crc = 0; 25966b5e971aSSven Eckelmann u8 flags; 2597a30e22caSAntonio Quartulli __be16 tmp_vid; 2598a73105b8SAntonio Quartulli 2599a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2600a73105b8SAntonio Quartulli head = &hash->table[i]; 2601a73105b8SAntonio Quartulli 2602a73105b8SAntonio Quartulli rcu_read_lock(); 2603b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 260456303d34SSven Eckelmann tt_global = container_of(tt_common, 260556303d34SSven Eckelmann struct batadv_tt_global_entry, 260648100bacSAntonio Quartulli common); 26077ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 26087ea7b4a1SAntonio Quartulli * VLAN identified by the vid passed as parameter 26097ea7b4a1SAntonio Quartulli */ 26107ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 26117ea7b4a1SAntonio Quartulli continue; 26127ea7b4a1SAntonio Quartulli 2613cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 2614cc47f66eSAntonio Quartulli * consistency only. They don't have to be 2615cc47f66eSAntonio Quartulli * taken into account while computing the 2616db08e6e5SSimon Wunderlich * global crc 2617db08e6e5SSimon Wunderlich */ 2618acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 2619cc47f66eSAntonio Quartulli continue; 262030cfd02bSAntonio Quartulli /* Temporary clients have not been announced yet, so 262130cfd02bSAntonio Quartulli * they have to be skipped while computing the global 262230cfd02bSAntonio Quartulli * crc 262330cfd02bSAntonio Quartulli */ 262430cfd02bSAntonio Quartulli if (tt_common->flags & BATADV_TT_CLIENT_TEMP) 262530cfd02bSAntonio Quartulli continue; 2626db08e6e5SSimon Wunderlich 2627db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 2628db08e6e5SSimon Wunderlich * originator 2629db08e6e5SSimon Wunderlich */ 263056303d34SSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global, 2631db08e6e5SSimon Wunderlich orig_node)) 2632db08e6e5SSimon Wunderlich continue; 2633db08e6e5SSimon Wunderlich 2634a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2635a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2636a30e22caSAntonio Quartulli */ 2637a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2638a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 26390eb01568SAntonio Quartulli 26400eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 26410eb01568SAntonio Quartulli * among nodes 26420eb01568SAntonio Quartulli */ 26430eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 26440eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 26450eb01568SAntonio Quartulli 26460ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2647a73105b8SAntonio Quartulli } 2648a73105b8SAntonio Quartulli rcu_read_unlock(); 2649a73105b8SAntonio Quartulli } 2650a73105b8SAntonio Quartulli 2651ced72933SAntonio Quartulli return crc; 2652a73105b8SAntonio Quartulli } 2653a73105b8SAntonio Quartulli 2654ced72933SAntonio Quartulli /** 2655ced72933SAntonio Quartulli * batadv_tt_local_crc - calculates the checksum of the local table 2656ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 26577ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 26580ffa9e8dSAntonio Quartulli * 26590ffa9e8dSAntonio Quartulli * For details about the computation, please refer to the documentation for 26600ffa9e8dSAntonio Quartulli * batadv_tt_global_crc(). 26610ffa9e8dSAntonio Quartulli * 266262fe710fSSven Eckelmann * Return: the checksum of the local table 2663ced72933SAntonio Quartulli */ 26646b5e971aSSven Eckelmann static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv, 26657ea7b4a1SAntonio Quartulli unsigned short vid) 2666a73105b8SAntonio Quartulli { 2667807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 266856303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 2669a73105b8SAntonio Quartulli struct hlist_head *head; 26706b5e971aSSven Eckelmann u32 i, crc_tmp, crc = 0; 26716b5e971aSSven Eckelmann u8 flags; 2672a30e22caSAntonio Quartulli __be16 tmp_vid; 2673a73105b8SAntonio Quartulli 2674a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2675a73105b8SAntonio Quartulli head = &hash->table[i]; 2676a73105b8SAntonio Quartulli 2677a73105b8SAntonio Quartulli rcu_read_lock(); 2678b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 26797ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 26807ea7b4a1SAntonio Quartulli * VLAN identified by vid 26817ea7b4a1SAntonio Quartulli */ 26827ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 26837ea7b4a1SAntonio Quartulli continue; 26847ea7b4a1SAntonio Quartulli 2685058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 26869cfc7bd6SSven Eckelmann * account while computing the CRC 26879cfc7bd6SSven Eckelmann */ 2688acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_NEW) 2689058d0e26SAntonio Quartulli continue; 2690ced72933SAntonio Quartulli 2691a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2692a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2693a30e22caSAntonio Quartulli */ 2694a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2695a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 26960eb01568SAntonio Quartulli 26970eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 26980eb01568SAntonio Quartulli * among nodes 26990eb01568SAntonio Quartulli */ 27000eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 27010eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 27020eb01568SAntonio Quartulli 27030ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2704a73105b8SAntonio Quartulli } 2705a73105b8SAntonio Quartulli rcu_read_unlock(); 2706a73105b8SAntonio Quartulli } 2707a73105b8SAntonio Quartulli 2708ced72933SAntonio Quartulli return crc; 2709a73105b8SAntonio Quartulli } 2710a73105b8SAntonio Quartulli 27119c4604a2SSven Eckelmann /** 27129c4604a2SSven Eckelmann * batadv_tt_req_node_release - free tt_req node entry 27139c4604a2SSven Eckelmann * @ref: kref pointer of the tt req_node entry 27149c4604a2SSven Eckelmann */ 27159c4604a2SSven Eckelmann static void batadv_tt_req_node_release(struct kref *ref) 27169c4604a2SSven Eckelmann { 27179c4604a2SSven Eckelmann struct batadv_tt_req_node *tt_req_node; 27189c4604a2SSven Eckelmann 27199c4604a2SSven Eckelmann tt_req_node = container_of(ref, struct batadv_tt_req_node, refcount); 27209c4604a2SSven Eckelmann 272186452f81SSven Eckelmann kmem_cache_free(batadv_tt_req_cache, tt_req_node); 27229c4604a2SSven Eckelmann } 27239c4604a2SSven Eckelmann 27249c4604a2SSven Eckelmann /** 27259c4604a2SSven Eckelmann * batadv_tt_req_node_put - decrement the tt_req_node refcounter and 27269c4604a2SSven Eckelmann * possibly release it 27279c4604a2SSven Eckelmann * @tt_req_node: tt_req_node to be free'd 27289c4604a2SSven Eckelmann */ 27299c4604a2SSven Eckelmann static void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node) 27309c4604a2SSven Eckelmann { 27319c4604a2SSven Eckelmann kref_put(&tt_req_node->refcount, batadv_tt_req_node_release); 27329c4604a2SSven Eckelmann } 27339c4604a2SSven Eckelmann 273456303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) 2735a73105b8SAntonio Quartulli { 27367c26a53bSMarek Lindner struct batadv_tt_req_node *node; 27377c26a53bSMarek Lindner struct hlist_node *safe; 2738a73105b8SAntonio Quartulli 2739807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2740a73105b8SAntonio Quartulli 27417c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 27427c26a53bSMarek Lindner hlist_del_init(&node->list); 27439c4604a2SSven Eckelmann batadv_tt_req_node_put(node); 2744a73105b8SAntonio Quartulli } 2745a73105b8SAntonio Quartulli 2746807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2747a73105b8SAntonio Quartulli } 2748a73105b8SAntonio Quartulli 274956303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, 275056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2751e8cf234aSAntonio Quartulli const void *tt_buff, 27526b5e971aSSven Eckelmann u16 tt_buff_len) 2753a73105b8SAntonio Quartulli { 2754a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 27559cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 27569cfc7bd6SSven Eckelmann */ 2757a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2758a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 2759a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2760a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2761a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 2762a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 2763a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 2764a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 2765a73105b8SAntonio Quartulli } 2766a73105b8SAntonio Quartulli } 2767a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2768a73105b8SAntonio Quartulli } 2769a73105b8SAntonio Quartulli 277056303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv) 2771a73105b8SAntonio Quartulli { 27727c26a53bSMarek Lindner struct batadv_tt_req_node *node; 27737c26a53bSMarek Lindner struct hlist_node *safe; 2774a73105b8SAntonio Quartulli 2775807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 27767c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 277742d0b044SSven Eckelmann if (batadv_has_timed_out(node->issued_at, 277842d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) { 27797c26a53bSMarek Lindner hlist_del_init(&node->list); 27809c4604a2SSven Eckelmann batadv_tt_req_node_put(node); 2781a73105b8SAntonio Quartulli } 2782a73105b8SAntonio Quartulli } 2783807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2784a73105b8SAntonio Quartulli } 2785a73105b8SAntonio Quartulli 2786383b8636SMarek Lindner /** 2787383b8636SMarek Lindner * batadv_tt_req_node_new - search and possibly create a tt_req_node object 2788383b8636SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2789383b8636SMarek Lindner * @orig_node: orig node this request is being issued for 2790383b8636SMarek Lindner * 279162fe710fSSven Eckelmann * Return: the pointer to the new tt_req_node struct if no request 2792383b8636SMarek Lindner * has already been issued for this orig_node, NULL otherwise. 27939cfc7bd6SSven Eckelmann */ 279456303d34SSven Eckelmann static struct batadv_tt_req_node * 2795383b8636SMarek Lindner batadv_tt_req_node_new(struct batadv_priv *bat_priv, 279656303d34SSven Eckelmann struct batadv_orig_node *orig_node) 2797a73105b8SAntonio Quartulli { 279856303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 2799a73105b8SAntonio Quartulli 2800807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 28017c26a53bSMarek Lindner hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { 28021eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 28031eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 280442d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) 2805a73105b8SAntonio Quartulli goto unlock; 2806a73105b8SAntonio Quartulli } 2807a73105b8SAntonio Quartulli 280886452f81SSven Eckelmann tt_req_node = kmem_cache_alloc(batadv_tt_req_cache, GFP_ATOMIC); 2809a73105b8SAntonio Quartulli if (!tt_req_node) 2810a73105b8SAntonio Quartulli goto unlock; 2811a73105b8SAntonio Quartulli 28129c4604a2SSven Eckelmann kref_init(&tt_req_node->refcount); 28138fdd0153SAntonio Quartulli ether_addr_copy(tt_req_node->addr, orig_node->orig); 2814a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 2815a73105b8SAntonio Quartulli 28169c4604a2SSven Eckelmann kref_get(&tt_req_node->refcount); 28177c26a53bSMarek Lindner hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list); 2818a73105b8SAntonio Quartulli unlock: 2819807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2820a73105b8SAntonio Quartulli return tt_req_node; 2821a73105b8SAntonio Quartulli } 2822a73105b8SAntonio Quartulli 2823335fbe0fSMarek Lindner /** 2824335fbe0fSMarek Lindner * batadv_tt_local_valid - verify that given tt entry is a valid one 2825335fbe0fSMarek Lindner * @entry_ptr: to be checked local tt entry 2826335fbe0fSMarek Lindner * @data_ptr: not used but definition required to satisfy the callback prototype 2827335fbe0fSMarek Lindner * 28284b426b10SSven Eckelmann * Return: true if the entry is a valid, false otherwise. 2829335fbe0fSMarek Lindner */ 28304b426b10SSven Eckelmann static bool batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) 2831058d0e26SAntonio Quartulli { 283256303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 2833058d0e26SAntonio Quartulli 2834acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) 28354b426b10SSven Eckelmann return false; 28364b426b10SSven Eckelmann return true; 2837058d0e26SAntonio Quartulli } 2838058d0e26SAntonio Quartulli 28394b426b10SSven Eckelmann static bool batadv_tt_global_valid(const void *entry_ptr, 2840a513088dSSven Eckelmann const void *data_ptr) 2841a73105b8SAntonio Quartulli { 284256303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 284356303d34SSven Eckelmann const struct batadv_tt_global_entry *tt_global_entry; 284456303d34SSven Eckelmann const struct batadv_orig_node *orig_node = data_ptr; 2845a73105b8SAntonio Quartulli 284630cfd02bSAntonio Quartulli if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || 284730cfd02bSAntonio Quartulli tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) 28484b426b10SSven Eckelmann return false; 2849cc47f66eSAntonio Quartulli 285056303d34SSven Eckelmann tt_global_entry = container_of(tt_common_entry, 285156303d34SSven Eckelmann struct batadv_tt_global_entry, 285248100bacSAntonio Quartulli common); 285348100bacSAntonio Quartulli 2854a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 2855a73105b8SAntonio Quartulli } 2856a73105b8SAntonio Quartulli 2857335fbe0fSMarek Lindner /** 28587ea7b4a1SAntonio Quartulli * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the 28597ea7b4a1SAntonio Quartulli * specified tt hash 2860335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2861335fbe0fSMarek Lindner * @hash: hash table containing the tt entries 2862335fbe0fSMarek Lindner * @tt_len: expected tvlv tt data buffer length in number of bytes 28637ea7b4a1SAntonio Quartulli * @tvlv_buff: pointer to the buffer to fill with the TT data 2864335fbe0fSMarek Lindner * @valid_cb: function to filter tt change entries 2865335fbe0fSMarek Lindner * @cb_data: data passed to the filter function as argument 2866335fbe0fSMarek Lindner */ 28677ea7b4a1SAntonio Quartulli static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, 28687ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash, 28696b5e971aSSven Eckelmann void *tvlv_buff, u16 tt_len, 28704b426b10SSven Eckelmann bool (*valid_cb)(const void *, 28714b426b10SSven Eckelmann const void *), 2872a73105b8SAntonio Quartulli void *cb_data) 2873a73105b8SAntonio Quartulli { 287456303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 2875335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 2876a73105b8SAntonio Quartulli struct hlist_head *head; 28776b5e971aSSven Eckelmann u16 tt_tot, tt_num_entries = 0; 28786b5e971aSSven Eckelmann u32 i; 2879a73105b8SAntonio Quartulli 2880298e6e68SAntonio Quartulli tt_tot = batadv_tt_entries(tt_len); 28817ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; 2882a73105b8SAntonio Quartulli 2883a73105b8SAntonio Quartulli rcu_read_lock(); 2884a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2885a73105b8SAntonio Quartulli head = &hash->table[i]; 2886a73105b8SAntonio Quartulli 2887b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 2888a73105b8SAntonio Quartulli head, hash_entry) { 2889335fbe0fSMarek Lindner if (tt_tot == tt_num_entries) 2890a73105b8SAntonio Quartulli break; 2891a73105b8SAntonio Quartulli 289248100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 2893a73105b8SAntonio Quartulli continue; 2894a73105b8SAntonio Quartulli 28958fdd0153SAntonio Quartulli ether_addr_copy(tt_change->addr, tt_common_entry->addr); 289627b37ebfSAntonio Quartulli tt_change->flags = tt_common_entry->flags; 2897c018ad3dSAntonio Quartulli tt_change->vid = htons(tt_common_entry->vid); 2898ca663046SAntonio Quartulli memset(tt_change->reserved, 0, 2899ca663046SAntonio Quartulli sizeof(tt_change->reserved)); 2900a73105b8SAntonio Quartulli 2901335fbe0fSMarek Lindner tt_num_entries++; 2902a73105b8SAntonio Quartulli tt_change++; 2903a73105b8SAntonio Quartulli } 2904a73105b8SAntonio Quartulli } 2905a73105b8SAntonio Quartulli rcu_read_unlock(); 29067ea7b4a1SAntonio Quartulli } 2907a73105b8SAntonio Quartulli 29087ea7b4a1SAntonio Quartulli /** 29097ea7b4a1SAntonio Quartulli * batadv_tt_global_check_crc - check if all the CRCs are correct 29107ea7b4a1SAntonio Quartulli * @orig_node: originator for which the CRCs have to be checked 29117ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN entry 29127ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 29137ea7b4a1SAntonio Quartulli * 291462fe710fSSven Eckelmann * Return: true if all the received CRCs match the locally stored ones, false 29157ea7b4a1SAntonio Quartulli * otherwise 29167ea7b4a1SAntonio Quartulli */ 29177ea7b4a1SAntonio Quartulli static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, 29187ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 29196b5e971aSSven Eckelmann u16 num_vlan) 29207ea7b4a1SAntonio Quartulli { 29217ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; 29227ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 2923c169c59dSSimon Wunderlich int i, orig_num_vlan; 29246b5e971aSSven Eckelmann u32 crc; 29257ea7b4a1SAntonio Quartulli 29267ea7b4a1SAntonio Quartulli /* check if each received CRC matches the locally stored one */ 29277ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 29287ea7b4a1SAntonio Quartulli tt_vlan_tmp = tt_vlan + i; 29297ea7b4a1SAntonio Quartulli 29307ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't check 29317ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 29327ea7b4a1SAntonio Quartulli */ 29337ea7b4a1SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, 2934cfd4f757SAntonio Quartulli orig_node->orig, 2935cfd4f757SAntonio Quartulli ntohs(tt_vlan_tmp->vid))) 29367ea7b4a1SAntonio Quartulli continue; 29377ea7b4a1SAntonio Quartulli 29387ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_node, 29397ea7b4a1SAntonio Quartulli ntohs(tt_vlan_tmp->vid)); 29407ea7b4a1SAntonio Quartulli if (!vlan) 29417ea7b4a1SAntonio Quartulli return false; 29427ea7b4a1SAntonio Quartulli 294391c2b1a9SAntonio Quartulli crc = vlan->tt.crc; 294421754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 294591c2b1a9SAntonio Quartulli 294691c2b1a9SAntonio Quartulli if (crc != ntohl(tt_vlan_tmp->crc)) 29477ea7b4a1SAntonio Quartulli return false; 29487ea7b4a1SAntonio Quartulli } 29497ea7b4a1SAntonio Quartulli 2950c169c59dSSimon Wunderlich /* check if any excess VLANs exist locally for the originator 2951c169c59dSSimon Wunderlich * which are not mentioned in the TVLV from the originator. 2952c169c59dSSimon Wunderlich */ 2953c169c59dSSimon Wunderlich rcu_read_lock(); 2954c169c59dSSimon Wunderlich orig_num_vlan = 0; 2955c169c59dSSimon Wunderlich hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) 2956c169c59dSSimon Wunderlich orig_num_vlan++; 2957c169c59dSSimon Wunderlich rcu_read_unlock(); 2958c169c59dSSimon Wunderlich 2959c169c59dSSimon Wunderlich if (orig_num_vlan > num_vlan) 2960c169c59dSSimon Wunderlich return false; 2961c169c59dSSimon Wunderlich 29627ea7b4a1SAntonio Quartulli return true; 29637ea7b4a1SAntonio Quartulli } 29647ea7b4a1SAntonio Quartulli 29657ea7b4a1SAntonio Quartulli /** 29667ea7b4a1SAntonio Quartulli * batadv_tt_local_update_crc - update all the local CRCs 29677ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 29687ea7b4a1SAntonio Quartulli */ 29697ea7b4a1SAntonio Quartulli static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) 29707ea7b4a1SAntonio Quartulli { 29717ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 29727ea7b4a1SAntonio Quartulli 29737ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 29747ea7b4a1SAntonio Quartulli rcu_read_lock(); 29757ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 29767ea7b4a1SAntonio Quartulli vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); 29777ea7b4a1SAntonio Quartulli } 29787ea7b4a1SAntonio Quartulli rcu_read_unlock(); 29797ea7b4a1SAntonio Quartulli } 29807ea7b4a1SAntonio Quartulli 29817ea7b4a1SAntonio Quartulli /** 29827ea7b4a1SAntonio Quartulli * batadv_tt_global_update_crc - update all the global CRCs for this orig_node 29837ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 29847ea7b4a1SAntonio Quartulli * @orig_node: the orig_node for which the CRCs have to be updated 29857ea7b4a1SAntonio Quartulli */ 29867ea7b4a1SAntonio Quartulli static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, 29877ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node) 29887ea7b4a1SAntonio Quartulli { 29897ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 29906b5e971aSSven Eckelmann u32 crc; 29917ea7b4a1SAntonio Quartulli 29927ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 29937ea7b4a1SAntonio Quartulli rcu_read_lock(); 2994d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 29957ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't compute 29967ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 29977ea7b4a1SAntonio Quartulli */ 2998cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, 2999cfd4f757SAntonio Quartulli vlan->vid)) 30007ea7b4a1SAntonio Quartulli continue; 30017ea7b4a1SAntonio Quartulli 30027ea7b4a1SAntonio Quartulli crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); 30037ea7b4a1SAntonio Quartulli vlan->tt.crc = crc; 30047ea7b4a1SAntonio Quartulli } 30057ea7b4a1SAntonio Quartulli rcu_read_unlock(); 3006a73105b8SAntonio Quartulli } 3007a73105b8SAntonio Quartulli 3008ced72933SAntonio Quartulli /** 3009ced72933SAntonio Quartulli * batadv_send_tt_request - send a TT Request message to a given node 3010ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3011ced72933SAntonio Quartulli * @dst_orig_node: the destination of the message 3012ced72933SAntonio Quartulli * @ttvn: the version number that the source of the message is looking for 30137ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN object to request 30147ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 3015ced72933SAntonio Quartulli * @full_table: ask for the entire translation table if true, while only for the 3016ced72933SAntonio Quartulli * last TT diff otherwise 3017d15cd622SAntonio Quartulli * 3018d15cd622SAntonio Quartulli * Return: true if the TT Request was sent, false otherwise 3019ced72933SAntonio Quartulli */ 30204b426b10SSven Eckelmann static bool batadv_send_tt_request(struct batadv_priv *bat_priv, 302156303d34SSven Eckelmann struct batadv_orig_node *dst_orig_node, 30226b5e971aSSven Eckelmann u8 ttvn, 30237ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 30246b5e971aSSven Eckelmann u16 num_vlan, bool full_table) 3025a73105b8SAntonio Quartulli { 3026335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 302756303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node = NULL; 30287ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_req; 30297ea7b4a1SAntonio Quartulli struct batadv_hard_iface *primary_if; 3030335fbe0fSMarek Lindner bool ret = false; 30317ea7b4a1SAntonio Quartulli int i, size; 3032a73105b8SAntonio Quartulli 3033e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 3034a73105b8SAntonio Quartulli if (!primary_if) 3035a73105b8SAntonio Quartulli goto out; 3036a73105b8SAntonio Quartulli 3037a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 30389cfc7bd6SSven Eckelmann * reply from the same orig_node yet 30399cfc7bd6SSven Eckelmann */ 3040383b8636SMarek Lindner tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node); 3041a73105b8SAntonio Quartulli if (!tt_req_node) 3042a73105b8SAntonio Quartulli goto out; 3043a73105b8SAntonio Quartulli 30447ea7b4a1SAntonio Quartulli size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; 30457ea7b4a1SAntonio Quartulli tvlv_tt_data = kzalloc(size, GFP_ATOMIC); 3046335fbe0fSMarek Lindner if (!tvlv_tt_data) 3047a73105b8SAntonio Quartulli goto out; 3048a73105b8SAntonio Quartulli 3049335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_REQUEST; 3050335fbe0fSMarek Lindner tvlv_tt_data->ttvn = ttvn; 30517ea7b4a1SAntonio Quartulli tvlv_tt_data->num_vlan = htons(num_vlan); 30527ea7b4a1SAntonio Quartulli 30537ea7b4a1SAntonio Quartulli /* send all the CRCs within the request. This is needed by intermediate 30547ea7b4a1SAntonio Quartulli * nodes to ensure they have the correct table before replying 30557ea7b4a1SAntonio Quartulli */ 30567ea7b4a1SAntonio Quartulli tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); 30577ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 30587ea7b4a1SAntonio Quartulli tt_vlan_req->vid = tt_vlan->vid; 30597ea7b4a1SAntonio Quartulli tt_vlan_req->crc = tt_vlan->crc; 30607ea7b4a1SAntonio Quartulli 30617ea7b4a1SAntonio Quartulli tt_vlan_req++; 30627ea7b4a1SAntonio Quartulli tt_vlan++; 30637ea7b4a1SAntonio Quartulli } 3064a73105b8SAntonio Quartulli 3065a73105b8SAntonio Quartulli if (full_table) 3066335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 3067a73105b8SAntonio Quartulli 3068bb351ba0SMartin Hundebøll batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", 3069335fbe0fSMarek Lindner dst_orig_node->orig, full_table ? 'F' : '.'); 3070a73105b8SAntonio Quartulli 3071d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); 3072335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 3073335fbe0fSMarek Lindner dst_orig_node->orig, BATADV_TVLV_TT, 1, 30747ea7b4a1SAntonio Quartulli tvlv_tt_data, size); 3075335fbe0fSMarek Lindner ret = true; 3076a73105b8SAntonio Quartulli 3077a73105b8SAntonio Quartulli out: 3078a73105b8SAntonio Quartulli if (primary_if) 307982047ad7SSven Eckelmann batadv_hardif_put(primary_if); 30809c4604a2SSven Eckelmann 3081a73105b8SAntonio Quartulli if (ret && tt_req_node) { 3082807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 30839c4604a2SSven Eckelmann if (!hlist_unhashed(&tt_req_node->list)) { 30847c26a53bSMarek Lindner hlist_del_init(&tt_req_node->list); 30859c4604a2SSven Eckelmann batadv_tt_req_node_put(tt_req_node); 3086a73105b8SAntonio Quartulli } 30879c4604a2SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 30889c4604a2SSven Eckelmann } 30899c4604a2SSven Eckelmann 30909c4604a2SSven Eckelmann if (tt_req_node) 30919c4604a2SSven Eckelmann batadv_tt_req_node_put(tt_req_node); 30929c4604a2SSven Eckelmann 3093335fbe0fSMarek Lindner kfree(tvlv_tt_data); 3094a73105b8SAntonio Quartulli return ret; 3095a73105b8SAntonio Quartulli } 3096a73105b8SAntonio Quartulli 3097335fbe0fSMarek Lindner /** 3098335fbe0fSMarek Lindner * batadv_send_other_tt_response - send reply to tt request concerning another 3099335fbe0fSMarek Lindner * node's translation table 3100335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3101335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 3102335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 3103335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 3104335fbe0fSMarek Lindner * 310562fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 3106335fbe0fSMarek Lindner */ 3107335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, 3108335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 31096b5e971aSSven Eckelmann u8 *req_src, u8 *req_dst) 3110a73105b8SAntonio Quartulli { 3111170173bfSSven Eckelmann struct batadv_orig_node *req_dst_orig_node; 311256303d34SSven Eckelmann struct batadv_orig_node *res_dst_orig_node = NULL; 31137ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 3114335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 31157ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 3116335fbe0fSMarek Lindner bool ret = false, full_table; 31176b5e971aSSven Eckelmann u8 orig_ttvn, req_ttvn; 31186b5e971aSSven Eckelmann u16 tvlv_len; 31196b5e971aSSven Eckelmann s32 tt_len; 3120a73105b8SAntonio Quartulli 312139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 312286ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 3123335fbe0fSMarek Lindner req_src, tt_data->ttvn, req_dst, 3124a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 3125a73105b8SAntonio Quartulli 3126a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 3127335fbe0fSMarek Lindner req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); 3128a73105b8SAntonio Quartulli if (!req_dst_orig_node) 3129a73105b8SAntonio Quartulli goto out; 3130a73105b8SAntonio Quartulli 3131335fbe0fSMarek Lindner res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); 3132a73105b8SAntonio Quartulli if (!res_dst_orig_node) 3133a73105b8SAntonio Quartulli goto out; 3134a73105b8SAntonio Quartulli 31356b5e971aSSven Eckelmann orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn); 3136335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 3137a73105b8SAntonio Quartulli 31387ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 3139335fbe0fSMarek Lindner /* this node doesn't have the requested data */ 3140a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 31417ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, 31427ea7b4a1SAntonio Quartulli ntohs(tt_data->num_vlan))) 3143a73105b8SAntonio Quartulli goto out; 3144a73105b8SAntonio Quartulli 3145015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 3146335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || 3147a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 3148a73105b8SAntonio Quartulli full_table = true; 3149a73105b8SAntonio Quartulli else 3150a73105b8SAntonio Quartulli full_table = false; 3151a73105b8SAntonio Quartulli 3152335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 3153335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 31549cfc7bd6SSven Eckelmann */ 3155a73105b8SAntonio Quartulli if (!full_table) { 3156a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 3157a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 3158a73105b8SAntonio Quartulli 31597ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 31607ea7b4a1SAntonio Quartulli &tvlv_tt_data, 31617ea7b4a1SAntonio Quartulli &tt_change, 31627ea7b4a1SAntonio Quartulli &tt_len); 31637ea7b4a1SAntonio Quartulli if (!tt_len) 3164a73105b8SAntonio Quartulli goto unlock; 3165a73105b8SAntonio Quartulli 3166a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 31677ea7b4a1SAntonio Quartulli memcpy(tt_change, req_dst_orig_node->tt_buff, 3168a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 3169a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 3170a73105b8SAntonio Quartulli } else { 31717ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 31727ea7b4a1SAntonio Quartulli * in the initial part 31737ea7b4a1SAntonio Quartulli */ 31747ea7b4a1SAntonio Quartulli tt_len = -1; 31757ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 31767ea7b4a1SAntonio Quartulli &tvlv_tt_data, 31777ea7b4a1SAntonio Quartulli &tt_change, 31787ea7b4a1SAntonio Quartulli &tt_len); 31797ea7b4a1SAntonio Quartulli if (!tt_len) 31807ea7b4a1SAntonio Quartulli goto out; 3181a73105b8SAntonio Quartulli 31827ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 31837ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, 31847ea7b4a1SAntonio Quartulli tt_change, tt_len, 3185a513088dSSven Eckelmann batadv_tt_global_valid, 3186a73105b8SAntonio Quartulli req_dst_orig_node); 3187a73105b8SAntonio Quartulli } 3188a73105b8SAntonio Quartulli 3189a19d3d85SMarek Lindner /* Don't send the response, if larger than fragmented packet. */ 3190a19d3d85SMarek Lindner tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len; 3191a19d3d85SMarek Lindner if (tt_len > atomic_read(&bat_priv->packet_size_max)) { 3192a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, bat_priv->soft_iface, 3193a19d3d85SMarek Lindner "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n", 3194a19d3d85SMarek Lindner res_dst_orig_node->orig); 3195a19d3d85SMarek Lindner goto out; 3196a19d3d85SMarek Lindner } 3197a19d3d85SMarek Lindner 3198335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 3199335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 3200a73105b8SAntonio Quartulli 3201a73105b8SAntonio Quartulli if (full_table) 3202335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 3203a73105b8SAntonio Quartulli 320439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 3205335fbe0fSMarek Lindner "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n", 3206335fbe0fSMarek Lindner res_dst_orig_node->orig, req_dst_orig_node->orig, 3207335fbe0fSMarek Lindner full_table ? 'F' : '.', req_ttvn); 3208a73105b8SAntonio Quartulli 3209d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 3210f8214865SMartin Hundebøll 3211335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, 32127ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 32137ea7b4a1SAntonio Quartulli tvlv_len); 3214e91ecfc6SMartin Hundebøll 3215335fbe0fSMarek Lindner ret = true; 3216a73105b8SAntonio Quartulli goto out; 3217a73105b8SAntonio Quartulli 3218a73105b8SAntonio Quartulli unlock: 3219a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 3220a73105b8SAntonio Quartulli 3221a73105b8SAntonio Quartulli out: 3222a73105b8SAntonio Quartulli if (res_dst_orig_node) 32235d967310SSven Eckelmann batadv_orig_node_put(res_dst_orig_node); 3224a73105b8SAntonio Quartulli if (req_dst_orig_node) 32255d967310SSven Eckelmann batadv_orig_node_put(req_dst_orig_node); 3226335fbe0fSMarek Lindner kfree(tvlv_tt_data); 3227a73105b8SAntonio Quartulli return ret; 3228a73105b8SAntonio Quartulli } 322996412690SSven Eckelmann 3230335fbe0fSMarek Lindner /** 3231335fbe0fSMarek Lindner * batadv_send_my_tt_response - send reply to tt request concerning this node's 3232335fbe0fSMarek Lindner * translation table 3233335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3234335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 3235335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 3236335fbe0fSMarek Lindner * 323762fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 3238335fbe0fSMarek Lindner */ 3239335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, 3240335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 32416b5e971aSSven Eckelmann u8 *req_src) 3242a73105b8SAntonio Quartulli { 3243335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 324456303d34SSven Eckelmann struct batadv_hard_iface *primary_if = NULL; 32457ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 32467ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node; 32476b5e971aSSven Eckelmann u8 my_ttvn, req_ttvn; 32486b5e971aSSven Eckelmann u16 tvlv_len; 3249a73105b8SAntonio Quartulli bool full_table; 32506b5e971aSSven Eckelmann s32 tt_len; 3251a73105b8SAntonio Quartulli 325239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 325386ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 3254335fbe0fSMarek Lindner req_src, tt_data->ttvn, 3255a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 3256a73105b8SAntonio Quartulli 3257a70a9aa9SAntonio Quartulli spin_lock_bh(&bat_priv->tt.commit_lock); 3258a73105b8SAntonio Quartulli 32596b5e971aSSven Eckelmann my_ttvn = (u8)atomic_read(&bat_priv->tt.vn); 3260335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 3261a73105b8SAntonio Quartulli 3262335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, req_src); 3263a73105b8SAntonio Quartulli if (!orig_node) 3264a73105b8SAntonio Quartulli goto out; 3265a73105b8SAntonio Quartulli 3266e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 3267a73105b8SAntonio Quartulli if (!primary_if) 3268a73105b8SAntonio Quartulli goto out; 3269a73105b8SAntonio Quartulli 3270a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 32719cfc7bd6SSven Eckelmann * is too big send the whole local translation table 32729cfc7bd6SSven Eckelmann */ 3273335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || 3274807736f6SSven Eckelmann !bat_priv->tt.last_changeset) 3275a73105b8SAntonio Quartulli full_table = true; 3276a73105b8SAntonio Quartulli else 3277a73105b8SAntonio Quartulli full_table = false; 3278a73105b8SAntonio Quartulli 3279335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 3280335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 32819cfc7bd6SSven Eckelmann */ 3282a73105b8SAntonio Quartulli if (!full_table) { 3283807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 3284a73105b8SAntonio Quartulli 32857ea7b4a1SAntonio Quartulli tt_len = bat_priv->tt.last_changeset_len; 32867ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 32877ea7b4a1SAntonio Quartulli &tvlv_tt_data, 32887ea7b4a1SAntonio Quartulli &tt_change, 32897ea7b4a1SAntonio Quartulli &tt_len); 3290c2d0f48aSSven Eckelmann if (!tt_len || !tvlv_len) 3291a73105b8SAntonio Quartulli goto unlock; 3292a73105b8SAntonio Quartulli 3293335fbe0fSMarek Lindner /* Copy the last orig_node's OGM buffer */ 32947ea7b4a1SAntonio Quartulli memcpy(tt_change, bat_priv->tt.last_changeset, 3295807736f6SSven Eckelmann bat_priv->tt.last_changeset_len); 3296807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 3297a73105b8SAntonio Quartulli } else { 32986b5e971aSSven Eckelmann req_ttvn = (u8)atomic_read(&bat_priv->tt.vn); 3299a73105b8SAntonio Quartulli 33007ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 33017ea7b4a1SAntonio Quartulli * in the initial part 33027ea7b4a1SAntonio Quartulli */ 33037ea7b4a1SAntonio Quartulli tt_len = -1; 33047ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 33057ea7b4a1SAntonio Quartulli &tvlv_tt_data, 33067ea7b4a1SAntonio Quartulli &tt_change, 33077ea7b4a1SAntonio Quartulli &tt_len); 3308c2d0f48aSSven Eckelmann if (!tt_len || !tvlv_len) 3309a73105b8SAntonio Quartulli goto out; 33107ea7b4a1SAntonio Quartulli 33117ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 33127ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, 33137ea7b4a1SAntonio Quartulli tt_change, tt_len, 33147ea7b4a1SAntonio Quartulli batadv_tt_local_valid, NULL); 3315a73105b8SAntonio Quartulli } 3316a73105b8SAntonio Quartulli 3317335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 3318335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 3319a73105b8SAntonio Quartulli 3320a73105b8SAntonio Quartulli if (full_table) 3321335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 3322a73105b8SAntonio Quartulli 332339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 3324335fbe0fSMarek Lindner "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n", 3325335fbe0fSMarek Lindner orig_node->orig, full_table ? 'F' : '.', req_ttvn); 3326a73105b8SAntonio Quartulli 3327d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 3328f8214865SMartin Hundebøll 3329335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 33307ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 33317ea7b4a1SAntonio Quartulli tvlv_len); 3332335fbe0fSMarek Lindner 3333a73105b8SAntonio Quartulli goto out; 3334a73105b8SAntonio Quartulli 3335a73105b8SAntonio Quartulli unlock: 3336807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 3337a73105b8SAntonio Quartulli out: 3338a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 3339a73105b8SAntonio Quartulli if (orig_node) 33405d967310SSven Eckelmann batadv_orig_node_put(orig_node); 3341a73105b8SAntonio Quartulli if (primary_if) 334282047ad7SSven Eckelmann batadv_hardif_put(primary_if); 3343335fbe0fSMarek Lindner kfree(tvlv_tt_data); 3344335fbe0fSMarek Lindner /* The packet was for this host, so it doesn't need to be re-routed */ 3345a73105b8SAntonio Quartulli return true; 3346a73105b8SAntonio Quartulli } 3347a73105b8SAntonio Quartulli 3348335fbe0fSMarek Lindner /** 3349335fbe0fSMarek Lindner * batadv_send_tt_response - send reply to tt request 3350335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3351335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 3352335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 3353335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 3354335fbe0fSMarek Lindner * 335562fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 3356335fbe0fSMarek Lindner */ 3357335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv, 3358335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 33596b5e971aSSven Eckelmann u8 *req_src, u8 *req_dst) 3360a73105b8SAntonio Quartulli { 3361cfd4f757SAntonio Quartulli if (batadv_is_my_mac(bat_priv, req_dst)) 3362335fbe0fSMarek Lindner return batadv_send_my_tt_response(bat_priv, tt_data, req_src); 336324820df1SAntonio Quartulli return batadv_send_other_tt_response(bat_priv, tt_data, req_src, 336424820df1SAntonio Quartulli req_dst); 3365a73105b8SAntonio Quartulli } 3366a73105b8SAntonio Quartulli 336756303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, 336856303d34SSven Eckelmann struct batadv_orig_node *orig_node, 3369335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change, 33706b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn) 3371a73105b8SAntonio Quartulli { 3372a73105b8SAntonio Quartulli int i; 3373a513088dSSven Eckelmann int roams; 3374a73105b8SAntonio Quartulli 3375a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 3376acd34afaSSven Eckelmann if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { 3377acd34afaSSven Eckelmann roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; 3378a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 3379a73105b8SAntonio Quartulli (tt_change + i)->addr, 3380c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 3381cc47f66eSAntonio Quartulli "tt removed by changes", 3382a513088dSSven Eckelmann roams); 338308c36d3eSSven Eckelmann } else { 338408c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 3385d4f44692SAntonio Quartulli (tt_change + i)->addr, 3386c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 3387d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 3388a73105b8SAntonio Quartulli /* In case of problem while storing a 3389a73105b8SAntonio Quartulli * global_entry, we stop the updating 3390a73105b8SAntonio Quartulli * procedure without committing the 3391a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 3392a73105b8SAntonio Quartulli * corrupted data on tt_request 3393a73105b8SAntonio Quartulli */ 3394a73105b8SAntonio Quartulli return; 3395a73105b8SAntonio Quartulli } 339608c36d3eSSven Eckelmann } 3397ac4eebd4SLinus Lüssing set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); 3398a73105b8SAntonio Quartulli } 3399a73105b8SAntonio Quartulli 340056303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, 34017ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 34026b5e971aSSven Eckelmann u8 ttvn, u8 *resp_src, 34036b5e971aSSven Eckelmann u16 num_entries) 3404a73105b8SAntonio Quartulli { 3405170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 3406a73105b8SAntonio Quartulli 3407335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 3408a73105b8SAntonio Quartulli if (!orig_node) 3409a73105b8SAntonio Quartulli goto out; 3410a73105b8SAntonio Quartulli 3411a73105b8SAntonio Quartulli /* Purge the old table first.. */ 341295fb130dSAntonio Quartulli batadv_tt_global_del_orig(bat_priv, orig_node, -1, 341395fb130dSAntonio Quartulli "Received full table"); 3414a73105b8SAntonio Quartulli 34157ea7b4a1SAntonio Quartulli _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, 34167ea7b4a1SAntonio Quartulli ttvn); 3417a73105b8SAntonio Quartulli 3418a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 3419a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 3420a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 3421a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 3422a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 3423a73105b8SAntonio Quartulli 34247ea7b4a1SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 3425a73105b8SAntonio Quartulli 3426a73105b8SAntonio Quartulli out: 3427a73105b8SAntonio Quartulli if (orig_node) 34285d967310SSven Eckelmann batadv_orig_node_put(orig_node); 3429a73105b8SAntonio Quartulli } 3430a73105b8SAntonio Quartulli 343156303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv, 343256303d34SSven Eckelmann struct batadv_orig_node *orig_node, 34336b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn, 3434335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change) 3435a73105b8SAntonio Quartulli { 3436a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 3437a513088dSSven Eckelmann tt_num_changes, ttvn); 3438a73105b8SAntonio Quartulli 3439e8cf234aSAntonio Quartulli batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, 3440e8cf234aSAntonio Quartulli batadv_tt_len(tt_num_changes)); 3441a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 3442a73105b8SAntonio Quartulli } 3443a73105b8SAntonio Quartulli 3444c018ad3dSAntonio Quartulli /** 3445c018ad3dSAntonio Quartulli * batadv_is_my_client - check if a client is served by the local node 3446c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 34473f68785eSAntonio Quartulli * @addr: the mac address of the client to check 3448c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3449c018ad3dSAntonio Quartulli * 345062fe710fSSven Eckelmann * Return: true if the client is served by this node, false otherwise. 3451c018ad3dSAntonio Quartulli */ 34526b5e971aSSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr, 3453c018ad3dSAntonio Quartulli unsigned short vid) 3454a73105b8SAntonio Quartulli { 3455170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 34567683fdc1SAntonio Quartulli bool ret = false; 3457a73105b8SAntonio Quartulli 3458c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 34597683fdc1SAntonio Quartulli if (!tt_local_entry) 34607683fdc1SAntonio Quartulli goto out; 3461058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 34629cfc7bd6SSven Eckelmann * consistency purpose) 34639cfc7bd6SSven Eckelmann */ 34647c1fd91dSAntonio Quartulli if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) || 34657c1fd91dSAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM)) 3466058d0e26SAntonio Quartulli goto out; 34677683fdc1SAntonio Quartulli ret = true; 34687683fdc1SAntonio Quartulli out: 3469a73105b8SAntonio Quartulli if (tt_local_entry) 347095c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 34717683fdc1SAntonio Quartulli return ret; 3472a73105b8SAntonio Quartulli } 3473a73105b8SAntonio Quartulli 3474335fbe0fSMarek Lindner /** 3475335fbe0fSMarek Lindner * batadv_handle_tt_response - process incoming tt reply 3476335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3477335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 3478335fbe0fSMarek Lindner * @resp_src: mac address of tt reply sender 3479335fbe0fSMarek Lindner * @num_entries: number of tt change entries appended to the tt data 3480335fbe0fSMarek Lindner */ 3481335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv, 3482335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 34836b5e971aSSven Eckelmann u8 *resp_src, u16 num_entries) 3484a73105b8SAntonio Quartulli { 34857c26a53bSMarek Lindner struct batadv_tt_req_node *node; 34867c26a53bSMarek Lindner struct hlist_node *safe; 348756303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 3488335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 34896b5e971aSSven Eckelmann u8 *tvlv_ptr = (u8 *)tt_data; 34906b5e971aSSven Eckelmann u16 change_offset; 3491a73105b8SAntonio Quartulli 349239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 349386ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 3494335fbe0fSMarek Lindner resp_src, tt_data->ttvn, num_entries, 3495a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 3496a73105b8SAntonio Quartulli 3497335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 3498a73105b8SAntonio Quartulli if (!orig_node) 3499a73105b8SAntonio Quartulli goto out; 3500a73105b8SAntonio Quartulli 3501a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 3502a70a9aa9SAntonio Quartulli 35037ea7b4a1SAntonio Quartulli change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); 35047ea7b4a1SAntonio Quartulli change_offset *= ntohs(tt_data->num_vlan); 35057ea7b4a1SAntonio Quartulli change_offset += sizeof(*tt_data); 35067ea7b4a1SAntonio Quartulli tvlv_ptr += change_offset; 35077ea7b4a1SAntonio Quartulli 35087ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; 3509335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) { 35107ea7b4a1SAntonio Quartulli batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, 35117ea7b4a1SAntonio Quartulli resp_src, num_entries); 351296412690SSven Eckelmann } else { 3513335fbe0fSMarek Lindner batadv_tt_update_changes(bat_priv, orig_node, num_entries, 3514335fbe0fSMarek Lindner tt_data->ttvn, tt_change); 351596412690SSven Eckelmann } 3516a73105b8SAntonio Quartulli 3517a70a9aa9SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 35187ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3519a70a9aa9SAntonio Quartulli 3520a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3521a70a9aa9SAntonio Quartulli 3522a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 3523807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 35247c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 3525335fbe0fSMarek Lindner if (!batadv_compare_eth(node->addr, resp_src)) 3526a73105b8SAntonio Quartulli continue; 35277c26a53bSMarek Lindner hlist_del_init(&node->list); 35289c4604a2SSven Eckelmann batadv_tt_req_node_put(node); 3529a73105b8SAntonio Quartulli } 35307ea7b4a1SAntonio Quartulli 3531807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 3532a73105b8SAntonio Quartulli out: 3533a73105b8SAntonio Quartulli if (orig_node) 35345d967310SSven Eckelmann batadv_orig_node_put(orig_node); 3535a73105b8SAntonio Quartulli } 3536a73105b8SAntonio Quartulli 353756303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) 3538a73105b8SAntonio Quartulli { 353956303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 3540a73105b8SAntonio Quartulli 3541807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3542a73105b8SAntonio Quartulli 3543807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 3544cc47f66eSAntonio Quartulli list_del(&node->list); 354586452f81SSven Eckelmann kmem_cache_free(batadv_tt_roam_cache, node); 3546cc47f66eSAntonio Quartulli } 3547cc47f66eSAntonio Quartulli 3548807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3549cc47f66eSAntonio Quartulli } 3550cc47f66eSAntonio Quartulli 355156303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) 3552cc47f66eSAntonio Quartulli { 355356303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 3554cc47f66eSAntonio Quartulli 3555807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3556807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 355742d0b044SSven Eckelmann if (!batadv_has_timed_out(node->first_time, 355842d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 3559cc47f66eSAntonio Quartulli continue; 3560cc47f66eSAntonio Quartulli 3561cc47f66eSAntonio Quartulli list_del(&node->list); 356286452f81SSven Eckelmann kmem_cache_free(batadv_tt_roam_cache, node); 3563cc47f66eSAntonio Quartulli } 3564807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3565cc47f66eSAntonio Quartulli } 3566cc47f66eSAntonio Quartulli 356762fe710fSSven Eckelmann /** 3568d15cd622SAntonio Quartulli * batadv_tt_check_roam_count - check if a client has roamed too frequently 3569d15cd622SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3570d15cd622SAntonio Quartulli * @client: mac address of the roaming client 357162fe710fSSven Eckelmann * 357262fe710fSSven Eckelmann * This function checks whether the client already reached the 3573cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 3574cc47f66eSAntonio Quartulli * will not be sent. 3575cc47f66eSAntonio Quartulli * 357662fe710fSSven Eckelmann * Return: true if the ROAMING_ADV can be sent, false otherwise 35779cfc7bd6SSven Eckelmann */ 35786b5e971aSSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client) 3579cc47f66eSAntonio Quartulli { 358056303d34SSven Eckelmann struct batadv_tt_roam_node *tt_roam_node; 3581cc47f66eSAntonio Quartulli bool ret = false; 3582cc47f66eSAntonio Quartulli 3583807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3584cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 35859cfc7bd6SSven Eckelmann * reply from the same orig_node yet 35869cfc7bd6SSven Eckelmann */ 3587807736f6SSven Eckelmann list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) { 35881eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 3589cc47f66eSAntonio Quartulli continue; 3590cc47f66eSAntonio Quartulli 35911eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 359242d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 3593cc47f66eSAntonio Quartulli continue; 3594cc47f66eSAntonio Quartulli 35953e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 3596cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 3597cc47f66eSAntonio Quartulli goto unlock; 3598cc47f66eSAntonio Quartulli ret = true; 3599cc47f66eSAntonio Quartulli break; 3600cc47f66eSAntonio Quartulli } 3601cc47f66eSAntonio Quartulli 3602cc47f66eSAntonio Quartulli if (!ret) { 360386452f81SSven Eckelmann tt_roam_node = kmem_cache_alloc(batadv_tt_roam_cache, 360486452f81SSven Eckelmann GFP_ATOMIC); 3605cc47f66eSAntonio Quartulli if (!tt_roam_node) 3606cc47f66eSAntonio Quartulli goto unlock; 3607cc47f66eSAntonio Quartulli 3608cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 360942d0b044SSven Eckelmann atomic_set(&tt_roam_node->counter, 361042d0b044SSven Eckelmann BATADV_ROAMING_MAX_COUNT - 1); 36118fdd0153SAntonio Quartulli ether_addr_copy(tt_roam_node->addr, client); 3612cc47f66eSAntonio Quartulli 3613807736f6SSven Eckelmann list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); 3614cc47f66eSAntonio Quartulli ret = true; 3615cc47f66eSAntonio Quartulli } 3616cc47f66eSAntonio Quartulli 3617cc47f66eSAntonio Quartulli unlock: 3618807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3619cc47f66eSAntonio Quartulli return ret; 3620cc47f66eSAntonio Quartulli } 3621cc47f66eSAntonio Quartulli 3622c018ad3dSAntonio Quartulli /** 3623c018ad3dSAntonio Quartulli * batadv_send_roam_adv - send a roaming advertisement message 3624c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3625c018ad3dSAntonio Quartulli * @client: mac address of the roaming client 3626c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3627c018ad3dSAntonio Quartulli * @orig_node: message destination 3628c018ad3dSAntonio Quartulli * 3629c018ad3dSAntonio Quartulli * Send a ROAMING_ADV message to the node which was previously serving this 3630c018ad3dSAntonio Quartulli * client. This is done to inform the node that from now on all traffic destined 3631c018ad3dSAntonio Quartulli * for this particular roamed client has to be forwarded to the sender of the 3632c018ad3dSAntonio Quartulli * roaming message. 3633c018ad3dSAntonio Quartulli */ 36346b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, 3635c018ad3dSAntonio Quartulli unsigned short vid, 363656303d34SSven Eckelmann struct batadv_orig_node *orig_node) 3637cc47f66eSAntonio Quartulli { 363856303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 3639122edaa0SMarek Lindner struct batadv_tvlv_roam_adv tvlv_roam; 3640122edaa0SMarek Lindner 3641122edaa0SMarek Lindner primary_if = batadv_primary_if_get_selected(bat_priv); 3642122edaa0SMarek Lindner if (!primary_if) 3643122edaa0SMarek Lindner goto out; 3644cc47f66eSAntonio Quartulli 3645cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 36469cfc7bd6SSven Eckelmann * already roamed to us too many times 36479cfc7bd6SSven Eckelmann */ 3648a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 3649cc47f66eSAntonio Quartulli goto out; 3650cc47f66eSAntonio Quartulli 365139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 365216052789SAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n", 3653f7a2bd65SSven Eckelmann orig_node->orig, client, batadv_print_vid(vid)); 3654cc47f66eSAntonio Quartulli 3655d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); 3656f8214865SMartin Hundebøll 3657122edaa0SMarek Lindner memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); 3658c018ad3dSAntonio Quartulli tvlv_roam.vid = htons(vid); 3659122edaa0SMarek Lindner 3660122edaa0SMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 3661122edaa0SMarek Lindner orig_node->orig, BATADV_TVLV_ROAM, 1, 3662122edaa0SMarek Lindner &tvlv_roam, sizeof(tvlv_roam)); 3663cc47f66eSAntonio Quartulli 3664cc47f66eSAntonio Quartulli out: 3665122edaa0SMarek Lindner if (primary_if) 366682047ad7SSven Eckelmann batadv_hardif_put(primary_if); 3667a73105b8SAntonio Quartulli } 3668a73105b8SAntonio Quartulli 3669a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 3670a73105b8SAntonio Quartulli { 367156303d34SSven Eckelmann struct delayed_work *delayed_work; 3672807736f6SSven Eckelmann struct batadv_priv_tt *priv_tt; 367356303d34SSven Eckelmann struct batadv_priv *bat_priv; 367456303d34SSven Eckelmann 36754ba4bc0fSGeliang Tang delayed_work = to_delayed_work(work); 3676807736f6SSven Eckelmann priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 3677807736f6SSven Eckelmann bat_priv = container_of(priv_tt, struct batadv_priv, tt); 3678a73105b8SAntonio Quartulli 3679a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT); 368030cfd02bSAntonio Quartulli batadv_tt_global_purge(bat_priv); 3681a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 3682a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 3683a73105b8SAntonio Quartulli 368472414442SAntonio Quartulli queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 368572414442SAntonio Quartulli msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3686a73105b8SAntonio Quartulli } 3687cc47f66eSAntonio Quartulli 368856303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv) 3689cc47f66eSAntonio Quartulli { 3690e1bf0c14SMarek Lindner batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); 3691e1bf0c14SMarek Lindner batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); 3692e1bf0c14SMarek Lindner 3693807736f6SSven Eckelmann cancel_delayed_work_sync(&bat_priv->tt.work); 3694cc47f66eSAntonio Quartulli 3695a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 3696a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 3697a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 3698a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 3699a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 3700cc47f66eSAntonio Quartulli 3701807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 3702cc47f66eSAntonio Quartulli } 3703058d0e26SAntonio Quartulli 37047ea7b4a1SAntonio Quartulli /** 37057ea7b4a1SAntonio Quartulli * batadv_tt_local_set_flags - set or unset the specified flags on the local 37067ea7b4a1SAntonio Quartulli * table and possibly count them in the TT size 37077ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 37087ea7b4a1SAntonio Quartulli * @flags: the flag to switch 37097ea7b4a1SAntonio Quartulli * @enable: whether to set or unset the flag 37107ea7b4a1SAntonio Quartulli * @count: whether to increase the TT size by the number of changed entries 37119cfc7bd6SSven Eckelmann */ 37126b5e971aSSven Eckelmann static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags, 37136b5e971aSSven Eckelmann bool enable, bool count) 3714058d0e26SAntonio Quartulli { 37157ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash = bat_priv->tt.local_hash; 37167ea7b4a1SAntonio Quartulli struct batadv_tt_common_entry *tt_common_entry; 3717058d0e26SAntonio Quartulli struct hlist_head *head; 37186b5e971aSSven Eckelmann u32 i; 3719058d0e26SAntonio Quartulli 3720058d0e26SAntonio Quartulli if (!hash) 37217ea7b4a1SAntonio Quartulli return; 3722058d0e26SAntonio Quartulli 3723058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3724058d0e26SAntonio Quartulli head = &hash->table[i]; 3725058d0e26SAntonio Quartulli 3726058d0e26SAntonio Quartulli rcu_read_lock(); 3727b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 3728058d0e26SAntonio Quartulli head, hash_entry) { 3729697f2531SAntonio Quartulli if (enable) { 3730697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 3731697f2531SAntonio Quartulli continue; 3732697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 3733697f2531SAntonio Quartulli } else { 373448100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 373531901264SAntonio Quartulli continue; 373648100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 3737697f2531SAntonio Quartulli } 37387ea7b4a1SAntonio Quartulli 37397ea7b4a1SAntonio Quartulli if (!count) 37407ea7b4a1SAntonio Quartulli continue; 37417ea7b4a1SAntonio Quartulli 37427ea7b4a1SAntonio Quartulli batadv_tt_local_size_inc(bat_priv, 37437ea7b4a1SAntonio Quartulli tt_common_entry->vid); 3744058d0e26SAntonio Quartulli } 3745058d0e26SAntonio Quartulli rcu_read_unlock(); 3746058d0e26SAntonio Quartulli } 3747058d0e26SAntonio Quartulli } 3748058d0e26SAntonio Quartulli 3749acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ 375056303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) 3751058d0e26SAntonio Quartulli { 3752807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 375356303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 375456303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 3755b67bfe0dSSasha Levin struct hlist_node *node_tmp; 3756058d0e26SAntonio Quartulli struct hlist_head *head; 3757058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 37586b5e971aSSven Eckelmann u32 i; 3759058d0e26SAntonio Quartulli 3760058d0e26SAntonio Quartulli if (!hash) 3761058d0e26SAntonio Quartulli return; 3762058d0e26SAntonio Quartulli 3763058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3764058d0e26SAntonio Quartulli head = &hash->table[i]; 3765058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 3766058d0e26SAntonio Quartulli 3767058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 3768b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 3769acd34afaSSven Eckelmann hash_entry) { 3770acd34afaSSven Eckelmann if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) 3771058d0e26SAntonio Quartulli continue; 3772058d0e26SAntonio Quartulli 377339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 377416052789SAntonio Quartulli "Deleting local tt entry (%pM, vid: %d): pending\n", 377516052789SAntonio Quartulli tt_common->addr, 3776f7a2bd65SSven Eckelmann batadv_print_vid(tt_common->vid)); 3777058d0e26SAntonio Quartulli 37787ea7b4a1SAntonio Quartulli batadv_tt_local_size_dec(bat_priv, tt_common->vid); 3779b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 378056303d34SSven Eckelmann tt_local = container_of(tt_common, 378156303d34SSven Eckelmann struct batadv_tt_local_entry, 378248100bacSAntonio Quartulli common); 378335df3b29SAntonio Quartulli 378495c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local); 3785058d0e26SAntonio Quartulli } 3786058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 3787058d0e26SAntonio Quartulli } 3788058d0e26SAntonio Quartulli } 3789058d0e26SAntonio Quartulli 3790e1bf0c14SMarek Lindner /** 3791a19d3d85SMarek Lindner * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes 3792a19d3d85SMarek Lindner * which have been queued in the time since the last commit 3793e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3794a19d3d85SMarek Lindner * 3795a19d3d85SMarek Lindner * Caller must hold tt->commit_lock. 3796e1bf0c14SMarek Lindner */ 3797a19d3d85SMarek Lindner static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) 3798058d0e26SAntonio Quartulli { 37995274cd68SSven Eckelmann lockdep_assert_held(&bat_priv->tt.commit_lock); 38005274cd68SSven Eckelmann 3801e1bf0c14SMarek Lindner if (atomic_read(&bat_priv->tt.local_changes) < 1) { 3802e1bf0c14SMarek Lindner if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 3803e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3804a19d3d85SMarek Lindner return; 3805e1bf0c14SMarek Lindner } 3806be9aa4c1SMarek Lindner 38077ea7b4a1SAntonio Quartulli batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); 3808be9aa4c1SMarek Lindner 3809a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 38107ea7b4a1SAntonio Quartulli batadv_tt_local_update_crc(bat_priv); 3811058d0e26SAntonio Quartulli 3812058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 3813807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.vn); 381439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 38151eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 38166b5e971aSSven Eckelmann (u8)atomic_read(&bat_priv->tt.vn)); 3817be9aa4c1SMarek Lindner 3818be9aa4c1SMarek Lindner /* reset the sending counter */ 3819807736f6SSven Eckelmann atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 3820e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3821a19d3d85SMarek Lindner } 3822a70a9aa9SAntonio Quartulli 3823a19d3d85SMarek Lindner /** 3824a19d3d85SMarek Lindner * batadv_tt_local_commit_changes - commit all pending local tt changes which 3825a19d3d85SMarek Lindner * have been queued in the time since the last commit 3826a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3827a19d3d85SMarek Lindner */ 3828a19d3d85SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) 3829a19d3d85SMarek Lindner { 3830a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3831a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3832a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 3833058d0e26SAntonio Quartulli } 383459b699cdSAntonio Quartulli 38356b5e971aSSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, 38366b5e971aSSven Eckelmann unsigned short vid) 383759b699cdSAntonio Quartulli { 3838393b299dSMarkus Elfring struct batadv_tt_local_entry *tt_local_entry; 3839393b299dSMarkus Elfring struct batadv_tt_global_entry *tt_global_entry; 3840b8cbd81dSAntonio Quartulli struct batadv_softif_vlan *vlan; 38415870adc6SMarek Lindner bool ret = false; 384259b699cdSAntonio Quartulli 3843b8cbd81dSAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 3844e087f34fSMarkus Elfring if (!vlan) 3845e087f34fSMarkus Elfring return false; 3846e087f34fSMarkus Elfring 3847e087f34fSMarkus Elfring if (!atomic_read(&vlan->ap_isolation)) 3848393b299dSMarkus Elfring goto vlan_put; 384959b699cdSAntonio Quartulli 3850b8cbd81dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); 385159b699cdSAntonio Quartulli if (!tt_local_entry) 3852393b299dSMarkus Elfring goto vlan_put; 385359b699cdSAntonio Quartulli 3854b8cbd81dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); 385559b699cdSAntonio Quartulli if (!tt_global_entry) 3856393b299dSMarkus Elfring goto local_entry_put; 385759b699cdSAntonio Quartulli 3858393b299dSMarkus Elfring if (_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 38595870adc6SMarek Lindner ret = true; 386059b699cdSAntonio Quartulli 38615dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 3862393b299dSMarkus Elfring local_entry_put: 386395c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 3864393b299dSMarkus Elfring vlan_put: 3865393b299dSMarkus Elfring batadv_softif_vlan_put(vlan); 386659b699cdSAntonio Quartulli return ret; 386759b699cdSAntonio Quartulli } 3868a943cac1SMarek Lindner 3869e1bf0c14SMarek Lindner /** 3870e1bf0c14SMarek Lindner * batadv_tt_update_orig - update global translation table with new tt 3871e1bf0c14SMarek Lindner * information received via ogms 3872e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3873e51f0397SSven Eckelmann * @orig_node: the orig_node of the ogm 3874e51f0397SSven Eckelmann * @tt_buff: pointer to the first tvlv VLAN entry 38757ea7b4a1SAntonio Quartulli * @tt_num_vlan: number of tvlv VLAN entries 38767ea7b4a1SAntonio Quartulli * @tt_change: pointer to the first entry in the TT buffer 3877e1bf0c14SMarek Lindner * @tt_num_changes: number of tt changes inside the tt buffer 3878e1bf0c14SMarek Lindner * @ttvn: translation table version number of this changeset 3879e1bf0c14SMarek Lindner */ 3880e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv, 388156303d34SSven Eckelmann struct batadv_orig_node *orig_node, 38826b5e971aSSven Eckelmann const void *tt_buff, u16 tt_num_vlan, 38837ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 38846b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn) 3885a943cac1SMarek Lindner { 38866b5e971aSSven Eckelmann u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); 38877ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 3888a943cac1SMarek Lindner bool full_table = true; 3889e17931d1SLinus Lüssing bool has_tt_init; 3890a943cac1SMarek Lindner 38917ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; 3892ac4eebd4SLinus Lüssing has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT, 3893ac4eebd4SLinus Lüssing &orig_node->capa_initialized); 3894e17931d1SLinus Lüssing 389517071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 38969cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 38979cfc7bd6SSven Eckelmann */ 3898e17931d1SLinus Lüssing if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) { 3899a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 390042d0b044SSven Eckelmann * because they have already been sent BATADV_TT_OGM_APPEND_MAX 390142d0b044SSven Eckelmann * times. 39029cfc7bd6SSven Eckelmann * In this case send a tt request 39039cfc7bd6SSven Eckelmann */ 3904a943cac1SMarek Lindner if (!tt_num_changes) { 3905a943cac1SMarek Lindner full_table = false; 3906a943cac1SMarek Lindner goto request_table; 3907a943cac1SMarek Lindner } 3908a943cac1SMarek Lindner 3909a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 3910a70a9aa9SAntonio Quartulli 3911a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 391296412690SSven Eckelmann ttvn, tt_change); 3913a943cac1SMarek Lindner 3914a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 3915a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 39169cfc7bd6SSven Eckelmann * in the global table 39179cfc7bd6SSven Eckelmann */ 39187ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3919a943cac1SMarek Lindner 3920a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3921a70a9aa9SAntonio Quartulli 3922a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 3923a943cac1SMarek Lindner * because a single value could represent different states 3924a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 3925a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 3926a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 3927a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 3928a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 39299cfc7bd6SSven Eckelmann * inconsistency 39309cfc7bd6SSven Eckelmann */ 39317ea7b4a1SAntonio Quartulli if (!batadv_tt_global_check_crc(orig_node, tt_vlan, 39327ea7b4a1SAntonio Quartulli tt_num_vlan)) 3933a943cac1SMarek Lindner goto request_table; 3934a943cac1SMarek Lindner } else { 3935a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 39369cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 39379cfc7bd6SSven Eckelmann */ 3938e17931d1SLinus Lüssing if (!has_tt_init || ttvn != orig_ttvn || 39397ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(orig_node, tt_vlan, 39407ea7b4a1SAntonio Quartulli tt_num_vlan)) { 3941a943cac1SMarek Lindner request_table: 394239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 39437ea7b4a1SAntonio Quartulli "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n", 39447ea7b4a1SAntonio Quartulli orig_node->orig, ttvn, orig_ttvn, 39457ea7b4a1SAntonio Quartulli tt_num_changes); 3946a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 39477ea7b4a1SAntonio Quartulli tt_vlan, tt_num_vlan, 39487ea7b4a1SAntonio Quartulli full_table); 3949a943cac1SMarek Lindner return; 3950a943cac1SMarek Lindner } 3951a943cac1SMarek Lindner } 3952a943cac1SMarek Lindner } 39533275e7ccSAntonio Quartulli 3954c018ad3dSAntonio Quartulli /** 3955c018ad3dSAntonio Quartulli * batadv_tt_global_client_is_roaming - check if a client is marked as roaming 3956c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3957c018ad3dSAntonio Quartulli * @addr: the mac address of the client to check 3958c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3959c018ad3dSAntonio Quartulli * 396062fe710fSSven Eckelmann * Return: true if we know that the client has moved from its old originator 3961c018ad3dSAntonio Quartulli * to another one. This entry is still kept for consistency purposes and will be 3962c018ad3dSAntonio Quartulli * deleted later by a DEL or because of timeout 39633275e7ccSAntonio Quartulli */ 396456303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, 39656b5e971aSSven Eckelmann u8 *addr, unsigned short vid) 39663275e7ccSAntonio Quartulli { 396756303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 39683275e7ccSAntonio Quartulli bool ret = false; 39693275e7ccSAntonio Quartulli 3970c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 39713275e7ccSAntonio Quartulli if (!tt_global_entry) 39723275e7ccSAntonio Quartulli goto out; 39733275e7ccSAntonio Quartulli 3974c1d07431SAntonio Quartulli ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; 39755dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 39763275e7ccSAntonio Quartulli out: 39773275e7ccSAntonio Quartulli return ret; 39783275e7ccSAntonio Quartulli } 397930cfd02bSAntonio Quartulli 39807c1fd91dSAntonio Quartulli /** 39817c1fd91dSAntonio Quartulli * batadv_tt_local_client_is_roaming - tells whether the client is roaming 39827c1fd91dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3983c018ad3dSAntonio Quartulli * @addr: the mac address of the local client to query 3984c018ad3dSAntonio Quartulli * @vid: VLAN identifier 39857c1fd91dSAntonio Quartulli * 398662fe710fSSven Eckelmann * Return: true if the local client is known to be roaming (it is not served by 39877c1fd91dSAntonio Quartulli * this node anymore) or not. If yes, the client is still present in the table 39887c1fd91dSAntonio Quartulli * to keep the latter consistent with the node TTVN 39897c1fd91dSAntonio Quartulli */ 39907c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, 39916b5e971aSSven Eckelmann u8 *addr, unsigned short vid) 39927c1fd91dSAntonio Quartulli { 39937c1fd91dSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry; 39947c1fd91dSAntonio Quartulli bool ret = false; 39957c1fd91dSAntonio Quartulli 3996c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 39977c1fd91dSAntonio Quartulli if (!tt_local_entry) 39987c1fd91dSAntonio Quartulli goto out; 39997c1fd91dSAntonio Quartulli 40007c1fd91dSAntonio Quartulli ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; 400195c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 40027c1fd91dSAntonio Quartulli out: 40037c1fd91dSAntonio Quartulli return ret; 40047c1fd91dSAntonio Quartulli } 40057c1fd91dSAntonio Quartulli 400630cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, 400730cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 4008c018ad3dSAntonio Quartulli const unsigned char *addr, 400916052789SAntonio Quartulli unsigned short vid) 401030cfd02bSAntonio Quartulli { 40111227c9aeSSimon Wunderlich /* ignore loop detect macs, they are not supposed to be in the tt local 40121227c9aeSSimon Wunderlich * data as well. 40131227c9aeSSimon Wunderlich */ 40141227c9aeSSimon Wunderlich if (batadv_bla_is_loopdetect_mac(addr)) 40151227c9aeSSimon Wunderlich return false; 40161227c9aeSSimon Wunderlich 401716052789SAntonio Quartulli if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, 401830cfd02bSAntonio Quartulli BATADV_TT_CLIENT_TEMP, 401930cfd02bSAntonio Quartulli atomic_read(&orig_node->last_ttvn))) 402075ae84a4SSimon Wunderlich return false; 402130cfd02bSAntonio Quartulli 402230cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 402316052789SAntonio Quartulli "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n", 4024f7a2bd65SSven Eckelmann addr, batadv_print_vid(vid), orig_node->orig); 402575ae84a4SSimon Wunderlich 402675ae84a4SSimon Wunderlich return true; 402730cfd02bSAntonio Quartulli } 4028e1bf0c14SMarek Lindner 4029e1bf0c14SMarek Lindner /** 4030a19d3d85SMarek Lindner * batadv_tt_local_resize_to_mtu - resize the local translation table fit the 4031a19d3d85SMarek Lindner * maximum packet size that can be transported through the mesh 4032a19d3d85SMarek Lindner * @soft_iface: netdev struct of the mesh interface 4033a19d3d85SMarek Lindner * 4034a19d3d85SMarek Lindner * Remove entries older than 'timeout' and half timeout if more entries need 4035a19d3d85SMarek Lindner * to be removed. 4036a19d3d85SMarek Lindner */ 4037a19d3d85SMarek Lindner void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface) 4038a19d3d85SMarek Lindner { 4039a19d3d85SMarek Lindner struct batadv_priv *bat_priv = netdev_priv(soft_iface); 4040a19d3d85SMarek Lindner int packet_size_max = atomic_read(&bat_priv->packet_size_max); 4041a19d3d85SMarek Lindner int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; 4042a19d3d85SMarek Lindner bool reduced = false; 4043a19d3d85SMarek Lindner 4044a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 4045a19d3d85SMarek Lindner 4046a19d3d85SMarek Lindner while (true) { 4047a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 4048a19d3d85SMarek Lindner if (packet_size_max >= table_size) 4049a19d3d85SMarek Lindner break; 4050a19d3d85SMarek Lindner 4051a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, timeout); 4052a19d3d85SMarek Lindner batadv_tt_local_purge_pending_clients(bat_priv); 4053a19d3d85SMarek Lindner 4054a19d3d85SMarek Lindner timeout /= 2; 4055a19d3d85SMarek Lindner reduced = true; 4056a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 4057a19d3d85SMarek Lindner "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n", 4058a19d3d85SMarek Lindner packet_size_max); 4059a19d3d85SMarek Lindner } 4060a19d3d85SMarek Lindner 4061a19d3d85SMarek Lindner /* commit these changes immediately, to avoid synchronization problem 4062a19d3d85SMarek Lindner * with the TTVN 4063a19d3d85SMarek Lindner */ 4064a19d3d85SMarek Lindner if (reduced) 4065a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 4066a19d3d85SMarek Lindner 4067a19d3d85SMarek Lindner spin_unlock_bh(&bat_priv->tt.commit_lock); 4068a19d3d85SMarek Lindner } 4069a19d3d85SMarek Lindner 4070a19d3d85SMarek Lindner /** 4071e1bf0c14SMarek Lindner * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container 4072e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 4073e1bf0c14SMarek Lindner * @orig: the orig_node of the ogm 4074e1bf0c14SMarek Lindner * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 4075e1bf0c14SMarek Lindner * @tvlv_value: tvlv buffer containing the gateway data 4076e1bf0c14SMarek Lindner * @tvlv_value_len: tvlv buffer length 4077e1bf0c14SMarek Lindner */ 4078e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 4079e1bf0c14SMarek Lindner struct batadv_orig_node *orig, 40806b5e971aSSven Eckelmann u8 flags, void *tvlv_value, 40816b5e971aSSven Eckelmann u16 tvlv_value_len) 4082e1bf0c14SMarek Lindner { 40837ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 40847ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 4085e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 40866b5e971aSSven Eckelmann u16 num_entries, num_vlan; 4087e1bf0c14SMarek Lindner 4088e1bf0c14SMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 4089e1bf0c14SMarek Lindner return; 4090e1bf0c14SMarek Lindner 4091e1bf0c14SMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 4092e1bf0c14SMarek Lindner tvlv_value_len -= sizeof(*tt_data); 4093e1bf0c14SMarek Lindner 40947ea7b4a1SAntonio Quartulli num_vlan = ntohs(tt_data->num_vlan); 40957ea7b4a1SAntonio Quartulli 40967ea7b4a1SAntonio Quartulli if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) 40977ea7b4a1SAntonio Quartulli return; 40987ea7b4a1SAntonio Quartulli 40997ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 41007ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); 41017ea7b4a1SAntonio Quartulli tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; 41027ea7b4a1SAntonio Quartulli 4103298e6e68SAntonio Quartulli num_entries = batadv_tt_entries(tvlv_value_len); 4104e1bf0c14SMarek Lindner 41057ea7b4a1SAntonio Quartulli batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, 41067ea7b4a1SAntonio Quartulli num_entries, tt_data->ttvn); 4107e1bf0c14SMarek Lindner } 4108e1bf0c14SMarek Lindner 4109e1bf0c14SMarek Lindner /** 4110335fbe0fSMarek Lindner * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv 4111335fbe0fSMarek Lindner * container 4112335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 4113335fbe0fSMarek Lindner * @src: mac address of tt tvlv sender 4114335fbe0fSMarek Lindner * @dst: mac address of tt tvlv recipient 4115335fbe0fSMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 4116335fbe0fSMarek Lindner * @tvlv_value_len: tvlv buffer length 4117335fbe0fSMarek Lindner * 411862fe710fSSven Eckelmann * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS 4119335fbe0fSMarek Lindner * otherwise. 4120335fbe0fSMarek Lindner */ 4121335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 41226b5e971aSSven Eckelmann u8 *src, u8 *dst, 4123335fbe0fSMarek Lindner void *tvlv_value, 41246b5e971aSSven Eckelmann u16 tvlv_value_len) 4125335fbe0fSMarek Lindner { 4126335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data; 41276b5e971aSSven Eckelmann u16 tt_vlan_len, tt_num_entries; 4128335fbe0fSMarek Lindner char tt_flag; 4129335fbe0fSMarek Lindner bool ret; 4130335fbe0fSMarek Lindner 4131335fbe0fSMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 4132335fbe0fSMarek Lindner return NET_RX_SUCCESS; 4133335fbe0fSMarek Lindner 4134335fbe0fSMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 4135335fbe0fSMarek Lindner tvlv_value_len -= sizeof(*tt_data); 4136335fbe0fSMarek Lindner 41377ea7b4a1SAntonio Quartulli tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); 41387ea7b4a1SAntonio Quartulli tt_vlan_len *= ntohs(tt_data->num_vlan); 41397ea7b4a1SAntonio Quartulli 41407ea7b4a1SAntonio Quartulli if (tvlv_value_len < tt_vlan_len) 41417ea7b4a1SAntonio Quartulli return NET_RX_SUCCESS; 41427ea7b4a1SAntonio Quartulli 41437ea7b4a1SAntonio Quartulli tvlv_value_len -= tt_vlan_len; 41447ea7b4a1SAntonio Quartulli tt_num_entries = batadv_tt_entries(tvlv_value_len); 4145335fbe0fSMarek Lindner 4146335fbe0fSMarek Lindner switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { 4147335fbe0fSMarek Lindner case BATADV_TT_REQUEST: 4148335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); 4149335fbe0fSMarek Lindner 4150335fbe0fSMarek Lindner /* If this node cannot provide a TT response the tt_request is 4151335fbe0fSMarek Lindner * forwarded 4152335fbe0fSMarek Lindner */ 4153335fbe0fSMarek Lindner ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); 4154335fbe0fSMarek Lindner if (!ret) { 4155335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 4156335fbe0fSMarek Lindner tt_flag = 'F'; 4157335fbe0fSMarek Lindner else 4158335fbe0fSMarek Lindner tt_flag = '.'; 4159335fbe0fSMarek Lindner 4160335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 4161335fbe0fSMarek Lindner "Routing TT_REQUEST to %pM [%c]\n", 4162335fbe0fSMarek Lindner dst, tt_flag); 4163335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 4164335fbe0fSMarek Lindner return NET_RX_DROP; 4165335fbe0fSMarek Lindner } 4166335fbe0fSMarek Lindner break; 4167335fbe0fSMarek Lindner case BATADV_TT_RESPONSE: 4168335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); 4169335fbe0fSMarek Lindner 4170335fbe0fSMarek Lindner if (batadv_is_my_mac(bat_priv, dst)) { 4171335fbe0fSMarek Lindner batadv_handle_tt_response(bat_priv, tt_data, 41727ea7b4a1SAntonio Quartulli src, tt_num_entries); 4173335fbe0fSMarek Lindner return NET_RX_SUCCESS; 4174335fbe0fSMarek Lindner } 4175335fbe0fSMarek Lindner 4176335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 4177335fbe0fSMarek Lindner tt_flag = 'F'; 4178335fbe0fSMarek Lindner else 4179335fbe0fSMarek Lindner tt_flag = '.'; 4180335fbe0fSMarek Lindner 4181335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 4182335fbe0fSMarek Lindner "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag); 4183335fbe0fSMarek Lindner 4184335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 4185335fbe0fSMarek Lindner return NET_RX_DROP; 4186335fbe0fSMarek Lindner } 4187335fbe0fSMarek Lindner 4188335fbe0fSMarek Lindner return NET_RX_SUCCESS; 4189335fbe0fSMarek Lindner } 4190335fbe0fSMarek Lindner 4191335fbe0fSMarek Lindner /** 4192122edaa0SMarek Lindner * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container 4193122edaa0SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 4194122edaa0SMarek Lindner * @src: mac address of tt tvlv sender 4195122edaa0SMarek Lindner * @dst: mac address of tt tvlv recipient 4196122edaa0SMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 4197122edaa0SMarek Lindner * @tvlv_value_len: tvlv buffer length 4198122edaa0SMarek Lindner * 419962fe710fSSven Eckelmann * Return: NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS 4200122edaa0SMarek Lindner * otherwise. 4201122edaa0SMarek Lindner */ 4202122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 42036b5e971aSSven Eckelmann u8 *src, u8 *dst, 4204122edaa0SMarek Lindner void *tvlv_value, 42056b5e971aSSven Eckelmann u16 tvlv_value_len) 4206122edaa0SMarek Lindner { 4207122edaa0SMarek Lindner struct batadv_tvlv_roam_adv *roaming_adv; 4208122edaa0SMarek Lindner struct batadv_orig_node *orig_node = NULL; 4209122edaa0SMarek Lindner 4210122edaa0SMarek Lindner /* If this node is not the intended recipient of the 4211122edaa0SMarek Lindner * roaming advertisement the packet is forwarded 4212122edaa0SMarek Lindner * (the tvlv API will re-route the packet). 4213122edaa0SMarek Lindner */ 4214122edaa0SMarek Lindner if (!batadv_is_my_mac(bat_priv, dst)) 4215122edaa0SMarek Lindner return NET_RX_DROP; 4216122edaa0SMarek Lindner 4217122edaa0SMarek Lindner if (tvlv_value_len < sizeof(*roaming_adv)) 4218122edaa0SMarek Lindner goto out; 4219122edaa0SMarek Lindner 4220122edaa0SMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, src); 4221122edaa0SMarek Lindner if (!orig_node) 4222122edaa0SMarek Lindner goto out; 4223122edaa0SMarek Lindner 4224122edaa0SMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); 4225122edaa0SMarek Lindner roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; 4226122edaa0SMarek Lindner 4227122edaa0SMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 4228122edaa0SMarek Lindner "Received ROAMING_ADV from %pM (client %pM)\n", 4229122edaa0SMarek Lindner src, roaming_adv->client); 4230122edaa0SMarek Lindner 4231122edaa0SMarek Lindner batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, 4232c018ad3dSAntonio Quartulli ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, 4233122edaa0SMarek Lindner atomic_read(&orig_node->last_ttvn) + 1); 4234122edaa0SMarek Lindner 4235122edaa0SMarek Lindner out: 4236122edaa0SMarek Lindner if (orig_node) 42375d967310SSven Eckelmann batadv_orig_node_put(orig_node); 4238122edaa0SMarek Lindner return NET_RX_SUCCESS; 4239122edaa0SMarek Lindner } 4240122edaa0SMarek Lindner 4241122edaa0SMarek Lindner /** 4242e1bf0c14SMarek Lindner * batadv_tt_init - initialise the translation table internals 4243e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 4244e1bf0c14SMarek Lindner * 424562fe710fSSven Eckelmann * Return: 0 on success or negative error number in case of failure. 4246e1bf0c14SMarek Lindner */ 4247e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv) 4248e1bf0c14SMarek Lindner { 4249e1bf0c14SMarek Lindner int ret; 4250e1bf0c14SMarek Lindner 42510eb01568SAntonio Quartulli /* synchronized flags must be remote */ 42520eb01568SAntonio Quartulli BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK)); 42530eb01568SAntonio Quartulli 4254e1bf0c14SMarek Lindner ret = batadv_tt_local_init(bat_priv); 4255e1bf0c14SMarek Lindner if (ret < 0) 4256e1bf0c14SMarek Lindner return ret; 4257e1bf0c14SMarek Lindner 4258e1bf0c14SMarek Lindner ret = batadv_tt_global_init(bat_priv); 4259e1bf0c14SMarek Lindner if (ret < 0) 4260e1bf0c14SMarek Lindner return ret; 4261e1bf0c14SMarek Lindner 4262e1bf0c14SMarek Lindner batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, 4263335fbe0fSMarek Lindner batadv_tt_tvlv_unicast_handler_v1, 4264335fbe0fSMarek Lindner BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); 4265e1bf0c14SMarek Lindner 4266122edaa0SMarek Lindner batadv_tvlv_handler_register(bat_priv, NULL, 4267122edaa0SMarek Lindner batadv_roam_tvlv_unicast_handler_v1, 4268122edaa0SMarek Lindner BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); 4269122edaa0SMarek Lindner 4270e1bf0c14SMarek Lindner INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); 4271e1bf0c14SMarek Lindner queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 4272e1bf0c14SMarek Lindner msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 4273e1bf0c14SMarek Lindner 4274e1bf0c14SMarek Lindner return 1; 4275e1bf0c14SMarek Lindner } 427642cb0befSAntonio Quartulli 427742cb0befSAntonio Quartulli /** 427842cb0befSAntonio Quartulli * batadv_tt_global_is_isolated - check if a client is marked as isolated 427942cb0befSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 428042cb0befSAntonio Quartulli * @addr: the mac address of the client 428142cb0befSAntonio Quartulli * @vid: the identifier of the VLAN where this client is connected 428242cb0befSAntonio Quartulli * 428362fe710fSSven Eckelmann * Return: true if the client is marked with the TT_CLIENT_ISOLA flag, false 428442cb0befSAntonio Quartulli * otherwise 428542cb0befSAntonio Quartulli */ 428642cb0befSAntonio Quartulli bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, 42876b5e971aSSven Eckelmann const u8 *addr, unsigned short vid) 428842cb0befSAntonio Quartulli { 428942cb0befSAntonio Quartulli struct batadv_tt_global_entry *tt; 429042cb0befSAntonio Quartulli bool ret; 429142cb0befSAntonio Quartulli 429242cb0befSAntonio Quartulli tt = batadv_tt_global_hash_find(bat_priv, addr, vid); 429342cb0befSAntonio Quartulli if (!tt) 429442cb0befSAntonio Quartulli return false; 429542cb0befSAntonio Quartulli 429642cb0befSAntonio Quartulli ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA; 429742cb0befSAntonio Quartulli 42985dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt); 429942cb0befSAntonio Quartulli 430042cb0befSAntonio Quartulli return ret; 430142cb0befSAntonio Quartulli } 430286452f81SSven Eckelmann 430386452f81SSven Eckelmann /** 430486452f81SSven Eckelmann * batadv_tt_cache_init - Initialize tt memory object cache 430586452f81SSven Eckelmann * 430686452f81SSven Eckelmann * Return: 0 on success or negative error number in case of failure. 430786452f81SSven Eckelmann */ 430886452f81SSven Eckelmann int __init batadv_tt_cache_init(void) 430986452f81SSven Eckelmann { 431086452f81SSven Eckelmann size_t tl_size = sizeof(struct batadv_tt_local_entry); 431186452f81SSven Eckelmann size_t tg_size = sizeof(struct batadv_tt_global_entry); 431286452f81SSven Eckelmann size_t tt_orig_size = sizeof(struct batadv_tt_orig_list_entry); 431386452f81SSven Eckelmann size_t tt_change_size = sizeof(struct batadv_tt_change_node); 431486452f81SSven Eckelmann size_t tt_req_size = sizeof(struct batadv_tt_req_node); 431586452f81SSven Eckelmann size_t tt_roam_size = sizeof(struct batadv_tt_roam_node); 431686452f81SSven Eckelmann 431786452f81SSven Eckelmann batadv_tl_cache = kmem_cache_create("batadv_tl_cache", tl_size, 0, 431886452f81SSven Eckelmann SLAB_HWCACHE_ALIGN, NULL); 431986452f81SSven Eckelmann if (!batadv_tl_cache) 432086452f81SSven Eckelmann return -ENOMEM; 432186452f81SSven Eckelmann 432286452f81SSven Eckelmann batadv_tg_cache = kmem_cache_create("batadv_tg_cache", tg_size, 0, 432386452f81SSven Eckelmann SLAB_HWCACHE_ALIGN, NULL); 432486452f81SSven Eckelmann if (!batadv_tg_cache) 432586452f81SSven Eckelmann goto err_tt_tl_destroy; 432686452f81SSven Eckelmann 432786452f81SSven Eckelmann batadv_tt_orig_cache = kmem_cache_create("batadv_tt_orig_cache", 432886452f81SSven Eckelmann tt_orig_size, 0, 432986452f81SSven Eckelmann SLAB_HWCACHE_ALIGN, NULL); 433086452f81SSven Eckelmann if (!batadv_tt_orig_cache) 433186452f81SSven Eckelmann goto err_tt_tg_destroy; 433286452f81SSven Eckelmann 433386452f81SSven Eckelmann batadv_tt_change_cache = kmem_cache_create("batadv_tt_change_cache", 433486452f81SSven Eckelmann tt_change_size, 0, 433586452f81SSven Eckelmann SLAB_HWCACHE_ALIGN, NULL); 433686452f81SSven Eckelmann if (!batadv_tt_change_cache) 433786452f81SSven Eckelmann goto err_tt_orig_destroy; 433886452f81SSven Eckelmann 433986452f81SSven Eckelmann batadv_tt_req_cache = kmem_cache_create("batadv_tt_req_cache", 434086452f81SSven Eckelmann tt_req_size, 0, 434186452f81SSven Eckelmann SLAB_HWCACHE_ALIGN, NULL); 434286452f81SSven Eckelmann if (!batadv_tt_req_cache) 434386452f81SSven Eckelmann goto err_tt_change_destroy; 434486452f81SSven Eckelmann 434586452f81SSven Eckelmann batadv_tt_roam_cache = kmem_cache_create("batadv_tt_roam_cache", 434686452f81SSven Eckelmann tt_roam_size, 0, 434786452f81SSven Eckelmann SLAB_HWCACHE_ALIGN, NULL); 434886452f81SSven Eckelmann if (!batadv_tt_roam_cache) 434986452f81SSven Eckelmann goto err_tt_req_destroy; 435086452f81SSven Eckelmann 435186452f81SSven Eckelmann return 0; 435286452f81SSven Eckelmann 435386452f81SSven Eckelmann err_tt_req_destroy: 435486452f81SSven Eckelmann kmem_cache_destroy(batadv_tt_req_cache); 435586452f81SSven Eckelmann batadv_tt_req_cache = NULL; 435686452f81SSven Eckelmann err_tt_change_destroy: 435786452f81SSven Eckelmann kmem_cache_destroy(batadv_tt_change_cache); 435886452f81SSven Eckelmann batadv_tt_change_cache = NULL; 435986452f81SSven Eckelmann err_tt_orig_destroy: 436086452f81SSven Eckelmann kmem_cache_destroy(batadv_tt_orig_cache); 436186452f81SSven Eckelmann batadv_tt_orig_cache = NULL; 436286452f81SSven Eckelmann err_tt_tg_destroy: 436386452f81SSven Eckelmann kmem_cache_destroy(batadv_tg_cache); 436486452f81SSven Eckelmann batadv_tg_cache = NULL; 436586452f81SSven Eckelmann err_tt_tl_destroy: 436686452f81SSven Eckelmann kmem_cache_destroy(batadv_tl_cache); 436786452f81SSven Eckelmann batadv_tl_cache = NULL; 436886452f81SSven Eckelmann 436986452f81SSven Eckelmann return -ENOMEM; 437086452f81SSven Eckelmann } 437186452f81SSven Eckelmann 437286452f81SSven Eckelmann /** 437386452f81SSven Eckelmann * batadv_tt_cache_destroy - Destroy tt memory object cache 437486452f81SSven Eckelmann */ 437586452f81SSven Eckelmann void batadv_tt_cache_destroy(void) 437686452f81SSven Eckelmann { 437786452f81SSven Eckelmann kmem_cache_destroy(batadv_tl_cache); 437886452f81SSven Eckelmann kmem_cache_destroy(batadv_tg_cache); 437986452f81SSven Eckelmann kmem_cache_destroy(batadv_tt_orig_cache); 438086452f81SSven Eckelmann kmem_cache_destroy(batadv_tt_change_cache); 438186452f81SSven Eckelmann kmem_cache_destroy(batadv_tt_req_cache); 438286452f81SSven Eckelmann kmem_cache_destroy(batadv_tt_roam_cache); 438386452f81SSven Eckelmann } 4384