10046b040SSven Eckelmann /* Copyright (C) 2007-2016 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> 251e2c2a4fSSven Eckelmann #include <linux/compiler.h> 26ced72933SAntonio Quartulli #include <linux/crc32c.h> 271e2c2a4fSSven Eckelmann #include <linux/errno.h> 281e2c2a4fSSven Eckelmann #include <linux/etherdevice.h> 291e2c2a4fSSven Eckelmann #include <linux/fs.h> 301e2c2a4fSSven Eckelmann #include <linux/if_ether.h> 311e2c2a4fSSven Eckelmann #include <linux/jhash.h> 321e2c2a4fSSven Eckelmann #include <linux/jiffies.h> 331e2c2a4fSSven Eckelmann #include <linux/kernel.h> 346e8ef69dSSven Eckelmann #include <linux/kref.h> 351e2c2a4fSSven Eckelmann #include <linux/list.h> 361e2c2a4fSSven Eckelmann #include <linux/lockdep.h> 371e2c2a4fSSven Eckelmann #include <linux/netdevice.h> 381e2c2a4fSSven Eckelmann #include <linux/rculist.h> 391e2c2a4fSSven Eckelmann #include <linux/rcupdate.h> 401e2c2a4fSSven Eckelmann #include <linux/seq_file.h> 411e2c2a4fSSven Eckelmann #include <linux/slab.h> 421e2c2a4fSSven Eckelmann #include <linux/spinlock.h> 431e2c2a4fSSven Eckelmann #include <linux/stddef.h> 441e2c2a4fSSven Eckelmann #include <linux/string.h> 451e2c2a4fSSven Eckelmann #include <linux/workqueue.h> 461e2c2a4fSSven Eckelmann #include <net/net_namespace.h> 471e2c2a4fSSven Eckelmann 481e2c2a4fSSven Eckelmann #include "bridge_loop_avoidance.h" 491e2c2a4fSSven Eckelmann #include "hard-interface.h" 501e2c2a4fSSven Eckelmann #include "hash.h" 511e2c2a4fSSven Eckelmann #include "multicast.h" 521e2c2a4fSSven Eckelmann #include "originator.h" 531e2c2a4fSSven Eckelmann #include "packet.h" 541e2c2a4fSSven Eckelmann #include "soft-interface.h" 55a73105b8SAntonio Quartulli 56dec05074SAntonio Quartulli /* hash class keys */ 57dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_local_hash_lock_class_key; 58dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_global_hash_lock_class_key; 59dec05074SAntonio Quartulli 606b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, 61c018ad3dSAntonio Quartulli unsigned short vid, 6256303d34SSven Eckelmann struct batadv_orig_node *orig_node); 63a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work); 64a513088dSSven Eckelmann static void 6556303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); 6630cfd02bSAntonio Quartulli static void batadv_tt_global_del(struct batadv_priv *bat_priv, 6730cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 6830cfd02bSAntonio Quartulli const unsigned char *addr, 69c018ad3dSAntonio Quartulli unsigned short vid, const char *message, 70c018ad3dSAntonio Quartulli bool roaming); 71c6c8fea2SSven Eckelmann 7262fe710fSSven Eckelmann /** 73d15cd622SAntonio Quartulli * batadv_compare_tt - check if two TT entries are the same 74d15cd622SAntonio Quartulli * @node: the list element pointer of the first TT entry 75d15cd622SAntonio Quartulli * @data2: pointer to the tt_common_entry of the second TT entry 7662fe710fSSven Eckelmann * 77d15cd622SAntonio Quartulli * Compare the MAC address and the VLAN ID of the two TT entries and check if 78d15cd622SAntonio Quartulli * they are the same TT client. 79d15cd622SAntonio Quartulli * Return: 1 if the two TT clients are the same, 0 otherwise 8062fe710fSSven Eckelmann */ 81a513088dSSven Eckelmann static int batadv_compare_tt(const struct hlist_node *node, const void *data2) 827aadf889SMarek Lindner { 8356303d34SSven Eckelmann const void *data1 = container_of(node, struct batadv_tt_common_entry, 84747e4221SSven Eckelmann hash_entry); 854c718958SMarek Lindner const struct batadv_tt_common_entry *tt1 = data1; 864c718958SMarek Lindner const struct batadv_tt_common_entry *tt2 = data2; 877aadf889SMarek Lindner 884c718958SMarek Lindner return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2); 897aadf889SMarek Lindner } 907aadf889SMarek Lindner 91c018ad3dSAntonio Quartulli /** 92c018ad3dSAntonio Quartulli * batadv_choose_tt - return the index of the tt entry in the hash table 93c018ad3dSAntonio Quartulli * @data: pointer to the tt_common_entry object to map 94c018ad3dSAntonio Quartulli * @size: the size of the hash table 95c018ad3dSAntonio Quartulli * 9662fe710fSSven Eckelmann * Return: the hash index where the object represented by 'data' should be 97c018ad3dSAntonio Quartulli * stored at. 98c018ad3dSAntonio Quartulli */ 996b5e971aSSven Eckelmann static inline u32 batadv_choose_tt(const void *data, u32 size) 100c018ad3dSAntonio Quartulli { 101c018ad3dSAntonio Quartulli struct batadv_tt_common_entry *tt; 1026b5e971aSSven Eckelmann u32 hash = 0; 103c018ad3dSAntonio Quartulli 104c018ad3dSAntonio Quartulli tt = (struct batadv_tt_common_entry *)data; 10536fd61cbSSven Eckelmann hash = jhash(&tt->addr, ETH_ALEN, hash); 10636fd61cbSSven Eckelmann hash = jhash(&tt->vid, sizeof(tt->vid), hash); 107c018ad3dSAntonio Quartulli 108c018ad3dSAntonio Quartulli return hash % size; 109c018ad3dSAntonio Quartulli } 110c018ad3dSAntonio Quartulli 111c018ad3dSAntonio Quartulli /** 112c018ad3dSAntonio Quartulli * batadv_tt_hash_find - look for a client in the given hash table 113c018ad3dSAntonio Quartulli * @hash: the hash table to search 114c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 115c018ad3dSAntonio Quartulli * @vid: VLAN identifier 116c018ad3dSAntonio Quartulli * 11762fe710fSSven Eckelmann * Return: a pointer to the tt_common struct belonging to the searched client if 118c018ad3dSAntonio Quartulli * found, NULL otherwise. 119c018ad3dSAntonio Quartulli */ 12056303d34SSven Eckelmann static struct batadv_tt_common_entry * 1216b5e971aSSven Eckelmann batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr, 122c018ad3dSAntonio Quartulli unsigned short vid) 1237aadf889SMarek Lindner { 1247aadf889SMarek Lindner struct hlist_head *head; 125c018ad3dSAntonio Quartulli struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; 1266b5e971aSSven Eckelmann u32 index; 1277aadf889SMarek Lindner 1287aadf889SMarek Lindner if (!hash) 1297aadf889SMarek Lindner return NULL; 1307aadf889SMarek Lindner 1318fdd0153SAntonio Quartulli ether_addr_copy(to_search.addr, addr); 132c018ad3dSAntonio Quartulli to_search.vid = vid; 133c018ad3dSAntonio Quartulli 134c018ad3dSAntonio Quartulli index = batadv_choose_tt(&to_search, hash->size); 1357aadf889SMarek Lindner head = &hash->table[index]; 1367aadf889SMarek Lindner 1377aadf889SMarek Lindner rcu_read_lock(); 138c018ad3dSAntonio Quartulli hlist_for_each_entry_rcu(tt, head, hash_entry) { 139c018ad3dSAntonio Quartulli if (!batadv_compare_eth(tt, addr)) 1407aadf889SMarek Lindner continue; 1417aadf889SMarek Lindner 142c018ad3dSAntonio Quartulli if (tt->vid != vid) 1437683fdc1SAntonio Quartulli continue; 1447683fdc1SAntonio Quartulli 14592dcdf09SSven Eckelmann if (!kref_get_unless_zero(&tt->refcount)) 146c018ad3dSAntonio Quartulli continue; 147c018ad3dSAntonio Quartulli 148c018ad3dSAntonio Quartulli tt_tmp = tt; 1497aadf889SMarek Lindner break; 1507aadf889SMarek Lindner } 1517aadf889SMarek Lindner rcu_read_unlock(); 1527aadf889SMarek Lindner 153c018ad3dSAntonio Quartulli return tt_tmp; 15448100bacSAntonio Quartulli } 15548100bacSAntonio Quartulli 156c018ad3dSAntonio Quartulli /** 157c018ad3dSAntonio Quartulli * batadv_tt_local_hash_find - search the local table for a given client 158c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 159c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 160c018ad3dSAntonio Quartulli * @vid: VLAN identifier 161c018ad3dSAntonio Quartulli * 16262fe710fSSven Eckelmann * Return: a pointer to the corresponding tt_local_entry struct if the client is 163c018ad3dSAntonio Quartulli * found, NULL otherwise. 164c018ad3dSAntonio Quartulli */ 16556303d34SSven Eckelmann static struct batadv_tt_local_entry * 1666b5e971aSSven Eckelmann batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr, 167c018ad3dSAntonio Quartulli unsigned short vid) 16848100bacSAntonio Quartulli { 16956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 17056303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 17148100bacSAntonio Quartulli 172c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, 173c018ad3dSAntonio Quartulli vid); 17448100bacSAntonio Quartulli if (tt_common_entry) 17548100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 17656303d34SSven Eckelmann struct batadv_tt_local_entry, 17756303d34SSven Eckelmann common); 17848100bacSAntonio Quartulli return tt_local_entry; 1797aadf889SMarek Lindner } 1807aadf889SMarek Lindner 181c018ad3dSAntonio Quartulli /** 182c018ad3dSAntonio Quartulli * batadv_tt_global_hash_find - search the global table for a given client 183c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 184c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 185c018ad3dSAntonio Quartulli * @vid: VLAN identifier 186c018ad3dSAntonio Quartulli * 18762fe710fSSven Eckelmann * Return: a pointer to the corresponding tt_global_entry struct if the client 188c018ad3dSAntonio Quartulli * is found, NULL otherwise. 189c018ad3dSAntonio Quartulli */ 19056303d34SSven Eckelmann static struct batadv_tt_global_entry * 1916b5e971aSSven Eckelmann batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, 192c018ad3dSAntonio Quartulli unsigned short vid) 1937aadf889SMarek Lindner { 19456303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 19556303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 1967aadf889SMarek Lindner 197c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, 198c018ad3dSAntonio Quartulli vid); 19948100bacSAntonio Quartulli if (tt_common_entry) 20048100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 20156303d34SSven Eckelmann struct batadv_tt_global_entry, 20256303d34SSven Eckelmann common); 20348100bacSAntonio Quartulli return tt_global_entry; 2047aadf889SMarek Lindner } 2057aadf889SMarek Lindner 20692dcdf09SSven Eckelmann /** 20792dcdf09SSven Eckelmann * batadv_tt_local_entry_release - release tt_local_entry from lists and queue 20892dcdf09SSven Eckelmann * for free after rcu grace period 20992dcdf09SSven Eckelmann * @ref: kref pointer of the nc_node 21092dcdf09SSven Eckelmann */ 21192dcdf09SSven Eckelmann static void batadv_tt_local_entry_release(struct kref *ref) 2127683fdc1SAntonio Quartulli { 21392dcdf09SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 21492dcdf09SSven Eckelmann 21592dcdf09SSven Eckelmann tt_local_entry = container_of(ref, struct batadv_tt_local_entry, 21692dcdf09SSven Eckelmann common.refcount); 21792dcdf09SSven Eckelmann 21848100bacSAntonio Quartulli kfree_rcu(tt_local_entry, common.rcu); 2197683fdc1SAntonio Quartulli } 2207683fdc1SAntonio Quartulli 22121026059SAntonio Quartulli /** 22292dcdf09SSven Eckelmann * batadv_tt_local_entry_free_ref - decrement the tt_local_entry refcounter and 22392dcdf09SSven Eckelmann * possibly release it 22492dcdf09SSven Eckelmann * @tt_local_entry: tt_local_entry to be free'd 22592dcdf09SSven Eckelmann */ 22692dcdf09SSven Eckelmann static void 22792dcdf09SSven Eckelmann batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry) 22892dcdf09SSven Eckelmann { 22992dcdf09SSven Eckelmann kref_put(&tt_local_entry->common.refcount, 23092dcdf09SSven Eckelmann batadv_tt_local_entry_release); 23192dcdf09SSven Eckelmann } 23292dcdf09SSven Eckelmann 23392dcdf09SSven Eckelmann /** 23492dcdf09SSven Eckelmann * batadv_tt_global_entry_release - release tt_global_entry from lists and queue 23592dcdf09SSven Eckelmann * for free after rcu grace period 23692dcdf09SSven Eckelmann * @ref: kref pointer of the nc_node 23792dcdf09SSven Eckelmann */ 23892dcdf09SSven Eckelmann static void batadv_tt_global_entry_release(struct kref *ref) 23992dcdf09SSven Eckelmann { 24092dcdf09SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 24192dcdf09SSven Eckelmann 24292dcdf09SSven Eckelmann tt_global_entry = container_of(ref, struct batadv_tt_global_entry, 24392dcdf09SSven Eckelmann common.refcount); 24492dcdf09SSven Eckelmann 24592dcdf09SSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 24692dcdf09SSven Eckelmann kfree_rcu(tt_global_entry, common.rcu); 24792dcdf09SSven Eckelmann } 24892dcdf09SSven Eckelmann 24992dcdf09SSven Eckelmann /** 25092dcdf09SSven Eckelmann * batadv_tt_global_entry_free_ref - decrement the tt_global_entry refcounter 25192dcdf09SSven Eckelmann * and possibly release it 25292dcdf09SSven Eckelmann * @tt_global_entry: tt_global_entry to be free'd 25321026059SAntonio Quartulli */ 254a513088dSSven Eckelmann static void 25556303d34SSven Eckelmann batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) 2567683fdc1SAntonio Quartulli { 25792dcdf09SSven Eckelmann kref_put(&tt_global_entry->common.refcount, 25892dcdf09SSven Eckelmann batadv_tt_global_entry_release); 259db08e6e5SSimon Wunderlich } 260db08e6e5SSimon Wunderlich 2611d8ab8d3SLinus Lüssing /** 2621d8ab8d3SLinus Lüssing * batadv_tt_global_hash_count - count the number of orig entries 263d15cd622SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2641d8ab8d3SLinus Lüssing * @addr: the mac address of the client to count entries for 2651d8ab8d3SLinus Lüssing * @vid: VLAN identifier 2661d8ab8d3SLinus Lüssing * 26762fe710fSSven Eckelmann * Return: the number of originators advertising the given address/data 2681d8ab8d3SLinus Lüssing * (excluding ourself). 2691d8ab8d3SLinus Lüssing */ 2701d8ab8d3SLinus Lüssing int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, 2716b5e971aSSven Eckelmann const u8 *addr, unsigned short vid) 2721d8ab8d3SLinus Lüssing { 2731d8ab8d3SLinus Lüssing struct batadv_tt_global_entry *tt_global_entry; 2741d8ab8d3SLinus Lüssing int count; 2751d8ab8d3SLinus Lüssing 2761d8ab8d3SLinus Lüssing tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 2771d8ab8d3SLinus Lüssing if (!tt_global_entry) 2781d8ab8d3SLinus Lüssing return 0; 2791d8ab8d3SLinus Lüssing 2801d8ab8d3SLinus Lüssing count = atomic_read(&tt_global_entry->orig_list_count); 2811d8ab8d3SLinus Lüssing batadv_tt_global_entry_free_ref(tt_global_entry); 2821d8ab8d3SLinus Lüssing 2831d8ab8d3SLinus Lüssing return count; 2841d8ab8d3SLinus Lüssing } 2851d8ab8d3SLinus Lüssing 2867ea7b4a1SAntonio Quartulli /** 2877ea7b4a1SAntonio Quartulli * batadv_tt_local_size_mod - change the size by v of the local table identified 2887ea7b4a1SAntonio Quartulli * by vid 2897ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2907ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier of the sub-table to change 2917ea7b4a1SAntonio Quartulli * @v: the amount to sum to the local table size 2927ea7b4a1SAntonio Quartulli */ 2937ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv, 2947ea7b4a1SAntonio Quartulli unsigned short vid, int v) 2957ea7b4a1SAntonio Quartulli { 2967ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 2977ea7b4a1SAntonio Quartulli 2987ea7b4a1SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 2997ea7b4a1SAntonio Quartulli if (!vlan) 3007ea7b4a1SAntonio Quartulli return; 3017ea7b4a1SAntonio Quartulli 3027ea7b4a1SAntonio Quartulli atomic_add(v, &vlan->tt.num_entries); 3037ea7b4a1SAntonio Quartulli 3049c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 3057ea7b4a1SAntonio Quartulli } 3067ea7b4a1SAntonio Quartulli 3077ea7b4a1SAntonio Quartulli /** 3087ea7b4a1SAntonio Quartulli * batadv_tt_local_size_inc - increase by one the local table size for the given 3097ea7b4a1SAntonio Quartulli * vid 3107ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3117ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3127ea7b4a1SAntonio Quartulli */ 3137ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv, 3147ea7b4a1SAntonio Quartulli unsigned short vid) 3157ea7b4a1SAntonio Quartulli { 3167ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, 1); 3177ea7b4a1SAntonio Quartulli } 3187ea7b4a1SAntonio Quartulli 3197ea7b4a1SAntonio Quartulli /** 3207ea7b4a1SAntonio Quartulli * batadv_tt_local_size_dec - decrease by one the local table size for the given 3217ea7b4a1SAntonio Quartulli * vid 3227ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3237ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3247ea7b4a1SAntonio Quartulli */ 3257ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv, 3267ea7b4a1SAntonio Quartulli unsigned short vid) 3277ea7b4a1SAntonio Quartulli { 3287ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, -1); 3297ea7b4a1SAntonio Quartulli } 3307ea7b4a1SAntonio Quartulli 3317ea7b4a1SAntonio Quartulli /** 332d15cd622SAntonio Quartulli * batadv_tt_global_size_mod - change the size by v of the global table 333d15cd622SAntonio Quartulli * for orig_node identified by vid 334d15cd622SAntonio Quartulli * @orig_node: the originator for which the table has to be modified 3357ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3367ea7b4a1SAntonio Quartulli * @v: the amount to sum to the global table size 3377ea7b4a1SAntonio Quartulli */ 3387ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, 3397ea7b4a1SAntonio Quartulli unsigned short vid, int v) 3407ea7b4a1SAntonio Quartulli { 3417ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 3427ea7b4a1SAntonio Quartulli 3437ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_new(orig_node, vid); 3447ea7b4a1SAntonio Quartulli if (!vlan) 3457ea7b4a1SAntonio Quartulli return; 3467ea7b4a1SAntonio Quartulli 3477ea7b4a1SAntonio Quartulli if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { 3487ea7b4a1SAntonio Quartulli spin_lock_bh(&orig_node->vlan_list_lock); 3493db15209SSven Eckelmann if (!hlist_unhashed(&vlan->list)) { 350a121048aSMarek Lindner hlist_del_init_rcu(&vlan->list); 3517ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 3527ea7b4a1SAntonio Quartulli } 3533db15209SSven Eckelmann spin_unlock_bh(&orig_node->vlan_list_lock); 3543db15209SSven Eckelmann } 3557ea7b4a1SAntonio Quartulli 3567ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 3577ea7b4a1SAntonio Quartulli } 3587ea7b4a1SAntonio Quartulli 3597ea7b4a1SAntonio Quartulli /** 3607ea7b4a1SAntonio Quartulli * batadv_tt_global_size_inc - increase by one the global table size for the 3617ea7b4a1SAntonio Quartulli * given vid 3627ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 3637ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 3647ea7b4a1SAntonio Quartulli */ 3657ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node, 3667ea7b4a1SAntonio Quartulli unsigned short vid) 3677ea7b4a1SAntonio Quartulli { 3687ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, 1); 3697ea7b4a1SAntonio Quartulli } 3707ea7b4a1SAntonio Quartulli 3717ea7b4a1SAntonio Quartulli /** 3727ea7b4a1SAntonio Quartulli * batadv_tt_global_size_dec - decrease by one the global table size for the 3737ea7b4a1SAntonio Quartulli * given vid 3747ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 3757ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 3767ea7b4a1SAntonio Quartulli */ 3777ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, 3787ea7b4a1SAntonio Quartulli unsigned short vid) 3797ea7b4a1SAntonio Quartulli { 3807ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, -1); 3817ea7b4a1SAntonio Quartulli } 3827ea7b4a1SAntonio Quartulli 38342eff6a6SSven Eckelmann /** 38442eff6a6SSven Eckelmann * batadv_tt_orig_list_entry_release - release tt orig entry from lists and 38542eff6a6SSven Eckelmann * queue for free after rcu grace period 3866e8ef69dSSven Eckelmann * @ref: kref pointer of the tt orig entry 38742eff6a6SSven Eckelmann */ 3886e8ef69dSSven Eckelmann static void batadv_tt_orig_list_entry_release(struct kref *ref) 38942eff6a6SSven Eckelmann { 3906e8ef69dSSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 3916e8ef69dSSven Eckelmann 3926e8ef69dSSven Eckelmann orig_entry = container_of(ref, struct batadv_tt_orig_list_entry, 3936e8ef69dSSven Eckelmann refcount); 3946e8ef69dSSven Eckelmann 3955d967310SSven Eckelmann batadv_orig_node_put(orig_entry->orig_node); 39642eff6a6SSven Eckelmann kfree_rcu(orig_entry, rcu); 39742eff6a6SSven Eckelmann } 39842eff6a6SSven Eckelmann 3996e8ef69dSSven Eckelmann /** 4006e8ef69dSSven Eckelmann * batadv_tt_orig_list_entry_free_ref - decrement the tt orig entry refcounter 4016e8ef69dSSven Eckelmann * and possibly release it 4026e8ef69dSSven Eckelmann * @orig_entry: tt orig entry to be free'd 4036e8ef69dSSven Eckelmann */ 404a513088dSSven Eckelmann static void 40556303d34SSven Eckelmann batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) 406db08e6e5SSimon Wunderlich { 4076e8ef69dSSven Eckelmann kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release); 408db08e6e5SSimon Wunderlich } 4097683fdc1SAntonio Quartulli 4103abe4adbSAntonio Quartulli /** 4113abe4adbSAntonio Quartulli * batadv_tt_local_event - store a local TT event (ADD/DEL) 4123abe4adbSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 4133abe4adbSAntonio Quartulli * @tt_local_entry: the TT entry involved in the event 4143abe4adbSAntonio Quartulli * @event_flags: flags to store in the event structure 4153abe4adbSAntonio Quartulli */ 41656303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv, 4173abe4adbSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry, 4186b5e971aSSven Eckelmann u8 event_flags) 419a73105b8SAntonio Quartulli { 42056303d34SSven Eckelmann struct batadv_tt_change_node *tt_change_node, *entry, *safe; 4213abe4adbSAntonio Quartulli struct batadv_tt_common_entry *common = &tt_local_entry->common; 4226b5e971aSSven Eckelmann u8 flags = common->flags | event_flags; 4233b643de5SAntonio Quartulli bool event_removed = false; 4243b643de5SAntonio Quartulli bool del_op_requested, del_op_entry; 425a73105b8SAntonio Quartulli 426a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 427a73105b8SAntonio Quartulli if (!tt_change_node) 428a73105b8SAntonio Quartulli return; 429a73105b8SAntonio Quartulli 430ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 431ca663046SAntonio Quartulli memset(tt_change_node->change.reserved, 0, 432ca663046SAntonio Quartulli sizeof(tt_change_node->change.reserved)); 4338fdd0153SAntonio Quartulli ether_addr_copy(tt_change_node->change.addr, common->addr); 434c018ad3dSAntonio Quartulli tt_change_node->change.vid = htons(common->vid); 435a73105b8SAntonio Quartulli 436acd34afaSSven Eckelmann del_op_requested = flags & BATADV_TT_CLIENT_DEL; 4373b643de5SAntonio Quartulli 4383b643de5SAntonio Quartulli /* check for ADD+DEL or DEL+ADD events */ 439807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 440807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 4413b643de5SAntonio Quartulli list) { 4423abe4adbSAntonio Quartulli if (!batadv_compare_eth(entry->change.addr, common->addr)) 4433b643de5SAntonio Quartulli continue; 4443b643de5SAntonio Quartulli 4453b643de5SAntonio Quartulli /* DEL+ADD in the same orig interval have no effect and can be 4463b643de5SAntonio Quartulli * removed to avoid silly behaviour on the receiver side. The 4473b643de5SAntonio Quartulli * other way around (ADD+DEL) can happen in case of roaming of 4483b643de5SAntonio Quartulli * a client still in the NEW state. Roaming of NEW clients is 4493b643de5SAntonio Quartulli * now possible due to automatically recognition of "temporary" 4503b643de5SAntonio Quartulli * clients 4513b643de5SAntonio Quartulli */ 452acd34afaSSven Eckelmann del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; 4533b643de5SAntonio Quartulli if (!del_op_requested && del_op_entry) 4543b643de5SAntonio Quartulli goto del; 4553b643de5SAntonio Quartulli if (del_op_requested && !del_op_entry) 4563b643de5SAntonio Quartulli goto del; 4573c4f7ab6SAntonio Quartulli 4583c4f7ab6SAntonio Quartulli /* this is a second add in the same originator interval. It 4593c4f7ab6SAntonio Quartulli * means that flags have been changed: update them! 4603c4f7ab6SAntonio Quartulli */ 4613c4f7ab6SAntonio Quartulli if (!del_op_requested && !del_op_entry) 4623c4f7ab6SAntonio Quartulli entry->change.flags = flags; 4633c4f7ab6SAntonio Quartulli 4643b643de5SAntonio Quartulli continue; 4653b643de5SAntonio Quartulli del: 4663b643de5SAntonio Quartulli list_del(&entry->list); 4673b643de5SAntonio Quartulli kfree(entry); 468155e4e12SJesper Juhl kfree(tt_change_node); 4693b643de5SAntonio Quartulli event_removed = true; 4703b643de5SAntonio Quartulli goto unlock; 4713b643de5SAntonio Quartulli } 4723b643de5SAntonio Quartulli 473a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 474807736f6SSven Eckelmann list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list); 4753b643de5SAntonio Quartulli 4763b643de5SAntonio Quartulli unlock: 477807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 478a73105b8SAntonio Quartulli 4793b643de5SAntonio Quartulli if (event_removed) 480807736f6SSven Eckelmann atomic_dec(&bat_priv->tt.local_changes); 4813b643de5SAntonio Quartulli else 482807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.local_changes); 483a73105b8SAntonio Quartulli } 484a73105b8SAntonio Quartulli 485335fbe0fSMarek Lindner /** 486335fbe0fSMarek Lindner * batadv_tt_len - compute length in bytes of given number of tt changes 487335fbe0fSMarek Lindner * @changes_num: number of tt changes 488335fbe0fSMarek Lindner * 48962fe710fSSven Eckelmann * Return: computed length in bytes. 490335fbe0fSMarek Lindner */ 491335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num) 492a73105b8SAntonio Quartulli { 493335fbe0fSMarek Lindner return changes_num * sizeof(struct batadv_tvlv_tt_change); 494a73105b8SAntonio Quartulli } 495a73105b8SAntonio Quartulli 496298e6e68SAntonio Quartulli /** 497298e6e68SAntonio Quartulli * batadv_tt_entries - compute the number of entries fitting in tt_len bytes 498298e6e68SAntonio Quartulli * @tt_len: available space 499298e6e68SAntonio Quartulli * 50062fe710fSSven Eckelmann * Return: the number of entries. 501298e6e68SAntonio Quartulli */ 5026b5e971aSSven Eckelmann static u16 batadv_tt_entries(u16 tt_len) 503298e6e68SAntonio Quartulli { 504298e6e68SAntonio Quartulli return tt_len / batadv_tt_len(1); 505298e6e68SAntonio Quartulli } 506298e6e68SAntonio Quartulli 507a19d3d85SMarek Lindner /** 508a19d3d85SMarek Lindner * batadv_tt_local_table_transmit_size - calculates the local translation table 509a19d3d85SMarek Lindner * size when transmitted over the air 510a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 511a19d3d85SMarek Lindner * 51262fe710fSSven Eckelmann * Return: local translation table size in bytes. 513a19d3d85SMarek Lindner */ 514a19d3d85SMarek Lindner static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) 515a19d3d85SMarek Lindner { 5164f248cffSSven Eckelmann u16 num_vlan = 0; 5174f248cffSSven Eckelmann u16 tt_local_entries = 0; 518a19d3d85SMarek Lindner struct batadv_softif_vlan *vlan; 519a19d3d85SMarek Lindner int hdr_size; 520a19d3d85SMarek Lindner 521a19d3d85SMarek Lindner rcu_read_lock(); 522a19d3d85SMarek Lindner hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 523a19d3d85SMarek Lindner num_vlan++; 524a19d3d85SMarek Lindner tt_local_entries += atomic_read(&vlan->tt.num_entries); 525a19d3d85SMarek Lindner } 526a19d3d85SMarek Lindner rcu_read_unlock(); 527a19d3d85SMarek Lindner 528a19d3d85SMarek Lindner /* header size of tvlv encapsulated tt response payload */ 529a19d3d85SMarek Lindner hdr_size = sizeof(struct batadv_unicast_tvlv_packet); 530a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_hdr); 531a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_tt_data); 532a19d3d85SMarek Lindner hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data); 533a19d3d85SMarek Lindner 534a19d3d85SMarek Lindner return hdr_size + batadv_tt_len(tt_local_entries); 535a19d3d85SMarek Lindner } 536a19d3d85SMarek Lindner 53756303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv) 538c6c8fea2SSven Eckelmann { 539807736f6SSven Eckelmann if (bat_priv->tt.local_hash) 5405346c35eSSven Eckelmann return 0; 541c6c8fea2SSven Eckelmann 542807736f6SSven Eckelmann bat_priv->tt.local_hash = batadv_hash_new(1024); 543c6c8fea2SSven Eckelmann 544807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 5455346c35eSSven Eckelmann return -ENOMEM; 546c6c8fea2SSven Eckelmann 547dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.local_hash, 548dec05074SAntonio Quartulli &batadv_tt_local_hash_lock_class_key); 549dec05074SAntonio Quartulli 5505346c35eSSven Eckelmann return 0; 551c6c8fea2SSven Eckelmann } 552c6c8fea2SSven Eckelmann 553068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv, 554068ee6e2SAntonio Quartulli struct batadv_tt_global_entry *tt_global, 555068ee6e2SAntonio Quartulli const char *message) 556068ee6e2SAntonio Quartulli { 557068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 55816052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 55916052789SAntonio Quartulli tt_global->common.addr, 56016052789SAntonio Quartulli BATADV_PRINT_VID(tt_global->common.vid), message); 561068ee6e2SAntonio Quartulli 562068ee6e2SAntonio Quartulli batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, 563c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_global->common); 564068ee6e2SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 565068ee6e2SAntonio Quartulli } 566068ee6e2SAntonio Quartulli 567c018ad3dSAntonio Quartulli /** 568c018ad3dSAntonio Quartulli * batadv_tt_local_add - add a new client to the local table or update an 569c018ad3dSAntonio Quartulli * existing client 570c018ad3dSAntonio Quartulli * @soft_iface: netdev struct of the mesh interface 571c018ad3dSAntonio Quartulli * @addr: the mac address of the client to add 572c018ad3dSAntonio Quartulli * @vid: VLAN identifier 573c018ad3dSAntonio Quartulli * @ifindex: index of the interface where the client is connected to (useful to 574c018ad3dSAntonio Quartulli * identify wireless clients) 5759464d071SAntonio Quartulli * @mark: the value contained in the skb->mark field of the received packet (if 5769464d071SAntonio Quartulli * any) 577a19d3d85SMarek Lindner * 57862fe710fSSven Eckelmann * Return: true if the client was successfully added, false otherwise. 579c018ad3dSAntonio Quartulli */ 5806b5e971aSSven Eckelmann bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, 5816b5e971aSSven Eckelmann unsigned short vid, int ifindex, u32 mark) 582c6c8fea2SSven Eckelmann { 58356303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(soft_iface); 584170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local; 585c5caf4efSLinus Lüssing struct batadv_tt_global_entry *tt_global = NULL; 58635df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 5870c69aeccSAntonio Quartulli struct net_device *in_dev = NULL; 588db08e6e5SSimon Wunderlich struct hlist_head *head; 58956303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 590a19d3d85SMarek Lindner int hash_added, table_size, packet_size_max; 5914f248cffSSven Eckelmann bool ret = false; 5924f248cffSSven Eckelmann bool roamed_back = false; 5936b5e971aSSven Eckelmann u8 remote_flags; 5946b5e971aSSven Eckelmann u32 match_mark; 595c6c8fea2SSven Eckelmann 5960c69aeccSAntonio Quartulli if (ifindex != BATADV_NULL_IFINDEX) 5970c69aeccSAntonio Quartulli in_dev = dev_get_by_index(&init_net, ifindex); 5980c69aeccSAntonio Quartulli 599c018ad3dSAntonio Quartulli tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); 600c5caf4efSLinus Lüssing 601c5caf4efSLinus Lüssing if (!is_multicast_ether_addr(addr)) 602c018ad3dSAntonio Quartulli tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); 603c6c8fea2SSven Eckelmann 60447c94655SAntonio Quartulli if (tt_local) { 60547c94655SAntonio Quartulli tt_local->last_seen = jiffies; 606068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { 607068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 60816052789SAntonio Quartulli "Re-adding pending client %pM (vid: %d)\n", 60916052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid)); 610068ee6e2SAntonio Quartulli /* whatever the reason why the PENDING flag was set, 611068ee6e2SAntonio Quartulli * this is a client which was enqueued to be removed in 612068ee6e2SAntonio Quartulli * this orig_interval. Since it popped up again, the 613068ee6e2SAntonio Quartulli * flag can be reset like it was never enqueued 614068ee6e2SAntonio Quartulli */ 61547c94655SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; 616068ee6e2SAntonio Quartulli goto add_event; 617068ee6e2SAntonio Quartulli } 618068ee6e2SAntonio Quartulli 619068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { 620068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 62116052789SAntonio Quartulli "Roaming client %pM (vid: %d) came back to its original location\n", 62216052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid)); 623068ee6e2SAntonio Quartulli /* the ROAM flag is set because this client roamed away 624068ee6e2SAntonio Quartulli * and the node got a roaming_advertisement message. Now 625068ee6e2SAntonio Quartulli * that the client popped up again at its original 626068ee6e2SAntonio Quartulli * location such flag can be unset 627068ee6e2SAntonio Quartulli */ 628068ee6e2SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; 629068ee6e2SAntonio Quartulli roamed_back = true; 630068ee6e2SAntonio Quartulli } 631068ee6e2SAntonio Quartulli goto check_roaming; 632c6c8fea2SSven Eckelmann } 633c6c8fea2SSven Eckelmann 634a19d3d85SMarek Lindner /* Ignore the client if we cannot send it in a full table response. */ 635a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 636a19d3d85SMarek Lindner table_size += batadv_tt_len(1); 637a19d3d85SMarek Lindner packet_size_max = atomic_read(&bat_priv->packet_size_max); 638a19d3d85SMarek Lindner if (table_size > packet_size_max) { 639a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 640a19d3d85SMarek Lindner "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n", 641a19d3d85SMarek Lindner table_size, packet_size_max, addr); 642a19d3d85SMarek Lindner goto out; 643a19d3d85SMarek Lindner } 644a19d3d85SMarek Lindner 64547c94655SAntonio Quartulli tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); 64647c94655SAntonio Quartulli if (!tt_local) 6477683fdc1SAntonio Quartulli goto out; 648a73105b8SAntonio Quartulli 64935df3b29SAntonio Quartulli /* increase the refcounter of the related vlan */ 65035df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 651354136bcSMarek Lindner if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d", 652fd7dec25SSven Eckelmann addr, BATADV_PRINT_VID(vid))) { 653fd7dec25SSven Eckelmann kfree(tt_local); 654fd7dec25SSven Eckelmann tt_local = NULL; 655354136bcSMarek Lindner goto out; 656fd7dec25SSven Eckelmann } 65735df3b29SAntonio Quartulli 65839c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 65916052789SAntonio Quartulli "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", 66016052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid), 6616b5e971aSSven Eckelmann (u8)atomic_read(&bat_priv->tt.vn)); 662c6c8fea2SSven Eckelmann 6638fdd0153SAntonio Quartulli ether_addr_copy(tt_local->common.addr, addr); 6648425ec6aSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 6658425ec6aSAntonio Quartulli * a full table response going out before the next ttvn increment 6668425ec6aSAntonio Quartulli * (consistency check) 6678425ec6aSAntonio Quartulli */ 6688425ec6aSAntonio Quartulli tt_local->common.flags = BATADV_TT_CLIENT_NEW; 669c018ad3dSAntonio Quartulli tt_local->common.vid = vid; 6700c69aeccSAntonio Quartulli if (batadv_is_wifi_netdev(in_dev)) 67147c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 67292dcdf09SSven Eckelmann kref_init(&tt_local->common.refcount); 67392dcdf09SSven Eckelmann kref_get(&tt_local->common.refcount); 67447c94655SAntonio Quartulli tt_local->last_seen = jiffies; 67547c94655SAntonio Quartulli tt_local->common.added_at = tt_local->last_seen; 676c6c8fea2SSven Eckelmann 677c5caf4efSLinus Lüssing /* the batman interface mac and multicast addresses should never be 678c5caf4efSLinus Lüssing * purged 679c5caf4efSLinus Lüssing */ 680c5caf4efSLinus Lüssing if (batadv_compare_eth(addr, soft_iface->dev_addr) || 681c5caf4efSLinus Lüssing is_multicast_ether_addr(addr)) 68247c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; 683c6c8fea2SSven Eckelmann 684807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, 685c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_local->common, 68647c94655SAntonio Quartulli &tt_local->common.hash_entry); 68780b3f58cSSimon Wunderlich 68880b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 68980b3f58cSSimon Wunderlich /* remove the reference for the hash */ 69047c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 6919c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 69280b3f58cSSimon Wunderlich goto out; 69380b3f58cSSimon Wunderlich } 69480b3f58cSSimon Wunderlich 695068ee6e2SAntonio Quartulli add_event: 6963abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 697ff66c975SAntonio Quartulli 698068ee6e2SAntonio Quartulli check_roaming: 699068ee6e2SAntonio Quartulli /* Check whether it is a roaming, but don't do anything if the roaming 700068ee6e2SAntonio Quartulli * process has already been handled 701068ee6e2SAntonio Quartulli */ 702068ee6e2SAntonio Quartulli if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { 703db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 70447c94655SAntonio Quartulli head = &tt_global->orig_list; 705db08e6e5SSimon Wunderlich rcu_read_lock(); 706b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 70747c94655SAntonio Quartulli batadv_send_roam_adv(bat_priv, tt_global->common.addr, 708c018ad3dSAntonio Quartulli tt_global->common.vid, 709db08e6e5SSimon Wunderlich orig_entry->orig_node); 710db08e6e5SSimon Wunderlich } 711db08e6e5SSimon Wunderlich rcu_read_unlock(); 712068ee6e2SAntonio Quartulli if (roamed_back) { 713068ee6e2SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global, 714068ee6e2SAntonio Quartulli "Roaming canceled"); 715068ee6e2SAntonio Quartulli tt_global = NULL; 716068ee6e2SAntonio Quartulli } else { 717db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 718db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 719db08e6e5SSimon Wunderlich */ 72047c94655SAntonio Quartulli tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; 72147c94655SAntonio Quartulli tt_global->roam_at = jiffies; 7227683fdc1SAntonio Quartulli } 723068ee6e2SAntonio Quartulli } 724068ee6e2SAntonio Quartulli 7253c4f7ab6SAntonio Quartulli /* store the current remote flags before altering them. This helps 7263c4f7ab6SAntonio Quartulli * understanding is flags are changing or not 7273c4f7ab6SAntonio Quartulli */ 7283c4f7ab6SAntonio Quartulli remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK; 729a19d3d85SMarek Lindner 7303c4f7ab6SAntonio Quartulli if (batadv_is_wifi_netdev(in_dev)) 7313c4f7ab6SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 7323c4f7ab6SAntonio Quartulli else 7333c4f7ab6SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; 7343c4f7ab6SAntonio Quartulli 7359464d071SAntonio Quartulli /* check the mark in the skb: if it's equal to the configured 7369464d071SAntonio Quartulli * isolation_mark, it means the packet is coming from an isolated 7379464d071SAntonio Quartulli * non-mesh client 7389464d071SAntonio Quartulli */ 7399464d071SAntonio Quartulli match_mark = (mark & bat_priv->isolation_mark_mask); 7409464d071SAntonio Quartulli if (bat_priv->isolation_mark_mask && 7419464d071SAntonio Quartulli match_mark == bat_priv->isolation_mark) 7429464d071SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA; 7439464d071SAntonio Quartulli else 7449464d071SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA; 7459464d071SAntonio Quartulli 7463c4f7ab6SAntonio Quartulli /* if any "dynamic" flag has been modified, resend an ADD event for this 7473c4f7ab6SAntonio Quartulli * entry so that all the nodes can get the new flags 7483c4f7ab6SAntonio Quartulli */ 7493c4f7ab6SAntonio Quartulli if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK)) 7503c4f7ab6SAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 7513c4f7ab6SAntonio Quartulli 7523c4f7ab6SAntonio Quartulli ret = true; 7537683fdc1SAntonio Quartulli out: 7540c69aeccSAntonio Quartulli if (in_dev) 7550c69aeccSAntonio Quartulli dev_put(in_dev); 75647c94655SAntonio Quartulli if (tt_local) 75747c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 75847c94655SAntonio Quartulli if (tt_global) 75947c94655SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 760a19d3d85SMarek Lindner return ret; 761c6c8fea2SSven Eckelmann } 762c6c8fea2SSven Eckelmann 763e1bf0c14SMarek Lindner /** 7647ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send 7657ea7b4a1SAntonio Quartulli * within a TT Response directed to another node 7667ea7b4a1SAntonio Quartulli * @orig_node: originator for which the TT data has to be prepared 7677ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 7687ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 7697ea7b4a1SAntonio Quartulli * changed can be stored 7707ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 7717ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire global TT 7727ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 7737ea7b4a1SAntonio Quartulli * reserved bytes 7747ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 7757ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 7767ea7b4a1SAntonio Quartulli * objects, one per active VLAN served by the originator node. 7777ea7b4a1SAntonio Quartulli * 77862fe710fSSven Eckelmann * Return: the size of the allocated buffer or 0 in case of failure. 7797ea7b4a1SAntonio Quartulli */ 7806b5e971aSSven Eckelmann static u16 7817ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, 7827ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 7837ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 7846b5e971aSSven Eckelmann s32 *tt_len) 7857ea7b4a1SAntonio Quartulli { 7864f248cffSSven Eckelmann u16 num_vlan = 0; 7874f248cffSSven Eckelmann u16 num_entries = 0; 7884f248cffSSven Eckelmann u16 change_offset; 7894f248cffSSven Eckelmann u16 tvlv_len; 7907ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 7917ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 7926b5e971aSSven Eckelmann u8 *tt_change_ptr; 7937ea7b4a1SAntonio Quartulli 7947ea7b4a1SAntonio Quartulli rcu_read_lock(); 795d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 7967ea7b4a1SAntonio Quartulli num_vlan++; 7977ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 7987ea7b4a1SAntonio Quartulli } 7997ea7b4a1SAntonio Quartulli 8007ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 8017ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 8027ea7b4a1SAntonio Quartulli 8037ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 8047ea7b4a1SAntonio Quartulli if (*tt_len < 0) 8057ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 8067ea7b4a1SAntonio Quartulli 8077ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 8087ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 8097ea7b4a1SAntonio Quartulli 8107ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 8117ea7b4a1SAntonio Quartulli if (!*tt_data) { 8127ea7b4a1SAntonio Quartulli *tt_len = 0; 8137ea7b4a1SAntonio Quartulli goto out; 8147ea7b4a1SAntonio Quartulli } 8157ea7b4a1SAntonio Quartulli 8167ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 8177ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); 8187ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 8197ea7b4a1SAntonio Quartulli 8207ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 821d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 8227ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 8237ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 8247ea7b4a1SAntonio Quartulli 8257ea7b4a1SAntonio Quartulli tt_vlan++; 8267ea7b4a1SAntonio Quartulli } 8277ea7b4a1SAntonio Quartulli 8286b5e971aSSven Eckelmann tt_change_ptr = (u8 *)*tt_data + change_offset; 8297ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 8307ea7b4a1SAntonio Quartulli 8317ea7b4a1SAntonio Quartulli out: 8327ea7b4a1SAntonio Quartulli rcu_read_unlock(); 8337ea7b4a1SAntonio Quartulli return tvlv_len; 8347ea7b4a1SAntonio Quartulli } 8357ea7b4a1SAntonio Quartulli 8367ea7b4a1SAntonio Quartulli /** 8377ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this 8387ea7b4a1SAntonio Quartulli * node 8397ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 8407ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 8417ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 8427ea7b4a1SAntonio Quartulli * changes can be stored 8437ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 8447ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire local TT 8457ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 8467ea7b4a1SAntonio Quartulli * reserved bytes 8477ea7b4a1SAntonio Quartulli * 8487ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 8497ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 8507ea7b4a1SAntonio Quartulli * objects, one per active VLAN. 8517ea7b4a1SAntonio Quartulli * 85262fe710fSSven Eckelmann * Return: the size of the allocated buffer or 0 in case of failure. 8537ea7b4a1SAntonio Quartulli */ 8546b5e971aSSven Eckelmann static u16 8557ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, 8567ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 8577ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 8586b5e971aSSven Eckelmann s32 *tt_len) 8597ea7b4a1SAntonio Quartulli { 8607ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 8617ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 8624f248cffSSven Eckelmann u16 num_vlan = 0; 8634f248cffSSven Eckelmann u16 num_entries = 0; 8644f248cffSSven Eckelmann u16 tvlv_len; 8656b5e971aSSven Eckelmann u8 *tt_change_ptr; 8667ea7b4a1SAntonio Quartulli int change_offset; 8677ea7b4a1SAntonio Quartulli 8687ea7b4a1SAntonio Quartulli rcu_read_lock(); 8697ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 8707ea7b4a1SAntonio Quartulli num_vlan++; 8717ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 8727ea7b4a1SAntonio Quartulli } 8737ea7b4a1SAntonio Quartulli 8747ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 8757ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 8767ea7b4a1SAntonio Quartulli 8777ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 8787ea7b4a1SAntonio Quartulli if (*tt_len < 0) 8797ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 8807ea7b4a1SAntonio Quartulli 8817ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 8827ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 8837ea7b4a1SAntonio Quartulli 8847ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 8857ea7b4a1SAntonio Quartulli if (!*tt_data) { 8867ea7b4a1SAntonio Quartulli tvlv_len = 0; 8877ea7b4a1SAntonio Quartulli goto out; 8887ea7b4a1SAntonio Quartulli } 8897ea7b4a1SAntonio Quartulli 8907ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 8917ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn); 8927ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 8937ea7b4a1SAntonio Quartulli 8947ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 8957ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 8967ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 8977ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 8987ea7b4a1SAntonio Quartulli 8997ea7b4a1SAntonio Quartulli tt_vlan++; 9007ea7b4a1SAntonio Quartulli } 9017ea7b4a1SAntonio Quartulli 9026b5e971aSSven Eckelmann tt_change_ptr = (u8 *)*tt_data + change_offset; 9037ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 9047ea7b4a1SAntonio Quartulli 9057ea7b4a1SAntonio Quartulli out: 9067ea7b4a1SAntonio Quartulli rcu_read_unlock(); 9077ea7b4a1SAntonio Quartulli return tvlv_len; 9087ea7b4a1SAntonio Quartulli } 9097ea7b4a1SAntonio Quartulli 9107ea7b4a1SAntonio Quartulli /** 911e1bf0c14SMarek Lindner * batadv_tt_tvlv_container_update - update the translation table tvlv container 912e1bf0c14SMarek Lindner * after local tt changes have been committed 913e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 914e1bf0c14SMarek Lindner */ 915e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) 916c6c8fea2SSven Eckelmann { 917e1bf0c14SMarek Lindner struct batadv_tt_change_node *entry, *safe; 918e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 919e1bf0c14SMarek Lindner struct batadv_tvlv_tt_change *tt_change; 9207ea7b4a1SAntonio Quartulli int tt_diff_len, tt_change_len = 0; 9214f248cffSSven Eckelmann int tt_diff_entries_num = 0; 9224f248cffSSven Eckelmann int tt_diff_entries_count = 0; 9236b5e971aSSven Eckelmann u16 tvlv_len; 924c6c8fea2SSven Eckelmann 9257ea7b4a1SAntonio Quartulli tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); 9267ea7b4a1SAntonio Quartulli tt_diff_len = batadv_tt_len(tt_diff_entries_num); 927be9aa4c1SMarek Lindner 928be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 929be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 930be9aa4c1SMarek Lindner */ 931e1bf0c14SMarek Lindner if (tt_diff_len > bat_priv->soft_iface->mtu) 932e1bf0c14SMarek Lindner tt_diff_len = 0; 933be9aa4c1SMarek Lindner 9347ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, 9357ea7b4a1SAntonio Quartulli &tt_change, &tt_diff_len); 9367ea7b4a1SAntonio Quartulli if (!tvlv_len) 937e1bf0c14SMarek Lindner return; 938be9aa4c1SMarek Lindner 939e1bf0c14SMarek Lindner tt_data->flags = BATADV_TT_OGM_DIFF; 940be9aa4c1SMarek Lindner 941e1bf0c14SMarek Lindner if (tt_diff_len == 0) 942e1bf0c14SMarek Lindner goto container_register; 943be9aa4c1SMarek Lindner 944807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 945807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 946c6c8fea2SSven Eckelmann 947807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 948a73105b8SAntonio Quartulli list) { 949e1bf0c14SMarek Lindner if (tt_diff_entries_count < tt_diff_entries_num) { 950e1bf0c14SMarek Lindner memcpy(tt_change + tt_diff_entries_count, 951e1bf0c14SMarek Lindner &entry->change, 952e1bf0c14SMarek Lindner sizeof(struct batadv_tvlv_tt_change)); 953e1bf0c14SMarek Lindner tt_diff_entries_count++; 954c6c8fea2SSven Eckelmann } 955a73105b8SAntonio Quartulli list_del(&entry->list); 956a73105b8SAntonio Quartulli kfree(entry); 957c6c8fea2SSven Eckelmann } 958807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 959c6c8fea2SSven Eckelmann 960a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 961807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 962807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 963807736f6SSven Eckelmann bat_priv->tt.last_changeset_len = 0; 964807736f6SSven Eckelmann bat_priv->tt.last_changeset = NULL; 965e1bf0c14SMarek Lindner tt_change_len = batadv_tt_len(tt_diff_entries_count); 966be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 967e1bf0c14SMarek Lindner if (tt_diff_entries_count > 0) { 968be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 969a73105b8SAntonio Quartulli * instead of providing the diff 970a73105b8SAntonio Quartulli */ 971e1bf0c14SMarek Lindner bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); 972807736f6SSven Eckelmann if (bat_priv->tt.last_changeset) { 973e1bf0c14SMarek Lindner memcpy(bat_priv->tt.last_changeset, 974e1bf0c14SMarek Lindner tt_change, tt_change_len); 975e1bf0c14SMarek Lindner bat_priv->tt.last_changeset_len = tt_diff_len; 976a73105b8SAntonio Quartulli } 977a73105b8SAntonio Quartulli } 978807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 979c6c8fea2SSven Eckelmann 980e1bf0c14SMarek Lindner container_register: 981e1bf0c14SMarek Lindner batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, 9827ea7b4a1SAntonio Quartulli tvlv_len); 983e1bf0c14SMarek Lindner kfree(tt_data); 984c6c8fea2SSven Eckelmann } 985c6c8fea2SSven Eckelmann 98608c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) 987c6c8fea2SSven Eckelmann { 988c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 98956303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 990807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 99156303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 99285766a82SAntonio Quartulli struct batadv_tt_local_entry *tt_local; 99356303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 9947ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 995c6c8fea2SSven Eckelmann struct hlist_head *head; 9967ea7b4a1SAntonio Quartulli unsigned short vid; 9976b5e971aSSven Eckelmann u32 i; 99885766a82SAntonio Quartulli int last_seen_secs; 99985766a82SAntonio Quartulli int last_seen_msecs; 100085766a82SAntonio Quartulli unsigned long last_seen_jiffies; 100185766a82SAntonio Quartulli bool no_purge; 10026b5e971aSSven Eckelmann u16 np_flag = BATADV_TT_CLIENT_NOPURGE; 1003c6c8fea2SSven Eckelmann 100430da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 100530da63a6SMarek Lindner if (!primary_if) 100632ae9b22SMarek Lindner goto out; 1007c6c8fea2SSven Eckelmann 100886ceb360SSven Eckelmann seq_printf(seq, 10097ea7b4a1SAntonio Quartulli "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", 10106b5e971aSSven Eckelmann net_dev->name, (u8)atomic_read(&bat_priv->tt.vn)); 1011dd24ddb2SAntonio Quartulli seq_printf(seq, " %-13s %s %-8s %-9s (%-10s)\n", "Client", "VID", 10127ea7b4a1SAntonio Quartulli "Flags", "Last seen", "CRC"); 1013c6c8fea2SSven Eckelmann 1014c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1015c6c8fea2SSven Eckelmann head = &hash->table[i]; 1016c6c8fea2SSven Eckelmann 10177aadf889SMarek Lindner rcu_read_lock(); 1018b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 10197aadf889SMarek Lindner head, hash_entry) { 102085766a82SAntonio Quartulli tt_local = container_of(tt_common_entry, 102185766a82SAntonio Quartulli struct batadv_tt_local_entry, 102285766a82SAntonio Quartulli common); 10237ea7b4a1SAntonio Quartulli vid = tt_common_entry->vid; 102485766a82SAntonio Quartulli last_seen_jiffies = jiffies - tt_local->last_seen; 102585766a82SAntonio Quartulli last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 102685766a82SAntonio Quartulli last_seen_secs = last_seen_msecs / 1000; 102785766a82SAntonio Quartulli last_seen_msecs = last_seen_msecs % 1000; 102885766a82SAntonio Quartulli 102985766a82SAntonio Quartulli no_purge = tt_common_entry->flags & np_flag; 103085766a82SAntonio Quartulli 10317ea7b4a1SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 10327ea7b4a1SAntonio Quartulli if (!vlan) { 10337ea7b4a1SAntonio Quartulli seq_printf(seq, "Cannot retrieve VLAN %d\n", 10347ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(vid)); 10357ea7b4a1SAntonio Quartulli continue; 10367ea7b4a1SAntonio Quartulli } 10377ea7b4a1SAntonio Quartulli 10387ea7b4a1SAntonio Quartulli seq_printf(seq, 1039dd24ddb2SAntonio Quartulli " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n", 104048100bacSAntonio Quartulli tt_common_entry->addr, 104116052789SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 1042a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1043a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 104485766a82SAntonio Quartulli no_purge ? 'P' : '.', 1045a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1046a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_NEW) ? 'N' : '.'), 1047a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1048a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_PENDING) ? 'X' : '.'), 1049a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1050a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1051a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1052a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1053a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_secs, 10547ea7b4a1SAntonio Quartulli no_purge ? 0 : last_seen_msecs, 10557ea7b4a1SAntonio Quartulli vlan->tt.crc); 10567ea7b4a1SAntonio Quartulli 10579c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 1058c6c8fea2SSven Eckelmann } 10597aadf889SMarek Lindner rcu_read_unlock(); 1060c6c8fea2SSven Eckelmann } 106132ae9b22SMarek Lindner out: 106232ae9b22SMarek Lindner if (primary_if) 106382047ad7SSven Eckelmann batadv_hardif_put(primary_if); 106430da63a6SMarek Lindner return 0; 1065c6c8fea2SSven Eckelmann } 1066c6c8fea2SSven Eckelmann 106756303d34SSven Eckelmann static void 106856303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv, 106956303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry, 10706b5e971aSSven Eckelmann u16 flags, const char *message) 1071c6c8fea2SSven Eckelmann { 10723abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, flags); 1073c6c8fea2SSven Eckelmann 1074015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 1075015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 10769cfc7bd6SSven Eckelmann * response issued before the net ttvn increment (consistency check) 10779cfc7bd6SSven Eckelmann */ 1078acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; 1079c566dbbeSAntonio Quartulli 108039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 108116052789SAntonio Quartulli "Local tt entry (%pM, vid: %d) pending to be removed: %s\n", 108216052789SAntonio Quartulli tt_local_entry->common.addr, 108316052789SAntonio Quartulli BATADV_PRINT_VID(tt_local_entry->common.vid), message); 1084c6c8fea2SSven Eckelmann } 1085c6c8fea2SSven Eckelmann 10867f91d06cSAntonio Quartulli /** 10877f91d06cSAntonio Quartulli * batadv_tt_local_remove - logically remove an entry from the local table 10887f91d06cSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 10897f91d06cSAntonio Quartulli * @addr: the MAC address of the client to remove 1090c018ad3dSAntonio Quartulli * @vid: VLAN identifier 10917f91d06cSAntonio Quartulli * @message: message to append to the log on deletion 10927f91d06cSAntonio Quartulli * @roaming: true if the deletion is due to a roaming event 10937f91d06cSAntonio Quartulli * 109462fe710fSSven Eckelmann * Return: the flags assigned to the local entry before being deleted 10957f91d06cSAntonio Quartulli */ 10966b5e971aSSven Eckelmann u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, 10976b5e971aSSven Eckelmann unsigned short vid, const char *message, 10986b5e971aSSven Eckelmann bool roaming) 1099c6c8fea2SSven Eckelmann { 1100170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 11016b5e971aSSven Eckelmann u16 flags, curr_flags = BATADV_NO_FLAGS; 110235df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 1103ef72706aSMarek Lindner void *tt_entry_exists; 1104c6c8fea2SSven Eckelmann 1105c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 11067683fdc1SAntonio Quartulli if (!tt_local_entry) 11077683fdc1SAntonio Quartulli goto out; 11087683fdc1SAntonio Quartulli 11097f91d06cSAntonio Quartulli curr_flags = tt_local_entry->common.flags; 11107f91d06cSAntonio Quartulli 1111acd34afaSSven Eckelmann flags = BATADV_TT_CLIENT_DEL; 1112068ee6e2SAntonio Quartulli /* if this global entry addition is due to a roaming, the node has to 1113068ee6e2SAntonio Quartulli * mark the local entry as "roamed" in order to correctly reroute 1114068ee6e2SAntonio Quartulli * packets later 1115068ee6e2SAntonio Quartulli */ 11167c1fd91dSAntonio Quartulli if (roaming) { 1117acd34afaSSven Eckelmann flags |= BATADV_TT_CLIENT_ROAM; 11187c1fd91dSAntonio Quartulli /* mark the local client as ROAMed */ 11197c1fd91dSAntonio Quartulli tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 11207c1fd91dSAntonio Quartulli } 112142d0b044SSven Eckelmann 1122068ee6e2SAntonio Quartulli if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { 1123068ee6e2SAntonio Quartulli batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, 1124068ee6e2SAntonio Quartulli message); 1125068ee6e2SAntonio Quartulli goto out; 1126068ee6e2SAntonio Quartulli } 1127068ee6e2SAntonio Quartulli /* if this client has been added right now, it is possible to 1128068ee6e2SAntonio Quartulli * immediately purge it 1129068ee6e2SAntonio Quartulli */ 11303abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); 1131ef72706aSMarek Lindner 1132ef72706aSMarek Lindner tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, 1133ef72706aSMarek Lindner batadv_compare_tt, 1134ef72706aSMarek Lindner batadv_choose_tt, 1135ef72706aSMarek Lindner &tt_local_entry->common); 1136ef72706aSMarek Lindner if (!tt_entry_exists) 1137ef72706aSMarek Lindner goto out; 1138ef72706aSMarek Lindner 1139ef72706aSMarek Lindner /* extra call to free the local tt entry */ 1140068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 11417f91d06cSAntonio Quartulli 114235df3b29SAntonio Quartulli /* decrease the reference held for this vlan */ 114335df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 1144354136bcSMarek Lindner if (!vlan) 1145354136bcSMarek Lindner goto out; 1146354136bcSMarek Lindner 11479c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 11489c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 114935df3b29SAntonio Quartulli 11507683fdc1SAntonio Quartulli out: 11517683fdc1SAntonio Quartulli if (tt_local_entry) 1152a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 11537f91d06cSAntonio Quartulli 11547f91d06cSAntonio Quartulli return curr_flags; 1155c6c8fea2SSven Eckelmann } 1156c6c8fea2SSven Eckelmann 1157a19d3d85SMarek Lindner /** 1158a19d3d85SMarek Lindner * batadv_tt_local_purge_list - purge inactive tt local entries 1159a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1160a19d3d85SMarek Lindner * @head: pointer to the list containing the local tt entries 1161a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1162a19d3d85SMarek Lindner * inactive or not 1163a19d3d85SMarek Lindner */ 116456303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 1165a19d3d85SMarek Lindner struct hlist_head *head, 1166a19d3d85SMarek Lindner int timeout) 1167c6c8fea2SSven Eckelmann { 116856303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 116956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1170b67bfe0dSSasha Levin struct hlist_node *node_tmp; 1171acd34afaSSven Eckelmann 1172b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, 1173acd34afaSSven Eckelmann hash_entry) { 1174acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common_entry, 117556303d34SSven Eckelmann struct batadv_tt_local_entry, 117656303d34SSven Eckelmann common); 1177acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) 1178acd34afaSSven Eckelmann continue; 1179acd34afaSSven Eckelmann 1180acd34afaSSven Eckelmann /* entry already marked for deletion */ 1181acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 1182acd34afaSSven Eckelmann continue; 1183acd34afaSSven Eckelmann 1184a19d3d85SMarek Lindner if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) 1185acd34afaSSven Eckelmann continue; 1186acd34afaSSven Eckelmann 1187acd34afaSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 1188acd34afaSSven Eckelmann BATADV_TT_CLIENT_DEL, "timed out"); 1189acd34afaSSven Eckelmann } 1190acd34afaSSven Eckelmann } 1191acd34afaSSven Eckelmann 1192a19d3d85SMarek Lindner /** 1193a19d3d85SMarek Lindner * batadv_tt_local_purge - purge inactive tt local entries 1194a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1195a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1196a19d3d85SMarek Lindner * inactive or not 1197a19d3d85SMarek Lindner */ 1198a19d3d85SMarek Lindner static void batadv_tt_local_purge(struct batadv_priv *bat_priv, 1199a19d3d85SMarek Lindner int timeout) 1200acd34afaSSven Eckelmann { 1201807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 1202c6c8fea2SSven Eckelmann struct hlist_head *head; 12037683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 12046b5e971aSSven Eckelmann u32 i; 1205c6c8fea2SSven Eckelmann 1206c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1207c6c8fea2SSven Eckelmann head = &hash->table[i]; 12087683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1209c6c8fea2SSven Eckelmann 12107683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1211a19d3d85SMarek Lindner batadv_tt_local_purge_list(bat_priv, head, timeout); 12127683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1213c6c8fea2SSven Eckelmann } 1214c6c8fea2SSven Eckelmann } 1215c6c8fea2SSven Eckelmann 121656303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) 1217c6c8fea2SSven Eckelmann { 12185bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 1219a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 122056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 122156303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 122235df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 1223b67bfe0dSSasha Levin struct hlist_node *node_tmp; 12247683fdc1SAntonio Quartulli struct hlist_head *head; 12256b5e971aSSven Eckelmann u32 i; 1226a73105b8SAntonio Quartulli 1227807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 1228c6c8fea2SSven Eckelmann return; 1229c6c8fea2SSven Eckelmann 1230807736f6SSven Eckelmann hash = bat_priv->tt.local_hash; 1231a73105b8SAntonio Quartulli 1232a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1233a73105b8SAntonio Quartulli head = &hash->table[i]; 1234a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 1235a73105b8SAntonio Quartulli 1236a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 1237b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 1238a73105b8SAntonio Quartulli head, hash_entry) { 1239b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 124056303d34SSven Eckelmann tt_local = container_of(tt_common_entry, 124156303d34SSven Eckelmann struct batadv_tt_local_entry, 124248100bacSAntonio Quartulli common); 124335df3b29SAntonio Quartulli 124435df3b29SAntonio Quartulli /* decrease the reference held for this vlan */ 124535df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, 124635df3b29SAntonio Quartulli tt_common_entry->vid); 1247354136bcSMarek Lindner if (vlan) { 12489c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 12499c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 1250354136bcSMarek Lindner } 125135df3b29SAntonio Quartulli 125256303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 1253a73105b8SAntonio Quartulli } 1254a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 1255a73105b8SAntonio Quartulli } 1256a73105b8SAntonio Quartulli 12571a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 1258a73105b8SAntonio Quartulli 1259807736f6SSven Eckelmann bat_priv->tt.local_hash = NULL; 1260c6c8fea2SSven Eckelmann } 1261c6c8fea2SSven Eckelmann 126256303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv) 1263c6c8fea2SSven Eckelmann { 1264807736f6SSven Eckelmann if (bat_priv->tt.global_hash) 12655346c35eSSven Eckelmann return 0; 1266c6c8fea2SSven Eckelmann 1267807736f6SSven Eckelmann bat_priv->tt.global_hash = batadv_hash_new(1024); 1268c6c8fea2SSven Eckelmann 1269807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 12705346c35eSSven Eckelmann return -ENOMEM; 1271c6c8fea2SSven Eckelmann 1272dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.global_hash, 1273dec05074SAntonio Quartulli &batadv_tt_global_hash_lock_class_key); 1274dec05074SAntonio Quartulli 12755346c35eSSven Eckelmann return 0; 1276c6c8fea2SSven Eckelmann } 1277c6c8fea2SSven Eckelmann 127856303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) 1279a73105b8SAntonio Quartulli { 128056303d34SSven Eckelmann struct batadv_tt_change_node *entry, *safe; 1281a73105b8SAntonio Quartulli 1282807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 1283a73105b8SAntonio Quartulli 1284807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 1285a73105b8SAntonio Quartulli list) { 1286a73105b8SAntonio Quartulli list_del(&entry->list); 1287a73105b8SAntonio Quartulli kfree(entry); 1288a73105b8SAntonio Quartulli } 1289a73105b8SAntonio Quartulli 1290807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 1291807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 1292a73105b8SAntonio Quartulli } 1293a73105b8SAntonio Quartulli 129462fe710fSSven Eckelmann /** 1295d15cd622SAntonio Quartulli * batadv_tt_global_orig_entry_find - find a TT orig_list_entry 1296d15cd622SAntonio Quartulli * @entry: the TT global entry where the orig_list_entry has to be 1297d15cd622SAntonio Quartulli * extracted from 1298d15cd622SAntonio Quartulli * @orig_node: the originator for which the orig_list_entry has to be found 129962fe710fSSven Eckelmann * 1300d15cd622SAntonio Quartulli * retrieve the orig_tt_list_entry belonging to orig_node from the 1301d657e621SAntonio Quartulli * batadv_tt_global_entry list 1302d657e621SAntonio Quartulli * 130362fe710fSSven Eckelmann * Return: it with an increased refcounter, NULL if not found 1304d657e621SAntonio Quartulli */ 1305d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry * 1306d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, 1307d657e621SAntonio Quartulli const struct batadv_orig_node *orig_node) 1308d657e621SAntonio Quartulli { 1309d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; 1310d657e621SAntonio Quartulli const struct hlist_head *head; 1311d657e621SAntonio Quartulli 1312d657e621SAntonio Quartulli rcu_read_lock(); 1313d657e621SAntonio Quartulli head = &entry->orig_list; 1314b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { 1315d657e621SAntonio Quartulli if (tmp_orig_entry->orig_node != orig_node) 1316d657e621SAntonio Quartulli continue; 13176e8ef69dSSven Eckelmann if (!kref_get_unless_zero(&tmp_orig_entry->refcount)) 1318d657e621SAntonio Quartulli continue; 1319d657e621SAntonio Quartulli 1320d657e621SAntonio Quartulli orig_entry = tmp_orig_entry; 1321d657e621SAntonio Quartulli break; 1322d657e621SAntonio Quartulli } 1323d657e621SAntonio Quartulli rcu_read_unlock(); 1324d657e621SAntonio Quartulli 1325d657e621SAntonio Quartulli return orig_entry; 1326d657e621SAntonio Quartulli } 1327d657e621SAntonio Quartulli 132862fe710fSSven Eckelmann /** 1329d15cd622SAntonio Quartulli * batadv_tt_global_entry_has_orig - check if a TT global entry is also handled 1330d15cd622SAntonio Quartulli * by a given originator 1331d15cd622SAntonio Quartulli * @entry: the TT global entry to check 1332d15cd622SAntonio Quartulli * @orig_node: the originator to search in the list 133362fe710fSSven Eckelmann * 133462fe710fSSven Eckelmann * find out if an orig_node is already in the list of a tt_global_entry. 133562fe710fSSven Eckelmann * 133662fe710fSSven Eckelmann * Return: true if found, false otherwise 1337db08e6e5SSimon Wunderlich */ 133856303d34SSven Eckelmann static bool 133956303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, 134056303d34SSven Eckelmann const struct batadv_orig_node *orig_node) 1341db08e6e5SSimon Wunderlich { 1342d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *orig_entry; 1343db08e6e5SSimon Wunderlich bool found = false; 1344db08e6e5SSimon Wunderlich 1345d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); 1346d657e621SAntonio Quartulli if (orig_entry) { 1347db08e6e5SSimon Wunderlich found = true; 1348d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 1349db08e6e5SSimon Wunderlich } 1350d657e621SAntonio Quartulli 1351db08e6e5SSimon Wunderlich return found; 1352db08e6e5SSimon Wunderlich } 1353db08e6e5SSimon Wunderlich 1354a513088dSSven Eckelmann static void 1355d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, 135656303d34SSven Eckelmann struct batadv_orig_node *orig_node, int ttvn) 1357db08e6e5SSimon Wunderlich { 135856303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1359db08e6e5SSimon Wunderlich 1360d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); 136130cfd02bSAntonio Quartulli if (orig_entry) { 136230cfd02bSAntonio Quartulli /* refresh the ttvn: the current value could be a bogus one that 136330cfd02bSAntonio Quartulli * was added during a "temporary client detection" 136430cfd02bSAntonio Quartulli */ 136530cfd02bSAntonio Quartulli orig_entry->ttvn = ttvn; 1366d657e621SAntonio Quartulli goto out; 136730cfd02bSAntonio Quartulli } 1368d657e621SAntonio Quartulli 1369db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 1370db08e6e5SSimon Wunderlich if (!orig_entry) 1371d657e621SAntonio Quartulli goto out; 1372db08e6e5SSimon Wunderlich 1373db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 13747c124391SSven Eckelmann kref_get(&orig_node->refcount); 13757ea7b4a1SAntonio Quartulli batadv_tt_global_size_inc(orig_node, tt_global->common.vid); 1376db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 1377db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 13786e8ef69dSSven Eckelmann kref_init(&orig_entry->refcount); 13796e8ef69dSSven Eckelmann kref_get(&orig_entry->refcount); 1380db08e6e5SSimon Wunderlich 1381d657e621SAntonio Quartulli spin_lock_bh(&tt_global->list_lock); 1382db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 1383d657e621SAntonio Quartulli &tt_global->orig_list); 1384d657e621SAntonio Quartulli spin_unlock_bh(&tt_global->list_lock); 13851d8ab8d3SLinus Lüssing atomic_inc(&tt_global->orig_list_count); 13861d8ab8d3SLinus Lüssing 1387d657e621SAntonio Quartulli out: 1388d657e621SAntonio Quartulli if (orig_entry) 1389d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 1390db08e6e5SSimon Wunderlich } 1391db08e6e5SSimon Wunderlich 1392d4ff40f6SAntonio Quartulli /** 1393d4ff40f6SAntonio Quartulli * batadv_tt_global_add - add a new TT global entry or update an existing one 1394d4ff40f6SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1395d4ff40f6SAntonio Quartulli * @orig_node: the originator announcing the client 1396d4ff40f6SAntonio Quartulli * @tt_addr: the mac address of the non-mesh client 1397c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1398d4ff40f6SAntonio Quartulli * @flags: TT flags that have to be set for this non-mesh client 1399d4ff40f6SAntonio Quartulli * @ttvn: the tt version number ever announcing this non-mesh client 1400d4ff40f6SAntonio Quartulli * 1401d4ff40f6SAntonio Quartulli * Add a new TT global entry for the given originator. If the entry already 1402d4ff40f6SAntonio Quartulli * exists add a new reference to the given originator (a global entry can have 1403d4ff40f6SAntonio Quartulli * references to multiple originators) and adjust the flags attribute to reflect 1404d4ff40f6SAntonio Quartulli * the function argument. 1405d4ff40f6SAntonio Quartulli * If a TT local entry exists for this non-mesh client remove it. 1406d4ff40f6SAntonio Quartulli * 1407d4ff40f6SAntonio Quartulli * The caller must hold orig_node refcount. 14081e5d49fcSAntonio Quartulli * 140962fe710fSSven Eckelmann * Return: true if the new entry has been added, false otherwise 1410d4ff40f6SAntonio Quartulli */ 14111e5d49fcSAntonio Quartulli static bool batadv_tt_global_add(struct batadv_priv *bat_priv, 141256303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1413c018ad3dSAntonio Quartulli const unsigned char *tt_addr, 14146b5e971aSSven Eckelmann unsigned short vid, u16 flags, u8 ttvn) 1415c6c8fea2SSven Eckelmann { 1416170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 1417170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 14181e5d49fcSAntonio Quartulli bool ret = false; 141980b3f58cSSimon Wunderlich int hash_added; 142056303d34SSven Eckelmann struct batadv_tt_common_entry *common; 14216b5e971aSSven Eckelmann u16 local_flags; 1422c6c8fea2SSven Eckelmann 1423cfd4f757SAntonio Quartulli /* ignore global entries from backbone nodes */ 1424cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) 1425cfd4f757SAntonio Quartulli return true; 1426cfd4f757SAntonio Quartulli 1427c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); 1428c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid); 1429068ee6e2SAntonio Quartulli 1430068ee6e2SAntonio Quartulli /* if the node already has a local client for this entry, it has to wait 1431068ee6e2SAntonio Quartulli * for a roaming advertisement instead of manually messing up the global 1432068ee6e2SAntonio Quartulli * table 1433068ee6e2SAntonio Quartulli */ 1434068ee6e2SAntonio Quartulli if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && 1435068ee6e2SAntonio Quartulli !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) 1436068ee6e2SAntonio Quartulli goto out; 1437c6c8fea2SSven Eckelmann 14382dafb49dSAntonio Quartulli if (!tt_global_entry) { 1439d4f44692SAntonio Quartulli tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); 14402dafb49dSAntonio Quartulli if (!tt_global_entry) 14417683fdc1SAntonio Quartulli goto out; 14427683fdc1SAntonio Quartulli 1443c0a55929SSven Eckelmann common = &tt_global_entry->common; 14448fdd0153SAntonio Quartulli ether_addr_copy(common->addr, tt_addr); 1445c018ad3dSAntonio Quartulli common->vid = vid; 1446db08e6e5SSimon Wunderlich 1447d4f44692SAntonio Quartulli common->flags = flags; 1448cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1449fdf79320SAntonio Quartulli /* node must store current time in case of roaming. This is 1450fdf79320SAntonio Quartulli * needed to purge this entry out on timeout (if nobody claims 1451fdf79320SAntonio Quartulli * it) 1452fdf79320SAntonio Quartulli */ 1453fdf79320SAntonio Quartulli if (flags & BATADV_TT_CLIENT_ROAM) 1454fdf79320SAntonio Quartulli tt_global_entry->roam_at = jiffies; 145592dcdf09SSven Eckelmann kref_init(&common->refcount); 145692dcdf09SSven Eckelmann kref_get(&common->refcount); 145730cfd02bSAntonio Quartulli common->added_at = jiffies; 1458db08e6e5SSimon Wunderlich 1459db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 14601d8ab8d3SLinus Lüssing atomic_set(&tt_global_entry->orig_list_count, 0); 1461db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 14627683fdc1SAntonio Quartulli 1463807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.global_hash, 1464a513088dSSven Eckelmann batadv_compare_tt, 1465c018ad3dSAntonio Quartulli batadv_choose_tt, common, 1466a513088dSSven Eckelmann &common->hash_entry); 146780b3f58cSSimon Wunderlich 146880b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 146980b3f58cSSimon Wunderlich /* remove the reference for the hash */ 1470a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 147180b3f58cSSimon Wunderlich goto out_remove; 147280b3f58cSSimon Wunderlich } 1473a73105b8SAntonio Quartulli } else { 1474068ee6e2SAntonio Quartulli common = &tt_global_entry->common; 147530cfd02bSAntonio Quartulli /* If there is already a global entry, we can use this one for 147630cfd02bSAntonio Quartulli * our processing. 1477068ee6e2SAntonio Quartulli * But if we are trying to add a temporary client then here are 1478068ee6e2SAntonio Quartulli * two options at this point: 1479068ee6e2SAntonio Quartulli * 1) the global client is not a temporary client: the global 1480068ee6e2SAntonio Quartulli * client has to be left as it is, temporary information 1481068ee6e2SAntonio Quartulli * should never override any already known client state 1482068ee6e2SAntonio Quartulli * 2) the global client is a temporary client: purge the 1483068ee6e2SAntonio Quartulli * originator list and add the new one orig_entry 148430cfd02bSAntonio Quartulli */ 1485068ee6e2SAntonio Quartulli if (flags & BATADV_TT_CLIENT_TEMP) { 1486068ee6e2SAntonio Quartulli if (!(common->flags & BATADV_TT_CLIENT_TEMP)) 148730cfd02bSAntonio Quartulli goto out; 1488068ee6e2SAntonio Quartulli if (batadv_tt_global_entry_has_orig(tt_global_entry, 1489068ee6e2SAntonio Quartulli orig_node)) 1490068ee6e2SAntonio Quartulli goto out_remove; 1491068ee6e2SAntonio Quartulli batadv_tt_global_del_orig_list(tt_global_entry); 1492068ee6e2SAntonio Quartulli goto add_orig_entry; 1493068ee6e2SAntonio Quartulli } 149430cfd02bSAntonio Quartulli 149530cfd02bSAntonio Quartulli /* if the client was temporary added before receiving the first 1496a6cb3909SSimon Wunderlich * OGM announcing it, we have to clear the TEMP flag. Also, 1497a6cb3909SSimon Wunderlich * remove the previous temporary orig node and re-add it 1498a6cb3909SSimon Wunderlich * if required. If the orig entry changed, the new one which 1499a6cb3909SSimon Wunderlich * is a non-temporary entry is preferred. 150030cfd02bSAntonio Quartulli */ 1501a6cb3909SSimon Wunderlich if (common->flags & BATADV_TT_CLIENT_TEMP) { 1502a6cb3909SSimon Wunderlich batadv_tt_global_del_orig_list(tt_global_entry); 1503068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_TEMP; 1504a6cb3909SSimon Wunderlich } 1505db08e6e5SSimon Wunderlich 1506e9c00136SAntonio Quartulli /* the change can carry possible "attribute" flags like the 1507e9c00136SAntonio Quartulli * TT_CLIENT_WIFI, therefore they have to be copied in the 1508e9c00136SAntonio Quartulli * client entry 1509e9c00136SAntonio Quartulli */ 1510ad7e2c46SSimon Wunderlich common->flags |= flags; 1511e9c00136SAntonio Quartulli 1512acd34afaSSven Eckelmann /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 1513acd34afaSSven Eckelmann * one originator left in the list and we previously received a 1514db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 1515db08e6e5SSimon Wunderlich * 1516db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 1517db08e6e5SSimon Wunderlich * new one. 1518db08e6e5SSimon Wunderlich */ 1519068ee6e2SAntonio Quartulli if (common->flags & BATADV_TT_CLIENT_ROAM) { 1520a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1521068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_ROAM; 1522cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1523c6c8fea2SSven Eckelmann } 1524db08e6e5SSimon Wunderlich } 1525068ee6e2SAntonio Quartulli add_orig_entry: 152630cfd02bSAntonio Quartulli /* add the new orig_entry (if needed) or update it */ 1527d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); 1528db08e6e5SSimon Wunderlich 152939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 153016052789SAntonio Quartulli "Creating new global tt entry: %pM (vid: %d, via %pM)\n", 153116052789SAntonio Quartulli common->addr, BATADV_PRINT_VID(common->vid), 153216052789SAntonio Quartulli orig_node->orig); 15331e5d49fcSAntonio Quartulli ret = true; 1534a73105b8SAntonio Quartulli 153580b3f58cSSimon Wunderlich out_remove: 1536c5caf4efSLinus Lüssing /* Do not remove multicast addresses from the local hash on 1537c5caf4efSLinus Lüssing * global additions 1538c5caf4efSLinus Lüssing */ 1539c5caf4efSLinus Lüssing if (is_multicast_ether_addr(tt_addr)) 1540c5caf4efSLinus Lüssing goto out; 15417f91d06cSAntonio Quartulli 1542c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 1543c018ad3dSAntonio Quartulli local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, 1544acd34afaSSven Eckelmann "global tt received", 1545c1d07431SAntonio Quartulli flags & BATADV_TT_CLIENT_ROAM); 15467f91d06cSAntonio Quartulli tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; 15477f91d06cSAntonio Quartulli 1548068ee6e2SAntonio Quartulli if (!(flags & BATADV_TT_CLIENT_ROAM)) 1549068ee6e2SAntonio Quartulli /* this is a normal global add. Therefore the client is not in a 1550068ee6e2SAntonio Quartulli * roaming state anymore. 1551068ee6e2SAntonio Quartulli */ 1552068ee6e2SAntonio Quartulli tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 1553068ee6e2SAntonio Quartulli 15547683fdc1SAntonio Quartulli out: 15557683fdc1SAntonio Quartulli if (tt_global_entry) 1556a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1557068ee6e2SAntonio Quartulli if (tt_local_entry) 1558068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 15597683fdc1SAntonio Quartulli return ret; 1560c6c8fea2SSven Eckelmann } 1561c6c8fea2SSven Eckelmann 15621b371d13SSimon Wunderlich /** 15631b371d13SSimon Wunderlich * batadv_transtable_best_orig - Get best originator list entry from tt entry 15644627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1565981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be analyzed 1566981d8900SSven Eckelmann * 1567981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 156862fe710fSSven Eckelmann * Return: best originator list entry or NULL on errors. 1569981d8900SSven Eckelmann */ 1570981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry * 15714627456aSAntonio Quartulli batadv_transtable_best_orig(struct batadv_priv *bat_priv, 15724627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry) 1573981d8900SSven Eckelmann { 15744627456aSAntonio Quartulli struct batadv_neigh_node *router, *best_router = NULL; 15754627456aSAntonio Quartulli struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; 1576981d8900SSven Eckelmann struct hlist_head *head; 1577981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; 1578981d8900SSven Eckelmann 1579981d8900SSven Eckelmann head = &tt_global_entry->orig_list; 1580b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 15817351a482SSimon Wunderlich router = batadv_orig_router_get(orig_entry->orig_node, 15827351a482SSimon Wunderlich BATADV_IF_DEFAULT); 1583981d8900SSven Eckelmann if (!router) 1584981d8900SSven Eckelmann continue; 1585981d8900SSven Eckelmann 15864627456aSAntonio Quartulli if (best_router && 158789652331SSimon Wunderlich bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, 158889652331SSimon Wunderlich best_router, BATADV_IF_DEFAULT) <= 0) { 158925bb2509SSven Eckelmann batadv_neigh_node_put(router); 15904627456aSAntonio Quartulli continue; 1591981d8900SSven Eckelmann } 1592981d8900SSven Eckelmann 15934627456aSAntonio Quartulli /* release the refcount for the "old" best */ 15944627456aSAntonio Quartulli if (best_router) 159525bb2509SSven Eckelmann batadv_neigh_node_put(best_router); 15964627456aSAntonio Quartulli 15974627456aSAntonio Quartulli best_entry = orig_entry; 15984627456aSAntonio Quartulli best_router = router; 1599981d8900SSven Eckelmann } 1600981d8900SSven Eckelmann 16014627456aSAntonio Quartulli if (best_router) 160225bb2509SSven Eckelmann batadv_neigh_node_put(best_router); 16034627456aSAntonio Quartulli 1604981d8900SSven Eckelmann return best_entry; 1605981d8900SSven Eckelmann } 1606981d8900SSven Eckelmann 16071b371d13SSimon Wunderlich /** 16081b371d13SSimon Wunderlich * batadv_tt_global_print_entry - print all orig nodes who announce the address 1609981d8900SSven Eckelmann * for this global entry 16104627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1611981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be printed 1612981d8900SSven Eckelmann * @seq: debugfs table seq_file struct 1613981d8900SSven Eckelmann * 1614981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 1615db08e6e5SSimon Wunderlich */ 1616a513088dSSven Eckelmann static void 16174627456aSAntonio Quartulli batadv_tt_global_print_entry(struct batadv_priv *bat_priv, 16184627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry, 1619db08e6e5SSimon Wunderlich struct seq_file *seq) 1620db08e6e5SSimon Wunderlich { 1621981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry; 162256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 16237ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 16247ea7b4a1SAntonio Quartulli struct hlist_head *head; 16256b5e971aSSven Eckelmann u8 last_ttvn; 16266b5e971aSSven Eckelmann u16 flags; 1627db08e6e5SSimon Wunderlich 1628db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 1629981d8900SSven Eckelmann flags = tt_common_entry->flags; 1630981d8900SSven Eckelmann 16314627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 1632981d8900SSven Eckelmann if (best_entry) { 16337ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(best_entry->orig_node, 16347ea7b4a1SAntonio Quartulli tt_common_entry->vid); 16357ea7b4a1SAntonio Quartulli if (!vlan) { 16367ea7b4a1SAntonio Quartulli seq_printf(seq, 16377ea7b4a1SAntonio Quartulli " * Cannot retrieve VLAN %d for originator %pM\n", 16387ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 16397ea7b4a1SAntonio Quartulli best_entry->orig_node->orig); 16407ea7b4a1SAntonio Quartulli goto print_list; 16417ea7b4a1SAntonio Quartulli } 16427ea7b4a1SAntonio Quartulli 1643981d8900SSven Eckelmann last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); 1644f9d8a537SAntonio Quartulli seq_printf(seq, 1645dd24ddb2SAntonio Quartulli " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1646981d8900SSven Eckelmann '*', tt_global_entry->common.addr, 164716052789SAntonio Quartulli BATADV_PRINT_VID(tt_global_entry->common.vid), 1648981d8900SSven Eckelmann best_entry->ttvn, best_entry->orig_node->orig, 16497ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1650a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 1651a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1652a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1653a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.')); 16547ea7b4a1SAntonio Quartulli 16557ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 1656981d8900SSven Eckelmann } 1657db08e6e5SSimon Wunderlich 16587ea7b4a1SAntonio Quartulli print_list: 1659db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1660db08e6e5SSimon Wunderlich 1661b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1662981d8900SSven Eckelmann if (best_entry == orig_entry) 1663981d8900SSven Eckelmann continue; 1664981d8900SSven Eckelmann 16657ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, 16667ea7b4a1SAntonio Quartulli tt_common_entry->vid); 16677ea7b4a1SAntonio Quartulli if (!vlan) { 16687ea7b4a1SAntonio Quartulli seq_printf(seq, 16697ea7b4a1SAntonio Quartulli " + Cannot retrieve VLAN %d for originator %pM\n", 16707ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 16717ea7b4a1SAntonio Quartulli orig_entry->orig_node->orig); 16727ea7b4a1SAntonio Quartulli continue; 16737ea7b4a1SAntonio Quartulli } 16747ea7b4a1SAntonio Quartulli 1675db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 167616052789SAntonio Quartulli seq_printf(seq, 1677dd24ddb2SAntonio Quartulli " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1678981d8900SSven Eckelmann '+', tt_global_entry->common.addr, 167916052789SAntonio Quartulli BATADV_PRINT_VID(tt_global_entry->common.vid), 1680981d8900SSven Eckelmann orig_entry->ttvn, orig_entry->orig_node->orig, 16817ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1682a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 1683a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1684a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1685a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.')); 16867ea7b4a1SAntonio Quartulli 16877ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 1688db08e6e5SSimon Wunderlich } 1689db08e6e5SSimon Wunderlich } 1690db08e6e5SSimon Wunderlich 169108c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 1692c6c8fea2SSven Eckelmann { 1693c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 169456303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 1695807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 169656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 169756303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 169856303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 1699c6c8fea2SSven Eckelmann struct hlist_head *head; 17006b5e971aSSven Eckelmann u32 i; 1701c6c8fea2SSven Eckelmann 170230da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 170330da63a6SMarek Lindner if (!primary_if) 170432ae9b22SMarek Lindner goto out; 1705c6c8fea2SSven Eckelmann 17062dafb49dSAntonio Quartulli seq_printf(seq, 17072dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 1708c6c8fea2SSven Eckelmann net_dev->name); 170916052789SAntonio Quartulli seq_printf(seq, " %-13s %s %s %-15s %s (%-10s) %s\n", 171016052789SAntonio Quartulli "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)", 171116052789SAntonio Quartulli "CRC", "Flags"); 1712c6c8fea2SSven Eckelmann 1713c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1714c6c8fea2SSven Eckelmann head = &hash->table[i]; 1715c6c8fea2SSven Eckelmann 17167aadf889SMarek Lindner rcu_read_lock(); 1717b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 17187aadf889SMarek Lindner head, hash_entry) { 171956303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 172056303d34SSven Eckelmann struct batadv_tt_global_entry, 172148100bacSAntonio Quartulli common); 17224627456aSAntonio Quartulli batadv_tt_global_print_entry(bat_priv, tt_global, seq); 1723c6c8fea2SSven Eckelmann } 17247aadf889SMarek Lindner rcu_read_unlock(); 1725c6c8fea2SSven Eckelmann } 172632ae9b22SMarek Lindner out: 172732ae9b22SMarek Lindner if (primary_if) 172882047ad7SSven Eckelmann batadv_hardif_put(primary_if); 172930da63a6SMarek Lindner return 0; 1730c6c8fea2SSven Eckelmann } 1731c6c8fea2SSven Eckelmann 17321d8ab8d3SLinus Lüssing /** 1733433ff98fSMarek Lindner * _batadv_tt_global_del_orig_entry - remove and free an orig_entry 17341d8ab8d3SLinus Lüssing * @tt_global_entry: the global entry to remove the orig_entry from 17351d8ab8d3SLinus Lüssing * @orig_entry: the orig entry to remove and free 17361d8ab8d3SLinus Lüssing * 17371d8ab8d3SLinus Lüssing * Remove an orig_entry from its list in the given tt_global_entry and 17381d8ab8d3SLinus Lüssing * free this orig_entry afterwards. 1739433ff98fSMarek Lindner * 1740433ff98fSMarek Lindner * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is 1741433ff98fSMarek Lindner * part of a list. 17421d8ab8d3SLinus Lüssing */ 17431d8ab8d3SLinus Lüssing static void 1744433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, 17451d8ab8d3SLinus Lüssing struct batadv_tt_orig_list_entry *orig_entry) 17461d8ab8d3SLinus Lüssing { 17472c72d655SSven Eckelmann lockdep_assert_held(&tt_global_entry->list_lock); 17482c72d655SSven Eckelmann 17491d8ab8d3SLinus Lüssing batadv_tt_global_size_dec(orig_entry->orig_node, 17501d8ab8d3SLinus Lüssing tt_global_entry->common.vid); 17511d8ab8d3SLinus Lüssing atomic_dec(&tt_global_entry->orig_list_count); 1752433ff98fSMarek Lindner /* requires holding tt_global_entry->list_lock and orig_entry->list 1753433ff98fSMarek Lindner * being part of a list 1754433ff98fSMarek Lindner */ 17551d8ab8d3SLinus Lüssing hlist_del_rcu(&orig_entry->list); 17561d8ab8d3SLinus Lüssing batadv_tt_orig_list_entry_free_ref(orig_entry); 17571d8ab8d3SLinus Lüssing } 17581d8ab8d3SLinus Lüssing 1759db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 1760a513088dSSven Eckelmann static void 176156303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) 1762db08e6e5SSimon Wunderlich { 1763db08e6e5SSimon Wunderlich struct hlist_head *head; 1764b67bfe0dSSasha Levin struct hlist_node *safe; 176556303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1766db08e6e5SSimon Wunderlich 1767db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1768db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 17691d8ab8d3SLinus Lüssing hlist_for_each_entry_safe(orig_entry, safe, head, list) 1770433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); 1771db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1772db08e6e5SSimon Wunderlich } 1773db08e6e5SSimon Wunderlich 17741d8ab8d3SLinus Lüssing /** 17751d8ab8d3SLinus Lüssing * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry 17761d8ab8d3SLinus Lüssing * @bat_priv: the bat priv with all the soft interface information 17771d8ab8d3SLinus Lüssing * @tt_global_entry: the global entry to remove the orig_node from 17781d8ab8d3SLinus Lüssing * @orig_node: the originator announcing the client 17791d8ab8d3SLinus Lüssing * @message: message to append to the log on deletion 17801d8ab8d3SLinus Lüssing * 17811d8ab8d3SLinus Lüssing * Remove the given orig_node and its according orig_entry from the given 17821d8ab8d3SLinus Lüssing * global tt entry. 17831d8ab8d3SLinus Lüssing */ 1784a513088dSSven Eckelmann static void 17851d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, 178656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 178756303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1788db08e6e5SSimon Wunderlich const char *message) 1789db08e6e5SSimon Wunderlich { 1790db08e6e5SSimon Wunderlich struct hlist_head *head; 1791b67bfe0dSSasha Levin struct hlist_node *safe; 179256303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 179316052789SAntonio Quartulli unsigned short vid; 1794db08e6e5SSimon Wunderlich 1795db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1796db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1797b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1798db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 179916052789SAntonio Quartulli vid = tt_global_entry->common.vid; 180039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 180116052789SAntonio Quartulli "Deleting %pM from global tt entry %pM (vid: %d): %s\n", 18021eda58bfSSven Eckelmann orig_node->orig, 180316052789SAntonio Quartulli tt_global_entry->common.addr, 180416052789SAntonio Quartulli BATADV_PRINT_VID(vid), message); 1805433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(tt_global_entry, 18061d8ab8d3SLinus Lüssing orig_entry); 1807db08e6e5SSimon Wunderlich } 1808db08e6e5SSimon Wunderlich } 1809db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1810db08e6e5SSimon Wunderlich } 1811db08e6e5SSimon Wunderlich 1812db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 1813acd34afaSSven Eckelmann * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the 1814acd34afaSSven Eckelmann * timer, otherwise we simply remove the originator scheduled for deletion. 1815db08e6e5SSimon Wunderlich */ 1816a513088dSSven Eckelmann static void 181756303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, 181856303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 181956303d34SSven Eckelmann struct batadv_orig_node *orig_node, 182056303d34SSven Eckelmann const char *message) 1821db08e6e5SSimon Wunderlich { 1822db08e6e5SSimon Wunderlich bool last_entry = true; 1823db08e6e5SSimon Wunderlich struct hlist_head *head; 182456303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1825db08e6e5SSimon Wunderlich 1826db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 1827db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 1828db08e6e5SSimon Wunderlich */ 1829db08e6e5SSimon Wunderlich 1830db08e6e5SSimon Wunderlich rcu_read_lock(); 1831db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1832b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1833db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 1834db08e6e5SSimon Wunderlich last_entry = false; 1835db08e6e5SSimon Wunderlich break; 1836db08e6e5SSimon Wunderlich } 1837db08e6e5SSimon Wunderlich } 1838db08e6e5SSimon Wunderlich rcu_read_unlock(); 1839db08e6e5SSimon Wunderlich 1840db08e6e5SSimon Wunderlich if (last_entry) { 1841db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 1842acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 1843db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 1844db08e6e5SSimon Wunderlich } else 1845db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 1846db08e6e5SSimon Wunderlich * one and can still use the other one. 1847db08e6e5SSimon Wunderlich */ 18481d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 1849db08e6e5SSimon Wunderlich orig_node, message); 1850db08e6e5SSimon Wunderlich } 1851db08e6e5SSimon Wunderlich 1852c018ad3dSAntonio Quartulli /** 1853c018ad3dSAntonio Quartulli * batadv_tt_global_del - remove a client from the global table 1854c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1855c018ad3dSAntonio Quartulli * @orig_node: an originator serving this client 1856c018ad3dSAntonio Quartulli * @addr: the mac address of the client 1857c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1858c018ad3dSAntonio Quartulli * @message: a message explaining the reason for deleting the client to print 1859c018ad3dSAntonio Quartulli * for debugging purpose 1860c018ad3dSAntonio Quartulli * @roaming: true if the deletion has been triggered by a roaming event 1861c018ad3dSAntonio Quartulli */ 186256303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv, 186356303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1864c018ad3dSAntonio Quartulli const unsigned char *addr, unsigned short vid, 1865cc47f66eSAntonio Quartulli const char *message, bool roaming) 1866a73105b8SAntonio Quartulli { 1867170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 186856303d34SSven Eckelmann struct batadv_tt_local_entry *local_entry = NULL; 1869a73105b8SAntonio Quartulli 1870c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 1871db08e6e5SSimon Wunderlich if (!tt_global_entry) 18727683fdc1SAntonio Quartulli goto out; 1873a73105b8SAntonio Quartulli 1874db08e6e5SSimon Wunderlich if (!roaming) { 18751d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 1876a513088dSSven Eckelmann orig_node, message); 187792f90f56SSven Eckelmann 1878db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 1879be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, 1880db08e6e5SSimon Wunderlich message); 1881db08e6e5SSimon Wunderlich 1882cc47f66eSAntonio Quartulli goto out; 1883cc47f66eSAntonio Quartulli } 188492f90f56SSven Eckelmann 1885db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 1886db08e6e5SSimon Wunderlich * event, there are two possibilities: 1887db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 1888db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 1889acd34afaSSven Eckelmann * it with BATADV_TT_CLIENT_ROAM, we start a timer and we 1890db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 1891db08e6e5SSimon Wunderlich * the entry is purged. 1892db08e6e5SSimon Wunderlich * 1893db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 1894db08e6e5SSimon Wunderlich * the originator. 1895db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 18969cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 18979cfc7bd6SSven Eckelmann */ 1898a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 1899c018ad3dSAntonio Quartulli tt_global_entry->common.addr, 1900c018ad3dSAntonio Quartulli vid); 1901a513088dSSven Eckelmann if (local_entry) { 1902db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 1903a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1904be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, message); 1905db08e6e5SSimon Wunderlich } else 1906db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 1907a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 1908a513088dSSven Eckelmann orig_node, message); 1909db08e6e5SSimon Wunderlich 1910cc47f66eSAntonio Quartulli out: 19117683fdc1SAntonio Quartulli if (tt_global_entry) 1912a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1913a513088dSSven Eckelmann if (local_entry) 1914a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(local_entry); 1915a73105b8SAntonio Quartulli } 1916a73105b8SAntonio Quartulli 191795fb130dSAntonio Quartulli /** 191895fb130dSAntonio Quartulli * batadv_tt_global_del_orig - remove all the TT global entries belonging to the 191995fb130dSAntonio Quartulli * given originator matching the provided vid 192095fb130dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 192195fb130dSAntonio Quartulli * @orig_node: the originator owning the entries to remove 192295fb130dSAntonio Quartulli * @match_vid: the VLAN identifier to match. If negative all the entries will be 192395fb130dSAntonio Quartulli * removed 192495fb130dSAntonio Quartulli * @message: debug message to print as "reason" 192595fb130dSAntonio Quartulli */ 192656303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, 192756303d34SSven Eckelmann struct batadv_orig_node *orig_node, 19286b5e971aSSven Eckelmann s32 match_vid, 192956303d34SSven Eckelmann const char *message) 1930c6c8fea2SSven Eckelmann { 193156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 193256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 19336b5e971aSSven Eckelmann u32 i; 1934807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 1935b67bfe0dSSasha Levin struct hlist_node *safe; 1936a73105b8SAntonio Quartulli struct hlist_head *head; 19377683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 193816052789SAntonio Quartulli unsigned short vid; 1939c6c8fea2SSven Eckelmann 19406e801494SSimon Wunderlich if (!hash) 19416e801494SSimon Wunderlich return; 19426e801494SSimon Wunderlich 1943a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1944a73105b8SAntonio Quartulli head = &hash->table[i]; 19457683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1946c6c8fea2SSven Eckelmann 19477683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1948b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, safe, 1949a73105b8SAntonio Quartulli head, hash_entry) { 195095fb130dSAntonio Quartulli /* remove only matching entries */ 195195fb130dSAntonio Quartulli if (match_vid >= 0 && tt_common_entry->vid != match_vid) 195295fb130dSAntonio Quartulli continue; 195395fb130dSAntonio Quartulli 195456303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 195556303d34SSven Eckelmann struct batadv_tt_global_entry, 195648100bacSAntonio Quartulli common); 1957db08e6e5SSimon Wunderlich 19581d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global, 1959db08e6e5SSimon Wunderlich orig_node, message); 1960db08e6e5SSimon Wunderlich 196156303d34SSven Eckelmann if (hlist_empty(&tt_global->orig_list)) { 196216052789SAntonio Quartulli vid = tt_global->common.vid; 196339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 196416052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 196516052789SAntonio Quartulli tt_global->common.addr, 196616052789SAntonio Quartulli BATADV_PRINT_VID(vid), message); 1967b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 196856303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 1969c6c8fea2SSven Eckelmann } 1970a73105b8SAntonio Quartulli } 19717683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 19727683fdc1SAntonio Quartulli } 1973ac4eebd4SLinus Lüssing clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); 1974c6c8fea2SSven Eckelmann } 1975c6c8fea2SSven Eckelmann 197630cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, 197730cfd02bSAntonio Quartulli char **msg) 1978cc47f66eSAntonio Quartulli { 197930cfd02bSAntonio Quartulli bool purge = false; 198030cfd02bSAntonio Quartulli unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; 198130cfd02bSAntonio Quartulli unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; 1982cc47f66eSAntonio Quartulli 198330cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && 198430cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { 198530cfd02bSAntonio Quartulli purge = true; 198630cfd02bSAntonio Quartulli *msg = "Roaming timeout\n"; 198742d0b044SSven Eckelmann } 198842d0b044SSven Eckelmann 198930cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) && 199030cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) { 199130cfd02bSAntonio Quartulli purge = true; 199230cfd02bSAntonio Quartulli *msg = "Temporary client timeout\n"; 199330cfd02bSAntonio Quartulli } 199430cfd02bSAntonio Quartulli 199530cfd02bSAntonio Quartulli return purge; 199630cfd02bSAntonio Quartulli } 199730cfd02bSAntonio Quartulli 199830cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv) 199942d0b044SSven Eckelmann { 2000807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 200142d0b044SSven Eckelmann struct hlist_head *head; 2002b67bfe0dSSasha Levin struct hlist_node *node_tmp; 200342d0b044SSven Eckelmann spinlock_t *list_lock; /* protects write access to the hash lists */ 20046b5e971aSSven Eckelmann u32 i; 200530cfd02bSAntonio Quartulli char *msg = NULL; 200630cfd02bSAntonio Quartulli struct batadv_tt_common_entry *tt_common; 200730cfd02bSAntonio Quartulli struct batadv_tt_global_entry *tt_global; 200842d0b044SSven Eckelmann 200942d0b044SSven Eckelmann for (i = 0; i < hash->size; i++) { 201042d0b044SSven Eckelmann head = &hash->table[i]; 201142d0b044SSven Eckelmann list_lock = &hash->list_locks[i]; 201242d0b044SSven Eckelmann 201342d0b044SSven Eckelmann spin_lock_bh(list_lock); 2014b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 201530cfd02bSAntonio Quartulli hash_entry) { 201630cfd02bSAntonio Quartulli tt_global = container_of(tt_common, 201730cfd02bSAntonio Quartulli struct batadv_tt_global_entry, 201830cfd02bSAntonio Quartulli common); 201930cfd02bSAntonio Quartulli 202030cfd02bSAntonio Quartulli if (!batadv_tt_global_to_purge(tt_global, &msg)) 202130cfd02bSAntonio Quartulli continue; 202230cfd02bSAntonio Quartulli 202330cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 202416052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 202516052789SAntonio Quartulli tt_global->common.addr, 202616052789SAntonio Quartulli BATADV_PRINT_VID(tt_global->common.vid), 202716052789SAntonio Quartulli msg); 202830cfd02bSAntonio Quartulli 2029b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 203030cfd02bSAntonio Quartulli 203130cfd02bSAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 203230cfd02bSAntonio Quartulli } 20337683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 2034cc47f66eSAntonio Quartulli } 2035cc47f66eSAntonio Quartulli } 2036cc47f66eSAntonio Quartulli 203756303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) 2038c6c8fea2SSven Eckelmann { 20395bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 20407683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 204156303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 204256303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 2043b67bfe0dSSasha Levin struct hlist_node *node_tmp; 20447683fdc1SAntonio Quartulli struct hlist_head *head; 20456b5e971aSSven Eckelmann u32 i; 20467683fdc1SAntonio Quartulli 2047807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 2048c6c8fea2SSven Eckelmann return; 2049c6c8fea2SSven Eckelmann 2050807736f6SSven Eckelmann hash = bat_priv->tt.global_hash; 20517683fdc1SAntonio Quartulli 20527683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 20537683fdc1SAntonio Quartulli head = &hash->table[i]; 20547683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 20557683fdc1SAntonio Quartulli 20567683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 2057b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 20587683fdc1SAntonio Quartulli head, hash_entry) { 2059b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 206056303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 206156303d34SSven Eckelmann struct batadv_tt_global_entry, 206248100bacSAntonio Quartulli common); 206356303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 20647683fdc1SAntonio Quartulli } 20657683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 20667683fdc1SAntonio Quartulli } 20677683fdc1SAntonio Quartulli 20681a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 20697683fdc1SAntonio Quartulli 2070807736f6SSven Eckelmann bat_priv->tt.global_hash = NULL; 2071c6c8fea2SSven Eckelmann } 2072c6c8fea2SSven Eckelmann 207356303d34SSven Eckelmann static bool 207456303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, 207556303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry) 207659b699cdSAntonio Quartulli { 207759b699cdSAntonio Quartulli bool ret = false; 207859b699cdSAntonio Quartulli 2079acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && 2080acd34afaSSven Eckelmann tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) 208159b699cdSAntonio Quartulli ret = true; 208259b699cdSAntonio Quartulli 20832d2fcc2aSAntonio Quartulli /* check if the two clients are marked as isolated */ 20842d2fcc2aSAntonio Quartulli if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA && 20852d2fcc2aSAntonio Quartulli tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA) 20862d2fcc2aSAntonio Quartulli ret = true; 20872d2fcc2aSAntonio Quartulli 208859b699cdSAntonio Quartulli return ret; 208959b699cdSAntonio Quartulli } 209059b699cdSAntonio Quartulli 2091c018ad3dSAntonio Quartulli /** 2092c018ad3dSAntonio Quartulli * batadv_transtable_search - get the mesh destination for a given client 2093c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2094c018ad3dSAntonio Quartulli * @src: mac address of the source client 2095c018ad3dSAntonio Quartulli * @addr: mac address of the destination client 2096c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2097c018ad3dSAntonio Quartulli * 209862fe710fSSven Eckelmann * Return: a pointer to the originator that was selected as destination in the 2099c018ad3dSAntonio Quartulli * mesh for contacting the client 'addr', NULL otherwise. 2100c018ad3dSAntonio Quartulli * In case of multiple originators serving the same client, the function returns 2101c018ad3dSAntonio Quartulli * the best one (best in terms of metric towards the destination node). 2102c018ad3dSAntonio Quartulli * 2103c018ad3dSAntonio Quartulli * If the two clients are AP isolated the function returns NULL. 2104c018ad3dSAntonio Quartulli */ 210556303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, 21066b5e971aSSven Eckelmann const u8 *src, 21076b5e971aSSven Eckelmann const u8 *addr, 2108c018ad3dSAntonio Quartulli unsigned short vid) 2109c6c8fea2SSven Eckelmann { 211056303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 211156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 211256303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 2113981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *best_entry; 2114c6c8fea2SSven Eckelmann 2115eceb22aeSAntonio Quartulli if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) { 2116c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); 2117068ee6e2SAntonio Quartulli if (!tt_local_entry || 2118068ee6e2SAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) 21193d393e47SAntonio Quartulli goto out; 21203d393e47SAntonio Quartulli } 21217aadf889SMarek Lindner 2122c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 21232dafb49dSAntonio Quartulli if (!tt_global_entry) 21247b36e8eeSMarek Lindner goto out; 2125c6c8fea2SSven Eckelmann 21263d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 21279cfc7bd6SSven Eckelmann * isolation 21289cfc7bd6SSven Eckelmann */ 2129a513088dSSven Eckelmann if (tt_local_entry && 2130a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 21313d393e47SAntonio Quartulli goto out; 21323d393e47SAntonio Quartulli 2133db08e6e5SSimon Wunderlich rcu_read_lock(); 21344627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 2135db08e6e5SSimon Wunderlich /* found anything? */ 2136981d8900SSven Eckelmann if (best_entry) 2137981d8900SSven Eckelmann orig_node = best_entry->orig_node; 21387c124391SSven Eckelmann if (orig_node && !kref_get_unless_zero(&orig_node->refcount)) 2139db08e6e5SSimon Wunderlich orig_node = NULL; 2140db08e6e5SSimon Wunderlich rcu_read_unlock(); 2141981d8900SSven Eckelmann 21427b36e8eeSMarek Lindner out: 21433d393e47SAntonio Quartulli if (tt_global_entry) 2144a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 21453d393e47SAntonio Quartulli if (tt_local_entry) 2146a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 21473d393e47SAntonio Quartulli 21487b36e8eeSMarek Lindner return orig_node; 2149c6c8fea2SSven Eckelmann } 2150a73105b8SAntonio Quartulli 2151ced72933SAntonio Quartulli /** 2152ced72933SAntonio Quartulli * batadv_tt_global_crc - calculates the checksum of the local table belonging 2153ced72933SAntonio Quartulli * to the given orig_node 2154ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 21550ffa9e8dSAntonio Quartulli * @orig_node: originator for which the CRC should be computed 21567ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 21570ffa9e8dSAntonio Quartulli * 21580ffa9e8dSAntonio Quartulli * This function computes the checksum for the global table corresponding to a 21590ffa9e8dSAntonio Quartulli * specific originator. In particular, the checksum is computed as follows: For 21600ffa9e8dSAntonio Quartulli * each client connected to the originator the CRC32C of the MAC address and the 21610ffa9e8dSAntonio Quartulli * VID is computed and then all the CRC32Cs of the various clients are xor'ed 21620ffa9e8dSAntonio Quartulli * together. 21630ffa9e8dSAntonio Quartulli * 21640ffa9e8dSAntonio Quartulli * The idea behind is that CRC32C should be used as much as possible in order to 21650ffa9e8dSAntonio Quartulli * produce a unique hash of the table, but since the order which is used to feed 21660ffa9e8dSAntonio Quartulli * the CRC32C function affects the result and since every node in the network 21670ffa9e8dSAntonio Quartulli * probably sorts the clients differently, the hash function cannot be directly 21680ffa9e8dSAntonio Quartulli * computed over the entire table. Hence the CRC32C is used only on 21690ffa9e8dSAntonio Quartulli * the single client entry, while all the results are then xor'ed together 21700ffa9e8dSAntonio Quartulli * because the XOR operation can combine them all while trying to reduce the 21710ffa9e8dSAntonio Quartulli * noise as much as possible. 21720ffa9e8dSAntonio Quartulli * 217362fe710fSSven Eckelmann * Return: the checksum of the global table of a given originator. 2174ced72933SAntonio Quartulli */ 21756b5e971aSSven Eckelmann static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv, 21767ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node, 21777ea7b4a1SAntonio Quartulli unsigned short vid) 2178a73105b8SAntonio Quartulli { 2179807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 218056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 218156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 2182a73105b8SAntonio Quartulli struct hlist_head *head; 21836b5e971aSSven Eckelmann u32 i, crc_tmp, crc = 0; 21846b5e971aSSven Eckelmann u8 flags; 2185a30e22caSAntonio Quartulli __be16 tmp_vid; 2186a73105b8SAntonio Quartulli 2187a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2188a73105b8SAntonio Quartulli head = &hash->table[i]; 2189a73105b8SAntonio Quartulli 2190a73105b8SAntonio Quartulli rcu_read_lock(); 2191b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 219256303d34SSven Eckelmann tt_global = container_of(tt_common, 219356303d34SSven Eckelmann struct batadv_tt_global_entry, 219448100bacSAntonio Quartulli common); 21957ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 21967ea7b4a1SAntonio Quartulli * VLAN identified by the vid passed as parameter 21977ea7b4a1SAntonio Quartulli */ 21987ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 21997ea7b4a1SAntonio Quartulli continue; 22007ea7b4a1SAntonio Quartulli 2201cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 2202cc47f66eSAntonio Quartulli * consistency only. They don't have to be 2203cc47f66eSAntonio Quartulli * taken into account while computing the 2204db08e6e5SSimon Wunderlich * global crc 2205db08e6e5SSimon Wunderlich */ 2206acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 2207cc47f66eSAntonio Quartulli continue; 220830cfd02bSAntonio Quartulli /* Temporary clients have not been announced yet, so 220930cfd02bSAntonio Quartulli * they have to be skipped while computing the global 221030cfd02bSAntonio Quartulli * crc 221130cfd02bSAntonio Quartulli */ 221230cfd02bSAntonio Quartulli if (tt_common->flags & BATADV_TT_CLIENT_TEMP) 221330cfd02bSAntonio Quartulli continue; 2214db08e6e5SSimon Wunderlich 2215db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 2216db08e6e5SSimon Wunderlich * originator 2217db08e6e5SSimon Wunderlich */ 221856303d34SSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global, 2219db08e6e5SSimon Wunderlich orig_node)) 2220db08e6e5SSimon Wunderlich continue; 2221db08e6e5SSimon Wunderlich 2222a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2223a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2224a30e22caSAntonio Quartulli */ 2225a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2226a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 22270eb01568SAntonio Quartulli 22280eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 22290eb01568SAntonio Quartulli * among nodes 22300eb01568SAntonio Quartulli */ 22310eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 22320eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 22330eb01568SAntonio Quartulli 22340ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2235a73105b8SAntonio Quartulli } 2236a73105b8SAntonio Quartulli rcu_read_unlock(); 2237a73105b8SAntonio Quartulli } 2238a73105b8SAntonio Quartulli 2239ced72933SAntonio Quartulli return crc; 2240a73105b8SAntonio Quartulli } 2241a73105b8SAntonio Quartulli 2242ced72933SAntonio Quartulli /** 2243ced72933SAntonio Quartulli * batadv_tt_local_crc - calculates the checksum of the local table 2244ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 22457ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 22460ffa9e8dSAntonio Quartulli * 22470ffa9e8dSAntonio Quartulli * For details about the computation, please refer to the documentation for 22480ffa9e8dSAntonio Quartulli * batadv_tt_global_crc(). 22490ffa9e8dSAntonio Quartulli * 225062fe710fSSven Eckelmann * Return: the checksum of the local table 2251ced72933SAntonio Quartulli */ 22526b5e971aSSven Eckelmann static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv, 22537ea7b4a1SAntonio Quartulli unsigned short vid) 2254a73105b8SAntonio Quartulli { 2255807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 225656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 2257a73105b8SAntonio Quartulli struct hlist_head *head; 22586b5e971aSSven Eckelmann u32 i, crc_tmp, crc = 0; 22596b5e971aSSven Eckelmann u8 flags; 2260a30e22caSAntonio Quartulli __be16 tmp_vid; 2261a73105b8SAntonio Quartulli 2262a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2263a73105b8SAntonio Quartulli head = &hash->table[i]; 2264a73105b8SAntonio Quartulli 2265a73105b8SAntonio Quartulli rcu_read_lock(); 2266b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 22677ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 22687ea7b4a1SAntonio Quartulli * VLAN identified by vid 22697ea7b4a1SAntonio Quartulli */ 22707ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 22717ea7b4a1SAntonio Quartulli continue; 22727ea7b4a1SAntonio Quartulli 2273058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 22749cfc7bd6SSven Eckelmann * account while computing the CRC 22759cfc7bd6SSven Eckelmann */ 2276acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_NEW) 2277058d0e26SAntonio Quartulli continue; 2278ced72933SAntonio Quartulli 2279a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2280a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2281a30e22caSAntonio Quartulli */ 2282a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2283a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 22840eb01568SAntonio Quartulli 22850eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 22860eb01568SAntonio Quartulli * among nodes 22870eb01568SAntonio Quartulli */ 22880eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 22890eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 22900eb01568SAntonio Quartulli 22910ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2292a73105b8SAntonio Quartulli } 2293a73105b8SAntonio Quartulli rcu_read_unlock(); 2294a73105b8SAntonio Quartulli } 2295a73105b8SAntonio Quartulli 2296ced72933SAntonio Quartulli return crc; 2297a73105b8SAntonio Quartulli } 2298a73105b8SAntonio Quartulli 229956303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) 2300a73105b8SAntonio Quartulli { 23017c26a53bSMarek Lindner struct batadv_tt_req_node *node; 23027c26a53bSMarek Lindner struct hlist_node *safe; 2303a73105b8SAntonio Quartulli 2304807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2305a73105b8SAntonio Quartulli 23067c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 23077c26a53bSMarek Lindner hlist_del_init(&node->list); 2308a73105b8SAntonio Quartulli kfree(node); 2309a73105b8SAntonio Quartulli } 2310a73105b8SAntonio Quartulli 2311807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2312a73105b8SAntonio Quartulli } 2313a73105b8SAntonio Quartulli 231456303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, 231556303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2316e8cf234aSAntonio Quartulli const void *tt_buff, 23176b5e971aSSven Eckelmann u16 tt_buff_len) 2318a73105b8SAntonio Quartulli { 2319a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 23209cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 23219cfc7bd6SSven Eckelmann */ 2322a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2323a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 2324a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2325a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2326a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 2327a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 2328a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 2329a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 2330a73105b8SAntonio Quartulli } 2331a73105b8SAntonio Quartulli } 2332a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2333a73105b8SAntonio Quartulli } 2334a73105b8SAntonio Quartulli 233556303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv) 2336a73105b8SAntonio Quartulli { 23377c26a53bSMarek Lindner struct batadv_tt_req_node *node; 23387c26a53bSMarek Lindner struct hlist_node *safe; 2339a73105b8SAntonio Quartulli 2340807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 23417c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 234242d0b044SSven Eckelmann if (batadv_has_timed_out(node->issued_at, 234342d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) { 23447c26a53bSMarek Lindner hlist_del_init(&node->list); 2345a73105b8SAntonio Quartulli kfree(node); 2346a73105b8SAntonio Quartulli } 2347a73105b8SAntonio Quartulli } 2348807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2349a73105b8SAntonio Quartulli } 2350a73105b8SAntonio Quartulli 2351383b8636SMarek Lindner /** 2352383b8636SMarek Lindner * batadv_tt_req_node_new - search and possibly create a tt_req_node object 2353383b8636SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2354383b8636SMarek Lindner * @orig_node: orig node this request is being issued for 2355383b8636SMarek Lindner * 235662fe710fSSven Eckelmann * Return: the pointer to the new tt_req_node struct if no request 2357383b8636SMarek Lindner * has already been issued for this orig_node, NULL otherwise. 23589cfc7bd6SSven Eckelmann */ 235956303d34SSven Eckelmann static struct batadv_tt_req_node * 2360383b8636SMarek Lindner batadv_tt_req_node_new(struct batadv_priv *bat_priv, 236156303d34SSven Eckelmann struct batadv_orig_node *orig_node) 2362a73105b8SAntonio Quartulli { 236356303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 2364a73105b8SAntonio Quartulli 2365807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 23667c26a53bSMarek Lindner hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { 23671eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 23681eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 236942d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) 2370a73105b8SAntonio Quartulli goto unlock; 2371a73105b8SAntonio Quartulli } 2372a73105b8SAntonio Quartulli 2373a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 2374a73105b8SAntonio Quartulli if (!tt_req_node) 2375a73105b8SAntonio Quartulli goto unlock; 2376a73105b8SAntonio Quartulli 23778fdd0153SAntonio Quartulli ether_addr_copy(tt_req_node->addr, orig_node->orig); 2378a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 2379a73105b8SAntonio Quartulli 23807c26a53bSMarek Lindner hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list); 2381a73105b8SAntonio Quartulli unlock: 2382807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2383a73105b8SAntonio Quartulli return tt_req_node; 2384a73105b8SAntonio Quartulli } 2385a73105b8SAntonio Quartulli 2386335fbe0fSMarek Lindner /** 2387335fbe0fSMarek Lindner * batadv_tt_local_valid - verify that given tt entry is a valid one 2388335fbe0fSMarek Lindner * @entry_ptr: to be checked local tt entry 2389335fbe0fSMarek Lindner * @data_ptr: not used but definition required to satisfy the callback prototype 2390335fbe0fSMarek Lindner * 239162fe710fSSven Eckelmann * Return: 1 if the entry is a valid, 0 otherwise. 2392335fbe0fSMarek Lindner */ 2393335fbe0fSMarek Lindner static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) 2394058d0e26SAntonio Quartulli { 239556303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 2396058d0e26SAntonio Quartulli 2397acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) 2398058d0e26SAntonio Quartulli return 0; 2399058d0e26SAntonio Quartulli return 1; 2400058d0e26SAntonio Quartulli } 2401058d0e26SAntonio Quartulli 2402a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr, 2403a513088dSSven Eckelmann const void *data_ptr) 2404a73105b8SAntonio Quartulli { 240556303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 240656303d34SSven Eckelmann const struct batadv_tt_global_entry *tt_global_entry; 240756303d34SSven Eckelmann const struct batadv_orig_node *orig_node = data_ptr; 2408a73105b8SAntonio Quartulli 240930cfd02bSAntonio Quartulli if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || 241030cfd02bSAntonio Quartulli tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) 2411cc47f66eSAntonio Quartulli return 0; 2412cc47f66eSAntonio Quartulli 241356303d34SSven Eckelmann tt_global_entry = container_of(tt_common_entry, 241456303d34SSven Eckelmann struct batadv_tt_global_entry, 241548100bacSAntonio Quartulli common); 241648100bacSAntonio Quartulli 2417a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 2418a73105b8SAntonio Quartulli } 2419a73105b8SAntonio Quartulli 2420335fbe0fSMarek Lindner /** 24217ea7b4a1SAntonio Quartulli * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the 24227ea7b4a1SAntonio Quartulli * specified tt hash 2423335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2424335fbe0fSMarek Lindner * @hash: hash table containing the tt entries 2425335fbe0fSMarek Lindner * @tt_len: expected tvlv tt data buffer length in number of bytes 24267ea7b4a1SAntonio Quartulli * @tvlv_buff: pointer to the buffer to fill with the TT data 2427335fbe0fSMarek Lindner * @valid_cb: function to filter tt change entries 2428335fbe0fSMarek Lindner * @cb_data: data passed to the filter function as argument 2429335fbe0fSMarek Lindner */ 24307ea7b4a1SAntonio Quartulli static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, 24317ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash, 24326b5e971aSSven Eckelmann void *tvlv_buff, u16 tt_len, 2433a513088dSSven Eckelmann int (*valid_cb)(const void *, const void *), 2434a73105b8SAntonio Quartulli void *cb_data) 2435a73105b8SAntonio Quartulli { 243656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 2437335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 2438a73105b8SAntonio Quartulli struct hlist_head *head; 24396b5e971aSSven Eckelmann u16 tt_tot, tt_num_entries = 0; 24406b5e971aSSven Eckelmann u32 i; 2441a73105b8SAntonio Quartulli 2442298e6e68SAntonio Quartulli tt_tot = batadv_tt_entries(tt_len); 24437ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; 2444a73105b8SAntonio Quartulli 2445a73105b8SAntonio Quartulli rcu_read_lock(); 2446a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2447a73105b8SAntonio Quartulli head = &hash->table[i]; 2448a73105b8SAntonio Quartulli 2449b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 2450a73105b8SAntonio Quartulli head, hash_entry) { 2451335fbe0fSMarek Lindner if (tt_tot == tt_num_entries) 2452a73105b8SAntonio Quartulli break; 2453a73105b8SAntonio Quartulli 245448100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 2455a73105b8SAntonio Quartulli continue; 2456a73105b8SAntonio Quartulli 24578fdd0153SAntonio Quartulli ether_addr_copy(tt_change->addr, tt_common_entry->addr); 245827b37ebfSAntonio Quartulli tt_change->flags = tt_common_entry->flags; 2459c018ad3dSAntonio Quartulli tt_change->vid = htons(tt_common_entry->vid); 2460ca663046SAntonio Quartulli memset(tt_change->reserved, 0, 2461ca663046SAntonio Quartulli sizeof(tt_change->reserved)); 2462a73105b8SAntonio Quartulli 2463335fbe0fSMarek Lindner tt_num_entries++; 2464a73105b8SAntonio Quartulli tt_change++; 2465a73105b8SAntonio Quartulli } 2466a73105b8SAntonio Quartulli } 2467a73105b8SAntonio Quartulli rcu_read_unlock(); 24687ea7b4a1SAntonio Quartulli } 2469a73105b8SAntonio Quartulli 24707ea7b4a1SAntonio Quartulli /** 24717ea7b4a1SAntonio Quartulli * batadv_tt_global_check_crc - check if all the CRCs are correct 24727ea7b4a1SAntonio Quartulli * @orig_node: originator for which the CRCs have to be checked 24737ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN entry 24747ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 24757ea7b4a1SAntonio Quartulli * 247662fe710fSSven Eckelmann * Return: true if all the received CRCs match the locally stored ones, false 24777ea7b4a1SAntonio Quartulli * otherwise 24787ea7b4a1SAntonio Quartulli */ 24797ea7b4a1SAntonio Quartulli static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, 24807ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 24816b5e971aSSven Eckelmann u16 num_vlan) 24827ea7b4a1SAntonio Quartulli { 24837ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; 24847ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 2485c169c59dSSimon Wunderlich int i, orig_num_vlan; 24866b5e971aSSven Eckelmann u32 crc; 24877ea7b4a1SAntonio Quartulli 24887ea7b4a1SAntonio Quartulli /* check if each received CRC matches the locally stored one */ 24897ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 24907ea7b4a1SAntonio Quartulli tt_vlan_tmp = tt_vlan + i; 24917ea7b4a1SAntonio Quartulli 24927ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't check 24937ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 24947ea7b4a1SAntonio Quartulli */ 24957ea7b4a1SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, 2496cfd4f757SAntonio Quartulli orig_node->orig, 2497cfd4f757SAntonio Quartulli ntohs(tt_vlan_tmp->vid))) 24987ea7b4a1SAntonio Quartulli continue; 24997ea7b4a1SAntonio Quartulli 25007ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_node, 25017ea7b4a1SAntonio Quartulli ntohs(tt_vlan_tmp->vid)); 25027ea7b4a1SAntonio Quartulli if (!vlan) 25037ea7b4a1SAntonio Quartulli return false; 25047ea7b4a1SAntonio Quartulli 250591c2b1a9SAntonio Quartulli crc = vlan->tt.crc; 250691c2b1a9SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 250791c2b1a9SAntonio Quartulli 250891c2b1a9SAntonio Quartulli if (crc != ntohl(tt_vlan_tmp->crc)) 25097ea7b4a1SAntonio Quartulli return false; 25107ea7b4a1SAntonio Quartulli } 25117ea7b4a1SAntonio Quartulli 2512c169c59dSSimon Wunderlich /* check if any excess VLANs exist locally for the originator 2513c169c59dSSimon Wunderlich * which are not mentioned in the TVLV from the originator. 2514c169c59dSSimon Wunderlich */ 2515c169c59dSSimon Wunderlich rcu_read_lock(); 2516c169c59dSSimon Wunderlich orig_num_vlan = 0; 2517c169c59dSSimon Wunderlich hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) 2518c169c59dSSimon Wunderlich orig_num_vlan++; 2519c169c59dSSimon Wunderlich rcu_read_unlock(); 2520c169c59dSSimon Wunderlich 2521c169c59dSSimon Wunderlich if (orig_num_vlan > num_vlan) 2522c169c59dSSimon Wunderlich return false; 2523c169c59dSSimon Wunderlich 25247ea7b4a1SAntonio Quartulli return true; 25257ea7b4a1SAntonio Quartulli } 25267ea7b4a1SAntonio Quartulli 25277ea7b4a1SAntonio Quartulli /** 25287ea7b4a1SAntonio Quartulli * batadv_tt_local_update_crc - update all the local CRCs 25297ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 25307ea7b4a1SAntonio Quartulli */ 25317ea7b4a1SAntonio Quartulli static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) 25327ea7b4a1SAntonio Quartulli { 25337ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 25347ea7b4a1SAntonio Quartulli 25357ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 25367ea7b4a1SAntonio Quartulli rcu_read_lock(); 25377ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 25387ea7b4a1SAntonio Quartulli vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); 25397ea7b4a1SAntonio Quartulli } 25407ea7b4a1SAntonio Quartulli rcu_read_unlock(); 25417ea7b4a1SAntonio Quartulli } 25427ea7b4a1SAntonio Quartulli 25437ea7b4a1SAntonio Quartulli /** 25447ea7b4a1SAntonio Quartulli * batadv_tt_global_update_crc - update all the global CRCs for this orig_node 25457ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 25467ea7b4a1SAntonio Quartulli * @orig_node: the orig_node for which the CRCs have to be updated 25477ea7b4a1SAntonio Quartulli */ 25487ea7b4a1SAntonio Quartulli static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, 25497ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node) 25507ea7b4a1SAntonio Quartulli { 25517ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 25526b5e971aSSven Eckelmann u32 crc; 25537ea7b4a1SAntonio Quartulli 25547ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 25557ea7b4a1SAntonio Quartulli rcu_read_lock(); 2556d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 25577ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't compute 25587ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 25597ea7b4a1SAntonio Quartulli */ 2560cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, 2561cfd4f757SAntonio Quartulli vlan->vid)) 25627ea7b4a1SAntonio Quartulli continue; 25637ea7b4a1SAntonio Quartulli 25647ea7b4a1SAntonio Quartulli crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); 25657ea7b4a1SAntonio Quartulli vlan->tt.crc = crc; 25667ea7b4a1SAntonio Quartulli } 25677ea7b4a1SAntonio Quartulli rcu_read_unlock(); 2568a73105b8SAntonio Quartulli } 2569a73105b8SAntonio Quartulli 2570ced72933SAntonio Quartulli /** 2571ced72933SAntonio Quartulli * batadv_send_tt_request - send a TT Request message to a given node 2572ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2573ced72933SAntonio Quartulli * @dst_orig_node: the destination of the message 2574ced72933SAntonio Quartulli * @ttvn: the version number that the source of the message is looking for 25757ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN object to request 25767ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 2577ced72933SAntonio Quartulli * @full_table: ask for the entire translation table if true, while only for the 2578ced72933SAntonio Quartulli * last TT diff otherwise 2579d15cd622SAntonio Quartulli * 2580d15cd622SAntonio Quartulli * Return: true if the TT Request was sent, false otherwise 2581ced72933SAntonio Quartulli */ 258256303d34SSven Eckelmann static int batadv_send_tt_request(struct batadv_priv *bat_priv, 258356303d34SSven Eckelmann struct batadv_orig_node *dst_orig_node, 25846b5e971aSSven Eckelmann u8 ttvn, 25857ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 25866b5e971aSSven Eckelmann u16 num_vlan, bool full_table) 2587a73105b8SAntonio Quartulli { 2588335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 258956303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node = NULL; 25907ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_req; 25917ea7b4a1SAntonio Quartulli struct batadv_hard_iface *primary_if; 2592335fbe0fSMarek Lindner bool ret = false; 25937ea7b4a1SAntonio Quartulli int i, size; 2594a73105b8SAntonio Quartulli 2595e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2596a73105b8SAntonio Quartulli if (!primary_if) 2597a73105b8SAntonio Quartulli goto out; 2598a73105b8SAntonio Quartulli 2599a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 26009cfc7bd6SSven Eckelmann * reply from the same orig_node yet 26019cfc7bd6SSven Eckelmann */ 2602383b8636SMarek Lindner tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node); 2603a73105b8SAntonio Quartulli if (!tt_req_node) 2604a73105b8SAntonio Quartulli goto out; 2605a73105b8SAntonio Quartulli 26067ea7b4a1SAntonio Quartulli size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; 26077ea7b4a1SAntonio Quartulli tvlv_tt_data = kzalloc(size, GFP_ATOMIC); 2608335fbe0fSMarek Lindner if (!tvlv_tt_data) 2609a73105b8SAntonio Quartulli goto out; 2610a73105b8SAntonio Quartulli 2611335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_REQUEST; 2612335fbe0fSMarek Lindner tvlv_tt_data->ttvn = ttvn; 26137ea7b4a1SAntonio Quartulli tvlv_tt_data->num_vlan = htons(num_vlan); 26147ea7b4a1SAntonio Quartulli 26157ea7b4a1SAntonio Quartulli /* send all the CRCs within the request. This is needed by intermediate 26167ea7b4a1SAntonio Quartulli * nodes to ensure they have the correct table before replying 26177ea7b4a1SAntonio Quartulli */ 26187ea7b4a1SAntonio Quartulli tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); 26197ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 26207ea7b4a1SAntonio Quartulli tt_vlan_req->vid = tt_vlan->vid; 26217ea7b4a1SAntonio Quartulli tt_vlan_req->crc = tt_vlan->crc; 26227ea7b4a1SAntonio Quartulli 26237ea7b4a1SAntonio Quartulli tt_vlan_req++; 26247ea7b4a1SAntonio Quartulli tt_vlan++; 26257ea7b4a1SAntonio Quartulli } 2626a73105b8SAntonio Quartulli 2627a73105b8SAntonio Quartulli if (full_table) 2628335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2629a73105b8SAntonio Quartulli 2630bb351ba0SMartin Hundebøll batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", 2631335fbe0fSMarek Lindner dst_orig_node->orig, full_table ? 'F' : '.'); 2632a73105b8SAntonio Quartulli 2633d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); 2634335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 2635335fbe0fSMarek Lindner dst_orig_node->orig, BATADV_TVLV_TT, 1, 26367ea7b4a1SAntonio Quartulli tvlv_tt_data, size); 2637335fbe0fSMarek Lindner ret = true; 2638a73105b8SAntonio Quartulli 2639a73105b8SAntonio Quartulli out: 2640a73105b8SAntonio Quartulli if (primary_if) 264182047ad7SSven Eckelmann batadv_hardif_put(primary_if); 2642a73105b8SAntonio Quartulli if (ret && tt_req_node) { 2643807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 26447c26a53bSMarek Lindner /* hlist_del_init() verifies tt_req_node still is in the list */ 26457c26a53bSMarek Lindner hlist_del_init(&tt_req_node->list); 2646807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2647a73105b8SAntonio Quartulli kfree(tt_req_node); 2648a73105b8SAntonio Quartulli } 2649335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2650a73105b8SAntonio Quartulli return ret; 2651a73105b8SAntonio Quartulli } 2652a73105b8SAntonio Quartulli 2653335fbe0fSMarek Lindner /** 2654335fbe0fSMarek Lindner * batadv_send_other_tt_response - send reply to tt request concerning another 2655335fbe0fSMarek Lindner * node's translation table 2656335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2657335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2658335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2659335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 2660335fbe0fSMarek Lindner * 266162fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2662335fbe0fSMarek Lindner */ 2663335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, 2664335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 26656b5e971aSSven Eckelmann u8 *req_src, u8 *req_dst) 2666a73105b8SAntonio Quartulli { 2667170173bfSSven Eckelmann struct batadv_orig_node *req_dst_orig_node; 266856303d34SSven Eckelmann struct batadv_orig_node *res_dst_orig_node = NULL; 26697ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 2670335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 26717ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 2672335fbe0fSMarek Lindner bool ret = false, full_table; 26736b5e971aSSven Eckelmann u8 orig_ttvn, req_ttvn; 26746b5e971aSSven Eckelmann u16 tvlv_len; 26756b5e971aSSven Eckelmann s32 tt_len; 2676a73105b8SAntonio Quartulli 267739c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 267886ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 2679335fbe0fSMarek Lindner req_src, tt_data->ttvn, req_dst, 2680a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 2681a73105b8SAntonio Quartulli 2682a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 2683335fbe0fSMarek Lindner req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); 2684a73105b8SAntonio Quartulli if (!req_dst_orig_node) 2685a73105b8SAntonio Quartulli goto out; 2686a73105b8SAntonio Quartulli 2687335fbe0fSMarek Lindner res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); 2688a73105b8SAntonio Quartulli if (!res_dst_orig_node) 2689a73105b8SAntonio Quartulli goto out; 2690a73105b8SAntonio Quartulli 26916b5e971aSSven Eckelmann orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn); 2692335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 2693a73105b8SAntonio Quartulli 26947ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 2695335fbe0fSMarek Lindner /* this node doesn't have the requested data */ 2696a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 26977ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, 26987ea7b4a1SAntonio Quartulli ntohs(tt_data->num_vlan))) 2699a73105b8SAntonio Quartulli goto out; 2700a73105b8SAntonio Quartulli 2701015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 2702335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || 2703a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 2704a73105b8SAntonio Quartulli full_table = true; 2705a73105b8SAntonio Quartulli else 2706a73105b8SAntonio Quartulli full_table = false; 2707a73105b8SAntonio Quartulli 2708335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 2709335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 27109cfc7bd6SSven Eckelmann */ 2711a73105b8SAntonio Quartulli if (!full_table) { 2712a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 2713a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 2714a73105b8SAntonio Quartulli 27157ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 27167ea7b4a1SAntonio Quartulli &tvlv_tt_data, 27177ea7b4a1SAntonio Quartulli &tt_change, 27187ea7b4a1SAntonio Quartulli &tt_len); 27197ea7b4a1SAntonio Quartulli if (!tt_len) 2720a73105b8SAntonio Quartulli goto unlock; 2721a73105b8SAntonio Quartulli 2722a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 27237ea7b4a1SAntonio Quartulli memcpy(tt_change, req_dst_orig_node->tt_buff, 2724a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 2725a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 2726a73105b8SAntonio Quartulli } else { 27277ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 27287ea7b4a1SAntonio Quartulli * in the initial part 27297ea7b4a1SAntonio Quartulli */ 27307ea7b4a1SAntonio Quartulli tt_len = -1; 27317ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 27327ea7b4a1SAntonio Quartulli &tvlv_tt_data, 27337ea7b4a1SAntonio Quartulli &tt_change, 27347ea7b4a1SAntonio Quartulli &tt_len); 27357ea7b4a1SAntonio Quartulli if (!tt_len) 27367ea7b4a1SAntonio Quartulli goto out; 2737a73105b8SAntonio Quartulli 27387ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 27397ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, 27407ea7b4a1SAntonio Quartulli tt_change, tt_len, 2741a513088dSSven Eckelmann batadv_tt_global_valid, 2742a73105b8SAntonio Quartulli req_dst_orig_node); 2743a73105b8SAntonio Quartulli } 2744a73105b8SAntonio Quartulli 2745a19d3d85SMarek Lindner /* Don't send the response, if larger than fragmented packet. */ 2746a19d3d85SMarek Lindner tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len; 2747a19d3d85SMarek Lindner if (tt_len > atomic_read(&bat_priv->packet_size_max)) { 2748a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, bat_priv->soft_iface, 2749a19d3d85SMarek Lindner "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n", 2750a19d3d85SMarek Lindner res_dst_orig_node->orig); 2751a19d3d85SMarek Lindner goto out; 2752a19d3d85SMarek Lindner } 2753a19d3d85SMarek Lindner 2754335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2755335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 2756a73105b8SAntonio Quartulli 2757a73105b8SAntonio Quartulli if (full_table) 2758335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2759a73105b8SAntonio Quartulli 276039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2761335fbe0fSMarek Lindner "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n", 2762335fbe0fSMarek Lindner res_dst_orig_node->orig, req_dst_orig_node->orig, 2763335fbe0fSMarek Lindner full_table ? 'F' : '.', req_ttvn); 2764a73105b8SAntonio Quartulli 2765d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 2766f8214865SMartin Hundebøll 2767335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, 27687ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 27697ea7b4a1SAntonio Quartulli tvlv_len); 2770e91ecfc6SMartin Hundebøll 2771335fbe0fSMarek Lindner ret = true; 2772a73105b8SAntonio Quartulli goto out; 2773a73105b8SAntonio Quartulli 2774a73105b8SAntonio Quartulli unlock: 2775a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 2776a73105b8SAntonio Quartulli 2777a73105b8SAntonio Quartulli out: 2778a73105b8SAntonio Quartulli if (res_dst_orig_node) 27795d967310SSven Eckelmann batadv_orig_node_put(res_dst_orig_node); 2780a73105b8SAntonio Quartulli if (req_dst_orig_node) 27815d967310SSven Eckelmann batadv_orig_node_put(req_dst_orig_node); 2782335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2783a73105b8SAntonio Quartulli return ret; 2784a73105b8SAntonio Quartulli } 278596412690SSven Eckelmann 2786335fbe0fSMarek Lindner /** 2787335fbe0fSMarek Lindner * batadv_send_my_tt_response - send reply to tt request concerning this node's 2788335fbe0fSMarek Lindner * translation table 2789335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2790335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2791335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2792335fbe0fSMarek Lindner * 279362fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2794335fbe0fSMarek Lindner */ 2795335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, 2796335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 27976b5e971aSSven Eckelmann u8 *req_src) 2798a73105b8SAntonio Quartulli { 2799335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 280056303d34SSven Eckelmann struct batadv_hard_iface *primary_if = NULL; 28017ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 28027ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node; 28036b5e971aSSven Eckelmann u8 my_ttvn, req_ttvn; 28046b5e971aSSven Eckelmann u16 tvlv_len; 2805a73105b8SAntonio Quartulli bool full_table; 28066b5e971aSSven Eckelmann s32 tt_len; 2807a73105b8SAntonio Quartulli 280839c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 280986ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 2810335fbe0fSMarek Lindner req_src, tt_data->ttvn, 2811a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 2812a73105b8SAntonio Quartulli 2813a70a9aa9SAntonio Quartulli spin_lock_bh(&bat_priv->tt.commit_lock); 2814a73105b8SAntonio Quartulli 28156b5e971aSSven Eckelmann my_ttvn = (u8)atomic_read(&bat_priv->tt.vn); 2816335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 2817a73105b8SAntonio Quartulli 2818335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, req_src); 2819a73105b8SAntonio Quartulli if (!orig_node) 2820a73105b8SAntonio Quartulli goto out; 2821a73105b8SAntonio Quartulli 2822e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2823a73105b8SAntonio Quartulli if (!primary_if) 2824a73105b8SAntonio Quartulli goto out; 2825a73105b8SAntonio Quartulli 2826a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 28279cfc7bd6SSven Eckelmann * is too big send the whole local translation table 28289cfc7bd6SSven Eckelmann */ 2829335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || 2830807736f6SSven Eckelmann !bat_priv->tt.last_changeset) 2831a73105b8SAntonio Quartulli full_table = true; 2832a73105b8SAntonio Quartulli else 2833a73105b8SAntonio Quartulli full_table = false; 2834a73105b8SAntonio Quartulli 2835335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 2836335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 28379cfc7bd6SSven Eckelmann */ 2838a73105b8SAntonio Quartulli if (!full_table) { 2839807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 2840a73105b8SAntonio Quartulli 28417ea7b4a1SAntonio Quartulli tt_len = bat_priv->tt.last_changeset_len; 28427ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 28437ea7b4a1SAntonio Quartulli &tvlv_tt_data, 28447ea7b4a1SAntonio Quartulli &tt_change, 28457ea7b4a1SAntonio Quartulli &tt_len); 28467ea7b4a1SAntonio Quartulli if (!tt_len) 2847a73105b8SAntonio Quartulli goto unlock; 2848a73105b8SAntonio Quartulli 2849335fbe0fSMarek Lindner /* Copy the last orig_node's OGM buffer */ 28507ea7b4a1SAntonio Quartulli memcpy(tt_change, bat_priv->tt.last_changeset, 2851807736f6SSven Eckelmann bat_priv->tt.last_changeset_len); 2852807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2853a73105b8SAntonio Quartulli } else { 28546b5e971aSSven Eckelmann req_ttvn = (u8)atomic_read(&bat_priv->tt.vn); 2855a73105b8SAntonio Quartulli 28567ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 28577ea7b4a1SAntonio Quartulli * in the initial part 28587ea7b4a1SAntonio Quartulli */ 28597ea7b4a1SAntonio Quartulli tt_len = -1; 28607ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 28617ea7b4a1SAntonio Quartulli &tvlv_tt_data, 28627ea7b4a1SAntonio Quartulli &tt_change, 28637ea7b4a1SAntonio Quartulli &tt_len); 28647ea7b4a1SAntonio Quartulli if (!tt_len) 2865a73105b8SAntonio Quartulli goto out; 28667ea7b4a1SAntonio Quartulli 28677ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 28687ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, 28697ea7b4a1SAntonio Quartulli tt_change, tt_len, 28707ea7b4a1SAntonio Quartulli batadv_tt_local_valid, NULL); 2871a73105b8SAntonio Quartulli } 2872a73105b8SAntonio Quartulli 2873335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2874335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 2875a73105b8SAntonio Quartulli 2876a73105b8SAntonio Quartulli if (full_table) 2877335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2878a73105b8SAntonio Quartulli 287939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2880335fbe0fSMarek Lindner "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n", 2881335fbe0fSMarek Lindner orig_node->orig, full_table ? 'F' : '.', req_ttvn); 2882a73105b8SAntonio Quartulli 2883d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 2884f8214865SMartin Hundebøll 2885335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 28867ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 28877ea7b4a1SAntonio Quartulli tvlv_len); 2888335fbe0fSMarek Lindner 2889a73105b8SAntonio Quartulli goto out; 2890a73105b8SAntonio Quartulli 2891a73105b8SAntonio Quartulli unlock: 2892807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2893a73105b8SAntonio Quartulli out: 2894a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 2895a73105b8SAntonio Quartulli if (orig_node) 28965d967310SSven Eckelmann batadv_orig_node_put(orig_node); 2897a73105b8SAntonio Quartulli if (primary_if) 289882047ad7SSven Eckelmann batadv_hardif_put(primary_if); 2899335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2900335fbe0fSMarek Lindner /* The packet was for this host, so it doesn't need to be re-routed */ 2901a73105b8SAntonio Quartulli return true; 2902a73105b8SAntonio Quartulli } 2903a73105b8SAntonio Quartulli 2904335fbe0fSMarek Lindner /** 2905335fbe0fSMarek Lindner * batadv_send_tt_response - send reply to tt request 2906335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2907335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2908335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2909335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 2910335fbe0fSMarek Lindner * 291162fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2912335fbe0fSMarek Lindner */ 2913335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv, 2914335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 29156b5e971aSSven Eckelmann u8 *req_src, u8 *req_dst) 2916a73105b8SAntonio Quartulli { 2917cfd4f757SAntonio Quartulli if (batadv_is_my_mac(bat_priv, req_dst)) 2918335fbe0fSMarek Lindner return batadv_send_my_tt_response(bat_priv, tt_data, req_src); 291924820df1SAntonio Quartulli return batadv_send_other_tt_response(bat_priv, tt_data, req_src, 292024820df1SAntonio Quartulli req_dst); 2921a73105b8SAntonio Quartulli } 2922a73105b8SAntonio Quartulli 292356303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, 292456303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2925335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change, 29266b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn) 2927a73105b8SAntonio Quartulli { 2928a73105b8SAntonio Quartulli int i; 2929a513088dSSven Eckelmann int roams; 2930a73105b8SAntonio Quartulli 2931a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 2932acd34afaSSven Eckelmann if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { 2933acd34afaSSven Eckelmann roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; 2934a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 2935a73105b8SAntonio Quartulli (tt_change + i)->addr, 2936c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 2937cc47f66eSAntonio Quartulli "tt removed by changes", 2938a513088dSSven Eckelmann roams); 293908c36d3eSSven Eckelmann } else { 294008c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 2941d4f44692SAntonio Quartulli (tt_change + i)->addr, 2942c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 2943d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 2944a73105b8SAntonio Quartulli /* In case of problem while storing a 2945a73105b8SAntonio Quartulli * global_entry, we stop the updating 2946a73105b8SAntonio Quartulli * procedure without committing the 2947a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 2948a73105b8SAntonio Quartulli * corrupted data on tt_request 2949a73105b8SAntonio Quartulli */ 2950a73105b8SAntonio Quartulli return; 2951a73105b8SAntonio Quartulli } 295208c36d3eSSven Eckelmann } 2953ac4eebd4SLinus Lüssing set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); 2954a73105b8SAntonio Quartulli } 2955a73105b8SAntonio Quartulli 295656303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, 29577ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 29586b5e971aSSven Eckelmann u8 ttvn, u8 *resp_src, 29596b5e971aSSven Eckelmann u16 num_entries) 2960a73105b8SAntonio Quartulli { 2961170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 2962a73105b8SAntonio Quartulli 2963335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 2964a73105b8SAntonio Quartulli if (!orig_node) 2965a73105b8SAntonio Quartulli goto out; 2966a73105b8SAntonio Quartulli 2967a73105b8SAntonio Quartulli /* Purge the old table first.. */ 296895fb130dSAntonio Quartulli batadv_tt_global_del_orig(bat_priv, orig_node, -1, 296995fb130dSAntonio Quartulli "Received full table"); 2970a73105b8SAntonio Quartulli 29717ea7b4a1SAntonio Quartulli _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, 29727ea7b4a1SAntonio Quartulli ttvn); 2973a73105b8SAntonio Quartulli 2974a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2975a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2976a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2977a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 2978a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2979a73105b8SAntonio Quartulli 29807ea7b4a1SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2981a73105b8SAntonio Quartulli 2982a73105b8SAntonio Quartulli out: 2983a73105b8SAntonio Quartulli if (orig_node) 29845d967310SSven Eckelmann batadv_orig_node_put(orig_node); 2985a73105b8SAntonio Quartulli } 2986a73105b8SAntonio Quartulli 298756303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv, 298856303d34SSven Eckelmann struct batadv_orig_node *orig_node, 29896b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn, 2990335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change) 2991a73105b8SAntonio Quartulli { 2992a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 2993a513088dSSven Eckelmann tt_num_changes, ttvn); 2994a73105b8SAntonio Quartulli 2995e8cf234aSAntonio Quartulli batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, 2996e8cf234aSAntonio Quartulli batadv_tt_len(tt_num_changes)); 2997a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2998a73105b8SAntonio Quartulli } 2999a73105b8SAntonio Quartulli 3000c018ad3dSAntonio Quartulli /** 3001c018ad3dSAntonio Quartulli * batadv_is_my_client - check if a client is served by the local node 3002c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 30033f68785eSAntonio Quartulli * @addr: the mac address of the client to check 3004c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3005c018ad3dSAntonio Quartulli * 300662fe710fSSven Eckelmann * Return: true if the client is served by this node, false otherwise. 3007c018ad3dSAntonio Quartulli */ 30086b5e971aSSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr, 3009c018ad3dSAntonio Quartulli unsigned short vid) 3010a73105b8SAntonio Quartulli { 3011170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 30127683fdc1SAntonio Quartulli bool ret = false; 3013a73105b8SAntonio Quartulli 3014c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 30157683fdc1SAntonio Quartulli if (!tt_local_entry) 30167683fdc1SAntonio Quartulli goto out; 3017058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 30189cfc7bd6SSven Eckelmann * consistency purpose) 30199cfc7bd6SSven Eckelmann */ 30207c1fd91dSAntonio Quartulli if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) || 30217c1fd91dSAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM)) 3022058d0e26SAntonio Quartulli goto out; 30237683fdc1SAntonio Quartulli ret = true; 30247683fdc1SAntonio Quartulli out: 3025a73105b8SAntonio Quartulli if (tt_local_entry) 3026a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 30277683fdc1SAntonio Quartulli return ret; 3028a73105b8SAntonio Quartulli } 3029a73105b8SAntonio Quartulli 3030335fbe0fSMarek Lindner /** 3031335fbe0fSMarek Lindner * batadv_handle_tt_response - process incoming tt reply 3032335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3033335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 3034335fbe0fSMarek Lindner * @resp_src: mac address of tt reply sender 3035335fbe0fSMarek Lindner * @num_entries: number of tt change entries appended to the tt data 3036335fbe0fSMarek Lindner */ 3037335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv, 3038335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 30396b5e971aSSven Eckelmann u8 *resp_src, u16 num_entries) 3040a73105b8SAntonio Quartulli { 30417c26a53bSMarek Lindner struct batadv_tt_req_node *node; 30427c26a53bSMarek Lindner struct hlist_node *safe; 304356303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 3044335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 30456b5e971aSSven Eckelmann u8 *tvlv_ptr = (u8 *)tt_data; 30466b5e971aSSven Eckelmann u16 change_offset; 3047a73105b8SAntonio Quartulli 304839c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 304986ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 3050335fbe0fSMarek Lindner resp_src, tt_data->ttvn, num_entries, 3051a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 3052a73105b8SAntonio Quartulli 3053335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 3054a73105b8SAntonio Quartulli if (!orig_node) 3055a73105b8SAntonio Quartulli goto out; 3056a73105b8SAntonio Quartulli 3057a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 3058a70a9aa9SAntonio Quartulli 30597ea7b4a1SAntonio Quartulli change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); 30607ea7b4a1SAntonio Quartulli change_offset *= ntohs(tt_data->num_vlan); 30617ea7b4a1SAntonio Quartulli change_offset += sizeof(*tt_data); 30627ea7b4a1SAntonio Quartulli tvlv_ptr += change_offset; 30637ea7b4a1SAntonio Quartulli 30647ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; 3065335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) { 30667ea7b4a1SAntonio Quartulli batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, 30677ea7b4a1SAntonio Quartulli resp_src, num_entries); 306896412690SSven Eckelmann } else { 3069335fbe0fSMarek Lindner batadv_tt_update_changes(bat_priv, orig_node, num_entries, 3070335fbe0fSMarek Lindner tt_data->ttvn, tt_change); 307196412690SSven Eckelmann } 3072a73105b8SAntonio Quartulli 3073a70a9aa9SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 30747ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3075a70a9aa9SAntonio Quartulli 3076a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3077a70a9aa9SAntonio Quartulli 3078a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 3079807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 30807c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 3081335fbe0fSMarek Lindner if (!batadv_compare_eth(node->addr, resp_src)) 3082a73105b8SAntonio Quartulli continue; 30837c26a53bSMarek Lindner hlist_del_init(&node->list); 3084a73105b8SAntonio Quartulli kfree(node); 3085a73105b8SAntonio Quartulli } 30867ea7b4a1SAntonio Quartulli 3087807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 3088a73105b8SAntonio Quartulli out: 3089a73105b8SAntonio Quartulli if (orig_node) 30905d967310SSven Eckelmann batadv_orig_node_put(orig_node); 3091a73105b8SAntonio Quartulli } 3092a73105b8SAntonio Quartulli 309356303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) 3094a73105b8SAntonio Quartulli { 309556303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 3096a73105b8SAntonio Quartulli 3097807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3098a73105b8SAntonio Quartulli 3099807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 3100cc47f66eSAntonio Quartulli list_del(&node->list); 3101cc47f66eSAntonio Quartulli kfree(node); 3102cc47f66eSAntonio Quartulli } 3103cc47f66eSAntonio Quartulli 3104807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3105cc47f66eSAntonio Quartulli } 3106cc47f66eSAntonio Quartulli 310756303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) 3108cc47f66eSAntonio Quartulli { 310956303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 3110cc47f66eSAntonio Quartulli 3111807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3112807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 311342d0b044SSven Eckelmann if (!batadv_has_timed_out(node->first_time, 311442d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 3115cc47f66eSAntonio Quartulli continue; 3116cc47f66eSAntonio Quartulli 3117cc47f66eSAntonio Quartulli list_del(&node->list); 3118cc47f66eSAntonio Quartulli kfree(node); 3119cc47f66eSAntonio Quartulli } 3120807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3121cc47f66eSAntonio Quartulli } 3122cc47f66eSAntonio Quartulli 312362fe710fSSven Eckelmann /** 3124d15cd622SAntonio Quartulli * batadv_tt_check_roam_count - check if a client has roamed too frequently 3125d15cd622SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3126d15cd622SAntonio Quartulli * @client: mac address of the roaming client 312762fe710fSSven Eckelmann * 312862fe710fSSven Eckelmann * This function checks whether the client already reached the 3129cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 3130cc47f66eSAntonio Quartulli * will not be sent. 3131cc47f66eSAntonio Quartulli * 313262fe710fSSven Eckelmann * Return: true if the ROAMING_ADV can be sent, false otherwise 31339cfc7bd6SSven Eckelmann */ 31346b5e971aSSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client) 3135cc47f66eSAntonio Quartulli { 313656303d34SSven Eckelmann struct batadv_tt_roam_node *tt_roam_node; 3137cc47f66eSAntonio Quartulli bool ret = false; 3138cc47f66eSAntonio Quartulli 3139807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3140cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 31419cfc7bd6SSven Eckelmann * reply from the same orig_node yet 31429cfc7bd6SSven Eckelmann */ 3143807736f6SSven Eckelmann list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) { 31441eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 3145cc47f66eSAntonio Quartulli continue; 3146cc47f66eSAntonio Quartulli 31471eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 314842d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 3149cc47f66eSAntonio Quartulli continue; 3150cc47f66eSAntonio Quartulli 31513e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 3152cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 3153cc47f66eSAntonio Quartulli goto unlock; 3154cc47f66eSAntonio Quartulli ret = true; 3155cc47f66eSAntonio Quartulli break; 3156cc47f66eSAntonio Quartulli } 3157cc47f66eSAntonio Quartulli 3158cc47f66eSAntonio Quartulli if (!ret) { 3159cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 3160cc47f66eSAntonio Quartulli if (!tt_roam_node) 3161cc47f66eSAntonio Quartulli goto unlock; 3162cc47f66eSAntonio Quartulli 3163cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 316442d0b044SSven Eckelmann atomic_set(&tt_roam_node->counter, 316542d0b044SSven Eckelmann BATADV_ROAMING_MAX_COUNT - 1); 31668fdd0153SAntonio Quartulli ether_addr_copy(tt_roam_node->addr, client); 3167cc47f66eSAntonio Quartulli 3168807736f6SSven Eckelmann list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); 3169cc47f66eSAntonio Quartulli ret = true; 3170cc47f66eSAntonio Quartulli } 3171cc47f66eSAntonio Quartulli 3172cc47f66eSAntonio Quartulli unlock: 3173807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3174cc47f66eSAntonio Quartulli return ret; 3175cc47f66eSAntonio Quartulli } 3176cc47f66eSAntonio Quartulli 3177c018ad3dSAntonio Quartulli /** 3178c018ad3dSAntonio Quartulli * batadv_send_roam_adv - send a roaming advertisement message 3179c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3180c018ad3dSAntonio Quartulli * @client: mac address of the roaming client 3181c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3182c018ad3dSAntonio Quartulli * @orig_node: message destination 3183c018ad3dSAntonio Quartulli * 3184c018ad3dSAntonio Quartulli * Send a ROAMING_ADV message to the node which was previously serving this 3185c018ad3dSAntonio Quartulli * client. This is done to inform the node that from now on all traffic destined 3186c018ad3dSAntonio Quartulli * for this particular roamed client has to be forwarded to the sender of the 3187c018ad3dSAntonio Quartulli * roaming message. 3188c018ad3dSAntonio Quartulli */ 31896b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, 3190c018ad3dSAntonio Quartulli unsigned short vid, 319156303d34SSven Eckelmann struct batadv_orig_node *orig_node) 3192cc47f66eSAntonio Quartulli { 319356303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 3194122edaa0SMarek Lindner struct batadv_tvlv_roam_adv tvlv_roam; 3195122edaa0SMarek Lindner 3196122edaa0SMarek Lindner primary_if = batadv_primary_if_get_selected(bat_priv); 3197122edaa0SMarek Lindner if (!primary_if) 3198122edaa0SMarek Lindner goto out; 3199cc47f66eSAntonio Quartulli 3200cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 32019cfc7bd6SSven Eckelmann * already roamed to us too many times 32029cfc7bd6SSven Eckelmann */ 3203a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 3204cc47f66eSAntonio Quartulli goto out; 3205cc47f66eSAntonio Quartulli 320639c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 320716052789SAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n", 320816052789SAntonio Quartulli orig_node->orig, client, BATADV_PRINT_VID(vid)); 3209cc47f66eSAntonio Quartulli 3210d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); 3211f8214865SMartin Hundebøll 3212122edaa0SMarek Lindner memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); 3213c018ad3dSAntonio Quartulli tvlv_roam.vid = htons(vid); 3214122edaa0SMarek Lindner 3215122edaa0SMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 3216122edaa0SMarek Lindner orig_node->orig, BATADV_TVLV_ROAM, 1, 3217122edaa0SMarek Lindner &tvlv_roam, sizeof(tvlv_roam)); 3218cc47f66eSAntonio Quartulli 3219cc47f66eSAntonio Quartulli out: 3220122edaa0SMarek Lindner if (primary_if) 322182047ad7SSven Eckelmann batadv_hardif_put(primary_if); 3222a73105b8SAntonio Quartulli } 3223a73105b8SAntonio Quartulli 3224a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 3225a73105b8SAntonio Quartulli { 322656303d34SSven Eckelmann struct delayed_work *delayed_work; 3227807736f6SSven Eckelmann struct batadv_priv_tt *priv_tt; 322856303d34SSven Eckelmann struct batadv_priv *bat_priv; 322956303d34SSven Eckelmann 323056303d34SSven Eckelmann delayed_work = container_of(work, struct delayed_work, work); 3231807736f6SSven Eckelmann priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 3232807736f6SSven Eckelmann bat_priv = container_of(priv_tt, struct batadv_priv, tt); 3233a73105b8SAntonio Quartulli 3234a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT); 323530cfd02bSAntonio Quartulli batadv_tt_global_purge(bat_priv); 3236a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 3237a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 3238a73105b8SAntonio Quartulli 323972414442SAntonio Quartulli queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 324072414442SAntonio Quartulli msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3241a73105b8SAntonio Quartulli } 3242cc47f66eSAntonio Quartulli 324356303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv) 3244cc47f66eSAntonio Quartulli { 3245e1bf0c14SMarek Lindner batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); 3246e1bf0c14SMarek Lindner batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); 3247e1bf0c14SMarek Lindner 3248807736f6SSven Eckelmann cancel_delayed_work_sync(&bat_priv->tt.work); 3249cc47f66eSAntonio Quartulli 3250a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 3251a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 3252a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 3253a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 3254a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 3255cc47f66eSAntonio Quartulli 3256807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 3257cc47f66eSAntonio Quartulli } 3258058d0e26SAntonio Quartulli 32597ea7b4a1SAntonio Quartulli /** 32607ea7b4a1SAntonio Quartulli * batadv_tt_local_set_flags - set or unset the specified flags on the local 32617ea7b4a1SAntonio Quartulli * table and possibly count them in the TT size 32627ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 32637ea7b4a1SAntonio Quartulli * @flags: the flag to switch 32647ea7b4a1SAntonio Quartulli * @enable: whether to set or unset the flag 32657ea7b4a1SAntonio Quartulli * @count: whether to increase the TT size by the number of changed entries 32669cfc7bd6SSven Eckelmann */ 32676b5e971aSSven Eckelmann static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags, 32686b5e971aSSven Eckelmann bool enable, bool count) 3269058d0e26SAntonio Quartulli { 32707ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash = bat_priv->tt.local_hash; 32717ea7b4a1SAntonio Quartulli struct batadv_tt_common_entry *tt_common_entry; 32726b5e971aSSven Eckelmann u16 changed_num = 0; 3273058d0e26SAntonio Quartulli struct hlist_head *head; 32746b5e971aSSven Eckelmann u32 i; 3275058d0e26SAntonio Quartulli 3276058d0e26SAntonio Quartulli if (!hash) 32777ea7b4a1SAntonio Quartulli return; 3278058d0e26SAntonio Quartulli 3279058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3280058d0e26SAntonio Quartulli head = &hash->table[i]; 3281058d0e26SAntonio Quartulli 3282058d0e26SAntonio Quartulli rcu_read_lock(); 3283b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 3284058d0e26SAntonio Quartulli head, hash_entry) { 3285697f2531SAntonio Quartulli if (enable) { 3286697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 3287697f2531SAntonio Quartulli continue; 3288697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 3289697f2531SAntonio Quartulli } else { 329048100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 329131901264SAntonio Quartulli continue; 329248100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 3293697f2531SAntonio Quartulli } 3294697f2531SAntonio Quartulli changed_num++; 32957ea7b4a1SAntonio Quartulli 32967ea7b4a1SAntonio Quartulli if (!count) 32977ea7b4a1SAntonio Quartulli continue; 32987ea7b4a1SAntonio Quartulli 32997ea7b4a1SAntonio Quartulli batadv_tt_local_size_inc(bat_priv, 33007ea7b4a1SAntonio Quartulli tt_common_entry->vid); 3301058d0e26SAntonio Quartulli } 3302058d0e26SAntonio Quartulli rcu_read_unlock(); 3303058d0e26SAntonio Quartulli } 3304058d0e26SAntonio Quartulli } 3305058d0e26SAntonio Quartulli 3306acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ 330756303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) 3308058d0e26SAntonio Quartulli { 3309807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 331056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 331156303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 331235df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 3313b67bfe0dSSasha Levin struct hlist_node *node_tmp; 3314058d0e26SAntonio Quartulli struct hlist_head *head; 3315058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 33166b5e971aSSven Eckelmann u32 i; 3317058d0e26SAntonio Quartulli 3318058d0e26SAntonio Quartulli if (!hash) 3319058d0e26SAntonio Quartulli return; 3320058d0e26SAntonio Quartulli 3321058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3322058d0e26SAntonio Quartulli head = &hash->table[i]; 3323058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 3324058d0e26SAntonio Quartulli 3325058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 3326b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 3327acd34afaSSven Eckelmann hash_entry) { 3328acd34afaSSven Eckelmann if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) 3329058d0e26SAntonio Quartulli continue; 3330058d0e26SAntonio Quartulli 333139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 333216052789SAntonio Quartulli "Deleting local tt entry (%pM, vid: %d): pending\n", 333316052789SAntonio Quartulli tt_common->addr, 333416052789SAntonio Quartulli BATADV_PRINT_VID(tt_common->vid)); 3335058d0e26SAntonio Quartulli 33367ea7b4a1SAntonio Quartulli batadv_tt_local_size_dec(bat_priv, tt_common->vid); 3337b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 333856303d34SSven Eckelmann tt_local = container_of(tt_common, 333956303d34SSven Eckelmann struct batadv_tt_local_entry, 334048100bacSAntonio Quartulli common); 334135df3b29SAntonio Quartulli 334235df3b29SAntonio Quartulli /* decrease the reference held for this vlan */ 334335df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid); 3344354136bcSMarek Lindner if (vlan) { 33459c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 33469c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 3347354136bcSMarek Lindner } 334835df3b29SAntonio Quartulli 334956303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 3350058d0e26SAntonio Quartulli } 3351058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 3352058d0e26SAntonio Quartulli } 3353058d0e26SAntonio Quartulli } 3354058d0e26SAntonio Quartulli 3355e1bf0c14SMarek Lindner /** 3356a19d3d85SMarek Lindner * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes 3357a19d3d85SMarek Lindner * which have been queued in the time since the last commit 3358e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3359a19d3d85SMarek Lindner * 3360a19d3d85SMarek Lindner * Caller must hold tt->commit_lock. 3361e1bf0c14SMarek Lindner */ 3362a19d3d85SMarek Lindner static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) 3363058d0e26SAntonio Quartulli { 33645274cd68SSven Eckelmann lockdep_assert_held(&bat_priv->tt.commit_lock); 33655274cd68SSven Eckelmann 3366c5caf4efSLinus Lüssing /* Update multicast addresses in local translation table */ 3367c5caf4efSLinus Lüssing batadv_mcast_mla_update(bat_priv); 3368c5caf4efSLinus Lüssing 3369e1bf0c14SMarek Lindner if (atomic_read(&bat_priv->tt.local_changes) < 1) { 3370e1bf0c14SMarek Lindner if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 3371e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3372a19d3d85SMarek Lindner return; 3373e1bf0c14SMarek Lindner } 3374be9aa4c1SMarek Lindner 33757ea7b4a1SAntonio Quartulli batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); 3376be9aa4c1SMarek Lindner 3377a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 33787ea7b4a1SAntonio Quartulli batadv_tt_local_update_crc(bat_priv); 3379058d0e26SAntonio Quartulli 3380058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 3381807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.vn); 338239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 33831eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 33846b5e971aSSven Eckelmann (u8)atomic_read(&bat_priv->tt.vn)); 3385be9aa4c1SMarek Lindner 3386be9aa4c1SMarek Lindner /* reset the sending counter */ 3387807736f6SSven Eckelmann atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 3388e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3389a19d3d85SMarek Lindner } 3390a70a9aa9SAntonio Quartulli 3391a19d3d85SMarek Lindner /** 3392a19d3d85SMarek Lindner * batadv_tt_local_commit_changes - commit all pending local tt changes which 3393a19d3d85SMarek Lindner * have been queued in the time since the last commit 3394a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3395a19d3d85SMarek Lindner */ 3396a19d3d85SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) 3397a19d3d85SMarek Lindner { 3398a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3399a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3400a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 3401058d0e26SAntonio Quartulli } 340259b699cdSAntonio Quartulli 34036b5e971aSSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, 34046b5e971aSSven Eckelmann unsigned short vid) 340559b699cdSAntonio Quartulli { 340656303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 340756303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 3408b8cbd81dSAntonio Quartulli struct batadv_softif_vlan *vlan; 34095870adc6SMarek Lindner bool ret = false; 341059b699cdSAntonio Quartulli 3411b8cbd81dSAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 3412e087f34fSMarkus Elfring if (!vlan) 3413e087f34fSMarkus Elfring return false; 3414e087f34fSMarkus Elfring 3415e087f34fSMarkus Elfring if (!atomic_read(&vlan->ap_isolation)) 34165870adc6SMarek Lindner goto out; 341759b699cdSAntonio Quartulli 3418b8cbd81dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); 341959b699cdSAntonio Quartulli if (!tt_local_entry) 342059b699cdSAntonio Quartulli goto out; 342159b699cdSAntonio Quartulli 3422b8cbd81dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); 342359b699cdSAntonio Quartulli if (!tt_global_entry) 342459b699cdSAntonio Quartulli goto out; 342559b699cdSAntonio Quartulli 34261f129fefSAntonio Quartulli if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 342759b699cdSAntonio Quartulli goto out; 342859b699cdSAntonio Quartulli 34295870adc6SMarek Lindner ret = true; 343059b699cdSAntonio Quartulli 343159b699cdSAntonio Quartulli out: 34329c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 343359b699cdSAntonio Quartulli if (tt_global_entry) 3434a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 343559b699cdSAntonio Quartulli if (tt_local_entry) 3436a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 343759b699cdSAntonio Quartulli return ret; 343859b699cdSAntonio Quartulli } 3439a943cac1SMarek Lindner 3440e1bf0c14SMarek Lindner /** 3441e1bf0c14SMarek Lindner * batadv_tt_update_orig - update global translation table with new tt 3442e1bf0c14SMarek Lindner * information received via ogms 3443e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3444e51f0397SSven Eckelmann * @orig_node: the orig_node of the ogm 3445e51f0397SSven Eckelmann * @tt_buff: pointer to the first tvlv VLAN entry 34467ea7b4a1SAntonio Quartulli * @tt_num_vlan: number of tvlv VLAN entries 34477ea7b4a1SAntonio Quartulli * @tt_change: pointer to the first entry in the TT buffer 3448e1bf0c14SMarek Lindner * @tt_num_changes: number of tt changes inside the tt buffer 3449e1bf0c14SMarek Lindner * @ttvn: translation table version number of this changeset 3450e1bf0c14SMarek Lindner */ 3451e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv, 345256303d34SSven Eckelmann struct batadv_orig_node *orig_node, 34536b5e971aSSven Eckelmann const void *tt_buff, u16 tt_num_vlan, 34547ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 34556b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn) 3456a943cac1SMarek Lindner { 34576b5e971aSSven Eckelmann u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); 34587ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 3459a943cac1SMarek Lindner bool full_table = true; 3460e17931d1SLinus Lüssing bool has_tt_init; 3461a943cac1SMarek Lindner 34627ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; 3463ac4eebd4SLinus Lüssing has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT, 3464ac4eebd4SLinus Lüssing &orig_node->capa_initialized); 3465e17931d1SLinus Lüssing 346617071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 34679cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 34689cfc7bd6SSven Eckelmann */ 3469e17931d1SLinus Lüssing if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) { 3470a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 347142d0b044SSven Eckelmann * because they have already been sent BATADV_TT_OGM_APPEND_MAX 347242d0b044SSven Eckelmann * times. 34739cfc7bd6SSven Eckelmann * In this case send a tt request 34749cfc7bd6SSven Eckelmann */ 3475a943cac1SMarek Lindner if (!tt_num_changes) { 3476a943cac1SMarek Lindner full_table = false; 3477a943cac1SMarek Lindner goto request_table; 3478a943cac1SMarek Lindner } 3479a943cac1SMarek Lindner 3480a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 3481a70a9aa9SAntonio Quartulli 3482a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 348396412690SSven Eckelmann ttvn, tt_change); 3484a943cac1SMarek Lindner 3485a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 3486a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 34879cfc7bd6SSven Eckelmann * in the global table 34889cfc7bd6SSven Eckelmann */ 34897ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3490a943cac1SMarek Lindner 3491a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3492a70a9aa9SAntonio Quartulli 3493a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 3494a943cac1SMarek Lindner * because a single value could represent different states 3495a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 3496a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 3497a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 3498a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 3499a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 35009cfc7bd6SSven Eckelmann * inconsistency 35019cfc7bd6SSven Eckelmann */ 35027ea7b4a1SAntonio Quartulli if (!batadv_tt_global_check_crc(orig_node, tt_vlan, 35037ea7b4a1SAntonio Quartulli tt_num_vlan)) 3504a943cac1SMarek Lindner goto request_table; 3505a943cac1SMarek Lindner } else { 3506a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 35079cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 35089cfc7bd6SSven Eckelmann */ 3509e17931d1SLinus Lüssing if (!has_tt_init || ttvn != orig_ttvn || 35107ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(orig_node, tt_vlan, 35117ea7b4a1SAntonio Quartulli tt_num_vlan)) { 3512a943cac1SMarek Lindner request_table: 351339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 35147ea7b4a1SAntonio Quartulli "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n", 35157ea7b4a1SAntonio Quartulli orig_node->orig, ttvn, orig_ttvn, 35167ea7b4a1SAntonio Quartulli tt_num_changes); 3517a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 35187ea7b4a1SAntonio Quartulli tt_vlan, tt_num_vlan, 35197ea7b4a1SAntonio Quartulli full_table); 3520a943cac1SMarek Lindner return; 3521a943cac1SMarek Lindner } 3522a943cac1SMarek Lindner } 3523a943cac1SMarek Lindner } 35243275e7ccSAntonio Quartulli 3525c018ad3dSAntonio Quartulli /** 3526c018ad3dSAntonio Quartulli * batadv_tt_global_client_is_roaming - check if a client is marked as roaming 3527c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3528c018ad3dSAntonio Quartulli * @addr: the mac address of the client to check 3529c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3530c018ad3dSAntonio Quartulli * 353162fe710fSSven Eckelmann * Return: true if we know that the client has moved from its old originator 3532c018ad3dSAntonio Quartulli * to another one. This entry is still kept for consistency purposes and will be 3533c018ad3dSAntonio Quartulli * deleted later by a DEL or because of timeout 35343275e7ccSAntonio Quartulli */ 353556303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, 35366b5e971aSSven Eckelmann u8 *addr, unsigned short vid) 35373275e7ccSAntonio Quartulli { 353856303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 35393275e7ccSAntonio Quartulli bool ret = false; 35403275e7ccSAntonio Quartulli 3541c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 35423275e7ccSAntonio Quartulli if (!tt_global_entry) 35433275e7ccSAntonio Quartulli goto out; 35443275e7ccSAntonio Quartulli 3545c1d07431SAntonio Quartulli ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; 3546a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 35473275e7ccSAntonio Quartulli out: 35483275e7ccSAntonio Quartulli return ret; 35493275e7ccSAntonio Quartulli } 355030cfd02bSAntonio Quartulli 35517c1fd91dSAntonio Quartulli /** 35527c1fd91dSAntonio Quartulli * batadv_tt_local_client_is_roaming - tells whether the client is roaming 35537c1fd91dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3554c018ad3dSAntonio Quartulli * @addr: the mac address of the local client to query 3555c018ad3dSAntonio Quartulli * @vid: VLAN identifier 35567c1fd91dSAntonio Quartulli * 355762fe710fSSven Eckelmann * Return: true if the local client is known to be roaming (it is not served by 35587c1fd91dSAntonio Quartulli * this node anymore) or not. If yes, the client is still present in the table 35597c1fd91dSAntonio Quartulli * to keep the latter consistent with the node TTVN 35607c1fd91dSAntonio Quartulli */ 35617c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, 35626b5e971aSSven Eckelmann u8 *addr, unsigned short vid) 35637c1fd91dSAntonio Quartulli { 35647c1fd91dSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry; 35657c1fd91dSAntonio Quartulli bool ret = false; 35667c1fd91dSAntonio Quartulli 3567c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 35687c1fd91dSAntonio Quartulli if (!tt_local_entry) 35697c1fd91dSAntonio Quartulli goto out; 35707c1fd91dSAntonio Quartulli 35717c1fd91dSAntonio Quartulli ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; 35727c1fd91dSAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 35737c1fd91dSAntonio Quartulli out: 35747c1fd91dSAntonio Quartulli return ret; 35757c1fd91dSAntonio Quartulli } 35767c1fd91dSAntonio Quartulli 357730cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, 357830cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 3579c018ad3dSAntonio Quartulli const unsigned char *addr, 358016052789SAntonio Quartulli unsigned short vid) 358130cfd02bSAntonio Quartulli { 358230cfd02bSAntonio Quartulli bool ret = false; 358330cfd02bSAntonio Quartulli 358416052789SAntonio Quartulli if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, 358530cfd02bSAntonio Quartulli BATADV_TT_CLIENT_TEMP, 358630cfd02bSAntonio Quartulli atomic_read(&orig_node->last_ttvn))) 358730cfd02bSAntonio Quartulli goto out; 358830cfd02bSAntonio Quartulli 358930cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 359016052789SAntonio Quartulli "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n", 359116052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid), orig_node->orig); 359230cfd02bSAntonio Quartulli ret = true; 359330cfd02bSAntonio Quartulli out: 359430cfd02bSAntonio Quartulli return ret; 359530cfd02bSAntonio Quartulli } 3596e1bf0c14SMarek Lindner 3597e1bf0c14SMarek Lindner /** 3598a19d3d85SMarek Lindner * batadv_tt_local_resize_to_mtu - resize the local translation table fit the 3599a19d3d85SMarek Lindner * maximum packet size that can be transported through the mesh 3600a19d3d85SMarek Lindner * @soft_iface: netdev struct of the mesh interface 3601a19d3d85SMarek Lindner * 3602a19d3d85SMarek Lindner * Remove entries older than 'timeout' and half timeout if more entries need 3603a19d3d85SMarek Lindner * to be removed. 3604a19d3d85SMarek Lindner */ 3605a19d3d85SMarek Lindner void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface) 3606a19d3d85SMarek Lindner { 3607a19d3d85SMarek Lindner struct batadv_priv *bat_priv = netdev_priv(soft_iface); 3608a19d3d85SMarek Lindner int packet_size_max = atomic_read(&bat_priv->packet_size_max); 3609a19d3d85SMarek Lindner int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; 3610a19d3d85SMarek Lindner bool reduced = false; 3611a19d3d85SMarek Lindner 3612a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3613a19d3d85SMarek Lindner 3614a19d3d85SMarek Lindner while (true) { 3615a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 3616a19d3d85SMarek Lindner if (packet_size_max >= table_size) 3617a19d3d85SMarek Lindner break; 3618a19d3d85SMarek Lindner 3619a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, timeout); 3620a19d3d85SMarek Lindner batadv_tt_local_purge_pending_clients(bat_priv); 3621a19d3d85SMarek Lindner 3622a19d3d85SMarek Lindner timeout /= 2; 3623a19d3d85SMarek Lindner reduced = true; 3624a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 3625a19d3d85SMarek Lindner "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n", 3626a19d3d85SMarek Lindner packet_size_max); 3627a19d3d85SMarek Lindner } 3628a19d3d85SMarek Lindner 3629a19d3d85SMarek Lindner /* commit these changes immediately, to avoid synchronization problem 3630a19d3d85SMarek Lindner * with the TTVN 3631a19d3d85SMarek Lindner */ 3632a19d3d85SMarek Lindner if (reduced) 3633a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3634a19d3d85SMarek Lindner 3635a19d3d85SMarek Lindner spin_unlock_bh(&bat_priv->tt.commit_lock); 3636a19d3d85SMarek Lindner } 3637a19d3d85SMarek Lindner 3638a19d3d85SMarek Lindner /** 3639e1bf0c14SMarek Lindner * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container 3640e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3641e1bf0c14SMarek Lindner * @orig: the orig_node of the ogm 3642e1bf0c14SMarek Lindner * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 3643e1bf0c14SMarek Lindner * @tvlv_value: tvlv buffer containing the gateway data 3644e1bf0c14SMarek Lindner * @tvlv_value_len: tvlv buffer length 3645e1bf0c14SMarek Lindner */ 3646e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 3647e1bf0c14SMarek Lindner struct batadv_orig_node *orig, 36486b5e971aSSven Eckelmann u8 flags, void *tvlv_value, 36496b5e971aSSven Eckelmann u16 tvlv_value_len) 3650e1bf0c14SMarek Lindner { 36517ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 36527ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 3653e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 36546b5e971aSSven Eckelmann u16 num_entries, num_vlan; 3655e1bf0c14SMarek Lindner 3656e1bf0c14SMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 3657e1bf0c14SMarek Lindner return; 3658e1bf0c14SMarek Lindner 3659e1bf0c14SMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 3660e1bf0c14SMarek Lindner tvlv_value_len -= sizeof(*tt_data); 3661e1bf0c14SMarek Lindner 36627ea7b4a1SAntonio Quartulli num_vlan = ntohs(tt_data->num_vlan); 36637ea7b4a1SAntonio Quartulli 36647ea7b4a1SAntonio Quartulli if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) 36657ea7b4a1SAntonio Quartulli return; 36667ea7b4a1SAntonio Quartulli 36677ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 36687ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); 36697ea7b4a1SAntonio Quartulli tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; 36707ea7b4a1SAntonio Quartulli 3671298e6e68SAntonio Quartulli num_entries = batadv_tt_entries(tvlv_value_len); 3672e1bf0c14SMarek Lindner 36737ea7b4a1SAntonio Quartulli batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, 36747ea7b4a1SAntonio Quartulli num_entries, tt_data->ttvn); 3675e1bf0c14SMarek Lindner } 3676e1bf0c14SMarek Lindner 3677e1bf0c14SMarek Lindner /** 3678335fbe0fSMarek Lindner * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv 3679335fbe0fSMarek Lindner * container 3680335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3681335fbe0fSMarek Lindner * @src: mac address of tt tvlv sender 3682335fbe0fSMarek Lindner * @dst: mac address of tt tvlv recipient 3683335fbe0fSMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 3684335fbe0fSMarek Lindner * @tvlv_value_len: tvlv buffer length 3685335fbe0fSMarek Lindner * 368662fe710fSSven Eckelmann * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS 3687335fbe0fSMarek Lindner * otherwise. 3688335fbe0fSMarek Lindner */ 3689335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 36906b5e971aSSven Eckelmann u8 *src, u8 *dst, 3691335fbe0fSMarek Lindner void *tvlv_value, 36926b5e971aSSven Eckelmann u16 tvlv_value_len) 3693335fbe0fSMarek Lindner { 3694335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data; 36956b5e971aSSven Eckelmann u16 tt_vlan_len, tt_num_entries; 3696335fbe0fSMarek Lindner char tt_flag; 3697335fbe0fSMarek Lindner bool ret; 3698335fbe0fSMarek Lindner 3699335fbe0fSMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 3700335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3701335fbe0fSMarek Lindner 3702335fbe0fSMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 3703335fbe0fSMarek Lindner tvlv_value_len -= sizeof(*tt_data); 3704335fbe0fSMarek Lindner 37057ea7b4a1SAntonio Quartulli tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); 37067ea7b4a1SAntonio Quartulli tt_vlan_len *= ntohs(tt_data->num_vlan); 37077ea7b4a1SAntonio Quartulli 37087ea7b4a1SAntonio Quartulli if (tvlv_value_len < tt_vlan_len) 37097ea7b4a1SAntonio Quartulli return NET_RX_SUCCESS; 37107ea7b4a1SAntonio Quartulli 37117ea7b4a1SAntonio Quartulli tvlv_value_len -= tt_vlan_len; 37127ea7b4a1SAntonio Quartulli tt_num_entries = batadv_tt_entries(tvlv_value_len); 3713335fbe0fSMarek Lindner 3714335fbe0fSMarek Lindner switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { 3715335fbe0fSMarek Lindner case BATADV_TT_REQUEST: 3716335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); 3717335fbe0fSMarek Lindner 3718335fbe0fSMarek Lindner /* If this node cannot provide a TT response the tt_request is 3719335fbe0fSMarek Lindner * forwarded 3720335fbe0fSMarek Lindner */ 3721335fbe0fSMarek Lindner ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); 3722335fbe0fSMarek Lindner if (!ret) { 3723335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 3724335fbe0fSMarek Lindner tt_flag = 'F'; 3725335fbe0fSMarek Lindner else 3726335fbe0fSMarek Lindner tt_flag = '.'; 3727335fbe0fSMarek Lindner 3728335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3729335fbe0fSMarek Lindner "Routing TT_REQUEST to %pM [%c]\n", 3730335fbe0fSMarek Lindner dst, tt_flag); 3731335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 3732335fbe0fSMarek Lindner return NET_RX_DROP; 3733335fbe0fSMarek Lindner } 3734335fbe0fSMarek Lindner break; 3735335fbe0fSMarek Lindner case BATADV_TT_RESPONSE: 3736335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); 3737335fbe0fSMarek Lindner 3738335fbe0fSMarek Lindner if (batadv_is_my_mac(bat_priv, dst)) { 3739335fbe0fSMarek Lindner batadv_handle_tt_response(bat_priv, tt_data, 37407ea7b4a1SAntonio Quartulli src, tt_num_entries); 3741335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3742335fbe0fSMarek Lindner } 3743335fbe0fSMarek Lindner 3744335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 3745335fbe0fSMarek Lindner tt_flag = 'F'; 3746335fbe0fSMarek Lindner else 3747335fbe0fSMarek Lindner tt_flag = '.'; 3748335fbe0fSMarek Lindner 3749335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3750335fbe0fSMarek Lindner "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag); 3751335fbe0fSMarek Lindner 3752335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 3753335fbe0fSMarek Lindner return NET_RX_DROP; 3754335fbe0fSMarek Lindner } 3755335fbe0fSMarek Lindner 3756335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3757335fbe0fSMarek Lindner } 3758335fbe0fSMarek Lindner 3759335fbe0fSMarek Lindner /** 3760122edaa0SMarek Lindner * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container 3761122edaa0SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3762122edaa0SMarek Lindner * @src: mac address of tt tvlv sender 3763122edaa0SMarek Lindner * @dst: mac address of tt tvlv recipient 3764122edaa0SMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 3765122edaa0SMarek Lindner * @tvlv_value_len: tvlv buffer length 3766122edaa0SMarek Lindner * 376762fe710fSSven Eckelmann * Return: NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS 3768122edaa0SMarek Lindner * otherwise. 3769122edaa0SMarek Lindner */ 3770122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 37716b5e971aSSven Eckelmann u8 *src, u8 *dst, 3772122edaa0SMarek Lindner void *tvlv_value, 37736b5e971aSSven Eckelmann u16 tvlv_value_len) 3774122edaa0SMarek Lindner { 3775122edaa0SMarek Lindner struct batadv_tvlv_roam_adv *roaming_adv; 3776122edaa0SMarek Lindner struct batadv_orig_node *orig_node = NULL; 3777122edaa0SMarek Lindner 3778122edaa0SMarek Lindner /* If this node is not the intended recipient of the 3779122edaa0SMarek Lindner * roaming advertisement the packet is forwarded 3780122edaa0SMarek Lindner * (the tvlv API will re-route the packet). 3781122edaa0SMarek Lindner */ 3782122edaa0SMarek Lindner if (!batadv_is_my_mac(bat_priv, dst)) 3783122edaa0SMarek Lindner return NET_RX_DROP; 3784122edaa0SMarek Lindner 3785122edaa0SMarek Lindner if (tvlv_value_len < sizeof(*roaming_adv)) 3786122edaa0SMarek Lindner goto out; 3787122edaa0SMarek Lindner 3788122edaa0SMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, src); 3789122edaa0SMarek Lindner if (!orig_node) 3790122edaa0SMarek Lindner goto out; 3791122edaa0SMarek Lindner 3792122edaa0SMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); 3793122edaa0SMarek Lindner roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; 3794122edaa0SMarek Lindner 3795122edaa0SMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3796122edaa0SMarek Lindner "Received ROAMING_ADV from %pM (client %pM)\n", 3797122edaa0SMarek Lindner src, roaming_adv->client); 3798122edaa0SMarek Lindner 3799122edaa0SMarek Lindner batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, 3800c018ad3dSAntonio Quartulli ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, 3801122edaa0SMarek Lindner atomic_read(&orig_node->last_ttvn) + 1); 3802122edaa0SMarek Lindner 3803122edaa0SMarek Lindner out: 3804122edaa0SMarek Lindner if (orig_node) 38055d967310SSven Eckelmann batadv_orig_node_put(orig_node); 3806122edaa0SMarek Lindner return NET_RX_SUCCESS; 3807122edaa0SMarek Lindner } 3808122edaa0SMarek Lindner 3809122edaa0SMarek Lindner /** 3810e1bf0c14SMarek Lindner * batadv_tt_init - initialise the translation table internals 3811e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3812e1bf0c14SMarek Lindner * 381362fe710fSSven Eckelmann * Return: 0 on success or negative error number in case of failure. 3814e1bf0c14SMarek Lindner */ 3815e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv) 3816e1bf0c14SMarek Lindner { 3817e1bf0c14SMarek Lindner int ret; 3818e1bf0c14SMarek Lindner 38190eb01568SAntonio Quartulli /* synchronized flags must be remote */ 38200eb01568SAntonio Quartulli BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK)); 38210eb01568SAntonio Quartulli 3822e1bf0c14SMarek Lindner ret = batadv_tt_local_init(bat_priv); 3823e1bf0c14SMarek Lindner if (ret < 0) 3824e1bf0c14SMarek Lindner return ret; 3825e1bf0c14SMarek Lindner 3826e1bf0c14SMarek Lindner ret = batadv_tt_global_init(bat_priv); 3827e1bf0c14SMarek Lindner if (ret < 0) 3828e1bf0c14SMarek Lindner return ret; 3829e1bf0c14SMarek Lindner 3830e1bf0c14SMarek Lindner batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, 3831335fbe0fSMarek Lindner batadv_tt_tvlv_unicast_handler_v1, 3832335fbe0fSMarek Lindner BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); 3833e1bf0c14SMarek Lindner 3834122edaa0SMarek Lindner batadv_tvlv_handler_register(bat_priv, NULL, 3835122edaa0SMarek Lindner batadv_roam_tvlv_unicast_handler_v1, 3836122edaa0SMarek Lindner BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); 3837122edaa0SMarek Lindner 3838e1bf0c14SMarek Lindner INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); 3839e1bf0c14SMarek Lindner queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 3840e1bf0c14SMarek Lindner msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3841e1bf0c14SMarek Lindner 3842e1bf0c14SMarek Lindner return 1; 3843e1bf0c14SMarek Lindner } 384442cb0befSAntonio Quartulli 384542cb0befSAntonio Quartulli /** 384642cb0befSAntonio Quartulli * batadv_tt_global_is_isolated - check if a client is marked as isolated 384742cb0befSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 384842cb0befSAntonio Quartulli * @addr: the mac address of the client 384942cb0befSAntonio Quartulli * @vid: the identifier of the VLAN where this client is connected 385042cb0befSAntonio Quartulli * 385162fe710fSSven Eckelmann * Return: true if the client is marked with the TT_CLIENT_ISOLA flag, false 385242cb0befSAntonio Quartulli * otherwise 385342cb0befSAntonio Quartulli */ 385442cb0befSAntonio Quartulli bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, 38556b5e971aSSven Eckelmann const u8 *addr, unsigned short vid) 385642cb0befSAntonio Quartulli { 385742cb0befSAntonio Quartulli struct batadv_tt_global_entry *tt; 385842cb0befSAntonio Quartulli bool ret; 385942cb0befSAntonio Quartulli 386042cb0befSAntonio Quartulli tt = batadv_tt_global_hash_find(bat_priv, addr, vid); 386142cb0befSAntonio Quartulli if (!tt) 386242cb0befSAntonio Quartulli return false; 386342cb0befSAntonio Quartulli 386442cb0befSAntonio Quartulli ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA; 386542cb0befSAntonio Quartulli 386642cb0befSAntonio Quartulli batadv_tt_global_entry_free_ref(tt); 386742cb0befSAntonio Quartulli 386842cb0befSAntonio Quartulli return ret; 386942cb0befSAntonio Quartulli } 3870