19f6446c7SSven Eckelmann /* Copyright (C) 2007-2015 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> 341e2c2a4fSSven Eckelmann #include <linux/list.h> 351e2c2a4fSSven Eckelmann #include <linux/lockdep.h> 361e2c2a4fSSven Eckelmann #include <linux/netdevice.h> 371e2c2a4fSSven Eckelmann #include <linux/rculist.h> 381e2c2a4fSSven Eckelmann #include <linux/rcupdate.h> 391e2c2a4fSSven Eckelmann #include <linux/seq_file.h> 401e2c2a4fSSven Eckelmann #include <linux/slab.h> 411e2c2a4fSSven Eckelmann #include <linux/spinlock.h> 421e2c2a4fSSven Eckelmann #include <linux/stddef.h> 431e2c2a4fSSven Eckelmann #include <linux/string.h> 441e2c2a4fSSven Eckelmann #include <linux/workqueue.h> 451e2c2a4fSSven Eckelmann #include <net/net_namespace.h> 461e2c2a4fSSven Eckelmann 471e2c2a4fSSven Eckelmann #include "bridge_loop_avoidance.h" 481e2c2a4fSSven Eckelmann #include "hard-interface.h" 491e2c2a4fSSven Eckelmann #include "hash.h" 501e2c2a4fSSven Eckelmann #include "multicast.h" 511e2c2a4fSSven Eckelmann #include "originator.h" 521e2c2a4fSSven Eckelmann #include "packet.h" 531e2c2a4fSSven Eckelmann #include "soft-interface.h" 54a73105b8SAntonio Quartulli 55dec05074SAntonio Quartulli /* hash class keys */ 56dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_local_hash_lock_class_key; 57dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_global_hash_lock_class_key; 58dec05074SAntonio Quartulli 596b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, 60c018ad3dSAntonio Quartulli unsigned short vid, 6156303d34SSven Eckelmann struct batadv_orig_node *orig_node); 62a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work); 63a513088dSSven Eckelmann static void 6456303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); 6530cfd02bSAntonio Quartulli static void batadv_tt_global_del(struct batadv_priv *bat_priv, 6630cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 6730cfd02bSAntonio Quartulli const unsigned char *addr, 68c018ad3dSAntonio Quartulli unsigned short vid, const char *message, 69c018ad3dSAntonio Quartulli bool roaming); 70c6c8fea2SSven Eckelmann 7162fe710fSSven Eckelmann /** 7262fe710fSSven Eckelmann * batadv_compare_tt 7362fe710fSSven Eckelmann * 7462fe710fSSven Eckelmann * Return: 1 if they are the same mac addr and vid 7562fe710fSSven Eckelmann */ 76a513088dSSven Eckelmann static int batadv_compare_tt(const struct hlist_node *node, const void *data2) 777aadf889SMarek Lindner { 7856303d34SSven Eckelmann const void *data1 = container_of(node, struct batadv_tt_common_entry, 79747e4221SSven Eckelmann hash_entry); 804c718958SMarek Lindner const struct batadv_tt_common_entry *tt1 = data1; 814c718958SMarek Lindner const struct batadv_tt_common_entry *tt2 = data2; 827aadf889SMarek Lindner 834c718958SMarek Lindner return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2); 847aadf889SMarek Lindner } 857aadf889SMarek Lindner 86c018ad3dSAntonio Quartulli /** 87c018ad3dSAntonio Quartulli * batadv_choose_tt - return the index of the tt entry in the hash table 88c018ad3dSAntonio Quartulli * @data: pointer to the tt_common_entry object to map 89c018ad3dSAntonio Quartulli * @size: the size of the hash table 90c018ad3dSAntonio Quartulli * 9162fe710fSSven Eckelmann * Return: the hash index where the object represented by 'data' should be 92c018ad3dSAntonio Quartulli * stored at. 93c018ad3dSAntonio Quartulli */ 946b5e971aSSven Eckelmann static inline u32 batadv_choose_tt(const void *data, u32 size) 95c018ad3dSAntonio Quartulli { 96c018ad3dSAntonio Quartulli struct batadv_tt_common_entry *tt; 976b5e971aSSven Eckelmann u32 hash = 0; 98c018ad3dSAntonio Quartulli 99c018ad3dSAntonio Quartulli tt = (struct batadv_tt_common_entry *)data; 10036fd61cbSSven Eckelmann hash = jhash(&tt->addr, ETH_ALEN, hash); 10136fd61cbSSven Eckelmann hash = jhash(&tt->vid, sizeof(tt->vid), hash); 102c018ad3dSAntonio Quartulli 103c018ad3dSAntonio Quartulli return hash % size; 104c018ad3dSAntonio Quartulli } 105c018ad3dSAntonio Quartulli 106c018ad3dSAntonio Quartulli /** 107c018ad3dSAntonio Quartulli * batadv_tt_hash_find - look for a client in the given hash table 108c018ad3dSAntonio Quartulli * @hash: the hash table to search 109c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 110c018ad3dSAntonio Quartulli * @vid: VLAN identifier 111c018ad3dSAntonio Quartulli * 11262fe710fSSven Eckelmann * Return: a pointer to the tt_common struct belonging to the searched client if 113c018ad3dSAntonio Quartulli * found, NULL otherwise. 114c018ad3dSAntonio Quartulli */ 11556303d34SSven Eckelmann static struct batadv_tt_common_entry * 1166b5e971aSSven Eckelmann batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr, 117c018ad3dSAntonio Quartulli unsigned short vid) 1187aadf889SMarek Lindner { 1197aadf889SMarek Lindner struct hlist_head *head; 120c018ad3dSAntonio Quartulli struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; 1216b5e971aSSven Eckelmann u32 index; 1227aadf889SMarek Lindner 1237aadf889SMarek Lindner if (!hash) 1247aadf889SMarek Lindner return NULL; 1257aadf889SMarek Lindner 1268fdd0153SAntonio Quartulli ether_addr_copy(to_search.addr, addr); 127c018ad3dSAntonio Quartulli to_search.vid = vid; 128c018ad3dSAntonio Quartulli 129c018ad3dSAntonio Quartulli index = batadv_choose_tt(&to_search, hash->size); 1307aadf889SMarek Lindner head = &hash->table[index]; 1317aadf889SMarek Lindner 1327aadf889SMarek Lindner rcu_read_lock(); 133c018ad3dSAntonio Quartulli hlist_for_each_entry_rcu(tt, head, hash_entry) { 134c018ad3dSAntonio Quartulli if (!batadv_compare_eth(tt, addr)) 1357aadf889SMarek Lindner continue; 1367aadf889SMarek Lindner 137c018ad3dSAntonio Quartulli if (tt->vid != vid) 1387683fdc1SAntonio Quartulli continue; 1397683fdc1SAntonio Quartulli 140c018ad3dSAntonio Quartulli if (!atomic_inc_not_zero(&tt->refcount)) 141c018ad3dSAntonio Quartulli continue; 142c018ad3dSAntonio Quartulli 143c018ad3dSAntonio Quartulli tt_tmp = tt; 1447aadf889SMarek Lindner break; 1457aadf889SMarek Lindner } 1467aadf889SMarek Lindner rcu_read_unlock(); 1477aadf889SMarek Lindner 148c018ad3dSAntonio Quartulli return tt_tmp; 14948100bacSAntonio Quartulli } 15048100bacSAntonio Quartulli 151c018ad3dSAntonio Quartulli /** 152c018ad3dSAntonio Quartulli * batadv_tt_local_hash_find - search the local table for a given client 153c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 154c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 155c018ad3dSAntonio Quartulli * @vid: VLAN identifier 156c018ad3dSAntonio Quartulli * 15762fe710fSSven Eckelmann * Return: a pointer to the corresponding tt_local_entry struct if the client is 158c018ad3dSAntonio Quartulli * found, NULL otherwise. 159c018ad3dSAntonio Quartulli */ 16056303d34SSven Eckelmann static struct batadv_tt_local_entry * 1616b5e971aSSven Eckelmann batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr, 162c018ad3dSAntonio Quartulli unsigned short vid) 16348100bacSAntonio Quartulli { 16456303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 16556303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 16648100bacSAntonio Quartulli 167c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, 168c018ad3dSAntonio Quartulli vid); 16948100bacSAntonio Quartulli if (tt_common_entry) 17048100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 17156303d34SSven Eckelmann struct batadv_tt_local_entry, 17256303d34SSven Eckelmann common); 17348100bacSAntonio Quartulli return tt_local_entry; 1747aadf889SMarek Lindner } 1757aadf889SMarek Lindner 176c018ad3dSAntonio Quartulli /** 177c018ad3dSAntonio Quartulli * batadv_tt_global_hash_find - search the global table for a given client 178c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 179c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 180c018ad3dSAntonio Quartulli * @vid: VLAN identifier 181c018ad3dSAntonio Quartulli * 18262fe710fSSven Eckelmann * Return: a pointer to the corresponding tt_global_entry struct if the client 183c018ad3dSAntonio Quartulli * is found, NULL otherwise. 184c018ad3dSAntonio Quartulli */ 18556303d34SSven Eckelmann static struct batadv_tt_global_entry * 1866b5e971aSSven Eckelmann batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, 187c018ad3dSAntonio Quartulli unsigned short vid) 1887aadf889SMarek Lindner { 18956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 19056303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 1917aadf889SMarek Lindner 192c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, 193c018ad3dSAntonio Quartulli vid); 19448100bacSAntonio Quartulli if (tt_common_entry) 19548100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 19656303d34SSven Eckelmann struct batadv_tt_global_entry, 19756303d34SSven Eckelmann common); 19848100bacSAntonio Quartulli return tt_global_entry; 1997aadf889SMarek Lindner } 2007aadf889SMarek Lindner 201a513088dSSven Eckelmann static void 20256303d34SSven Eckelmann batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry) 2037683fdc1SAntonio Quartulli { 20448100bacSAntonio Quartulli if (atomic_dec_and_test(&tt_local_entry->common.refcount)) 20548100bacSAntonio Quartulli kfree_rcu(tt_local_entry, common.rcu); 2067683fdc1SAntonio Quartulli } 2077683fdc1SAntonio Quartulli 20821026059SAntonio Quartulli /** 20921026059SAntonio Quartulli * batadv_tt_global_entry_free_ref - decrement the refcounter for a 21021026059SAntonio Quartulli * tt_global_entry and possibly free it 21121026059SAntonio Quartulli * @tt_global_entry: the object to free 21221026059SAntonio Quartulli */ 213a513088dSSven Eckelmann static void 21456303d34SSven Eckelmann batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) 2157683fdc1SAntonio Quartulli { 216db08e6e5SSimon Wunderlich if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { 217a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 21821026059SAntonio Quartulli kfree_rcu(tt_global_entry, common.rcu); 2197683fdc1SAntonio Quartulli } 220db08e6e5SSimon Wunderlich } 221db08e6e5SSimon Wunderlich 2221d8ab8d3SLinus Lüssing /** 2231d8ab8d3SLinus Lüssing * batadv_tt_global_hash_count - count the number of orig entries 2241d8ab8d3SLinus Lüssing * @addr: the mac address of the client to count entries for 2251d8ab8d3SLinus Lüssing * @vid: VLAN identifier 2261d8ab8d3SLinus Lüssing * 22762fe710fSSven Eckelmann * Return: the number of originators advertising the given address/data 2281d8ab8d3SLinus Lüssing * (excluding ourself). 2291d8ab8d3SLinus Lüssing */ 2301d8ab8d3SLinus Lüssing int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, 2316b5e971aSSven Eckelmann const u8 *addr, unsigned short vid) 2321d8ab8d3SLinus Lüssing { 2331d8ab8d3SLinus Lüssing struct batadv_tt_global_entry *tt_global_entry; 2341d8ab8d3SLinus Lüssing int count; 2351d8ab8d3SLinus Lüssing 2361d8ab8d3SLinus Lüssing tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 2371d8ab8d3SLinus Lüssing if (!tt_global_entry) 2381d8ab8d3SLinus Lüssing return 0; 2391d8ab8d3SLinus Lüssing 2401d8ab8d3SLinus Lüssing count = atomic_read(&tt_global_entry->orig_list_count); 2411d8ab8d3SLinus Lüssing batadv_tt_global_entry_free_ref(tt_global_entry); 2421d8ab8d3SLinus Lüssing 2431d8ab8d3SLinus Lüssing return count; 2441d8ab8d3SLinus Lüssing } 2451d8ab8d3SLinus Lüssing 2467ea7b4a1SAntonio Quartulli /** 2477ea7b4a1SAntonio Quartulli * batadv_tt_local_size_mod - change the size by v of the local table identified 2487ea7b4a1SAntonio Quartulli * by vid 2497ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2507ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier of the sub-table to change 2517ea7b4a1SAntonio Quartulli * @v: the amount to sum to the local table size 2527ea7b4a1SAntonio Quartulli */ 2537ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv, 2547ea7b4a1SAntonio Quartulli unsigned short vid, int v) 2557ea7b4a1SAntonio Quartulli { 2567ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 2577ea7b4a1SAntonio Quartulli 2587ea7b4a1SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 2597ea7b4a1SAntonio Quartulli if (!vlan) 2607ea7b4a1SAntonio Quartulli return; 2617ea7b4a1SAntonio Quartulli 2627ea7b4a1SAntonio Quartulli atomic_add(v, &vlan->tt.num_entries); 2637ea7b4a1SAntonio Quartulli 2647ea7b4a1SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 2657ea7b4a1SAntonio Quartulli } 2667ea7b4a1SAntonio Quartulli 2677ea7b4a1SAntonio Quartulli /** 2687ea7b4a1SAntonio Quartulli * batadv_tt_local_size_inc - increase by one the local table size for the given 2697ea7b4a1SAntonio Quartulli * vid 2707ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2717ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 2727ea7b4a1SAntonio Quartulli */ 2737ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv, 2747ea7b4a1SAntonio Quartulli unsigned short vid) 2757ea7b4a1SAntonio Quartulli { 2767ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, 1); 2777ea7b4a1SAntonio Quartulli } 2787ea7b4a1SAntonio Quartulli 2797ea7b4a1SAntonio Quartulli /** 2807ea7b4a1SAntonio Quartulli * batadv_tt_local_size_dec - decrease by one the local table size for the given 2817ea7b4a1SAntonio Quartulli * vid 2827ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2837ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 2847ea7b4a1SAntonio Quartulli */ 2857ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv, 2867ea7b4a1SAntonio Quartulli unsigned short vid) 2877ea7b4a1SAntonio Quartulli { 2887ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, -1); 2897ea7b4a1SAntonio Quartulli } 2907ea7b4a1SAntonio Quartulli 2917ea7b4a1SAntonio Quartulli /** 2927ea7b4a1SAntonio Quartulli * batadv_tt_global_size_mod - change the size by v of the local table 2937ea7b4a1SAntonio Quartulli * identified by vid 2947ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 2957ea7b4a1SAntonio Quartulli * @v: the amount to sum to the global table size 2967ea7b4a1SAntonio Quartulli */ 2977ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, 2987ea7b4a1SAntonio Quartulli unsigned short vid, int v) 2997ea7b4a1SAntonio Quartulli { 3007ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 3017ea7b4a1SAntonio Quartulli 3027ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_new(orig_node, vid); 3037ea7b4a1SAntonio Quartulli if (!vlan) 3047ea7b4a1SAntonio Quartulli return; 3057ea7b4a1SAntonio Quartulli 3067ea7b4a1SAntonio Quartulli if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { 3077ea7b4a1SAntonio Quartulli spin_lock_bh(&orig_node->vlan_list_lock); 308a121048aSMarek Lindner hlist_del_init_rcu(&vlan->list); 3097ea7b4a1SAntonio Quartulli spin_unlock_bh(&orig_node->vlan_list_lock); 3107ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 3117ea7b4a1SAntonio Quartulli } 3127ea7b4a1SAntonio Quartulli 3137ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 3147ea7b4a1SAntonio Quartulli } 3157ea7b4a1SAntonio Quartulli 3167ea7b4a1SAntonio Quartulli /** 3177ea7b4a1SAntonio Quartulli * batadv_tt_global_size_inc - increase by one the global table size for the 3187ea7b4a1SAntonio Quartulli * given vid 3197ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 3207ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 3217ea7b4a1SAntonio Quartulli */ 3227ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node, 3237ea7b4a1SAntonio Quartulli unsigned short vid) 3247ea7b4a1SAntonio Quartulli { 3257ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, 1); 3267ea7b4a1SAntonio Quartulli } 3277ea7b4a1SAntonio Quartulli 3287ea7b4a1SAntonio Quartulli /** 3297ea7b4a1SAntonio Quartulli * batadv_tt_global_size_dec - decrease by one the global table size for the 3307ea7b4a1SAntonio Quartulli * given vid 3317ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 3327ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 3337ea7b4a1SAntonio Quartulli */ 3347ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, 3357ea7b4a1SAntonio Quartulli unsigned short vid) 3367ea7b4a1SAntonio Quartulli { 3377ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, -1); 3387ea7b4a1SAntonio Quartulli } 3397ea7b4a1SAntonio Quartulli 34042eff6a6SSven Eckelmann /** 34142eff6a6SSven Eckelmann * batadv_tt_orig_list_entry_release - release tt orig entry from lists and 34242eff6a6SSven Eckelmann * queue for free after rcu grace period 34342eff6a6SSven Eckelmann * @orig_entry: tt orig entry to be free'd 34442eff6a6SSven Eckelmann */ 34542eff6a6SSven Eckelmann static void 34642eff6a6SSven Eckelmann batadv_tt_orig_list_entry_release(struct batadv_tt_orig_list_entry *orig_entry) 34742eff6a6SSven Eckelmann { 34842eff6a6SSven Eckelmann batadv_orig_node_free_ref(orig_entry->orig_node); 34942eff6a6SSven Eckelmann kfree_rcu(orig_entry, rcu); 35042eff6a6SSven Eckelmann } 35142eff6a6SSven Eckelmann 352a513088dSSven Eckelmann static void 35356303d34SSven Eckelmann batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) 354db08e6e5SSimon Wunderlich { 355d657e621SAntonio Quartulli if (!atomic_dec_and_test(&orig_entry->refcount)) 356d657e621SAntonio Quartulli return; 3577ea7b4a1SAntonio Quartulli 35842eff6a6SSven Eckelmann batadv_tt_orig_list_entry_release(orig_entry); 359db08e6e5SSimon Wunderlich } 3607683fdc1SAntonio Quartulli 3613abe4adbSAntonio Quartulli /** 3623abe4adbSAntonio Quartulli * batadv_tt_local_event - store a local TT event (ADD/DEL) 3633abe4adbSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3643abe4adbSAntonio Quartulli * @tt_local_entry: the TT entry involved in the event 3653abe4adbSAntonio Quartulli * @event_flags: flags to store in the event structure 3663abe4adbSAntonio Quartulli */ 36756303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv, 3683abe4adbSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry, 3696b5e971aSSven Eckelmann u8 event_flags) 370a73105b8SAntonio Quartulli { 37156303d34SSven Eckelmann struct batadv_tt_change_node *tt_change_node, *entry, *safe; 3723abe4adbSAntonio Quartulli struct batadv_tt_common_entry *common = &tt_local_entry->common; 3736b5e971aSSven Eckelmann u8 flags = common->flags | event_flags; 3743b643de5SAntonio Quartulli bool event_removed = false; 3753b643de5SAntonio Quartulli bool del_op_requested, del_op_entry; 376a73105b8SAntonio Quartulli 377a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 378a73105b8SAntonio Quartulli if (!tt_change_node) 379a73105b8SAntonio Quartulli return; 380a73105b8SAntonio Quartulli 381ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 382ca663046SAntonio Quartulli memset(tt_change_node->change.reserved, 0, 383ca663046SAntonio Quartulli sizeof(tt_change_node->change.reserved)); 3848fdd0153SAntonio Quartulli ether_addr_copy(tt_change_node->change.addr, common->addr); 385c018ad3dSAntonio Quartulli tt_change_node->change.vid = htons(common->vid); 386a73105b8SAntonio Quartulli 387acd34afaSSven Eckelmann del_op_requested = flags & BATADV_TT_CLIENT_DEL; 3883b643de5SAntonio Quartulli 3893b643de5SAntonio Quartulli /* check for ADD+DEL or DEL+ADD events */ 390807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 391807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 3923b643de5SAntonio Quartulli list) { 3933abe4adbSAntonio Quartulli if (!batadv_compare_eth(entry->change.addr, common->addr)) 3943b643de5SAntonio Quartulli continue; 3953b643de5SAntonio Quartulli 3963b643de5SAntonio Quartulli /* DEL+ADD in the same orig interval have no effect and can be 3973b643de5SAntonio Quartulli * removed to avoid silly behaviour on the receiver side. The 3983b643de5SAntonio Quartulli * other way around (ADD+DEL) can happen in case of roaming of 3993b643de5SAntonio Quartulli * a client still in the NEW state. Roaming of NEW clients is 4003b643de5SAntonio Quartulli * now possible due to automatically recognition of "temporary" 4013b643de5SAntonio Quartulli * clients 4023b643de5SAntonio Quartulli */ 403acd34afaSSven Eckelmann del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; 4043b643de5SAntonio Quartulli if (!del_op_requested && del_op_entry) 4053b643de5SAntonio Quartulli goto del; 4063b643de5SAntonio Quartulli if (del_op_requested && !del_op_entry) 4073b643de5SAntonio Quartulli goto del; 4083c4f7ab6SAntonio Quartulli 4093c4f7ab6SAntonio Quartulli /* this is a second add in the same originator interval. It 4103c4f7ab6SAntonio Quartulli * means that flags have been changed: update them! 4113c4f7ab6SAntonio Quartulli */ 4123c4f7ab6SAntonio Quartulli if (!del_op_requested && !del_op_entry) 4133c4f7ab6SAntonio Quartulli entry->change.flags = flags; 4143c4f7ab6SAntonio Quartulli 4153b643de5SAntonio Quartulli continue; 4163b643de5SAntonio Quartulli del: 4173b643de5SAntonio Quartulli list_del(&entry->list); 4183b643de5SAntonio Quartulli kfree(entry); 419155e4e12SJesper Juhl kfree(tt_change_node); 4203b643de5SAntonio Quartulli event_removed = true; 4213b643de5SAntonio Quartulli goto unlock; 4223b643de5SAntonio Quartulli } 4233b643de5SAntonio Quartulli 424a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 425807736f6SSven Eckelmann list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list); 4263b643de5SAntonio Quartulli 4273b643de5SAntonio Quartulli unlock: 428807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 429a73105b8SAntonio Quartulli 4303b643de5SAntonio Quartulli if (event_removed) 431807736f6SSven Eckelmann atomic_dec(&bat_priv->tt.local_changes); 4323b643de5SAntonio Quartulli else 433807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.local_changes); 434a73105b8SAntonio Quartulli } 435a73105b8SAntonio Quartulli 436335fbe0fSMarek Lindner /** 437335fbe0fSMarek Lindner * batadv_tt_len - compute length in bytes of given number of tt changes 438335fbe0fSMarek Lindner * @changes_num: number of tt changes 439335fbe0fSMarek Lindner * 44062fe710fSSven Eckelmann * Return: computed length in bytes. 441335fbe0fSMarek Lindner */ 442335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num) 443a73105b8SAntonio Quartulli { 444335fbe0fSMarek Lindner return changes_num * sizeof(struct batadv_tvlv_tt_change); 445a73105b8SAntonio Quartulli } 446a73105b8SAntonio Quartulli 447298e6e68SAntonio Quartulli /** 448298e6e68SAntonio Quartulli * batadv_tt_entries - compute the number of entries fitting in tt_len bytes 449298e6e68SAntonio Quartulli * @tt_len: available space 450298e6e68SAntonio Quartulli * 45162fe710fSSven Eckelmann * Return: the number of entries. 452298e6e68SAntonio Quartulli */ 4536b5e971aSSven Eckelmann static u16 batadv_tt_entries(u16 tt_len) 454298e6e68SAntonio Quartulli { 455298e6e68SAntonio Quartulli return tt_len / batadv_tt_len(1); 456298e6e68SAntonio Quartulli } 457298e6e68SAntonio Quartulli 458a19d3d85SMarek Lindner /** 459a19d3d85SMarek Lindner * batadv_tt_local_table_transmit_size - calculates the local translation table 460a19d3d85SMarek Lindner * size when transmitted over the air 461a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 462a19d3d85SMarek Lindner * 46362fe710fSSven Eckelmann * Return: local translation table size in bytes. 464a19d3d85SMarek Lindner */ 465a19d3d85SMarek Lindner static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) 466a19d3d85SMarek Lindner { 4674f248cffSSven Eckelmann u16 num_vlan = 0; 4684f248cffSSven Eckelmann u16 tt_local_entries = 0; 469a19d3d85SMarek Lindner struct batadv_softif_vlan *vlan; 470a19d3d85SMarek Lindner int hdr_size; 471a19d3d85SMarek Lindner 472a19d3d85SMarek Lindner rcu_read_lock(); 473a19d3d85SMarek Lindner hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 474a19d3d85SMarek Lindner num_vlan++; 475a19d3d85SMarek Lindner tt_local_entries += atomic_read(&vlan->tt.num_entries); 476a19d3d85SMarek Lindner } 477a19d3d85SMarek Lindner rcu_read_unlock(); 478a19d3d85SMarek Lindner 479a19d3d85SMarek Lindner /* header size of tvlv encapsulated tt response payload */ 480a19d3d85SMarek Lindner hdr_size = sizeof(struct batadv_unicast_tvlv_packet); 481a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_hdr); 482a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_tt_data); 483a19d3d85SMarek Lindner hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data); 484a19d3d85SMarek Lindner 485a19d3d85SMarek Lindner return hdr_size + batadv_tt_len(tt_local_entries); 486a19d3d85SMarek Lindner } 487a19d3d85SMarek Lindner 48856303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv) 489c6c8fea2SSven Eckelmann { 490807736f6SSven Eckelmann if (bat_priv->tt.local_hash) 4915346c35eSSven Eckelmann return 0; 492c6c8fea2SSven Eckelmann 493807736f6SSven Eckelmann bat_priv->tt.local_hash = batadv_hash_new(1024); 494c6c8fea2SSven Eckelmann 495807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 4965346c35eSSven Eckelmann return -ENOMEM; 497c6c8fea2SSven Eckelmann 498dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.local_hash, 499dec05074SAntonio Quartulli &batadv_tt_local_hash_lock_class_key); 500dec05074SAntonio Quartulli 5015346c35eSSven Eckelmann return 0; 502c6c8fea2SSven Eckelmann } 503c6c8fea2SSven Eckelmann 504068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv, 505068ee6e2SAntonio Quartulli struct batadv_tt_global_entry *tt_global, 506068ee6e2SAntonio Quartulli const char *message) 507068ee6e2SAntonio Quartulli { 508068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 50916052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 51016052789SAntonio Quartulli tt_global->common.addr, 51116052789SAntonio Quartulli BATADV_PRINT_VID(tt_global->common.vid), message); 512068ee6e2SAntonio Quartulli 513068ee6e2SAntonio Quartulli batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, 514c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_global->common); 515068ee6e2SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 516068ee6e2SAntonio Quartulli } 517068ee6e2SAntonio Quartulli 518c018ad3dSAntonio Quartulli /** 519c018ad3dSAntonio Quartulli * batadv_tt_local_add - add a new client to the local table or update an 520c018ad3dSAntonio Quartulli * existing client 521c018ad3dSAntonio Quartulli * @soft_iface: netdev struct of the mesh interface 522c018ad3dSAntonio Quartulli * @addr: the mac address of the client to add 523c018ad3dSAntonio Quartulli * @vid: VLAN identifier 524c018ad3dSAntonio Quartulli * @ifindex: index of the interface where the client is connected to (useful to 525c018ad3dSAntonio Quartulli * identify wireless clients) 5269464d071SAntonio Quartulli * @mark: the value contained in the skb->mark field of the received packet (if 5279464d071SAntonio Quartulli * any) 528a19d3d85SMarek Lindner * 52962fe710fSSven Eckelmann * Return: true if the client was successfully added, false otherwise. 530c018ad3dSAntonio Quartulli */ 5316b5e971aSSven Eckelmann bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, 5326b5e971aSSven Eckelmann unsigned short vid, int ifindex, u32 mark) 533c6c8fea2SSven Eckelmann { 53456303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(soft_iface); 535170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local; 536c5caf4efSLinus Lüssing struct batadv_tt_global_entry *tt_global = NULL; 53735df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 5380c69aeccSAntonio Quartulli struct net_device *in_dev = NULL; 539db08e6e5SSimon Wunderlich struct hlist_head *head; 54056303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 541a19d3d85SMarek Lindner int hash_added, table_size, packet_size_max; 5424f248cffSSven Eckelmann bool ret = false; 5434f248cffSSven Eckelmann bool roamed_back = false; 5446b5e971aSSven Eckelmann u8 remote_flags; 5456b5e971aSSven Eckelmann u32 match_mark; 546c6c8fea2SSven Eckelmann 5470c69aeccSAntonio Quartulli if (ifindex != BATADV_NULL_IFINDEX) 5480c69aeccSAntonio Quartulli in_dev = dev_get_by_index(&init_net, ifindex); 5490c69aeccSAntonio Quartulli 550c018ad3dSAntonio Quartulli tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); 551c5caf4efSLinus Lüssing 552c5caf4efSLinus Lüssing if (!is_multicast_ether_addr(addr)) 553c018ad3dSAntonio Quartulli tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); 554c6c8fea2SSven Eckelmann 55547c94655SAntonio Quartulli if (tt_local) { 55647c94655SAntonio Quartulli tt_local->last_seen = jiffies; 557068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { 558068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 55916052789SAntonio Quartulli "Re-adding pending client %pM (vid: %d)\n", 56016052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid)); 561068ee6e2SAntonio Quartulli /* whatever the reason why the PENDING flag was set, 562068ee6e2SAntonio Quartulli * this is a client which was enqueued to be removed in 563068ee6e2SAntonio Quartulli * this orig_interval. Since it popped up again, the 564068ee6e2SAntonio Quartulli * flag can be reset like it was never enqueued 565068ee6e2SAntonio Quartulli */ 56647c94655SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; 567068ee6e2SAntonio Quartulli goto add_event; 568068ee6e2SAntonio Quartulli } 569068ee6e2SAntonio Quartulli 570068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { 571068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 57216052789SAntonio Quartulli "Roaming client %pM (vid: %d) came back to its original location\n", 57316052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid)); 574068ee6e2SAntonio Quartulli /* the ROAM flag is set because this client roamed away 575068ee6e2SAntonio Quartulli * and the node got a roaming_advertisement message. Now 576068ee6e2SAntonio Quartulli * that the client popped up again at its original 577068ee6e2SAntonio Quartulli * location such flag can be unset 578068ee6e2SAntonio Quartulli */ 579068ee6e2SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; 580068ee6e2SAntonio Quartulli roamed_back = true; 581068ee6e2SAntonio Quartulli } 582068ee6e2SAntonio Quartulli goto check_roaming; 583c6c8fea2SSven Eckelmann } 584c6c8fea2SSven Eckelmann 585a19d3d85SMarek Lindner /* Ignore the client if we cannot send it in a full table response. */ 586a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 587a19d3d85SMarek Lindner table_size += batadv_tt_len(1); 588a19d3d85SMarek Lindner packet_size_max = atomic_read(&bat_priv->packet_size_max); 589a19d3d85SMarek Lindner if (table_size > packet_size_max) { 590a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 591a19d3d85SMarek Lindner "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n", 592a19d3d85SMarek Lindner table_size, packet_size_max, addr); 593a19d3d85SMarek Lindner goto out; 594a19d3d85SMarek Lindner } 595a19d3d85SMarek Lindner 59647c94655SAntonio Quartulli tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); 59747c94655SAntonio Quartulli if (!tt_local) 5987683fdc1SAntonio Quartulli goto out; 599a73105b8SAntonio Quartulli 60035df3b29SAntonio Quartulli /* increase the refcounter of the related vlan */ 60135df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 602354136bcSMarek Lindner if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d", 603fd7dec25SSven Eckelmann addr, BATADV_PRINT_VID(vid))) { 604fd7dec25SSven Eckelmann kfree(tt_local); 605fd7dec25SSven Eckelmann tt_local = NULL; 606354136bcSMarek Lindner goto out; 607fd7dec25SSven Eckelmann } 60835df3b29SAntonio Quartulli 60939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 61016052789SAntonio Quartulli "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", 61116052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid), 6126b5e971aSSven Eckelmann (u8)atomic_read(&bat_priv->tt.vn)); 613c6c8fea2SSven Eckelmann 6148fdd0153SAntonio Quartulli ether_addr_copy(tt_local->common.addr, addr); 6158425ec6aSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 6168425ec6aSAntonio Quartulli * a full table response going out before the next ttvn increment 6178425ec6aSAntonio Quartulli * (consistency check) 6188425ec6aSAntonio Quartulli */ 6198425ec6aSAntonio Quartulli tt_local->common.flags = BATADV_TT_CLIENT_NEW; 620c018ad3dSAntonio Quartulli tt_local->common.vid = vid; 6210c69aeccSAntonio Quartulli if (batadv_is_wifi_netdev(in_dev)) 62247c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 62347c94655SAntonio Quartulli atomic_set(&tt_local->common.refcount, 2); 62447c94655SAntonio Quartulli tt_local->last_seen = jiffies; 62547c94655SAntonio Quartulli tt_local->common.added_at = tt_local->last_seen; 626c6c8fea2SSven Eckelmann 627c5caf4efSLinus Lüssing /* the batman interface mac and multicast addresses should never be 628c5caf4efSLinus Lüssing * purged 629c5caf4efSLinus Lüssing */ 630c5caf4efSLinus Lüssing if (batadv_compare_eth(addr, soft_iface->dev_addr) || 631c5caf4efSLinus Lüssing is_multicast_ether_addr(addr)) 63247c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; 633c6c8fea2SSven Eckelmann 634807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, 635c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_local->common, 63647c94655SAntonio Quartulli &tt_local->common.hash_entry); 63780b3f58cSSimon Wunderlich 63880b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 63980b3f58cSSimon Wunderlich /* remove the reference for the hash */ 64047c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 64135df3b29SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 64280b3f58cSSimon Wunderlich goto out; 64380b3f58cSSimon Wunderlich } 64480b3f58cSSimon Wunderlich 645068ee6e2SAntonio Quartulli add_event: 6463abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 647ff66c975SAntonio Quartulli 648068ee6e2SAntonio Quartulli check_roaming: 649068ee6e2SAntonio Quartulli /* Check whether it is a roaming, but don't do anything if the roaming 650068ee6e2SAntonio Quartulli * process has already been handled 651068ee6e2SAntonio Quartulli */ 652068ee6e2SAntonio Quartulli if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { 653db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 65447c94655SAntonio Quartulli head = &tt_global->orig_list; 655db08e6e5SSimon Wunderlich rcu_read_lock(); 656b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 65747c94655SAntonio Quartulli batadv_send_roam_adv(bat_priv, tt_global->common.addr, 658c018ad3dSAntonio Quartulli tt_global->common.vid, 659db08e6e5SSimon Wunderlich orig_entry->orig_node); 660db08e6e5SSimon Wunderlich } 661db08e6e5SSimon Wunderlich rcu_read_unlock(); 662068ee6e2SAntonio Quartulli if (roamed_back) { 663068ee6e2SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global, 664068ee6e2SAntonio Quartulli "Roaming canceled"); 665068ee6e2SAntonio Quartulli tt_global = NULL; 666068ee6e2SAntonio Quartulli } else { 667db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 668db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 669db08e6e5SSimon Wunderlich */ 67047c94655SAntonio Quartulli tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; 67147c94655SAntonio Quartulli tt_global->roam_at = jiffies; 6727683fdc1SAntonio Quartulli } 673068ee6e2SAntonio Quartulli } 674068ee6e2SAntonio Quartulli 6753c4f7ab6SAntonio Quartulli /* store the current remote flags before altering them. This helps 6763c4f7ab6SAntonio Quartulli * understanding is flags are changing or not 6773c4f7ab6SAntonio Quartulli */ 6783c4f7ab6SAntonio Quartulli remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK; 679a19d3d85SMarek Lindner 6803c4f7ab6SAntonio Quartulli if (batadv_is_wifi_netdev(in_dev)) 6813c4f7ab6SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 6823c4f7ab6SAntonio Quartulli else 6833c4f7ab6SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; 6843c4f7ab6SAntonio Quartulli 6859464d071SAntonio Quartulli /* check the mark in the skb: if it's equal to the configured 6869464d071SAntonio Quartulli * isolation_mark, it means the packet is coming from an isolated 6879464d071SAntonio Quartulli * non-mesh client 6889464d071SAntonio Quartulli */ 6899464d071SAntonio Quartulli match_mark = (mark & bat_priv->isolation_mark_mask); 6909464d071SAntonio Quartulli if (bat_priv->isolation_mark_mask && 6919464d071SAntonio Quartulli match_mark == bat_priv->isolation_mark) 6929464d071SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA; 6939464d071SAntonio Quartulli else 6949464d071SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA; 6959464d071SAntonio Quartulli 6963c4f7ab6SAntonio Quartulli /* if any "dynamic" flag has been modified, resend an ADD event for this 6973c4f7ab6SAntonio Quartulli * entry so that all the nodes can get the new flags 6983c4f7ab6SAntonio Quartulli */ 6993c4f7ab6SAntonio Quartulli if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK)) 7003c4f7ab6SAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 7013c4f7ab6SAntonio Quartulli 7023c4f7ab6SAntonio Quartulli ret = true; 7037683fdc1SAntonio Quartulli out: 7040c69aeccSAntonio Quartulli if (in_dev) 7050c69aeccSAntonio Quartulli dev_put(in_dev); 70647c94655SAntonio Quartulli if (tt_local) 70747c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 70847c94655SAntonio Quartulli if (tt_global) 70947c94655SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 710a19d3d85SMarek Lindner return ret; 711c6c8fea2SSven Eckelmann } 712c6c8fea2SSven Eckelmann 713e1bf0c14SMarek Lindner /** 7147ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send 7157ea7b4a1SAntonio Quartulli * within a TT Response directed to another node 7167ea7b4a1SAntonio Quartulli * @orig_node: originator for which the TT data has to be prepared 7177ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 7187ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 7197ea7b4a1SAntonio Quartulli * changed can be stored 7207ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 7217ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire global TT 7227ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 7237ea7b4a1SAntonio Quartulli * reserved bytes 7247ea7b4a1SAntonio Quartulli 7257ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 7267ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 7277ea7b4a1SAntonio Quartulli * objects, one per active VLAN served by the originator node. 7287ea7b4a1SAntonio Quartulli * 72962fe710fSSven Eckelmann * Return: the size of the allocated buffer or 0 in case of failure. 7307ea7b4a1SAntonio Quartulli */ 7316b5e971aSSven Eckelmann static u16 7327ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, 7337ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 7347ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 7356b5e971aSSven Eckelmann s32 *tt_len) 7367ea7b4a1SAntonio Quartulli { 7374f248cffSSven Eckelmann u16 num_vlan = 0; 7384f248cffSSven Eckelmann u16 num_entries = 0; 7394f248cffSSven Eckelmann u16 change_offset; 7404f248cffSSven Eckelmann u16 tvlv_len; 7417ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 7427ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 7436b5e971aSSven Eckelmann u8 *tt_change_ptr; 7447ea7b4a1SAntonio Quartulli 7457ea7b4a1SAntonio Quartulli rcu_read_lock(); 746d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 7477ea7b4a1SAntonio Quartulli num_vlan++; 7487ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 7497ea7b4a1SAntonio Quartulli } 7507ea7b4a1SAntonio Quartulli 7517ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 7527ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 7537ea7b4a1SAntonio Quartulli 7547ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 7557ea7b4a1SAntonio Quartulli if (*tt_len < 0) 7567ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 7577ea7b4a1SAntonio Quartulli 7587ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 7597ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 7607ea7b4a1SAntonio Quartulli 7617ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 7627ea7b4a1SAntonio Quartulli if (!*tt_data) { 7637ea7b4a1SAntonio Quartulli *tt_len = 0; 7647ea7b4a1SAntonio Quartulli goto out; 7657ea7b4a1SAntonio Quartulli } 7667ea7b4a1SAntonio Quartulli 7677ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 7687ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); 7697ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 7707ea7b4a1SAntonio Quartulli 7717ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 772d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 7737ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 7747ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 7757ea7b4a1SAntonio Quartulli 7767ea7b4a1SAntonio Quartulli tt_vlan++; 7777ea7b4a1SAntonio Quartulli } 7787ea7b4a1SAntonio Quartulli 7796b5e971aSSven Eckelmann tt_change_ptr = (u8 *)*tt_data + change_offset; 7807ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 7817ea7b4a1SAntonio Quartulli 7827ea7b4a1SAntonio Quartulli out: 7837ea7b4a1SAntonio Quartulli rcu_read_unlock(); 7847ea7b4a1SAntonio Quartulli return tvlv_len; 7857ea7b4a1SAntonio Quartulli } 7867ea7b4a1SAntonio Quartulli 7877ea7b4a1SAntonio Quartulli /** 7887ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this 7897ea7b4a1SAntonio Quartulli * node 7907ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 7917ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 7927ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 7937ea7b4a1SAntonio Quartulli * changes can be stored 7947ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 7957ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire local TT 7967ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 7977ea7b4a1SAntonio Quartulli * reserved bytes 7987ea7b4a1SAntonio Quartulli * 7997ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 8007ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 8017ea7b4a1SAntonio Quartulli * objects, one per active VLAN. 8027ea7b4a1SAntonio Quartulli * 80362fe710fSSven Eckelmann * Return: the size of the allocated buffer or 0 in case of failure. 8047ea7b4a1SAntonio Quartulli */ 8056b5e971aSSven Eckelmann static u16 8067ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, 8077ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 8087ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 8096b5e971aSSven Eckelmann s32 *tt_len) 8107ea7b4a1SAntonio Quartulli { 8117ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 8127ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 8134f248cffSSven Eckelmann u16 num_vlan = 0; 8144f248cffSSven Eckelmann u16 num_entries = 0; 8154f248cffSSven Eckelmann u16 tvlv_len; 8166b5e971aSSven Eckelmann u8 *tt_change_ptr; 8177ea7b4a1SAntonio Quartulli int change_offset; 8187ea7b4a1SAntonio Quartulli 8197ea7b4a1SAntonio Quartulli rcu_read_lock(); 8207ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 8217ea7b4a1SAntonio Quartulli num_vlan++; 8227ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 8237ea7b4a1SAntonio Quartulli } 8247ea7b4a1SAntonio Quartulli 8257ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 8267ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 8277ea7b4a1SAntonio Quartulli 8287ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 8297ea7b4a1SAntonio Quartulli if (*tt_len < 0) 8307ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 8317ea7b4a1SAntonio Quartulli 8327ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 8337ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 8347ea7b4a1SAntonio Quartulli 8357ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 8367ea7b4a1SAntonio Quartulli if (!*tt_data) { 8377ea7b4a1SAntonio Quartulli tvlv_len = 0; 8387ea7b4a1SAntonio Quartulli goto out; 8397ea7b4a1SAntonio Quartulli } 8407ea7b4a1SAntonio Quartulli 8417ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 8427ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn); 8437ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 8447ea7b4a1SAntonio Quartulli 8457ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 8467ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 8477ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 8487ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 8497ea7b4a1SAntonio Quartulli 8507ea7b4a1SAntonio Quartulli tt_vlan++; 8517ea7b4a1SAntonio Quartulli } 8527ea7b4a1SAntonio Quartulli 8536b5e971aSSven Eckelmann tt_change_ptr = (u8 *)*tt_data + change_offset; 8547ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 8557ea7b4a1SAntonio Quartulli 8567ea7b4a1SAntonio Quartulli out: 8577ea7b4a1SAntonio Quartulli rcu_read_unlock(); 8587ea7b4a1SAntonio Quartulli return tvlv_len; 8597ea7b4a1SAntonio Quartulli } 8607ea7b4a1SAntonio Quartulli 8617ea7b4a1SAntonio Quartulli /** 862e1bf0c14SMarek Lindner * batadv_tt_tvlv_container_update - update the translation table tvlv container 863e1bf0c14SMarek Lindner * after local tt changes have been committed 864e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 865e1bf0c14SMarek Lindner */ 866e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) 867c6c8fea2SSven Eckelmann { 868e1bf0c14SMarek Lindner struct batadv_tt_change_node *entry, *safe; 869e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 870e1bf0c14SMarek Lindner struct batadv_tvlv_tt_change *tt_change; 8717ea7b4a1SAntonio Quartulli int tt_diff_len, tt_change_len = 0; 8724f248cffSSven Eckelmann int tt_diff_entries_num = 0; 8734f248cffSSven Eckelmann int tt_diff_entries_count = 0; 8746b5e971aSSven Eckelmann u16 tvlv_len; 875c6c8fea2SSven Eckelmann 8767ea7b4a1SAntonio Quartulli tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); 8777ea7b4a1SAntonio Quartulli tt_diff_len = batadv_tt_len(tt_diff_entries_num); 878be9aa4c1SMarek Lindner 879be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 880be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 881be9aa4c1SMarek Lindner */ 882e1bf0c14SMarek Lindner if (tt_diff_len > bat_priv->soft_iface->mtu) 883e1bf0c14SMarek Lindner tt_diff_len = 0; 884be9aa4c1SMarek Lindner 8857ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, 8867ea7b4a1SAntonio Quartulli &tt_change, &tt_diff_len); 8877ea7b4a1SAntonio Quartulli if (!tvlv_len) 888e1bf0c14SMarek Lindner return; 889be9aa4c1SMarek Lindner 890e1bf0c14SMarek Lindner tt_data->flags = BATADV_TT_OGM_DIFF; 891be9aa4c1SMarek Lindner 892e1bf0c14SMarek Lindner if (tt_diff_len == 0) 893e1bf0c14SMarek Lindner goto container_register; 894be9aa4c1SMarek Lindner 895807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 896807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 897c6c8fea2SSven Eckelmann 898807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 899a73105b8SAntonio Quartulli list) { 900e1bf0c14SMarek Lindner if (tt_diff_entries_count < tt_diff_entries_num) { 901e1bf0c14SMarek Lindner memcpy(tt_change + tt_diff_entries_count, 902e1bf0c14SMarek Lindner &entry->change, 903e1bf0c14SMarek Lindner sizeof(struct batadv_tvlv_tt_change)); 904e1bf0c14SMarek Lindner tt_diff_entries_count++; 905c6c8fea2SSven Eckelmann } 906a73105b8SAntonio Quartulli list_del(&entry->list); 907a73105b8SAntonio Quartulli kfree(entry); 908c6c8fea2SSven Eckelmann } 909807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 910c6c8fea2SSven Eckelmann 911a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 912807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 913807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 914807736f6SSven Eckelmann bat_priv->tt.last_changeset_len = 0; 915807736f6SSven Eckelmann bat_priv->tt.last_changeset = NULL; 916e1bf0c14SMarek Lindner tt_change_len = batadv_tt_len(tt_diff_entries_count); 917be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 918e1bf0c14SMarek Lindner if (tt_diff_entries_count > 0) { 919be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 920a73105b8SAntonio Quartulli * instead of providing the diff 921a73105b8SAntonio Quartulli */ 922e1bf0c14SMarek Lindner bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); 923807736f6SSven Eckelmann if (bat_priv->tt.last_changeset) { 924e1bf0c14SMarek Lindner memcpy(bat_priv->tt.last_changeset, 925e1bf0c14SMarek Lindner tt_change, tt_change_len); 926e1bf0c14SMarek Lindner bat_priv->tt.last_changeset_len = tt_diff_len; 927a73105b8SAntonio Quartulli } 928a73105b8SAntonio Quartulli } 929807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 930c6c8fea2SSven Eckelmann 931e1bf0c14SMarek Lindner container_register: 932e1bf0c14SMarek Lindner batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, 9337ea7b4a1SAntonio Quartulli tvlv_len); 934e1bf0c14SMarek Lindner kfree(tt_data); 935c6c8fea2SSven Eckelmann } 936c6c8fea2SSven Eckelmann 93708c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) 938c6c8fea2SSven Eckelmann { 939c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 94056303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 941807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 94256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 94385766a82SAntonio Quartulli struct batadv_tt_local_entry *tt_local; 94456303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 9457ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 946c6c8fea2SSven Eckelmann struct hlist_head *head; 9477ea7b4a1SAntonio Quartulli unsigned short vid; 9486b5e971aSSven Eckelmann u32 i; 94985766a82SAntonio Quartulli int last_seen_secs; 95085766a82SAntonio Quartulli int last_seen_msecs; 95185766a82SAntonio Quartulli unsigned long last_seen_jiffies; 95285766a82SAntonio Quartulli bool no_purge; 9536b5e971aSSven Eckelmann u16 np_flag = BATADV_TT_CLIENT_NOPURGE; 954c6c8fea2SSven Eckelmann 95530da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 95630da63a6SMarek Lindner if (!primary_if) 95732ae9b22SMarek Lindner goto out; 958c6c8fea2SSven Eckelmann 95986ceb360SSven Eckelmann seq_printf(seq, 9607ea7b4a1SAntonio Quartulli "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", 9616b5e971aSSven Eckelmann net_dev->name, (u8)atomic_read(&bat_priv->tt.vn)); 962dd24ddb2SAntonio Quartulli seq_printf(seq, " %-13s %s %-8s %-9s (%-10s)\n", "Client", "VID", 9637ea7b4a1SAntonio Quartulli "Flags", "Last seen", "CRC"); 964c6c8fea2SSven Eckelmann 965c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 966c6c8fea2SSven Eckelmann head = &hash->table[i]; 967c6c8fea2SSven Eckelmann 9687aadf889SMarek Lindner rcu_read_lock(); 969b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 9707aadf889SMarek Lindner head, hash_entry) { 97185766a82SAntonio Quartulli tt_local = container_of(tt_common_entry, 97285766a82SAntonio Quartulli struct batadv_tt_local_entry, 97385766a82SAntonio Quartulli common); 9747ea7b4a1SAntonio Quartulli vid = tt_common_entry->vid; 97585766a82SAntonio Quartulli last_seen_jiffies = jiffies - tt_local->last_seen; 97685766a82SAntonio Quartulli last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 97785766a82SAntonio Quartulli last_seen_secs = last_seen_msecs / 1000; 97885766a82SAntonio Quartulli last_seen_msecs = last_seen_msecs % 1000; 97985766a82SAntonio Quartulli 98085766a82SAntonio Quartulli no_purge = tt_common_entry->flags & np_flag; 98185766a82SAntonio Quartulli 9827ea7b4a1SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 9837ea7b4a1SAntonio Quartulli if (!vlan) { 9847ea7b4a1SAntonio Quartulli seq_printf(seq, "Cannot retrieve VLAN %d\n", 9857ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(vid)); 9867ea7b4a1SAntonio Quartulli continue; 9877ea7b4a1SAntonio Quartulli } 9887ea7b4a1SAntonio Quartulli 9897ea7b4a1SAntonio Quartulli seq_printf(seq, 990dd24ddb2SAntonio Quartulli " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n", 99148100bacSAntonio Quartulli tt_common_entry->addr, 99216052789SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 993a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 994a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 99585766a82SAntonio Quartulli no_purge ? 'P' : '.', 996a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 997a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_NEW) ? 'N' : '.'), 998a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 999a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_PENDING) ? 'X' : '.'), 1000a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1001a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1002a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1003a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1004a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_secs, 10057ea7b4a1SAntonio Quartulli no_purge ? 0 : last_seen_msecs, 10067ea7b4a1SAntonio Quartulli vlan->tt.crc); 10077ea7b4a1SAntonio Quartulli 10087ea7b4a1SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 1009c6c8fea2SSven Eckelmann } 10107aadf889SMarek Lindner rcu_read_unlock(); 1011c6c8fea2SSven Eckelmann } 101232ae9b22SMarek Lindner out: 101332ae9b22SMarek Lindner if (primary_if) 1014e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 101530da63a6SMarek Lindner return 0; 1016c6c8fea2SSven Eckelmann } 1017c6c8fea2SSven Eckelmann 101856303d34SSven Eckelmann static void 101956303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv, 102056303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry, 10216b5e971aSSven Eckelmann u16 flags, const char *message) 1022c6c8fea2SSven Eckelmann { 10233abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, flags); 1024c6c8fea2SSven Eckelmann 1025015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 1026015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 10279cfc7bd6SSven Eckelmann * response issued before the net ttvn increment (consistency check) 10289cfc7bd6SSven Eckelmann */ 1029acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; 1030c566dbbeSAntonio Quartulli 103139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 103216052789SAntonio Quartulli "Local tt entry (%pM, vid: %d) pending to be removed: %s\n", 103316052789SAntonio Quartulli tt_local_entry->common.addr, 103416052789SAntonio Quartulli BATADV_PRINT_VID(tt_local_entry->common.vid), message); 1035c6c8fea2SSven Eckelmann } 1036c6c8fea2SSven Eckelmann 10377f91d06cSAntonio Quartulli /** 10387f91d06cSAntonio Quartulli * batadv_tt_local_remove - logically remove an entry from the local table 10397f91d06cSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 10407f91d06cSAntonio Quartulli * @addr: the MAC address of the client to remove 1041c018ad3dSAntonio Quartulli * @vid: VLAN identifier 10427f91d06cSAntonio Quartulli * @message: message to append to the log on deletion 10437f91d06cSAntonio Quartulli * @roaming: true if the deletion is due to a roaming event 10447f91d06cSAntonio Quartulli * 104562fe710fSSven Eckelmann * Return: the flags assigned to the local entry before being deleted 10467f91d06cSAntonio Quartulli */ 10476b5e971aSSven Eckelmann u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, 10486b5e971aSSven Eckelmann unsigned short vid, const char *message, 10496b5e971aSSven Eckelmann bool roaming) 1050c6c8fea2SSven Eckelmann { 1051170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 10526b5e971aSSven Eckelmann u16 flags, curr_flags = BATADV_NO_FLAGS; 105335df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 1054ef72706aSMarek Lindner void *tt_entry_exists; 1055c6c8fea2SSven Eckelmann 1056c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 10577683fdc1SAntonio Quartulli if (!tt_local_entry) 10587683fdc1SAntonio Quartulli goto out; 10597683fdc1SAntonio Quartulli 10607f91d06cSAntonio Quartulli curr_flags = tt_local_entry->common.flags; 10617f91d06cSAntonio Quartulli 1062acd34afaSSven Eckelmann flags = BATADV_TT_CLIENT_DEL; 1063068ee6e2SAntonio Quartulli /* if this global entry addition is due to a roaming, the node has to 1064068ee6e2SAntonio Quartulli * mark the local entry as "roamed" in order to correctly reroute 1065068ee6e2SAntonio Quartulli * packets later 1066068ee6e2SAntonio Quartulli */ 10677c1fd91dSAntonio Quartulli if (roaming) { 1068acd34afaSSven Eckelmann flags |= BATADV_TT_CLIENT_ROAM; 10697c1fd91dSAntonio Quartulli /* mark the local client as ROAMed */ 10707c1fd91dSAntonio Quartulli tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 10717c1fd91dSAntonio Quartulli } 107242d0b044SSven Eckelmann 1073068ee6e2SAntonio Quartulli if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { 1074068ee6e2SAntonio Quartulli batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, 1075068ee6e2SAntonio Quartulli message); 1076068ee6e2SAntonio Quartulli goto out; 1077068ee6e2SAntonio Quartulli } 1078068ee6e2SAntonio Quartulli /* if this client has been added right now, it is possible to 1079068ee6e2SAntonio Quartulli * immediately purge it 1080068ee6e2SAntonio Quartulli */ 10813abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); 1082ef72706aSMarek Lindner 1083ef72706aSMarek Lindner tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, 1084ef72706aSMarek Lindner batadv_compare_tt, 1085ef72706aSMarek Lindner batadv_choose_tt, 1086ef72706aSMarek Lindner &tt_local_entry->common); 1087ef72706aSMarek Lindner if (!tt_entry_exists) 1088ef72706aSMarek Lindner goto out; 1089ef72706aSMarek Lindner 1090ef72706aSMarek Lindner /* extra call to free the local tt entry */ 1091068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 10927f91d06cSAntonio Quartulli 109335df3b29SAntonio Quartulli /* decrease the reference held for this vlan */ 109435df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 1095354136bcSMarek Lindner if (!vlan) 1096354136bcSMarek Lindner goto out; 1097354136bcSMarek Lindner 109835df3b29SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 109935df3b29SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 110035df3b29SAntonio Quartulli 11017683fdc1SAntonio Quartulli out: 11027683fdc1SAntonio Quartulli if (tt_local_entry) 1103a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 11047f91d06cSAntonio Quartulli 11057f91d06cSAntonio Quartulli return curr_flags; 1106c6c8fea2SSven Eckelmann } 1107c6c8fea2SSven Eckelmann 1108a19d3d85SMarek Lindner /** 1109a19d3d85SMarek Lindner * batadv_tt_local_purge_list - purge inactive tt local entries 1110a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1111a19d3d85SMarek Lindner * @head: pointer to the list containing the local tt entries 1112a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1113a19d3d85SMarek Lindner * inactive or not 1114a19d3d85SMarek Lindner */ 111556303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 1116a19d3d85SMarek Lindner struct hlist_head *head, 1117a19d3d85SMarek Lindner int timeout) 1118c6c8fea2SSven Eckelmann { 111956303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 112056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1121b67bfe0dSSasha Levin struct hlist_node *node_tmp; 1122acd34afaSSven Eckelmann 1123b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, 1124acd34afaSSven Eckelmann hash_entry) { 1125acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common_entry, 112656303d34SSven Eckelmann struct batadv_tt_local_entry, 112756303d34SSven Eckelmann common); 1128acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) 1129acd34afaSSven Eckelmann continue; 1130acd34afaSSven Eckelmann 1131acd34afaSSven Eckelmann /* entry already marked for deletion */ 1132acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 1133acd34afaSSven Eckelmann continue; 1134acd34afaSSven Eckelmann 1135a19d3d85SMarek Lindner if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) 1136acd34afaSSven Eckelmann continue; 1137acd34afaSSven Eckelmann 1138acd34afaSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 1139acd34afaSSven Eckelmann BATADV_TT_CLIENT_DEL, "timed out"); 1140acd34afaSSven Eckelmann } 1141acd34afaSSven Eckelmann } 1142acd34afaSSven Eckelmann 1143a19d3d85SMarek Lindner /** 1144a19d3d85SMarek Lindner * batadv_tt_local_purge - purge inactive tt local entries 1145a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1146a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1147a19d3d85SMarek Lindner * inactive or not 1148a19d3d85SMarek Lindner */ 1149a19d3d85SMarek Lindner static void batadv_tt_local_purge(struct batadv_priv *bat_priv, 1150a19d3d85SMarek Lindner int timeout) 1151acd34afaSSven Eckelmann { 1152807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 1153c6c8fea2SSven Eckelmann struct hlist_head *head; 11547683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 11556b5e971aSSven Eckelmann u32 i; 1156c6c8fea2SSven Eckelmann 1157c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1158c6c8fea2SSven Eckelmann head = &hash->table[i]; 11597683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1160c6c8fea2SSven Eckelmann 11617683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1162a19d3d85SMarek Lindner batadv_tt_local_purge_list(bat_priv, head, timeout); 11637683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1164c6c8fea2SSven Eckelmann } 1165c6c8fea2SSven Eckelmann } 1166c6c8fea2SSven Eckelmann 116756303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) 1168c6c8fea2SSven Eckelmann { 11695bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 1170a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 117156303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 117256303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 117335df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 1174b67bfe0dSSasha Levin struct hlist_node *node_tmp; 11757683fdc1SAntonio Quartulli struct hlist_head *head; 11766b5e971aSSven Eckelmann u32 i; 1177a73105b8SAntonio Quartulli 1178807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 1179c6c8fea2SSven Eckelmann return; 1180c6c8fea2SSven Eckelmann 1181807736f6SSven Eckelmann hash = bat_priv->tt.local_hash; 1182a73105b8SAntonio Quartulli 1183a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1184a73105b8SAntonio Quartulli head = &hash->table[i]; 1185a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 1186a73105b8SAntonio Quartulli 1187a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 1188b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 1189a73105b8SAntonio Quartulli head, hash_entry) { 1190b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 119156303d34SSven Eckelmann tt_local = container_of(tt_common_entry, 119256303d34SSven Eckelmann struct batadv_tt_local_entry, 119348100bacSAntonio Quartulli common); 119435df3b29SAntonio Quartulli 119535df3b29SAntonio Quartulli /* decrease the reference held for this vlan */ 119635df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, 119735df3b29SAntonio Quartulli tt_common_entry->vid); 1198354136bcSMarek Lindner if (vlan) { 119935df3b29SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 120035df3b29SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 1201354136bcSMarek Lindner } 120235df3b29SAntonio Quartulli 120356303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 1204a73105b8SAntonio Quartulli } 1205a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 1206a73105b8SAntonio Quartulli } 1207a73105b8SAntonio Quartulli 12081a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 1209a73105b8SAntonio Quartulli 1210807736f6SSven Eckelmann bat_priv->tt.local_hash = NULL; 1211c6c8fea2SSven Eckelmann } 1212c6c8fea2SSven Eckelmann 121356303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv) 1214c6c8fea2SSven Eckelmann { 1215807736f6SSven Eckelmann if (bat_priv->tt.global_hash) 12165346c35eSSven Eckelmann return 0; 1217c6c8fea2SSven Eckelmann 1218807736f6SSven Eckelmann bat_priv->tt.global_hash = batadv_hash_new(1024); 1219c6c8fea2SSven Eckelmann 1220807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 12215346c35eSSven Eckelmann return -ENOMEM; 1222c6c8fea2SSven Eckelmann 1223dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.global_hash, 1224dec05074SAntonio Quartulli &batadv_tt_global_hash_lock_class_key); 1225dec05074SAntonio Quartulli 12265346c35eSSven Eckelmann return 0; 1227c6c8fea2SSven Eckelmann } 1228c6c8fea2SSven Eckelmann 122956303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) 1230a73105b8SAntonio Quartulli { 123156303d34SSven Eckelmann struct batadv_tt_change_node *entry, *safe; 1232a73105b8SAntonio Quartulli 1233807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 1234a73105b8SAntonio Quartulli 1235807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 1236a73105b8SAntonio Quartulli list) { 1237a73105b8SAntonio Quartulli list_del(&entry->list); 1238a73105b8SAntonio Quartulli kfree(entry); 1239a73105b8SAntonio Quartulli } 1240a73105b8SAntonio Quartulli 1241807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 1242807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 1243a73105b8SAntonio Quartulli } 1244a73105b8SAntonio Quartulli 124562fe710fSSven Eckelmann /** 124662fe710fSSven Eckelmann * batadv_tt_global_orig_entry_find 124762fe710fSSven Eckelmann * 124862fe710fSSven Eckelmann * retrieves the orig_tt_list_entry belonging to orig_node from the 1249d657e621SAntonio Quartulli * batadv_tt_global_entry list 1250d657e621SAntonio Quartulli * 125162fe710fSSven Eckelmann * Return: it with an increased refcounter, NULL if not found 1252d657e621SAntonio Quartulli */ 1253d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry * 1254d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, 1255d657e621SAntonio Quartulli const struct batadv_orig_node *orig_node) 1256d657e621SAntonio Quartulli { 1257d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; 1258d657e621SAntonio Quartulli const struct hlist_head *head; 1259d657e621SAntonio Quartulli 1260d657e621SAntonio Quartulli rcu_read_lock(); 1261d657e621SAntonio Quartulli head = &entry->orig_list; 1262b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { 1263d657e621SAntonio Quartulli if (tmp_orig_entry->orig_node != orig_node) 1264d657e621SAntonio Quartulli continue; 1265d657e621SAntonio Quartulli if (!atomic_inc_not_zero(&tmp_orig_entry->refcount)) 1266d657e621SAntonio Quartulli continue; 1267d657e621SAntonio Quartulli 1268d657e621SAntonio Quartulli orig_entry = tmp_orig_entry; 1269d657e621SAntonio Quartulli break; 1270d657e621SAntonio Quartulli } 1271d657e621SAntonio Quartulli rcu_read_unlock(); 1272d657e621SAntonio Quartulli 1273d657e621SAntonio Quartulli return orig_entry; 1274d657e621SAntonio Quartulli } 1275d657e621SAntonio Quartulli 127662fe710fSSven Eckelmann /** 127762fe710fSSven Eckelmann * batadv_tt_global_entry_has_orig 127862fe710fSSven Eckelmann * 127962fe710fSSven Eckelmann * find out if an orig_node is already in the list of a tt_global_entry. 128062fe710fSSven Eckelmann * 128162fe710fSSven Eckelmann * Return: true if found, false otherwise 1282db08e6e5SSimon Wunderlich */ 128356303d34SSven Eckelmann static bool 128456303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, 128556303d34SSven Eckelmann const struct batadv_orig_node *orig_node) 1286db08e6e5SSimon Wunderlich { 1287d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *orig_entry; 1288db08e6e5SSimon Wunderlich bool found = false; 1289db08e6e5SSimon Wunderlich 1290d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); 1291d657e621SAntonio Quartulli if (orig_entry) { 1292db08e6e5SSimon Wunderlich found = true; 1293d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 1294db08e6e5SSimon Wunderlich } 1295d657e621SAntonio Quartulli 1296db08e6e5SSimon Wunderlich return found; 1297db08e6e5SSimon Wunderlich } 1298db08e6e5SSimon Wunderlich 1299a513088dSSven Eckelmann static void 1300d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, 130156303d34SSven Eckelmann struct batadv_orig_node *orig_node, int ttvn) 1302db08e6e5SSimon Wunderlich { 130356303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1304db08e6e5SSimon Wunderlich 1305d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); 130630cfd02bSAntonio Quartulli if (orig_entry) { 130730cfd02bSAntonio Quartulli /* refresh the ttvn: the current value could be a bogus one that 130830cfd02bSAntonio Quartulli * was added during a "temporary client detection" 130930cfd02bSAntonio Quartulli */ 131030cfd02bSAntonio Quartulli orig_entry->ttvn = ttvn; 1311d657e621SAntonio Quartulli goto out; 131230cfd02bSAntonio Quartulli } 1313d657e621SAntonio Quartulli 1314db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 1315db08e6e5SSimon Wunderlich if (!orig_entry) 1316d657e621SAntonio Quartulli goto out; 1317db08e6e5SSimon Wunderlich 1318db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 1319db08e6e5SSimon Wunderlich atomic_inc(&orig_node->refcount); 13207ea7b4a1SAntonio Quartulli batadv_tt_global_size_inc(orig_node, tt_global->common.vid); 1321db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 1322db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 1323d657e621SAntonio Quartulli atomic_set(&orig_entry->refcount, 2); 1324db08e6e5SSimon Wunderlich 1325d657e621SAntonio Quartulli spin_lock_bh(&tt_global->list_lock); 1326db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 1327d657e621SAntonio Quartulli &tt_global->orig_list); 1328d657e621SAntonio Quartulli spin_unlock_bh(&tt_global->list_lock); 13291d8ab8d3SLinus Lüssing atomic_inc(&tt_global->orig_list_count); 13301d8ab8d3SLinus Lüssing 1331d657e621SAntonio Quartulli out: 1332d657e621SAntonio Quartulli if (orig_entry) 1333d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 1334db08e6e5SSimon Wunderlich } 1335db08e6e5SSimon Wunderlich 1336d4ff40f6SAntonio Quartulli /** 1337d4ff40f6SAntonio Quartulli * batadv_tt_global_add - add a new TT global entry or update an existing one 1338d4ff40f6SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1339d4ff40f6SAntonio Quartulli * @orig_node: the originator announcing the client 1340d4ff40f6SAntonio Quartulli * @tt_addr: the mac address of the non-mesh client 1341c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1342d4ff40f6SAntonio Quartulli * @flags: TT flags that have to be set for this non-mesh client 1343d4ff40f6SAntonio Quartulli * @ttvn: the tt version number ever announcing this non-mesh client 1344d4ff40f6SAntonio Quartulli * 1345d4ff40f6SAntonio Quartulli * Add a new TT global entry for the given originator. If the entry already 1346d4ff40f6SAntonio Quartulli * exists add a new reference to the given originator (a global entry can have 1347d4ff40f6SAntonio Quartulli * references to multiple originators) and adjust the flags attribute to reflect 1348d4ff40f6SAntonio Quartulli * the function argument. 1349d4ff40f6SAntonio Quartulli * If a TT local entry exists for this non-mesh client remove it. 1350d4ff40f6SAntonio Quartulli * 1351d4ff40f6SAntonio Quartulli * The caller must hold orig_node refcount. 13521e5d49fcSAntonio Quartulli * 135362fe710fSSven Eckelmann * Return: true if the new entry has been added, false otherwise 1354d4ff40f6SAntonio Quartulli */ 13551e5d49fcSAntonio Quartulli static bool batadv_tt_global_add(struct batadv_priv *bat_priv, 135656303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1357c018ad3dSAntonio Quartulli const unsigned char *tt_addr, 13586b5e971aSSven Eckelmann unsigned short vid, u16 flags, u8 ttvn) 1359c6c8fea2SSven Eckelmann { 1360170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 1361170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 13621e5d49fcSAntonio Quartulli bool ret = false; 136380b3f58cSSimon Wunderlich int hash_added; 136456303d34SSven Eckelmann struct batadv_tt_common_entry *common; 13656b5e971aSSven Eckelmann u16 local_flags; 1366c6c8fea2SSven Eckelmann 1367cfd4f757SAntonio Quartulli /* ignore global entries from backbone nodes */ 1368cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) 1369cfd4f757SAntonio Quartulli return true; 1370cfd4f757SAntonio Quartulli 1371c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); 1372c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid); 1373068ee6e2SAntonio Quartulli 1374068ee6e2SAntonio Quartulli /* if the node already has a local client for this entry, it has to wait 1375068ee6e2SAntonio Quartulli * for a roaming advertisement instead of manually messing up the global 1376068ee6e2SAntonio Quartulli * table 1377068ee6e2SAntonio Quartulli */ 1378068ee6e2SAntonio Quartulli if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && 1379068ee6e2SAntonio Quartulli !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) 1380068ee6e2SAntonio Quartulli goto out; 1381c6c8fea2SSven Eckelmann 13822dafb49dSAntonio Quartulli if (!tt_global_entry) { 1383d4f44692SAntonio Quartulli tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); 13842dafb49dSAntonio Quartulli if (!tt_global_entry) 13857683fdc1SAntonio Quartulli goto out; 13867683fdc1SAntonio Quartulli 1387c0a55929SSven Eckelmann common = &tt_global_entry->common; 13888fdd0153SAntonio Quartulli ether_addr_copy(common->addr, tt_addr); 1389c018ad3dSAntonio Quartulli common->vid = vid; 1390db08e6e5SSimon Wunderlich 1391d4f44692SAntonio Quartulli common->flags = flags; 1392cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1393fdf79320SAntonio Quartulli /* node must store current time in case of roaming. This is 1394fdf79320SAntonio Quartulli * needed to purge this entry out on timeout (if nobody claims 1395fdf79320SAntonio Quartulli * it) 1396fdf79320SAntonio Quartulli */ 1397fdf79320SAntonio Quartulli if (flags & BATADV_TT_CLIENT_ROAM) 1398fdf79320SAntonio Quartulli tt_global_entry->roam_at = jiffies; 1399c0a55929SSven Eckelmann atomic_set(&common->refcount, 2); 140030cfd02bSAntonio Quartulli common->added_at = jiffies; 1401db08e6e5SSimon Wunderlich 1402db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 14031d8ab8d3SLinus Lüssing atomic_set(&tt_global_entry->orig_list_count, 0); 1404db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 14057683fdc1SAntonio Quartulli 1406807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.global_hash, 1407a513088dSSven Eckelmann batadv_compare_tt, 1408c018ad3dSAntonio Quartulli batadv_choose_tt, common, 1409a513088dSSven Eckelmann &common->hash_entry); 141080b3f58cSSimon Wunderlich 141180b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 141280b3f58cSSimon Wunderlich /* remove the reference for the hash */ 1413a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 141480b3f58cSSimon Wunderlich goto out_remove; 141580b3f58cSSimon Wunderlich } 1416a73105b8SAntonio Quartulli } else { 1417068ee6e2SAntonio Quartulli common = &tt_global_entry->common; 141830cfd02bSAntonio Quartulli /* If there is already a global entry, we can use this one for 141930cfd02bSAntonio Quartulli * our processing. 1420068ee6e2SAntonio Quartulli * But if we are trying to add a temporary client then here are 1421068ee6e2SAntonio Quartulli * two options at this point: 1422068ee6e2SAntonio Quartulli * 1) the global client is not a temporary client: the global 1423068ee6e2SAntonio Quartulli * client has to be left as it is, temporary information 1424068ee6e2SAntonio Quartulli * should never override any already known client state 1425068ee6e2SAntonio Quartulli * 2) the global client is a temporary client: purge the 1426068ee6e2SAntonio Quartulli * originator list and add the new one orig_entry 142730cfd02bSAntonio Quartulli */ 1428068ee6e2SAntonio Quartulli if (flags & BATADV_TT_CLIENT_TEMP) { 1429068ee6e2SAntonio Quartulli if (!(common->flags & BATADV_TT_CLIENT_TEMP)) 143030cfd02bSAntonio Quartulli goto out; 1431068ee6e2SAntonio Quartulli if (batadv_tt_global_entry_has_orig(tt_global_entry, 1432068ee6e2SAntonio Quartulli orig_node)) 1433068ee6e2SAntonio Quartulli goto out_remove; 1434068ee6e2SAntonio Quartulli batadv_tt_global_del_orig_list(tt_global_entry); 1435068ee6e2SAntonio Quartulli goto add_orig_entry; 1436068ee6e2SAntonio Quartulli } 143730cfd02bSAntonio Quartulli 143830cfd02bSAntonio Quartulli /* if the client was temporary added before receiving the first 1439a6cb3909SSimon Wunderlich * OGM announcing it, we have to clear the TEMP flag. Also, 1440a6cb3909SSimon Wunderlich * remove the previous temporary orig node and re-add it 1441a6cb3909SSimon Wunderlich * if required. If the orig entry changed, the new one which 1442a6cb3909SSimon Wunderlich * is a non-temporary entry is preferred. 144330cfd02bSAntonio Quartulli */ 1444a6cb3909SSimon Wunderlich if (common->flags & BATADV_TT_CLIENT_TEMP) { 1445a6cb3909SSimon Wunderlich batadv_tt_global_del_orig_list(tt_global_entry); 1446068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_TEMP; 1447a6cb3909SSimon Wunderlich } 1448db08e6e5SSimon Wunderlich 1449e9c00136SAntonio Quartulli /* the change can carry possible "attribute" flags like the 1450e9c00136SAntonio Quartulli * TT_CLIENT_WIFI, therefore they have to be copied in the 1451e9c00136SAntonio Quartulli * client entry 1452e9c00136SAntonio Quartulli */ 1453ad7e2c46SSimon Wunderlich common->flags |= flags; 1454e9c00136SAntonio Quartulli 1455acd34afaSSven Eckelmann /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 1456acd34afaSSven Eckelmann * one originator left in the list and we previously received a 1457db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 1458db08e6e5SSimon Wunderlich * 1459db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 1460db08e6e5SSimon Wunderlich * new one. 1461db08e6e5SSimon Wunderlich */ 1462068ee6e2SAntonio Quartulli if (common->flags & BATADV_TT_CLIENT_ROAM) { 1463a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1464068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_ROAM; 1465cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1466c6c8fea2SSven Eckelmann } 1467db08e6e5SSimon Wunderlich } 1468068ee6e2SAntonio Quartulli add_orig_entry: 146930cfd02bSAntonio Quartulli /* add the new orig_entry (if needed) or update it */ 1470d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); 1471db08e6e5SSimon Wunderlich 147239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 147316052789SAntonio Quartulli "Creating new global tt entry: %pM (vid: %d, via %pM)\n", 147416052789SAntonio Quartulli common->addr, BATADV_PRINT_VID(common->vid), 147516052789SAntonio Quartulli orig_node->orig); 14761e5d49fcSAntonio Quartulli ret = true; 1477a73105b8SAntonio Quartulli 147880b3f58cSSimon Wunderlich out_remove: 1479c5caf4efSLinus Lüssing /* Do not remove multicast addresses from the local hash on 1480c5caf4efSLinus Lüssing * global additions 1481c5caf4efSLinus Lüssing */ 1482c5caf4efSLinus Lüssing if (is_multicast_ether_addr(tt_addr)) 1483c5caf4efSLinus Lüssing goto out; 14847f91d06cSAntonio Quartulli 1485c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 1486c018ad3dSAntonio Quartulli local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, 1487acd34afaSSven Eckelmann "global tt received", 1488c1d07431SAntonio Quartulli flags & BATADV_TT_CLIENT_ROAM); 14897f91d06cSAntonio Quartulli tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; 14907f91d06cSAntonio Quartulli 1491068ee6e2SAntonio Quartulli if (!(flags & BATADV_TT_CLIENT_ROAM)) 1492068ee6e2SAntonio Quartulli /* this is a normal global add. Therefore the client is not in a 1493068ee6e2SAntonio Quartulli * roaming state anymore. 1494068ee6e2SAntonio Quartulli */ 1495068ee6e2SAntonio Quartulli tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 1496068ee6e2SAntonio Quartulli 14977683fdc1SAntonio Quartulli out: 14987683fdc1SAntonio Quartulli if (tt_global_entry) 1499a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1500068ee6e2SAntonio Quartulli if (tt_local_entry) 1501068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 15027683fdc1SAntonio Quartulli return ret; 1503c6c8fea2SSven Eckelmann } 1504c6c8fea2SSven Eckelmann 15051b371d13SSimon Wunderlich /** 15061b371d13SSimon Wunderlich * batadv_transtable_best_orig - Get best originator list entry from tt entry 15074627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1508981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be analyzed 1509981d8900SSven Eckelmann * 1510981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 151162fe710fSSven Eckelmann * Return: best originator list entry or NULL on errors. 1512981d8900SSven Eckelmann */ 1513981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry * 15144627456aSAntonio Quartulli batadv_transtable_best_orig(struct batadv_priv *bat_priv, 15154627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry) 1516981d8900SSven Eckelmann { 15174627456aSAntonio Quartulli struct batadv_neigh_node *router, *best_router = NULL; 15184627456aSAntonio Quartulli struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; 1519981d8900SSven Eckelmann struct hlist_head *head; 1520981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; 1521981d8900SSven Eckelmann 1522981d8900SSven Eckelmann head = &tt_global_entry->orig_list; 1523b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 15247351a482SSimon Wunderlich router = batadv_orig_router_get(orig_entry->orig_node, 15257351a482SSimon Wunderlich BATADV_IF_DEFAULT); 1526981d8900SSven Eckelmann if (!router) 1527981d8900SSven Eckelmann continue; 1528981d8900SSven Eckelmann 15294627456aSAntonio Quartulli if (best_router && 153089652331SSimon Wunderlich bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, 153189652331SSimon Wunderlich best_router, BATADV_IF_DEFAULT) <= 0) { 15324627456aSAntonio Quartulli batadv_neigh_node_free_ref(router); 15334627456aSAntonio Quartulli continue; 1534981d8900SSven Eckelmann } 1535981d8900SSven Eckelmann 15364627456aSAntonio Quartulli /* release the refcount for the "old" best */ 15374627456aSAntonio Quartulli if (best_router) 15384627456aSAntonio Quartulli batadv_neigh_node_free_ref(best_router); 15394627456aSAntonio Quartulli 15404627456aSAntonio Quartulli best_entry = orig_entry; 15414627456aSAntonio Quartulli best_router = router; 1542981d8900SSven Eckelmann } 1543981d8900SSven Eckelmann 15444627456aSAntonio Quartulli if (best_router) 15454627456aSAntonio Quartulli batadv_neigh_node_free_ref(best_router); 15464627456aSAntonio Quartulli 1547981d8900SSven Eckelmann return best_entry; 1548981d8900SSven Eckelmann } 1549981d8900SSven Eckelmann 15501b371d13SSimon Wunderlich /** 15511b371d13SSimon Wunderlich * batadv_tt_global_print_entry - print all orig nodes who announce the address 1552981d8900SSven Eckelmann * for this global entry 15534627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1554981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be printed 1555981d8900SSven Eckelmann * @seq: debugfs table seq_file struct 1556981d8900SSven Eckelmann * 1557981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 1558db08e6e5SSimon Wunderlich */ 1559a513088dSSven Eckelmann static void 15604627456aSAntonio Quartulli batadv_tt_global_print_entry(struct batadv_priv *bat_priv, 15614627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry, 1562db08e6e5SSimon Wunderlich struct seq_file *seq) 1563db08e6e5SSimon Wunderlich { 1564981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry; 156556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 15667ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 15677ea7b4a1SAntonio Quartulli struct hlist_head *head; 15686b5e971aSSven Eckelmann u8 last_ttvn; 15696b5e971aSSven Eckelmann u16 flags; 1570db08e6e5SSimon Wunderlich 1571db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 1572981d8900SSven Eckelmann flags = tt_common_entry->flags; 1573981d8900SSven Eckelmann 15744627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 1575981d8900SSven Eckelmann if (best_entry) { 15767ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(best_entry->orig_node, 15777ea7b4a1SAntonio Quartulli tt_common_entry->vid); 15787ea7b4a1SAntonio Quartulli if (!vlan) { 15797ea7b4a1SAntonio Quartulli seq_printf(seq, 15807ea7b4a1SAntonio Quartulli " * Cannot retrieve VLAN %d for originator %pM\n", 15817ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 15827ea7b4a1SAntonio Quartulli best_entry->orig_node->orig); 15837ea7b4a1SAntonio Quartulli goto print_list; 15847ea7b4a1SAntonio Quartulli } 15857ea7b4a1SAntonio Quartulli 1586981d8900SSven Eckelmann last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); 1587f9d8a537SAntonio Quartulli seq_printf(seq, 1588dd24ddb2SAntonio Quartulli " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1589981d8900SSven Eckelmann '*', tt_global_entry->common.addr, 159016052789SAntonio Quartulli BATADV_PRINT_VID(tt_global_entry->common.vid), 1591981d8900SSven Eckelmann best_entry->ttvn, best_entry->orig_node->orig, 15927ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1593a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 1594a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1595a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1596a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.')); 15977ea7b4a1SAntonio Quartulli 15987ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 1599981d8900SSven Eckelmann } 1600db08e6e5SSimon Wunderlich 16017ea7b4a1SAntonio Quartulli print_list: 1602db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1603db08e6e5SSimon Wunderlich 1604b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1605981d8900SSven Eckelmann if (best_entry == orig_entry) 1606981d8900SSven Eckelmann continue; 1607981d8900SSven Eckelmann 16087ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, 16097ea7b4a1SAntonio Quartulli tt_common_entry->vid); 16107ea7b4a1SAntonio Quartulli if (!vlan) { 16117ea7b4a1SAntonio Quartulli seq_printf(seq, 16127ea7b4a1SAntonio Quartulli " + Cannot retrieve VLAN %d for originator %pM\n", 16137ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 16147ea7b4a1SAntonio Quartulli orig_entry->orig_node->orig); 16157ea7b4a1SAntonio Quartulli continue; 16167ea7b4a1SAntonio Quartulli } 16177ea7b4a1SAntonio Quartulli 1618db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 161916052789SAntonio Quartulli seq_printf(seq, 1620dd24ddb2SAntonio Quartulli " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1621981d8900SSven Eckelmann '+', tt_global_entry->common.addr, 162216052789SAntonio Quartulli BATADV_PRINT_VID(tt_global_entry->common.vid), 1623981d8900SSven Eckelmann orig_entry->ttvn, orig_entry->orig_node->orig, 16247ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1625a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 1626a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1627a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1628a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.')); 16297ea7b4a1SAntonio Quartulli 16307ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 1631db08e6e5SSimon Wunderlich } 1632db08e6e5SSimon Wunderlich } 1633db08e6e5SSimon Wunderlich 163408c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 1635c6c8fea2SSven Eckelmann { 1636c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 163756303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 1638807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 163956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 164056303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 164156303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 1642c6c8fea2SSven Eckelmann struct hlist_head *head; 16436b5e971aSSven Eckelmann u32 i; 1644c6c8fea2SSven Eckelmann 164530da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 164630da63a6SMarek Lindner if (!primary_if) 164732ae9b22SMarek Lindner goto out; 1648c6c8fea2SSven Eckelmann 16492dafb49dSAntonio Quartulli seq_printf(seq, 16502dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 1651c6c8fea2SSven Eckelmann net_dev->name); 165216052789SAntonio Quartulli seq_printf(seq, " %-13s %s %s %-15s %s (%-10s) %s\n", 165316052789SAntonio Quartulli "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)", 165416052789SAntonio Quartulli "CRC", "Flags"); 1655c6c8fea2SSven Eckelmann 1656c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1657c6c8fea2SSven Eckelmann head = &hash->table[i]; 1658c6c8fea2SSven Eckelmann 16597aadf889SMarek Lindner rcu_read_lock(); 1660b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 16617aadf889SMarek Lindner head, hash_entry) { 166256303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 166356303d34SSven Eckelmann struct batadv_tt_global_entry, 166448100bacSAntonio Quartulli common); 16654627456aSAntonio Quartulli batadv_tt_global_print_entry(bat_priv, tt_global, seq); 1666c6c8fea2SSven Eckelmann } 16677aadf889SMarek Lindner rcu_read_unlock(); 1668c6c8fea2SSven Eckelmann } 166932ae9b22SMarek Lindner out: 167032ae9b22SMarek Lindner if (primary_if) 1671e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 167230da63a6SMarek Lindner return 0; 1673c6c8fea2SSven Eckelmann } 1674c6c8fea2SSven Eckelmann 16751d8ab8d3SLinus Lüssing /** 1676433ff98fSMarek Lindner * _batadv_tt_global_del_orig_entry - remove and free an orig_entry 16771d8ab8d3SLinus Lüssing * @tt_global_entry: the global entry to remove the orig_entry from 16781d8ab8d3SLinus Lüssing * @orig_entry: the orig entry to remove and free 16791d8ab8d3SLinus Lüssing * 16801d8ab8d3SLinus Lüssing * Remove an orig_entry from its list in the given tt_global_entry and 16811d8ab8d3SLinus Lüssing * free this orig_entry afterwards. 1682433ff98fSMarek Lindner * 1683433ff98fSMarek Lindner * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is 1684433ff98fSMarek Lindner * part of a list. 16851d8ab8d3SLinus Lüssing */ 16861d8ab8d3SLinus Lüssing static void 1687433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, 16881d8ab8d3SLinus Lüssing struct batadv_tt_orig_list_entry *orig_entry) 16891d8ab8d3SLinus Lüssing { 16902c72d655SSven Eckelmann lockdep_assert_held(&tt_global_entry->list_lock); 16912c72d655SSven Eckelmann 16921d8ab8d3SLinus Lüssing batadv_tt_global_size_dec(orig_entry->orig_node, 16931d8ab8d3SLinus Lüssing tt_global_entry->common.vid); 16941d8ab8d3SLinus Lüssing atomic_dec(&tt_global_entry->orig_list_count); 1695433ff98fSMarek Lindner /* requires holding tt_global_entry->list_lock and orig_entry->list 1696433ff98fSMarek Lindner * being part of a list 1697433ff98fSMarek Lindner */ 16981d8ab8d3SLinus Lüssing hlist_del_rcu(&orig_entry->list); 16991d8ab8d3SLinus Lüssing batadv_tt_orig_list_entry_free_ref(orig_entry); 17001d8ab8d3SLinus Lüssing } 17011d8ab8d3SLinus Lüssing 1702db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 1703a513088dSSven Eckelmann static void 170456303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) 1705db08e6e5SSimon Wunderlich { 1706db08e6e5SSimon Wunderlich struct hlist_head *head; 1707b67bfe0dSSasha Levin struct hlist_node *safe; 170856303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1709db08e6e5SSimon Wunderlich 1710db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1711db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 17121d8ab8d3SLinus Lüssing hlist_for_each_entry_safe(orig_entry, safe, head, list) 1713433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); 1714db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1715db08e6e5SSimon Wunderlich } 1716db08e6e5SSimon Wunderlich 17171d8ab8d3SLinus Lüssing /** 17181d8ab8d3SLinus Lüssing * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry 17191d8ab8d3SLinus Lüssing * @bat_priv: the bat priv with all the soft interface information 17201d8ab8d3SLinus Lüssing * @tt_global_entry: the global entry to remove the orig_node from 17211d8ab8d3SLinus Lüssing * @orig_node: the originator announcing the client 17221d8ab8d3SLinus Lüssing * @message: message to append to the log on deletion 17231d8ab8d3SLinus Lüssing * 17241d8ab8d3SLinus Lüssing * Remove the given orig_node and its according orig_entry from the given 17251d8ab8d3SLinus Lüssing * global tt entry. 17261d8ab8d3SLinus Lüssing */ 1727a513088dSSven Eckelmann static void 17281d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, 172956303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 173056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1731db08e6e5SSimon Wunderlich const char *message) 1732db08e6e5SSimon Wunderlich { 1733db08e6e5SSimon Wunderlich struct hlist_head *head; 1734b67bfe0dSSasha Levin struct hlist_node *safe; 173556303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 173616052789SAntonio Quartulli unsigned short vid; 1737db08e6e5SSimon Wunderlich 1738db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1739db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1740b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1741db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 174216052789SAntonio Quartulli vid = tt_global_entry->common.vid; 174339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 174416052789SAntonio Quartulli "Deleting %pM from global tt entry %pM (vid: %d): %s\n", 17451eda58bfSSven Eckelmann orig_node->orig, 174616052789SAntonio Quartulli tt_global_entry->common.addr, 174716052789SAntonio Quartulli BATADV_PRINT_VID(vid), message); 1748433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(tt_global_entry, 17491d8ab8d3SLinus Lüssing orig_entry); 1750db08e6e5SSimon Wunderlich } 1751db08e6e5SSimon Wunderlich } 1752db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1753db08e6e5SSimon Wunderlich } 1754db08e6e5SSimon Wunderlich 1755db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 1756acd34afaSSven Eckelmann * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the 1757acd34afaSSven Eckelmann * timer, otherwise we simply remove the originator scheduled for deletion. 1758db08e6e5SSimon Wunderlich */ 1759a513088dSSven Eckelmann static void 176056303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, 176156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 176256303d34SSven Eckelmann struct batadv_orig_node *orig_node, 176356303d34SSven Eckelmann const char *message) 1764db08e6e5SSimon Wunderlich { 1765db08e6e5SSimon Wunderlich bool last_entry = true; 1766db08e6e5SSimon Wunderlich struct hlist_head *head; 176756303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1768db08e6e5SSimon Wunderlich 1769db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 1770db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 1771db08e6e5SSimon Wunderlich */ 1772db08e6e5SSimon Wunderlich 1773db08e6e5SSimon Wunderlich rcu_read_lock(); 1774db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1775b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1776db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 1777db08e6e5SSimon Wunderlich last_entry = false; 1778db08e6e5SSimon Wunderlich break; 1779db08e6e5SSimon Wunderlich } 1780db08e6e5SSimon Wunderlich } 1781db08e6e5SSimon Wunderlich rcu_read_unlock(); 1782db08e6e5SSimon Wunderlich 1783db08e6e5SSimon Wunderlich if (last_entry) { 1784db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 1785acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 1786db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 1787db08e6e5SSimon Wunderlich } else 1788db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 1789db08e6e5SSimon Wunderlich * one and can still use the other one. 1790db08e6e5SSimon Wunderlich */ 17911d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 1792db08e6e5SSimon Wunderlich orig_node, message); 1793db08e6e5SSimon Wunderlich } 1794db08e6e5SSimon Wunderlich 1795c018ad3dSAntonio Quartulli /** 1796c018ad3dSAntonio Quartulli * batadv_tt_global_del - remove a client from the global table 1797c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1798c018ad3dSAntonio Quartulli * @orig_node: an originator serving this client 1799c018ad3dSAntonio Quartulli * @addr: the mac address of the client 1800c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1801c018ad3dSAntonio Quartulli * @message: a message explaining the reason for deleting the client to print 1802c018ad3dSAntonio Quartulli * for debugging purpose 1803c018ad3dSAntonio Quartulli * @roaming: true if the deletion has been triggered by a roaming event 1804c018ad3dSAntonio Quartulli */ 180556303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv, 180656303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1807c018ad3dSAntonio Quartulli const unsigned char *addr, unsigned short vid, 1808cc47f66eSAntonio Quartulli const char *message, bool roaming) 1809a73105b8SAntonio Quartulli { 1810170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 181156303d34SSven Eckelmann struct batadv_tt_local_entry *local_entry = NULL; 1812a73105b8SAntonio Quartulli 1813c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 1814db08e6e5SSimon Wunderlich if (!tt_global_entry) 18157683fdc1SAntonio Quartulli goto out; 1816a73105b8SAntonio Quartulli 1817db08e6e5SSimon Wunderlich if (!roaming) { 18181d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 1819a513088dSSven Eckelmann orig_node, message); 182092f90f56SSven Eckelmann 1821db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 1822be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, 1823db08e6e5SSimon Wunderlich message); 1824db08e6e5SSimon Wunderlich 1825cc47f66eSAntonio Quartulli goto out; 1826cc47f66eSAntonio Quartulli } 182792f90f56SSven Eckelmann 1828db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 1829db08e6e5SSimon Wunderlich * event, there are two possibilities: 1830db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 1831db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 1832acd34afaSSven Eckelmann * it with BATADV_TT_CLIENT_ROAM, we start a timer and we 1833db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 1834db08e6e5SSimon Wunderlich * the entry is purged. 1835db08e6e5SSimon Wunderlich * 1836db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 1837db08e6e5SSimon Wunderlich * the originator. 1838db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 18399cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 18409cfc7bd6SSven Eckelmann */ 1841a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 1842c018ad3dSAntonio Quartulli tt_global_entry->common.addr, 1843c018ad3dSAntonio Quartulli vid); 1844a513088dSSven Eckelmann if (local_entry) { 1845db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 1846a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1847be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, message); 1848db08e6e5SSimon Wunderlich } else 1849db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 1850a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 1851a513088dSSven Eckelmann orig_node, message); 1852db08e6e5SSimon Wunderlich 1853cc47f66eSAntonio Quartulli out: 18547683fdc1SAntonio Quartulli if (tt_global_entry) 1855a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1856a513088dSSven Eckelmann if (local_entry) 1857a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(local_entry); 1858a73105b8SAntonio Quartulli } 1859a73105b8SAntonio Quartulli 186095fb130dSAntonio Quartulli /** 186195fb130dSAntonio Quartulli * batadv_tt_global_del_orig - remove all the TT global entries belonging to the 186295fb130dSAntonio Quartulli * given originator matching the provided vid 186395fb130dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 186495fb130dSAntonio Quartulli * @orig_node: the originator owning the entries to remove 186595fb130dSAntonio Quartulli * @match_vid: the VLAN identifier to match. If negative all the entries will be 186695fb130dSAntonio Quartulli * removed 186795fb130dSAntonio Quartulli * @message: debug message to print as "reason" 186895fb130dSAntonio Quartulli */ 186956303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, 187056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 18716b5e971aSSven Eckelmann s32 match_vid, 187256303d34SSven Eckelmann const char *message) 1873c6c8fea2SSven Eckelmann { 187456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 187556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 18766b5e971aSSven Eckelmann u32 i; 1877807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 1878b67bfe0dSSasha Levin struct hlist_node *safe; 1879a73105b8SAntonio Quartulli struct hlist_head *head; 18807683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 188116052789SAntonio Quartulli unsigned short vid; 1882c6c8fea2SSven Eckelmann 18836e801494SSimon Wunderlich if (!hash) 18846e801494SSimon Wunderlich return; 18856e801494SSimon Wunderlich 1886a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1887a73105b8SAntonio Quartulli head = &hash->table[i]; 18887683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1889c6c8fea2SSven Eckelmann 18907683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1891b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, safe, 1892a73105b8SAntonio Quartulli head, hash_entry) { 189395fb130dSAntonio Quartulli /* remove only matching entries */ 189495fb130dSAntonio Quartulli if (match_vid >= 0 && tt_common_entry->vid != match_vid) 189595fb130dSAntonio Quartulli continue; 189695fb130dSAntonio Quartulli 189756303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 189856303d34SSven Eckelmann struct batadv_tt_global_entry, 189948100bacSAntonio Quartulli common); 1900db08e6e5SSimon Wunderlich 19011d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global, 1902db08e6e5SSimon Wunderlich orig_node, message); 1903db08e6e5SSimon Wunderlich 190456303d34SSven Eckelmann if (hlist_empty(&tt_global->orig_list)) { 190516052789SAntonio Quartulli vid = tt_global->common.vid; 190639c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 190716052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 190816052789SAntonio Quartulli tt_global->common.addr, 190916052789SAntonio Quartulli BATADV_PRINT_VID(vid), message); 1910b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 191156303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 1912c6c8fea2SSven Eckelmann } 1913a73105b8SAntonio Quartulli } 19147683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 19157683fdc1SAntonio Quartulli } 1916ac4eebd4SLinus Lüssing clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); 1917c6c8fea2SSven Eckelmann } 1918c6c8fea2SSven Eckelmann 191930cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, 192030cfd02bSAntonio Quartulli char **msg) 1921cc47f66eSAntonio Quartulli { 192230cfd02bSAntonio Quartulli bool purge = false; 192330cfd02bSAntonio Quartulli unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; 192430cfd02bSAntonio Quartulli unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; 1925cc47f66eSAntonio Quartulli 192630cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && 192730cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { 192830cfd02bSAntonio Quartulli purge = true; 192930cfd02bSAntonio Quartulli *msg = "Roaming timeout\n"; 193042d0b044SSven Eckelmann } 193142d0b044SSven Eckelmann 193230cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) && 193330cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) { 193430cfd02bSAntonio Quartulli purge = true; 193530cfd02bSAntonio Quartulli *msg = "Temporary client timeout\n"; 193630cfd02bSAntonio Quartulli } 193730cfd02bSAntonio Quartulli 193830cfd02bSAntonio Quartulli return purge; 193930cfd02bSAntonio Quartulli } 194030cfd02bSAntonio Quartulli 194130cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv) 194242d0b044SSven Eckelmann { 1943807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 194442d0b044SSven Eckelmann struct hlist_head *head; 1945b67bfe0dSSasha Levin struct hlist_node *node_tmp; 194642d0b044SSven Eckelmann spinlock_t *list_lock; /* protects write access to the hash lists */ 19476b5e971aSSven Eckelmann u32 i; 194830cfd02bSAntonio Quartulli char *msg = NULL; 194930cfd02bSAntonio Quartulli struct batadv_tt_common_entry *tt_common; 195030cfd02bSAntonio Quartulli struct batadv_tt_global_entry *tt_global; 195142d0b044SSven Eckelmann 195242d0b044SSven Eckelmann for (i = 0; i < hash->size; i++) { 195342d0b044SSven Eckelmann head = &hash->table[i]; 195442d0b044SSven Eckelmann list_lock = &hash->list_locks[i]; 195542d0b044SSven Eckelmann 195642d0b044SSven Eckelmann spin_lock_bh(list_lock); 1957b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 195830cfd02bSAntonio Quartulli hash_entry) { 195930cfd02bSAntonio Quartulli tt_global = container_of(tt_common, 196030cfd02bSAntonio Quartulli struct batadv_tt_global_entry, 196130cfd02bSAntonio Quartulli common); 196230cfd02bSAntonio Quartulli 196330cfd02bSAntonio Quartulli if (!batadv_tt_global_to_purge(tt_global, &msg)) 196430cfd02bSAntonio Quartulli continue; 196530cfd02bSAntonio Quartulli 196630cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 196716052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 196816052789SAntonio Quartulli tt_global->common.addr, 196916052789SAntonio Quartulli BATADV_PRINT_VID(tt_global->common.vid), 197016052789SAntonio Quartulli msg); 197130cfd02bSAntonio Quartulli 1972b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 197330cfd02bSAntonio Quartulli 197430cfd02bSAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 197530cfd02bSAntonio Quartulli } 19767683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1977cc47f66eSAntonio Quartulli } 1978cc47f66eSAntonio Quartulli } 1979cc47f66eSAntonio Quartulli 198056303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) 1981c6c8fea2SSven Eckelmann { 19825bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 19837683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 198456303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 198556303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 1986b67bfe0dSSasha Levin struct hlist_node *node_tmp; 19877683fdc1SAntonio Quartulli struct hlist_head *head; 19886b5e971aSSven Eckelmann u32 i; 19897683fdc1SAntonio Quartulli 1990807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 1991c6c8fea2SSven Eckelmann return; 1992c6c8fea2SSven Eckelmann 1993807736f6SSven Eckelmann hash = bat_priv->tt.global_hash; 19947683fdc1SAntonio Quartulli 19957683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 19967683fdc1SAntonio Quartulli head = &hash->table[i]; 19977683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 19987683fdc1SAntonio Quartulli 19997683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 2000b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 20017683fdc1SAntonio Quartulli head, hash_entry) { 2002b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 200356303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 200456303d34SSven Eckelmann struct batadv_tt_global_entry, 200548100bacSAntonio Quartulli common); 200656303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 20077683fdc1SAntonio Quartulli } 20087683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 20097683fdc1SAntonio Quartulli } 20107683fdc1SAntonio Quartulli 20111a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 20127683fdc1SAntonio Quartulli 2013807736f6SSven Eckelmann bat_priv->tt.global_hash = NULL; 2014c6c8fea2SSven Eckelmann } 2015c6c8fea2SSven Eckelmann 201656303d34SSven Eckelmann static bool 201756303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, 201856303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry) 201959b699cdSAntonio Quartulli { 202059b699cdSAntonio Quartulli bool ret = false; 202159b699cdSAntonio Quartulli 2022acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && 2023acd34afaSSven Eckelmann tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) 202459b699cdSAntonio Quartulli ret = true; 202559b699cdSAntonio Quartulli 20262d2fcc2aSAntonio Quartulli /* check if the two clients are marked as isolated */ 20272d2fcc2aSAntonio Quartulli if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA && 20282d2fcc2aSAntonio Quartulli tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA) 20292d2fcc2aSAntonio Quartulli ret = true; 20302d2fcc2aSAntonio Quartulli 203159b699cdSAntonio Quartulli return ret; 203259b699cdSAntonio Quartulli } 203359b699cdSAntonio Quartulli 2034c018ad3dSAntonio Quartulli /** 2035c018ad3dSAntonio Quartulli * batadv_transtable_search - get the mesh destination for a given client 2036c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2037c018ad3dSAntonio Quartulli * @src: mac address of the source client 2038c018ad3dSAntonio Quartulli * @addr: mac address of the destination client 2039c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2040c018ad3dSAntonio Quartulli * 204162fe710fSSven Eckelmann * Return: a pointer to the originator that was selected as destination in the 2042c018ad3dSAntonio Quartulli * mesh for contacting the client 'addr', NULL otherwise. 2043c018ad3dSAntonio Quartulli * In case of multiple originators serving the same client, the function returns 2044c018ad3dSAntonio Quartulli * the best one (best in terms of metric towards the destination node). 2045c018ad3dSAntonio Quartulli * 2046c018ad3dSAntonio Quartulli * If the two clients are AP isolated the function returns NULL. 2047c018ad3dSAntonio Quartulli */ 204856303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, 20496b5e971aSSven Eckelmann const u8 *src, 20506b5e971aSSven Eckelmann const u8 *addr, 2051c018ad3dSAntonio Quartulli unsigned short vid) 2052c6c8fea2SSven Eckelmann { 205356303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 205456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 205556303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 2056981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *best_entry; 2057c6c8fea2SSven Eckelmann 2058eceb22aeSAntonio Quartulli if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) { 2059c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); 2060068ee6e2SAntonio Quartulli if (!tt_local_entry || 2061068ee6e2SAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) 20623d393e47SAntonio Quartulli goto out; 20633d393e47SAntonio Quartulli } 20647aadf889SMarek Lindner 2065c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 20662dafb49dSAntonio Quartulli if (!tt_global_entry) 20677b36e8eeSMarek Lindner goto out; 2068c6c8fea2SSven Eckelmann 20693d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 20709cfc7bd6SSven Eckelmann * isolation 20719cfc7bd6SSven Eckelmann */ 2072a513088dSSven Eckelmann if (tt_local_entry && 2073a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 20743d393e47SAntonio Quartulli goto out; 20753d393e47SAntonio Quartulli 2076db08e6e5SSimon Wunderlich rcu_read_lock(); 20774627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 2078db08e6e5SSimon Wunderlich /* found anything? */ 2079981d8900SSven Eckelmann if (best_entry) 2080981d8900SSven Eckelmann orig_node = best_entry->orig_node; 2081db08e6e5SSimon Wunderlich if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) 2082db08e6e5SSimon Wunderlich orig_node = NULL; 2083db08e6e5SSimon Wunderlich rcu_read_unlock(); 2084981d8900SSven Eckelmann 20857b36e8eeSMarek Lindner out: 20863d393e47SAntonio Quartulli if (tt_global_entry) 2087a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 20883d393e47SAntonio Quartulli if (tt_local_entry) 2089a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 20903d393e47SAntonio Quartulli 20917b36e8eeSMarek Lindner return orig_node; 2092c6c8fea2SSven Eckelmann } 2093a73105b8SAntonio Quartulli 2094ced72933SAntonio Quartulli /** 2095ced72933SAntonio Quartulli * batadv_tt_global_crc - calculates the checksum of the local table belonging 2096ced72933SAntonio Quartulli * to the given orig_node 2097ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 20980ffa9e8dSAntonio Quartulli * @orig_node: originator for which the CRC should be computed 20997ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 21000ffa9e8dSAntonio Quartulli * 21010ffa9e8dSAntonio Quartulli * This function computes the checksum for the global table corresponding to a 21020ffa9e8dSAntonio Quartulli * specific originator. In particular, the checksum is computed as follows: For 21030ffa9e8dSAntonio Quartulli * each client connected to the originator the CRC32C of the MAC address and the 21040ffa9e8dSAntonio Quartulli * VID is computed and then all the CRC32Cs of the various clients are xor'ed 21050ffa9e8dSAntonio Quartulli * together. 21060ffa9e8dSAntonio Quartulli * 21070ffa9e8dSAntonio Quartulli * The idea behind is that CRC32C should be used as much as possible in order to 21080ffa9e8dSAntonio Quartulli * produce a unique hash of the table, but since the order which is used to feed 21090ffa9e8dSAntonio Quartulli * the CRC32C function affects the result and since every node in the network 21100ffa9e8dSAntonio Quartulli * probably sorts the clients differently, the hash function cannot be directly 21110ffa9e8dSAntonio Quartulli * computed over the entire table. Hence the CRC32C is used only on 21120ffa9e8dSAntonio Quartulli * the single client entry, while all the results are then xor'ed together 21130ffa9e8dSAntonio Quartulli * because the XOR operation can combine them all while trying to reduce the 21140ffa9e8dSAntonio Quartulli * noise as much as possible. 21150ffa9e8dSAntonio Quartulli * 211662fe710fSSven Eckelmann * Return: the checksum of the global table of a given originator. 2117ced72933SAntonio Quartulli */ 21186b5e971aSSven Eckelmann static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv, 21197ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node, 21207ea7b4a1SAntonio Quartulli unsigned short vid) 2121a73105b8SAntonio Quartulli { 2122807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 212356303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 212456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 2125a73105b8SAntonio Quartulli struct hlist_head *head; 21266b5e971aSSven Eckelmann u32 i, crc_tmp, crc = 0; 21276b5e971aSSven Eckelmann u8 flags; 2128a30e22caSAntonio Quartulli __be16 tmp_vid; 2129a73105b8SAntonio Quartulli 2130a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2131a73105b8SAntonio Quartulli head = &hash->table[i]; 2132a73105b8SAntonio Quartulli 2133a73105b8SAntonio Quartulli rcu_read_lock(); 2134b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 213556303d34SSven Eckelmann tt_global = container_of(tt_common, 213656303d34SSven Eckelmann struct batadv_tt_global_entry, 213748100bacSAntonio Quartulli common); 21387ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 21397ea7b4a1SAntonio Quartulli * VLAN identified by the vid passed as parameter 21407ea7b4a1SAntonio Quartulli */ 21417ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 21427ea7b4a1SAntonio Quartulli continue; 21437ea7b4a1SAntonio Quartulli 2144cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 2145cc47f66eSAntonio Quartulli * consistency only. They don't have to be 2146cc47f66eSAntonio Quartulli * taken into account while computing the 2147db08e6e5SSimon Wunderlich * global crc 2148db08e6e5SSimon Wunderlich */ 2149acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 2150cc47f66eSAntonio Quartulli continue; 215130cfd02bSAntonio Quartulli /* Temporary clients have not been announced yet, so 215230cfd02bSAntonio Quartulli * they have to be skipped while computing the global 215330cfd02bSAntonio Quartulli * crc 215430cfd02bSAntonio Quartulli */ 215530cfd02bSAntonio Quartulli if (tt_common->flags & BATADV_TT_CLIENT_TEMP) 215630cfd02bSAntonio Quartulli continue; 2157db08e6e5SSimon Wunderlich 2158db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 2159db08e6e5SSimon Wunderlich * originator 2160db08e6e5SSimon Wunderlich */ 216156303d34SSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global, 2162db08e6e5SSimon Wunderlich orig_node)) 2163db08e6e5SSimon Wunderlich continue; 2164db08e6e5SSimon Wunderlich 2165a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2166a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2167a30e22caSAntonio Quartulli */ 2168a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2169a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 21700eb01568SAntonio Quartulli 21710eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 21720eb01568SAntonio Quartulli * among nodes 21730eb01568SAntonio Quartulli */ 21740eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 21750eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 21760eb01568SAntonio Quartulli 21770ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2178a73105b8SAntonio Quartulli } 2179a73105b8SAntonio Quartulli rcu_read_unlock(); 2180a73105b8SAntonio Quartulli } 2181a73105b8SAntonio Quartulli 2182ced72933SAntonio Quartulli return crc; 2183a73105b8SAntonio Quartulli } 2184a73105b8SAntonio Quartulli 2185ced72933SAntonio Quartulli /** 2186ced72933SAntonio Quartulli * batadv_tt_local_crc - calculates the checksum of the local table 2187ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 21887ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 21890ffa9e8dSAntonio Quartulli * 21900ffa9e8dSAntonio Quartulli * For details about the computation, please refer to the documentation for 21910ffa9e8dSAntonio Quartulli * batadv_tt_global_crc(). 21920ffa9e8dSAntonio Quartulli * 219362fe710fSSven Eckelmann * Return: the checksum of the local table 2194ced72933SAntonio Quartulli */ 21956b5e971aSSven Eckelmann static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv, 21967ea7b4a1SAntonio Quartulli unsigned short vid) 2197a73105b8SAntonio Quartulli { 2198807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 219956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 2200a73105b8SAntonio Quartulli struct hlist_head *head; 22016b5e971aSSven Eckelmann u32 i, crc_tmp, crc = 0; 22026b5e971aSSven Eckelmann u8 flags; 2203a30e22caSAntonio Quartulli __be16 tmp_vid; 2204a73105b8SAntonio Quartulli 2205a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2206a73105b8SAntonio Quartulli head = &hash->table[i]; 2207a73105b8SAntonio Quartulli 2208a73105b8SAntonio Quartulli rcu_read_lock(); 2209b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 22107ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 22117ea7b4a1SAntonio Quartulli * VLAN identified by vid 22127ea7b4a1SAntonio Quartulli */ 22137ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 22147ea7b4a1SAntonio Quartulli continue; 22157ea7b4a1SAntonio Quartulli 2216058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 22179cfc7bd6SSven Eckelmann * account while computing the CRC 22189cfc7bd6SSven Eckelmann */ 2219acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_NEW) 2220058d0e26SAntonio Quartulli continue; 2221ced72933SAntonio Quartulli 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 224256303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) 2243a73105b8SAntonio Quartulli { 22447c26a53bSMarek Lindner struct batadv_tt_req_node *node; 22457c26a53bSMarek Lindner struct hlist_node *safe; 2246a73105b8SAntonio Quartulli 2247807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2248a73105b8SAntonio Quartulli 22497c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 22507c26a53bSMarek Lindner hlist_del_init(&node->list); 2251a73105b8SAntonio Quartulli kfree(node); 2252a73105b8SAntonio Quartulli } 2253a73105b8SAntonio Quartulli 2254807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2255a73105b8SAntonio Quartulli } 2256a73105b8SAntonio Quartulli 225756303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, 225856303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2259e8cf234aSAntonio Quartulli const void *tt_buff, 22606b5e971aSSven Eckelmann u16 tt_buff_len) 2261a73105b8SAntonio Quartulli { 2262a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 22639cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 22649cfc7bd6SSven Eckelmann */ 2265a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2266a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 2267a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2268a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2269a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 2270a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 2271a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 2272a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 2273a73105b8SAntonio Quartulli } 2274a73105b8SAntonio Quartulli } 2275a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2276a73105b8SAntonio Quartulli } 2277a73105b8SAntonio Quartulli 227856303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv) 2279a73105b8SAntonio Quartulli { 22807c26a53bSMarek Lindner struct batadv_tt_req_node *node; 22817c26a53bSMarek Lindner struct hlist_node *safe; 2282a73105b8SAntonio Quartulli 2283807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 22847c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 228542d0b044SSven Eckelmann if (batadv_has_timed_out(node->issued_at, 228642d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) { 22877c26a53bSMarek Lindner hlist_del_init(&node->list); 2288a73105b8SAntonio Quartulli kfree(node); 2289a73105b8SAntonio Quartulli } 2290a73105b8SAntonio Quartulli } 2291807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2292a73105b8SAntonio Quartulli } 2293a73105b8SAntonio Quartulli 2294383b8636SMarek Lindner /** 2295383b8636SMarek Lindner * batadv_tt_req_node_new - search and possibly create a tt_req_node object 2296383b8636SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2297383b8636SMarek Lindner * @orig_node: orig node this request is being issued for 2298383b8636SMarek Lindner * 229962fe710fSSven Eckelmann * Return: the pointer to the new tt_req_node struct if no request 2300383b8636SMarek Lindner * has already been issued for this orig_node, NULL otherwise. 23019cfc7bd6SSven Eckelmann */ 230256303d34SSven Eckelmann static struct batadv_tt_req_node * 2303383b8636SMarek Lindner batadv_tt_req_node_new(struct batadv_priv *bat_priv, 230456303d34SSven Eckelmann struct batadv_orig_node *orig_node) 2305a73105b8SAntonio Quartulli { 230656303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 2307a73105b8SAntonio Quartulli 2308807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 23097c26a53bSMarek Lindner hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { 23101eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 23111eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 231242d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) 2313a73105b8SAntonio Quartulli goto unlock; 2314a73105b8SAntonio Quartulli } 2315a73105b8SAntonio Quartulli 2316a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 2317a73105b8SAntonio Quartulli if (!tt_req_node) 2318a73105b8SAntonio Quartulli goto unlock; 2319a73105b8SAntonio Quartulli 23208fdd0153SAntonio Quartulli ether_addr_copy(tt_req_node->addr, orig_node->orig); 2321a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 2322a73105b8SAntonio Quartulli 23237c26a53bSMarek Lindner hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list); 2324a73105b8SAntonio Quartulli unlock: 2325807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2326a73105b8SAntonio Quartulli return tt_req_node; 2327a73105b8SAntonio Quartulli } 2328a73105b8SAntonio Quartulli 2329335fbe0fSMarek Lindner /** 2330335fbe0fSMarek Lindner * batadv_tt_local_valid - verify that given tt entry is a valid one 2331335fbe0fSMarek Lindner * @entry_ptr: to be checked local tt entry 2332335fbe0fSMarek Lindner * @data_ptr: not used but definition required to satisfy the callback prototype 2333335fbe0fSMarek Lindner * 233462fe710fSSven Eckelmann * Return: 1 if the entry is a valid, 0 otherwise. 2335335fbe0fSMarek Lindner */ 2336335fbe0fSMarek Lindner static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) 2337058d0e26SAntonio Quartulli { 233856303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 2339058d0e26SAntonio Quartulli 2340acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) 2341058d0e26SAntonio Quartulli return 0; 2342058d0e26SAntonio Quartulli return 1; 2343058d0e26SAntonio Quartulli } 2344058d0e26SAntonio Quartulli 2345a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr, 2346a513088dSSven Eckelmann const void *data_ptr) 2347a73105b8SAntonio Quartulli { 234856303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 234956303d34SSven Eckelmann const struct batadv_tt_global_entry *tt_global_entry; 235056303d34SSven Eckelmann const struct batadv_orig_node *orig_node = data_ptr; 2351a73105b8SAntonio Quartulli 235230cfd02bSAntonio Quartulli if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || 235330cfd02bSAntonio Quartulli tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) 2354cc47f66eSAntonio Quartulli return 0; 2355cc47f66eSAntonio Quartulli 235656303d34SSven Eckelmann tt_global_entry = container_of(tt_common_entry, 235756303d34SSven Eckelmann struct batadv_tt_global_entry, 235848100bacSAntonio Quartulli common); 235948100bacSAntonio Quartulli 2360a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 2361a73105b8SAntonio Quartulli } 2362a73105b8SAntonio Quartulli 2363335fbe0fSMarek Lindner /** 23647ea7b4a1SAntonio Quartulli * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the 23657ea7b4a1SAntonio Quartulli * specified tt hash 2366335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2367335fbe0fSMarek Lindner * @hash: hash table containing the tt entries 2368335fbe0fSMarek Lindner * @tt_len: expected tvlv tt data buffer length in number of bytes 23697ea7b4a1SAntonio Quartulli * @tvlv_buff: pointer to the buffer to fill with the TT data 2370335fbe0fSMarek Lindner * @valid_cb: function to filter tt change entries 2371335fbe0fSMarek Lindner * @cb_data: data passed to the filter function as argument 2372335fbe0fSMarek Lindner */ 23737ea7b4a1SAntonio Quartulli static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, 23747ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash, 23756b5e971aSSven Eckelmann void *tvlv_buff, u16 tt_len, 2376a513088dSSven Eckelmann int (*valid_cb)(const void *, const void *), 2377a73105b8SAntonio Quartulli void *cb_data) 2378a73105b8SAntonio Quartulli { 237956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 2380335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 2381a73105b8SAntonio Quartulli struct hlist_head *head; 23826b5e971aSSven Eckelmann u16 tt_tot, tt_num_entries = 0; 23836b5e971aSSven Eckelmann u32 i; 2384a73105b8SAntonio Quartulli 2385298e6e68SAntonio Quartulli tt_tot = batadv_tt_entries(tt_len); 23867ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; 2387a73105b8SAntonio Quartulli 2388a73105b8SAntonio Quartulli rcu_read_lock(); 2389a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2390a73105b8SAntonio Quartulli head = &hash->table[i]; 2391a73105b8SAntonio Quartulli 2392b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 2393a73105b8SAntonio Quartulli head, hash_entry) { 2394335fbe0fSMarek Lindner if (tt_tot == tt_num_entries) 2395a73105b8SAntonio Quartulli break; 2396a73105b8SAntonio Quartulli 239748100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 2398a73105b8SAntonio Quartulli continue; 2399a73105b8SAntonio Quartulli 24008fdd0153SAntonio Quartulli ether_addr_copy(tt_change->addr, tt_common_entry->addr); 240127b37ebfSAntonio Quartulli tt_change->flags = tt_common_entry->flags; 2402c018ad3dSAntonio Quartulli tt_change->vid = htons(tt_common_entry->vid); 2403ca663046SAntonio Quartulli memset(tt_change->reserved, 0, 2404ca663046SAntonio Quartulli sizeof(tt_change->reserved)); 2405a73105b8SAntonio Quartulli 2406335fbe0fSMarek Lindner tt_num_entries++; 2407a73105b8SAntonio Quartulli tt_change++; 2408a73105b8SAntonio Quartulli } 2409a73105b8SAntonio Quartulli } 2410a73105b8SAntonio Quartulli rcu_read_unlock(); 24117ea7b4a1SAntonio Quartulli } 2412a73105b8SAntonio Quartulli 24137ea7b4a1SAntonio Quartulli /** 24147ea7b4a1SAntonio Quartulli * batadv_tt_global_check_crc - check if all the CRCs are correct 24157ea7b4a1SAntonio Quartulli * @orig_node: originator for which the CRCs have to be checked 24167ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN entry 24177ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 24187ea7b4a1SAntonio Quartulli * 241962fe710fSSven Eckelmann * Return: true if all the received CRCs match the locally stored ones, false 24207ea7b4a1SAntonio Quartulli * otherwise 24217ea7b4a1SAntonio Quartulli */ 24227ea7b4a1SAntonio Quartulli static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, 24237ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 24246b5e971aSSven Eckelmann u16 num_vlan) 24257ea7b4a1SAntonio Quartulli { 24267ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; 24277ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 2428c169c59dSSimon Wunderlich int i, orig_num_vlan; 24296b5e971aSSven Eckelmann u32 crc; 24307ea7b4a1SAntonio Quartulli 24317ea7b4a1SAntonio Quartulli /* check if each received CRC matches the locally stored one */ 24327ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 24337ea7b4a1SAntonio Quartulli tt_vlan_tmp = tt_vlan + i; 24347ea7b4a1SAntonio Quartulli 24357ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't check 24367ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 24377ea7b4a1SAntonio Quartulli */ 24387ea7b4a1SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, 2439cfd4f757SAntonio Quartulli orig_node->orig, 2440cfd4f757SAntonio Quartulli ntohs(tt_vlan_tmp->vid))) 24417ea7b4a1SAntonio Quartulli continue; 24427ea7b4a1SAntonio Quartulli 24437ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_node, 24447ea7b4a1SAntonio Quartulli ntohs(tt_vlan_tmp->vid)); 24457ea7b4a1SAntonio Quartulli if (!vlan) 24467ea7b4a1SAntonio Quartulli return false; 24477ea7b4a1SAntonio Quartulli 244891c2b1a9SAntonio Quartulli crc = vlan->tt.crc; 244991c2b1a9SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 245091c2b1a9SAntonio Quartulli 245191c2b1a9SAntonio Quartulli if (crc != ntohl(tt_vlan_tmp->crc)) 24527ea7b4a1SAntonio Quartulli return false; 24537ea7b4a1SAntonio Quartulli } 24547ea7b4a1SAntonio Quartulli 2455c169c59dSSimon Wunderlich /* check if any excess VLANs exist locally for the originator 2456c169c59dSSimon Wunderlich * which are not mentioned in the TVLV from the originator. 2457c169c59dSSimon Wunderlich */ 2458c169c59dSSimon Wunderlich rcu_read_lock(); 2459c169c59dSSimon Wunderlich orig_num_vlan = 0; 2460c169c59dSSimon Wunderlich hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) 2461c169c59dSSimon Wunderlich orig_num_vlan++; 2462c169c59dSSimon Wunderlich rcu_read_unlock(); 2463c169c59dSSimon Wunderlich 2464c169c59dSSimon Wunderlich if (orig_num_vlan > num_vlan) 2465c169c59dSSimon Wunderlich return false; 2466c169c59dSSimon Wunderlich 24677ea7b4a1SAntonio Quartulli return true; 24687ea7b4a1SAntonio Quartulli } 24697ea7b4a1SAntonio Quartulli 24707ea7b4a1SAntonio Quartulli /** 24717ea7b4a1SAntonio Quartulli * batadv_tt_local_update_crc - update all the local CRCs 24727ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 24737ea7b4a1SAntonio Quartulli */ 24747ea7b4a1SAntonio Quartulli static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) 24757ea7b4a1SAntonio Quartulli { 24767ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 24777ea7b4a1SAntonio Quartulli 24787ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 24797ea7b4a1SAntonio Quartulli rcu_read_lock(); 24807ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 24817ea7b4a1SAntonio Quartulli vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); 24827ea7b4a1SAntonio Quartulli } 24837ea7b4a1SAntonio Quartulli rcu_read_unlock(); 24847ea7b4a1SAntonio Quartulli } 24857ea7b4a1SAntonio Quartulli 24867ea7b4a1SAntonio Quartulli /** 24877ea7b4a1SAntonio Quartulli * batadv_tt_global_update_crc - update all the global CRCs for this orig_node 24887ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 24897ea7b4a1SAntonio Quartulli * @orig_node: the orig_node for which the CRCs have to be updated 24907ea7b4a1SAntonio Quartulli */ 24917ea7b4a1SAntonio Quartulli static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, 24927ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node) 24937ea7b4a1SAntonio Quartulli { 24947ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 24956b5e971aSSven Eckelmann u32 crc; 24967ea7b4a1SAntonio Quartulli 24977ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 24987ea7b4a1SAntonio Quartulli rcu_read_lock(); 2499d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 25007ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't compute 25017ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 25027ea7b4a1SAntonio Quartulli */ 2503cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, 2504cfd4f757SAntonio Quartulli vlan->vid)) 25057ea7b4a1SAntonio Quartulli continue; 25067ea7b4a1SAntonio Quartulli 25077ea7b4a1SAntonio Quartulli crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); 25087ea7b4a1SAntonio Quartulli vlan->tt.crc = crc; 25097ea7b4a1SAntonio Quartulli } 25107ea7b4a1SAntonio Quartulli rcu_read_unlock(); 2511a73105b8SAntonio Quartulli } 2512a73105b8SAntonio Quartulli 2513ced72933SAntonio Quartulli /** 2514ced72933SAntonio Quartulli * batadv_send_tt_request - send a TT Request message to a given node 2515ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2516ced72933SAntonio Quartulli * @dst_orig_node: the destination of the message 2517ced72933SAntonio Quartulli * @ttvn: the version number that the source of the message is looking for 25187ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN object to request 25197ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 2520ced72933SAntonio Quartulli * @full_table: ask for the entire translation table if true, while only for the 2521ced72933SAntonio Quartulli * last TT diff otherwise 2522ced72933SAntonio Quartulli */ 252356303d34SSven Eckelmann static int batadv_send_tt_request(struct batadv_priv *bat_priv, 252456303d34SSven Eckelmann struct batadv_orig_node *dst_orig_node, 25256b5e971aSSven Eckelmann u8 ttvn, 25267ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 25276b5e971aSSven Eckelmann u16 num_vlan, bool full_table) 2528a73105b8SAntonio Quartulli { 2529335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 253056303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node = NULL; 25317ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_req; 25327ea7b4a1SAntonio Quartulli struct batadv_hard_iface *primary_if; 2533335fbe0fSMarek Lindner bool ret = false; 25347ea7b4a1SAntonio Quartulli int i, size; 2535a73105b8SAntonio Quartulli 2536e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2537a73105b8SAntonio Quartulli if (!primary_if) 2538a73105b8SAntonio Quartulli goto out; 2539a73105b8SAntonio Quartulli 2540a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 25419cfc7bd6SSven Eckelmann * reply from the same orig_node yet 25429cfc7bd6SSven Eckelmann */ 2543383b8636SMarek Lindner tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node); 2544a73105b8SAntonio Quartulli if (!tt_req_node) 2545a73105b8SAntonio Quartulli goto out; 2546a73105b8SAntonio Quartulli 25477ea7b4a1SAntonio Quartulli size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; 25487ea7b4a1SAntonio Quartulli tvlv_tt_data = kzalloc(size, GFP_ATOMIC); 2549335fbe0fSMarek Lindner if (!tvlv_tt_data) 2550a73105b8SAntonio Quartulli goto out; 2551a73105b8SAntonio Quartulli 2552335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_REQUEST; 2553335fbe0fSMarek Lindner tvlv_tt_data->ttvn = ttvn; 25547ea7b4a1SAntonio Quartulli tvlv_tt_data->num_vlan = htons(num_vlan); 25557ea7b4a1SAntonio Quartulli 25567ea7b4a1SAntonio Quartulli /* send all the CRCs within the request. This is needed by intermediate 25577ea7b4a1SAntonio Quartulli * nodes to ensure they have the correct table before replying 25587ea7b4a1SAntonio Quartulli */ 25597ea7b4a1SAntonio Quartulli tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); 25607ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 25617ea7b4a1SAntonio Quartulli tt_vlan_req->vid = tt_vlan->vid; 25627ea7b4a1SAntonio Quartulli tt_vlan_req->crc = tt_vlan->crc; 25637ea7b4a1SAntonio Quartulli 25647ea7b4a1SAntonio Quartulli tt_vlan_req++; 25657ea7b4a1SAntonio Quartulli tt_vlan++; 25667ea7b4a1SAntonio Quartulli } 2567a73105b8SAntonio Quartulli 2568a73105b8SAntonio Quartulli if (full_table) 2569335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2570a73105b8SAntonio Quartulli 2571bb351ba0SMartin Hundebøll batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", 2572335fbe0fSMarek Lindner dst_orig_node->orig, full_table ? 'F' : '.'); 2573a73105b8SAntonio Quartulli 2574d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); 2575335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 2576335fbe0fSMarek Lindner dst_orig_node->orig, BATADV_TVLV_TT, 1, 25777ea7b4a1SAntonio Quartulli tvlv_tt_data, size); 2578335fbe0fSMarek Lindner ret = true; 2579a73105b8SAntonio Quartulli 2580a73105b8SAntonio Quartulli out: 2581a73105b8SAntonio Quartulli if (primary_if) 2582e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 2583a73105b8SAntonio Quartulli if (ret && tt_req_node) { 2584807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 25857c26a53bSMarek Lindner /* hlist_del_init() verifies tt_req_node still is in the list */ 25867c26a53bSMarek Lindner hlist_del_init(&tt_req_node->list); 2587807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2588a73105b8SAntonio Quartulli kfree(tt_req_node); 2589a73105b8SAntonio Quartulli } 2590335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2591a73105b8SAntonio Quartulli return ret; 2592a73105b8SAntonio Quartulli } 2593a73105b8SAntonio Quartulli 2594335fbe0fSMarek Lindner /** 2595335fbe0fSMarek Lindner * batadv_send_other_tt_response - send reply to tt request concerning another 2596335fbe0fSMarek Lindner * node's translation table 2597335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2598335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2599335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2600335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 2601335fbe0fSMarek Lindner * 260262fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2603335fbe0fSMarek Lindner */ 2604335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, 2605335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 26066b5e971aSSven Eckelmann u8 *req_src, u8 *req_dst) 2607a73105b8SAntonio Quartulli { 2608170173bfSSven Eckelmann struct batadv_orig_node *req_dst_orig_node; 260956303d34SSven Eckelmann struct batadv_orig_node *res_dst_orig_node = NULL; 26107ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 2611335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 26127ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 2613335fbe0fSMarek Lindner bool ret = false, full_table; 26146b5e971aSSven Eckelmann u8 orig_ttvn, req_ttvn; 26156b5e971aSSven Eckelmann u16 tvlv_len; 26166b5e971aSSven Eckelmann s32 tt_len; 2617a73105b8SAntonio Quartulli 261839c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 261986ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 2620335fbe0fSMarek Lindner req_src, tt_data->ttvn, req_dst, 2621a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 2622a73105b8SAntonio Quartulli 2623a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 2624335fbe0fSMarek Lindner req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); 2625a73105b8SAntonio Quartulli if (!req_dst_orig_node) 2626a73105b8SAntonio Quartulli goto out; 2627a73105b8SAntonio Quartulli 2628335fbe0fSMarek Lindner res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); 2629a73105b8SAntonio Quartulli if (!res_dst_orig_node) 2630a73105b8SAntonio Quartulli goto out; 2631a73105b8SAntonio Quartulli 26326b5e971aSSven Eckelmann orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn); 2633335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 2634a73105b8SAntonio Quartulli 26357ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 2636335fbe0fSMarek Lindner /* this node doesn't have the requested data */ 2637a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 26387ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, 26397ea7b4a1SAntonio Quartulli ntohs(tt_data->num_vlan))) 2640a73105b8SAntonio Quartulli goto out; 2641a73105b8SAntonio Quartulli 2642015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 2643335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || 2644a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 2645a73105b8SAntonio Quartulli full_table = true; 2646a73105b8SAntonio Quartulli else 2647a73105b8SAntonio Quartulli full_table = false; 2648a73105b8SAntonio Quartulli 2649335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 2650335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 26519cfc7bd6SSven Eckelmann */ 2652a73105b8SAntonio Quartulli if (!full_table) { 2653a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 2654a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 2655a73105b8SAntonio Quartulli 26567ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 26577ea7b4a1SAntonio Quartulli &tvlv_tt_data, 26587ea7b4a1SAntonio Quartulli &tt_change, 26597ea7b4a1SAntonio Quartulli &tt_len); 26607ea7b4a1SAntonio Quartulli if (!tt_len) 2661a73105b8SAntonio Quartulli goto unlock; 2662a73105b8SAntonio Quartulli 2663a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 26647ea7b4a1SAntonio Quartulli memcpy(tt_change, req_dst_orig_node->tt_buff, 2665a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 2666a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 2667a73105b8SAntonio Quartulli } else { 26687ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 26697ea7b4a1SAntonio Quartulli * in the initial part 26707ea7b4a1SAntonio Quartulli */ 26717ea7b4a1SAntonio Quartulli tt_len = -1; 26727ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 26737ea7b4a1SAntonio Quartulli &tvlv_tt_data, 26747ea7b4a1SAntonio Quartulli &tt_change, 26757ea7b4a1SAntonio Quartulli &tt_len); 26767ea7b4a1SAntonio Quartulli if (!tt_len) 26777ea7b4a1SAntonio Quartulli goto out; 2678a73105b8SAntonio Quartulli 26797ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 26807ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, 26817ea7b4a1SAntonio Quartulli tt_change, tt_len, 2682a513088dSSven Eckelmann batadv_tt_global_valid, 2683a73105b8SAntonio Quartulli req_dst_orig_node); 2684a73105b8SAntonio Quartulli } 2685a73105b8SAntonio Quartulli 2686a19d3d85SMarek Lindner /* Don't send the response, if larger than fragmented packet. */ 2687a19d3d85SMarek Lindner tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len; 2688a19d3d85SMarek Lindner if (tt_len > atomic_read(&bat_priv->packet_size_max)) { 2689a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, bat_priv->soft_iface, 2690a19d3d85SMarek Lindner "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n", 2691a19d3d85SMarek Lindner res_dst_orig_node->orig); 2692a19d3d85SMarek Lindner goto out; 2693a19d3d85SMarek Lindner } 2694a19d3d85SMarek Lindner 2695335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2696335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 2697a73105b8SAntonio Quartulli 2698a73105b8SAntonio Quartulli if (full_table) 2699335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2700a73105b8SAntonio Quartulli 270139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2702335fbe0fSMarek Lindner "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n", 2703335fbe0fSMarek Lindner res_dst_orig_node->orig, req_dst_orig_node->orig, 2704335fbe0fSMarek Lindner full_table ? 'F' : '.', req_ttvn); 2705a73105b8SAntonio Quartulli 2706d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 2707f8214865SMartin Hundebøll 2708335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, 27097ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 27107ea7b4a1SAntonio Quartulli tvlv_len); 2711e91ecfc6SMartin Hundebøll 2712335fbe0fSMarek Lindner ret = true; 2713a73105b8SAntonio Quartulli goto out; 2714a73105b8SAntonio Quartulli 2715a73105b8SAntonio Quartulli unlock: 2716a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 2717a73105b8SAntonio Quartulli 2718a73105b8SAntonio Quartulli out: 2719a73105b8SAntonio Quartulli if (res_dst_orig_node) 27207d211efcSSven Eckelmann batadv_orig_node_free_ref(res_dst_orig_node); 2721a73105b8SAntonio Quartulli if (req_dst_orig_node) 27227d211efcSSven Eckelmann batadv_orig_node_free_ref(req_dst_orig_node); 2723335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2724a73105b8SAntonio Quartulli return ret; 2725a73105b8SAntonio Quartulli } 272696412690SSven Eckelmann 2727335fbe0fSMarek Lindner /** 2728335fbe0fSMarek Lindner * batadv_send_my_tt_response - send reply to tt request concerning this node's 2729335fbe0fSMarek Lindner * translation table 2730335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2731335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2732335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2733335fbe0fSMarek Lindner * 273462fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2735335fbe0fSMarek Lindner */ 2736335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, 2737335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 27386b5e971aSSven Eckelmann u8 *req_src) 2739a73105b8SAntonio Quartulli { 2740335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 274156303d34SSven Eckelmann struct batadv_hard_iface *primary_if = NULL; 27427ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 27437ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node; 27446b5e971aSSven Eckelmann u8 my_ttvn, req_ttvn; 27456b5e971aSSven Eckelmann u16 tvlv_len; 2746a73105b8SAntonio Quartulli bool full_table; 27476b5e971aSSven Eckelmann s32 tt_len; 2748a73105b8SAntonio Quartulli 274939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 275086ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 2751335fbe0fSMarek Lindner req_src, tt_data->ttvn, 2752a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 2753a73105b8SAntonio Quartulli 2754a70a9aa9SAntonio Quartulli spin_lock_bh(&bat_priv->tt.commit_lock); 2755a73105b8SAntonio Quartulli 27566b5e971aSSven Eckelmann my_ttvn = (u8)atomic_read(&bat_priv->tt.vn); 2757335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 2758a73105b8SAntonio Quartulli 2759335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, req_src); 2760a73105b8SAntonio Quartulli if (!orig_node) 2761a73105b8SAntonio Quartulli goto out; 2762a73105b8SAntonio Quartulli 2763e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2764a73105b8SAntonio Quartulli if (!primary_if) 2765a73105b8SAntonio Quartulli goto out; 2766a73105b8SAntonio Quartulli 2767a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 27689cfc7bd6SSven Eckelmann * is too big send the whole local translation table 27699cfc7bd6SSven Eckelmann */ 2770335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || 2771807736f6SSven Eckelmann !bat_priv->tt.last_changeset) 2772a73105b8SAntonio Quartulli full_table = true; 2773a73105b8SAntonio Quartulli else 2774a73105b8SAntonio Quartulli full_table = false; 2775a73105b8SAntonio Quartulli 2776335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 2777335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 27789cfc7bd6SSven Eckelmann */ 2779a73105b8SAntonio Quartulli if (!full_table) { 2780807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 2781a73105b8SAntonio Quartulli 27827ea7b4a1SAntonio Quartulli tt_len = bat_priv->tt.last_changeset_len; 27837ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 27847ea7b4a1SAntonio Quartulli &tvlv_tt_data, 27857ea7b4a1SAntonio Quartulli &tt_change, 27867ea7b4a1SAntonio Quartulli &tt_len); 27877ea7b4a1SAntonio Quartulli if (!tt_len) 2788a73105b8SAntonio Quartulli goto unlock; 2789a73105b8SAntonio Quartulli 2790335fbe0fSMarek Lindner /* Copy the last orig_node's OGM buffer */ 27917ea7b4a1SAntonio Quartulli memcpy(tt_change, bat_priv->tt.last_changeset, 2792807736f6SSven Eckelmann bat_priv->tt.last_changeset_len); 2793807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2794a73105b8SAntonio Quartulli } else { 27956b5e971aSSven Eckelmann req_ttvn = (u8)atomic_read(&bat_priv->tt.vn); 2796a73105b8SAntonio Quartulli 27977ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 27987ea7b4a1SAntonio Quartulli * in the initial part 27997ea7b4a1SAntonio Quartulli */ 28007ea7b4a1SAntonio Quartulli tt_len = -1; 28017ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 28027ea7b4a1SAntonio Quartulli &tvlv_tt_data, 28037ea7b4a1SAntonio Quartulli &tt_change, 28047ea7b4a1SAntonio Quartulli &tt_len); 28057ea7b4a1SAntonio Quartulli if (!tt_len) 2806a73105b8SAntonio Quartulli goto out; 28077ea7b4a1SAntonio Quartulli 28087ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 28097ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, 28107ea7b4a1SAntonio Quartulli tt_change, tt_len, 28117ea7b4a1SAntonio Quartulli batadv_tt_local_valid, NULL); 2812a73105b8SAntonio Quartulli } 2813a73105b8SAntonio Quartulli 2814335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2815335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 2816a73105b8SAntonio Quartulli 2817a73105b8SAntonio Quartulli if (full_table) 2818335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2819a73105b8SAntonio Quartulli 282039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2821335fbe0fSMarek Lindner "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n", 2822335fbe0fSMarek Lindner orig_node->orig, full_table ? 'F' : '.', req_ttvn); 2823a73105b8SAntonio Quartulli 2824d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 2825f8214865SMartin Hundebøll 2826335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 28277ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 28287ea7b4a1SAntonio Quartulli tvlv_len); 2829335fbe0fSMarek Lindner 2830a73105b8SAntonio Quartulli goto out; 2831a73105b8SAntonio Quartulli 2832a73105b8SAntonio Quartulli unlock: 2833807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2834a73105b8SAntonio Quartulli out: 2835a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 2836a73105b8SAntonio Quartulli if (orig_node) 28377d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2838a73105b8SAntonio Quartulli if (primary_if) 2839e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 2840335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2841335fbe0fSMarek Lindner /* The packet was for this host, so it doesn't need to be re-routed */ 2842a73105b8SAntonio Quartulli return true; 2843a73105b8SAntonio Quartulli } 2844a73105b8SAntonio Quartulli 2845335fbe0fSMarek Lindner /** 2846335fbe0fSMarek Lindner * batadv_send_tt_response - send reply to tt request 2847335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2848335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2849335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2850335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 2851335fbe0fSMarek Lindner * 285262fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2853335fbe0fSMarek Lindner */ 2854335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv, 2855335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 28566b5e971aSSven Eckelmann u8 *req_src, u8 *req_dst) 2857a73105b8SAntonio Quartulli { 2858cfd4f757SAntonio Quartulli if (batadv_is_my_mac(bat_priv, req_dst)) 2859335fbe0fSMarek Lindner return batadv_send_my_tt_response(bat_priv, tt_data, req_src); 286024820df1SAntonio Quartulli return batadv_send_other_tt_response(bat_priv, tt_data, req_src, 286124820df1SAntonio Quartulli req_dst); 2862a73105b8SAntonio Quartulli } 2863a73105b8SAntonio Quartulli 286456303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, 286556303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2866335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change, 28676b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn) 2868a73105b8SAntonio Quartulli { 2869a73105b8SAntonio Quartulli int i; 2870a513088dSSven Eckelmann int roams; 2871a73105b8SAntonio Quartulli 2872a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 2873acd34afaSSven Eckelmann if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { 2874acd34afaSSven Eckelmann roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; 2875a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 2876a73105b8SAntonio Quartulli (tt_change + i)->addr, 2877c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 2878cc47f66eSAntonio Quartulli "tt removed by changes", 2879a513088dSSven Eckelmann roams); 288008c36d3eSSven Eckelmann } else { 288108c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 2882d4f44692SAntonio Quartulli (tt_change + i)->addr, 2883c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 2884d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 2885a73105b8SAntonio Quartulli /* In case of problem while storing a 2886a73105b8SAntonio Quartulli * global_entry, we stop the updating 2887a73105b8SAntonio Quartulli * procedure without committing the 2888a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 2889a73105b8SAntonio Quartulli * corrupted data on tt_request 2890a73105b8SAntonio Quartulli */ 2891a73105b8SAntonio Quartulli return; 2892a73105b8SAntonio Quartulli } 289308c36d3eSSven Eckelmann } 2894ac4eebd4SLinus Lüssing set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); 2895a73105b8SAntonio Quartulli } 2896a73105b8SAntonio Quartulli 289756303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, 28987ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 28996b5e971aSSven Eckelmann u8 ttvn, u8 *resp_src, 29006b5e971aSSven Eckelmann u16 num_entries) 2901a73105b8SAntonio Quartulli { 2902170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 2903a73105b8SAntonio Quartulli 2904335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 2905a73105b8SAntonio Quartulli if (!orig_node) 2906a73105b8SAntonio Quartulli goto out; 2907a73105b8SAntonio Quartulli 2908a73105b8SAntonio Quartulli /* Purge the old table first.. */ 290995fb130dSAntonio Quartulli batadv_tt_global_del_orig(bat_priv, orig_node, -1, 291095fb130dSAntonio Quartulli "Received full table"); 2911a73105b8SAntonio Quartulli 29127ea7b4a1SAntonio Quartulli _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, 29137ea7b4a1SAntonio Quartulli ttvn); 2914a73105b8SAntonio Quartulli 2915a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2916a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2917a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2918a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 2919a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2920a73105b8SAntonio Quartulli 29217ea7b4a1SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2922a73105b8SAntonio Quartulli 2923a73105b8SAntonio Quartulli out: 2924a73105b8SAntonio Quartulli if (orig_node) 29257d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2926a73105b8SAntonio Quartulli } 2927a73105b8SAntonio Quartulli 292856303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv, 292956303d34SSven Eckelmann struct batadv_orig_node *orig_node, 29306b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn, 2931335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change) 2932a73105b8SAntonio Quartulli { 2933a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 2934a513088dSSven Eckelmann tt_num_changes, ttvn); 2935a73105b8SAntonio Quartulli 2936e8cf234aSAntonio Quartulli batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, 2937e8cf234aSAntonio Quartulli batadv_tt_len(tt_num_changes)); 2938a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2939a73105b8SAntonio Quartulli } 2940a73105b8SAntonio Quartulli 2941c018ad3dSAntonio Quartulli /** 2942c018ad3dSAntonio Quartulli * batadv_is_my_client - check if a client is served by the local node 2943c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 29443f68785eSAntonio Quartulli * @addr: the mac address of the client to check 2945c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2946c018ad3dSAntonio Quartulli * 294762fe710fSSven Eckelmann * Return: true if the client is served by this node, false otherwise. 2948c018ad3dSAntonio Quartulli */ 29496b5e971aSSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr, 2950c018ad3dSAntonio Quartulli unsigned short vid) 2951a73105b8SAntonio Quartulli { 2952170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 29537683fdc1SAntonio Quartulli bool ret = false; 2954a73105b8SAntonio Quartulli 2955c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 29567683fdc1SAntonio Quartulli if (!tt_local_entry) 29577683fdc1SAntonio Quartulli goto out; 2958058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 29599cfc7bd6SSven Eckelmann * consistency purpose) 29609cfc7bd6SSven Eckelmann */ 29617c1fd91dSAntonio Quartulli if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) || 29627c1fd91dSAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM)) 2963058d0e26SAntonio Quartulli goto out; 29647683fdc1SAntonio Quartulli ret = true; 29657683fdc1SAntonio Quartulli out: 2966a73105b8SAntonio Quartulli if (tt_local_entry) 2967a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 29687683fdc1SAntonio Quartulli return ret; 2969a73105b8SAntonio Quartulli } 2970a73105b8SAntonio Quartulli 2971335fbe0fSMarek Lindner /** 2972335fbe0fSMarek Lindner * batadv_handle_tt_response - process incoming tt reply 2973335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2974335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2975335fbe0fSMarek Lindner * @resp_src: mac address of tt reply sender 2976335fbe0fSMarek Lindner * @num_entries: number of tt change entries appended to the tt data 2977335fbe0fSMarek Lindner */ 2978335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv, 2979335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 29806b5e971aSSven Eckelmann u8 *resp_src, u16 num_entries) 2981a73105b8SAntonio Quartulli { 29827c26a53bSMarek Lindner struct batadv_tt_req_node *node; 29837c26a53bSMarek Lindner struct hlist_node *safe; 298456303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 2985335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 29866b5e971aSSven Eckelmann u8 *tvlv_ptr = (u8 *)tt_data; 29876b5e971aSSven Eckelmann u16 change_offset; 2988a73105b8SAntonio Quartulli 298939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 299086ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 2991335fbe0fSMarek Lindner resp_src, tt_data->ttvn, num_entries, 2992a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 2993a73105b8SAntonio Quartulli 2994335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 2995a73105b8SAntonio Quartulli if (!orig_node) 2996a73105b8SAntonio Quartulli goto out; 2997a73105b8SAntonio Quartulli 2998a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 2999a70a9aa9SAntonio Quartulli 30007ea7b4a1SAntonio Quartulli change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); 30017ea7b4a1SAntonio Quartulli change_offset *= ntohs(tt_data->num_vlan); 30027ea7b4a1SAntonio Quartulli change_offset += sizeof(*tt_data); 30037ea7b4a1SAntonio Quartulli tvlv_ptr += change_offset; 30047ea7b4a1SAntonio Quartulli 30057ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; 3006335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) { 30077ea7b4a1SAntonio Quartulli batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, 30087ea7b4a1SAntonio Quartulli resp_src, num_entries); 300996412690SSven Eckelmann } else { 3010335fbe0fSMarek Lindner batadv_tt_update_changes(bat_priv, orig_node, num_entries, 3011335fbe0fSMarek Lindner tt_data->ttvn, tt_change); 301296412690SSven Eckelmann } 3013a73105b8SAntonio Quartulli 3014a70a9aa9SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 30157ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3016a70a9aa9SAntonio Quartulli 3017a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3018a70a9aa9SAntonio Quartulli 3019a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 3020807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 30217c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 3022335fbe0fSMarek Lindner if (!batadv_compare_eth(node->addr, resp_src)) 3023a73105b8SAntonio Quartulli continue; 30247c26a53bSMarek Lindner hlist_del_init(&node->list); 3025a73105b8SAntonio Quartulli kfree(node); 3026a73105b8SAntonio Quartulli } 30277ea7b4a1SAntonio Quartulli 3028807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 3029a73105b8SAntonio Quartulli out: 3030a73105b8SAntonio Quartulli if (orig_node) 30317d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 3032a73105b8SAntonio Quartulli } 3033a73105b8SAntonio Quartulli 303456303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) 3035a73105b8SAntonio Quartulli { 303656303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 3037a73105b8SAntonio Quartulli 3038807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3039a73105b8SAntonio Quartulli 3040807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 3041cc47f66eSAntonio Quartulli list_del(&node->list); 3042cc47f66eSAntonio Quartulli kfree(node); 3043cc47f66eSAntonio Quartulli } 3044cc47f66eSAntonio Quartulli 3045807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3046cc47f66eSAntonio Quartulli } 3047cc47f66eSAntonio Quartulli 304856303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) 3049cc47f66eSAntonio Quartulli { 305056303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 3051cc47f66eSAntonio Quartulli 3052807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3053807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 305442d0b044SSven Eckelmann if (!batadv_has_timed_out(node->first_time, 305542d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 3056cc47f66eSAntonio Quartulli continue; 3057cc47f66eSAntonio Quartulli 3058cc47f66eSAntonio Quartulli list_del(&node->list); 3059cc47f66eSAntonio Quartulli kfree(node); 3060cc47f66eSAntonio Quartulli } 3061807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3062cc47f66eSAntonio Quartulli } 3063cc47f66eSAntonio Quartulli 306462fe710fSSven Eckelmann /** 306562fe710fSSven Eckelmann * batadv_tt_check_roam_count 306662fe710fSSven Eckelmann * 306762fe710fSSven Eckelmann * This function checks whether the client already reached the 3068cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 3069cc47f66eSAntonio Quartulli * will not be sent. 3070cc47f66eSAntonio Quartulli * 307162fe710fSSven Eckelmann * Return: true if the ROAMING_ADV can be sent, false otherwise 30729cfc7bd6SSven Eckelmann */ 30736b5e971aSSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client) 3074cc47f66eSAntonio Quartulli { 307556303d34SSven Eckelmann struct batadv_tt_roam_node *tt_roam_node; 3076cc47f66eSAntonio Quartulli bool ret = false; 3077cc47f66eSAntonio Quartulli 3078807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3079cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 30809cfc7bd6SSven Eckelmann * reply from the same orig_node yet 30819cfc7bd6SSven Eckelmann */ 3082807736f6SSven Eckelmann list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) { 30831eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 3084cc47f66eSAntonio Quartulli continue; 3085cc47f66eSAntonio Quartulli 30861eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 308742d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 3088cc47f66eSAntonio Quartulli continue; 3089cc47f66eSAntonio Quartulli 30903e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 3091cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 3092cc47f66eSAntonio Quartulli goto unlock; 3093cc47f66eSAntonio Quartulli ret = true; 3094cc47f66eSAntonio Quartulli break; 3095cc47f66eSAntonio Quartulli } 3096cc47f66eSAntonio Quartulli 3097cc47f66eSAntonio Quartulli if (!ret) { 3098cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 3099cc47f66eSAntonio Quartulli if (!tt_roam_node) 3100cc47f66eSAntonio Quartulli goto unlock; 3101cc47f66eSAntonio Quartulli 3102cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 310342d0b044SSven Eckelmann atomic_set(&tt_roam_node->counter, 310442d0b044SSven Eckelmann BATADV_ROAMING_MAX_COUNT - 1); 31058fdd0153SAntonio Quartulli ether_addr_copy(tt_roam_node->addr, client); 3106cc47f66eSAntonio Quartulli 3107807736f6SSven Eckelmann list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); 3108cc47f66eSAntonio Quartulli ret = true; 3109cc47f66eSAntonio Quartulli } 3110cc47f66eSAntonio Quartulli 3111cc47f66eSAntonio Quartulli unlock: 3112807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3113cc47f66eSAntonio Quartulli return ret; 3114cc47f66eSAntonio Quartulli } 3115cc47f66eSAntonio Quartulli 3116c018ad3dSAntonio Quartulli /** 3117c018ad3dSAntonio Quartulli * batadv_send_roam_adv - send a roaming advertisement message 3118c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3119c018ad3dSAntonio Quartulli * @client: mac address of the roaming client 3120c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3121c018ad3dSAntonio Quartulli * @orig_node: message destination 3122c018ad3dSAntonio Quartulli * 3123c018ad3dSAntonio Quartulli * Send a ROAMING_ADV message to the node which was previously serving this 3124c018ad3dSAntonio Quartulli * client. This is done to inform the node that from now on all traffic destined 3125c018ad3dSAntonio Quartulli * for this particular roamed client has to be forwarded to the sender of the 3126c018ad3dSAntonio Quartulli * roaming message. 3127c018ad3dSAntonio Quartulli */ 31286b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, 3129c018ad3dSAntonio Quartulli unsigned short vid, 313056303d34SSven Eckelmann struct batadv_orig_node *orig_node) 3131cc47f66eSAntonio Quartulli { 313256303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 3133122edaa0SMarek Lindner struct batadv_tvlv_roam_adv tvlv_roam; 3134122edaa0SMarek Lindner 3135122edaa0SMarek Lindner primary_if = batadv_primary_if_get_selected(bat_priv); 3136122edaa0SMarek Lindner if (!primary_if) 3137122edaa0SMarek Lindner goto out; 3138cc47f66eSAntonio Quartulli 3139cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 31409cfc7bd6SSven Eckelmann * already roamed to us too many times 31419cfc7bd6SSven Eckelmann */ 3142a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 3143cc47f66eSAntonio Quartulli goto out; 3144cc47f66eSAntonio Quartulli 314539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 314616052789SAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n", 314716052789SAntonio Quartulli orig_node->orig, client, BATADV_PRINT_VID(vid)); 3148cc47f66eSAntonio Quartulli 3149d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); 3150f8214865SMartin Hundebøll 3151122edaa0SMarek Lindner memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); 3152c018ad3dSAntonio Quartulli tvlv_roam.vid = htons(vid); 3153122edaa0SMarek Lindner 3154122edaa0SMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 3155122edaa0SMarek Lindner orig_node->orig, BATADV_TVLV_ROAM, 1, 3156122edaa0SMarek Lindner &tvlv_roam, sizeof(tvlv_roam)); 3157cc47f66eSAntonio Quartulli 3158cc47f66eSAntonio Quartulli out: 3159122edaa0SMarek Lindner if (primary_if) 3160122edaa0SMarek Lindner batadv_hardif_free_ref(primary_if); 3161a73105b8SAntonio Quartulli } 3162a73105b8SAntonio Quartulli 3163a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 3164a73105b8SAntonio Quartulli { 316556303d34SSven Eckelmann struct delayed_work *delayed_work; 3166807736f6SSven Eckelmann struct batadv_priv_tt *priv_tt; 316756303d34SSven Eckelmann struct batadv_priv *bat_priv; 316856303d34SSven Eckelmann 316956303d34SSven Eckelmann delayed_work = container_of(work, struct delayed_work, work); 3170807736f6SSven Eckelmann priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 3171807736f6SSven Eckelmann bat_priv = container_of(priv_tt, struct batadv_priv, tt); 3172a73105b8SAntonio Quartulli 3173a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT); 317430cfd02bSAntonio Quartulli batadv_tt_global_purge(bat_priv); 3175a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 3176a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 3177a73105b8SAntonio Quartulli 317872414442SAntonio Quartulli queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 317972414442SAntonio Quartulli msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3180a73105b8SAntonio Quartulli } 3181cc47f66eSAntonio Quartulli 318256303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv) 3183cc47f66eSAntonio Quartulli { 3184e1bf0c14SMarek Lindner batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); 3185e1bf0c14SMarek Lindner batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); 3186e1bf0c14SMarek Lindner 3187807736f6SSven Eckelmann cancel_delayed_work_sync(&bat_priv->tt.work); 3188cc47f66eSAntonio Quartulli 3189a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 3190a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 3191a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 3192a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 3193a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 3194cc47f66eSAntonio Quartulli 3195807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 3196cc47f66eSAntonio Quartulli } 3197058d0e26SAntonio Quartulli 31987ea7b4a1SAntonio Quartulli /** 31997ea7b4a1SAntonio Quartulli * batadv_tt_local_set_flags - set or unset the specified flags on the local 32007ea7b4a1SAntonio Quartulli * table and possibly count them in the TT size 32017ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 32027ea7b4a1SAntonio Quartulli * @flags: the flag to switch 32037ea7b4a1SAntonio Quartulli * @enable: whether to set or unset the flag 32047ea7b4a1SAntonio Quartulli * @count: whether to increase the TT size by the number of changed entries 32059cfc7bd6SSven Eckelmann */ 32066b5e971aSSven Eckelmann static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags, 32076b5e971aSSven Eckelmann bool enable, bool count) 3208058d0e26SAntonio Quartulli { 32097ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash = bat_priv->tt.local_hash; 32107ea7b4a1SAntonio Quartulli struct batadv_tt_common_entry *tt_common_entry; 32116b5e971aSSven Eckelmann u16 changed_num = 0; 3212058d0e26SAntonio Quartulli struct hlist_head *head; 32136b5e971aSSven Eckelmann u32 i; 3214058d0e26SAntonio Quartulli 3215058d0e26SAntonio Quartulli if (!hash) 32167ea7b4a1SAntonio Quartulli return; 3217058d0e26SAntonio Quartulli 3218058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3219058d0e26SAntonio Quartulli head = &hash->table[i]; 3220058d0e26SAntonio Quartulli 3221058d0e26SAntonio Quartulli rcu_read_lock(); 3222b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 3223058d0e26SAntonio Quartulli head, hash_entry) { 3224697f2531SAntonio Quartulli if (enable) { 3225697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 3226697f2531SAntonio Quartulli continue; 3227697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 3228697f2531SAntonio Quartulli } else { 322948100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 323031901264SAntonio Quartulli continue; 323148100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 3232697f2531SAntonio Quartulli } 3233697f2531SAntonio Quartulli changed_num++; 32347ea7b4a1SAntonio Quartulli 32357ea7b4a1SAntonio Quartulli if (!count) 32367ea7b4a1SAntonio Quartulli continue; 32377ea7b4a1SAntonio Quartulli 32387ea7b4a1SAntonio Quartulli batadv_tt_local_size_inc(bat_priv, 32397ea7b4a1SAntonio Quartulli tt_common_entry->vid); 3240058d0e26SAntonio Quartulli } 3241058d0e26SAntonio Quartulli rcu_read_unlock(); 3242058d0e26SAntonio Quartulli } 3243058d0e26SAntonio Quartulli } 3244058d0e26SAntonio Quartulli 3245acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ 324656303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) 3247058d0e26SAntonio Quartulli { 3248807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 324956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 325056303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 325135df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 3252b67bfe0dSSasha Levin struct hlist_node *node_tmp; 3253058d0e26SAntonio Quartulli struct hlist_head *head; 3254058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 32556b5e971aSSven Eckelmann u32 i; 3256058d0e26SAntonio Quartulli 3257058d0e26SAntonio Quartulli if (!hash) 3258058d0e26SAntonio Quartulli return; 3259058d0e26SAntonio Quartulli 3260058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3261058d0e26SAntonio Quartulli head = &hash->table[i]; 3262058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 3263058d0e26SAntonio Quartulli 3264058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 3265b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 3266acd34afaSSven Eckelmann hash_entry) { 3267acd34afaSSven Eckelmann if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) 3268058d0e26SAntonio Quartulli continue; 3269058d0e26SAntonio Quartulli 327039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 327116052789SAntonio Quartulli "Deleting local tt entry (%pM, vid: %d): pending\n", 327216052789SAntonio Quartulli tt_common->addr, 327316052789SAntonio Quartulli BATADV_PRINT_VID(tt_common->vid)); 3274058d0e26SAntonio Quartulli 32757ea7b4a1SAntonio Quartulli batadv_tt_local_size_dec(bat_priv, tt_common->vid); 3276b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 327756303d34SSven Eckelmann tt_local = container_of(tt_common, 327856303d34SSven Eckelmann struct batadv_tt_local_entry, 327948100bacSAntonio Quartulli common); 328035df3b29SAntonio Quartulli 328135df3b29SAntonio Quartulli /* decrease the reference held for this vlan */ 328235df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid); 3283354136bcSMarek Lindner if (vlan) { 328435df3b29SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 328535df3b29SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 3286354136bcSMarek Lindner } 328735df3b29SAntonio Quartulli 328856303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 3289058d0e26SAntonio Quartulli } 3290058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 3291058d0e26SAntonio Quartulli } 3292058d0e26SAntonio Quartulli } 3293058d0e26SAntonio Quartulli 3294e1bf0c14SMarek Lindner /** 3295a19d3d85SMarek Lindner * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes 3296a19d3d85SMarek Lindner * which have been queued in the time since the last commit 3297e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3298a19d3d85SMarek Lindner * 3299a19d3d85SMarek Lindner * Caller must hold tt->commit_lock. 3300e1bf0c14SMarek Lindner */ 3301a19d3d85SMarek Lindner static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) 3302058d0e26SAntonio Quartulli { 33035274cd68SSven Eckelmann lockdep_assert_held(&bat_priv->tt.commit_lock); 33045274cd68SSven Eckelmann 3305c5caf4efSLinus Lüssing /* Update multicast addresses in local translation table */ 3306c5caf4efSLinus Lüssing batadv_mcast_mla_update(bat_priv); 3307c5caf4efSLinus Lüssing 3308e1bf0c14SMarek Lindner if (atomic_read(&bat_priv->tt.local_changes) < 1) { 3309e1bf0c14SMarek Lindner if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 3310e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3311a19d3d85SMarek Lindner return; 3312e1bf0c14SMarek Lindner } 3313be9aa4c1SMarek Lindner 33147ea7b4a1SAntonio Quartulli batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); 3315be9aa4c1SMarek Lindner 3316a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 33177ea7b4a1SAntonio Quartulli batadv_tt_local_update_crc(bat_priv); 3318058d0e26SAntonio Quartulli 3319058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 3320807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.vn); 332139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 33221eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 33236b5e971aSSven Eckelmann (u8)atomic_read(&bat_priv->tt.vn)); 3324be9aa4c1SMarek Lindner 3325be9aa4c1SMarek Lindner /* reset the sending counter */ 3326807736f6SSven Eckelmann atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 3327e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3328a19d3d85SMarek Lindner } 3329a70a9aa9SAntonio Quartulli 3330a19d3d85SMarek Lindner /** 3331a19d3d85SMarek Lindner * batadv_tt_local_commit_changes - commit all pending local tt changes which 3332a19d3d85SMarek Lindner * have been queued in the time since the last commit 3333a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3334a19d3d85SMarek Lindner */ 3335a19d3d85SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) 3336a19d3d85SMarek Lindner { 3337a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3338a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3339a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 3340058d0e26SAntonio Quartulli } 334159b699cdSAntonio Quartulli 33426b5e971aSSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, 33436b5e971aSSven Eckelmann unsigned short vid) 334459b699cdSAntonio Quartulli { 334556303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 334656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 3347b8cbd81dSAntonio Quartulli struct batadv_softif_vlan *vlan; 33485870adc6SMarek Lindner bool ret = false; 334959b699cdSAntonio Quartulli 3350b8cbd81dSAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 3351e087f34fSMarkus Elfring if (!vlan) 3352e087f34fSMarkus Elfring return false; 3353e087f34fSMarkus Elfring 3354e087f34fSMarkus Elfring if (!atomic_read(&vlan->ap_isolation)) 33555870adc6SMarek Lindner goto out; 335659b699cdSAntonio Quartulli 3357b8cbd81dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); 335859b699cdSAntonio Quartulli if (!tt_local_entry) 335959b699cdSAntonio Quartulli goto out; 336059b699cdSAntonio Quartulli 3361b8cbd81dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); 336259b699cdSAntonio Quartulli if (!tt_global_entry) 336359b699cdSAntonio Quartulli goto out; 336459b699cdSAntonio Quartulli 33651f129fefSAntonio Quartulli if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 336659b699cdSAntonio Quartulli goto out; 336759b699cdSAntonio Quartulli 33685870adc6SMarek Lindner ret = true; 336959b699cdSAntonio Quartulli 337059b699cdSAntonio Quartulli out: 3371b8cbd81dSAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 337259b699cdSAntonio Quartulli if (tt_global_entry) 3373a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 337459b699cdSAntonio Quartulli if (tt_local_entry) 3375a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 337659b699cdSAntonio Quartulli return ret; 337759b699cdSAntonio Quartulli } 3378a943cac1SMarek Lindner 3379e1bf0c14SMarek Lindner /** 3380e1bf0c14SMarek Lindner * batadv_tt_update_orig - update global translation table with new tt 3381e1bf0c14SMarek Lindner * information received via ogms 3382e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3383e51f0397SSven Eckelmann * @orig_node: the orig_node of the ogm 3384e51f0397SSven Eckelmann * @tt_buff: pointer to the first tvlv VLAN entry 33857ea7b4a1SAntonio Quartulli * @tt_num_vlan: number of tvlv VLAN entries 33867ea7b4a1SAntonio Quartulli * @tt_change: pointer to the first entry in the TT buffer 3387e1bf0c14SMarek Lindner * @tt_num_changes: number of tt changes inside the tt buffer 3388e1bf0c14SMarek Lindner * @ttvn: translation table version number of this changeset 3389e1bf0c14SMarek Lindner */ 3390e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv, 339156303d34SSven Eckelmann struct batadv_orig_node *orig_node, 33926b5e971aSSven Eckelmann const void *tt_buff, u16 tt_num_vlan, 33937ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 33946b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn) 3395a943cac1SMarek Lindner { 33966b5e971aSSven Eckelmann u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); 33977ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 3398a943cac1SMarek Lindner bool full_table = true; 3399e17931d1SLinus Lüssing bool has_tt_init; 3400a943cac1SMarek Lindner 34017ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; 3402ac4eebd4SLinus Lüssing has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT, 3403ac4eebd4SLinus Lüssing &orig_node->capa_initialized); 3404e17931d1SLinus Lüssing 340517071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 34069cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 34079cfc7bd6SSven Eckelmann */ 3408e17931d1SLinus Lüssing if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) { 3409a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 341042d0b044SSven Eckelmann * because they have already been sent BATADV_TT_OGM_APPEND_MAX 341142d0b044SSven Eckelmann * times. 34129cfc7bd6SSven Eckelmann * In this case send a tt request 34139cfc7bd6SSven Eckelmann */ 3414a943cac1SMarek Lindner if (!tt_num_changes) { 3415a943cac1SMarek Lindner full_table = false; 3416a943cac1SMarek Lindner goto request_table; 3417a943cac1SMarek Lindner } 3418a943cac1SMarek Lindner 3419a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 3420a70a9aa9SAntonio Quartulli 3421a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 342296412690SSven Eckelmann ttvn, tt_change); 3423a943cac1SMarek Lindner 3424a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 3425a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 34269cfc7bd6SSven Eckelmann * in the global table 34279cfc7bd6SSven Eckelmann */ 34287ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3429a943cac1SMarek Lindner 3430a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3431a70a9aa9SAntonio Quartulli 3432a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 3433a943cac1SMarek Lindner * because a single value could represent different states 3434a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 3435a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 3436a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 3437a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 3438a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 34399cfc7bd6SSven Eckelmann * inconsistency 34409cfc7bd6SSven Eckelmann */ 34417ea7b4a1SAntonio Quartulli if (!batadv_tt_global_check_crc(orig_node, tt_vlan, 34427ea7b4a1SAntonio Quartulli tt_num_vlan)) 3443a943cac1SMarek Lindner goto request_table; 3444a943cac1SMarek Lindner } else { 3445a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 34469cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 34479cfc7bd6SSven Eckelmann */ 3448e17931d1SLinus Lüssing if (!has_tt_init || ttvn != orig_ttvn || 34497ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(orig_node, tt_vlan, 34507ea7b4a1SAntonio Quartulli tt_num_vlan)) { 3451a943cac1SMarek Lindner request_table: 345239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 34537ea7b4a1SAntonio Quartulli "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n", 34547ea7b4a1SAntonio Quartulli orig_node->orig, ttvn, orig_ttvn, 34557ea7b4a1SAntonio Quartulli tt_num_changes); 3456a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 34577ea7b4a1SAntonio Quartulli tt_vlan, tt_num_vlan, 34587ea7b4a1SAntonio Quartulli full_table); 3459a943cac1SMarek Lindner return; 3460a943cac1SMarek Lindner } 3461a943cac1SMarek Lindner } 3462a943cac1SMarek Lindner } 34633275e7ccSAntonio Quartulli 3464c018ad3dSAntonio Quartulli /** 3465c018ad3dSAntonio Quartulli * batadv_tt_global_client_is_roaming - check if a client is marked as roaming 3466c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3467c018ad3dSAntonio Quartulli * @addr: the mac address of the client to check 3468c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3469c018ad3dSAntonio Quartulli * 347062fe710fSSven Eckelmann * Return: true if we know that the client has moved from its old originator 3471c018ad3dSAntonio Quartulli * to another one. This entry is still kept for consistency purposes and will be 3472c018ad3dSAntonio Quartulli * deleted later by a DEL or because of timeout 34733275e7ccSAntonio Quartulli */ 347456303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, 34756b5e971aSSven Eckelmann u8 *addr, unsigned short vid) 34763275e7ccSAntonio Quartulli { 347756303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 34783275e7ccSAntonio Quartulli bool ret = false; 34793275e7ccSAntonio Quartulli 3480c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 34813275e7ccSAntonio Quartulli if (!tt_global_entry) 34823275e7ccSAntonio Quartulli goto out; 34833275e7ccSAntonio Quartulli 3484c1d07431SAntonio Quartulli ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; 3485a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 34863275e7ccSAntonio Quartulli out: 34873275e7ccSAntonio Quartulli return ret; 34883275e7ccSAntonio Quartulli } 348930cfd02bSAntonio Quartulli 34907c1fd91dSAntonio Quartulli /** 34917c1fd91dSAntonio Quartulli * batadv_tt_local_client_is_roaming - tells whether the client is roaming 34927c1fd91dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3493c018ad3dSAntonio Quartulli * @addr: the mac address of the local client to query 3494c018ad3dSAntonio Quartulli * @vid: VLAN identifier 34957c1fd91dSAntonio Quartulli * 349662fe710fSSven Eckelmann * Return: true if the local client is known to be roaming (it is not served by 34977c1fd91dSAntonio Quartulli * this node anymore) or not. If yes, the client is still present in the table 34987c1fd91dSAntonio Quartulli * to keep the latter consistent with the node TTVN 34997c1fd91dSAntonio Quartulli */ 35007c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, 35016b5e971aSSven Eckelmann u8 *addr, unsigned short vid) 35027c1fd91dSAntonio Quartulli { 35037c1fd91dSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry; 35047c1fd91dSAntonio Quartulli bool ret = false; 35057c1fd91dSAntonio Quartulli 3506c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 35077c1fd91dSAntonio Quartulli if (!tt_local_entry) 35087c1fd91dSAntonio Quartulli goto out; 35097c1fd91dSAntonio Quartulli 35107c1fd91dSAntonio Quartulli ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; 35117c1fd91dSAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 35127c1fd91dSAntonio Quartulli out: 35137c1fd91dSAntonio Quartulli return ret; 35147c1fd91dSAntonio Quartulli } 35157c1fd91dSAntonio Quartulli 351630cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, 351730cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 3518c018ad3dSAntonio Quartulli const unsigned char *addr, 351916052789SAntonio Quartulli unsigned short vid) 352030cfd02bSAntonio Quartulli { 352130cfd02bSAntonio Quartulli bool ret = false; 352230cfd02bSAntonio Quartulli 352316052789SAntonio Quartulli if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, 352430cfd02bSAntonio Quartulli BATADV_TT_CLIENT_TEMP, 352530cfd02bSAntonio Quartulli atomic_read(&orig_node->last_ttvn))) 352630cfd02bSAntonio Quartulli goto out; 352730cfd02bSAntonio Quartulli 352830cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 352916052789SAntonio Quartulli "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n", 353016052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid), orig_node->orig); 353130cfd02bSAntonio Quartulli ret = true; 353230cfd02bSAntonio Quartulli out: 353330cfd02bSAntonio Quartulli return ret; 353430cfd02bSAntonio Quartulli } 3535e1bf0c14SMarek Lindner 3536e1bf0c14SMarek Lindner /** 3537a19d3d85SMarek Lindner * batadv_tt_local_resize_to_mtu - resize the local translation table fit the 3538a19d3d85SMarek Lindner * maximum packet size that can be transported through the mesh 3539a19d3d85SMarek Lindner * @soft_iface: netdev struct of the mesh interface 3540a19d3d85SMarek Lindner * 3541a19d3d85SMarek Lindner * Remove entries older than 'timeout' and half timeout if more entries need 3542a19d3d85SMarek Lindner * to be removed. 3543a19d3d85SMarek Lindner */ 3544a19d3d85SMarek Lindner void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface) 3545a19d3d85SMarek Lindner { 3546a19d3d85SMarek Lindner struct batadv_priv *bat_priv = netdev_priv(soft_iface); 3547a19d3d85SMarek Lindner int packet_size_max = atomic_read(&bat_priv->packet_size_max); 3548a19d3d85SMarek Lindner int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; 3549a19d3d85SMarek Lindner bool reduced = false; 3550a19d3d85SMarek Lindner 3551a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3552a19d3d85SMarek Lindner 3553a19d3d85SMarek Lindner while (true) { 3554a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 3555a19d3d85SMarek Lindner if (packet_size_max >= table_size) 3556a19d3d85SMarek Lindner break; 3557a19d3d85SMarek Lindner 3558a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, timeout); 3559a19d3d85SMarek Lindner batadv_tt_local_purge_pending_clients(bat_priv); 3560a19d3d85SMarek Lindner 3561a19d3d85SMarek Lindner timeout /= 2; 3562a19d3d85SMarek Lindner reduced = true; 3563a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 3564a19d3d85SMarek Lindner "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n", 3565a19d3d85SMarek Lindner packet_size_max); 3566a19d3d85SMarek Lindner } 3567a19d3d85SMarek Lindner 3568a19d3d85SMarek Lindner /* commit these changes immediately, to avoid synchronization problem 3569a19d3d85SMarek Lindner * with the TTVN 3570a19d3d85SMarek Lindner */ 3571a19d3d85SMarek Lindner if (reduced) 3572a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3573a19d3d85SMarek Lindner 3574a19d3d85SMarek Lindner spin_unlock_bh(&bat_priv->tt.commit_lock); 3575a19d3d85SMarek Lindner } 3576a19d3d85SMarek Lindner 3577a19d3d85SMarek Lindner /** 3578e1bf0c14SMarek Lindner * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container 3579e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3580e1bf0c14SMarek Lindner * @orig: the orig_node of the ogm 3581e1bf0c14SMarek Lindner * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 3582e1bf0c14SMarek Lindner * @tvlv_value: tvlv buffer containing the gateway data 3583e1bf0c14SMarek Lindner * @tvlv_value_len: tvlv buffer length 3584e1bf0c14SMarek Lindner */ 3585e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 3586e1bf0c14SMarek Lindner struct batadv_orig_node *orig, 35876b5e971aSSven Eckelmann u8 flags, void *tvlv_value, 35886b5e971aSSven Eckelmann u16 tvlv_value_len) 3589e1bf0c14SMarek Lindner { 35907ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 35917ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 3592e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 35936b5e971aSSven Eckelmann u16 num_entries, num_vlan; 3594e1bf0c14SMarek Lindner 3595e1bf0c14SMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 3596e1bf0c14SMarek Lindner return; 3597e1bf0c14SMarek Lindner 3598e1bf0c14SMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 3599e1bf0c14SMarek Lindner tvlv_value_len -= sizeof(*tt_data); 3600e1bf0c14SMarek Lindner 36017ea7b4a1SAntonio Quartulli num_vlan = ntohs(tt_data->num_vlan); 36027ea7b4a1SAntonio Quartulli 36037ea7b4a1SAntonio Quartulli if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) 36047ea7b4a1SAntonio Quartulli return; 36057ea7b4a1SAntonio Quartulli 36067ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 36077ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); 36087ea7b4a1SAntonio Quartulli tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; 36097ea7b4a1SAntonio Quartulli 3610298e6e68SAntonio Quartulli num_entries = batadv_tt_entries(tvlv_value_len); 3611e1bf0c14SMarek Lindner 36127ea7b4a1SAntonio Quartulli batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, 36137ea7b4a1SAntonio Quartulli num_entries, tt_data->ttvn); 3614e1bf0c14SMarek Lindner } 3615e1bf0c14SMarek Lindner 3616e1bf0c14SMarek Lindner /** 3617335fbe0fSMarek Lindner * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv 3618335fbe0fSMarek Lindner * container 3619335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3620335fbe0fSMarek Lindner * @src: mac address of tt tvlv sender 3621335fbe0fSMarek Lindner * @dst: mac address of tt tvlv recipient 3622335fbe0fSMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 3623335fbe0fSMarek Lindner * @tvlv_value_len: tvlv buffer length 3624335fbe0fSMarek Lindner * 362562fe710fSSven Eckelmann * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS 3626335fbe0fSMarek Lindner * otherwise. 3627335fbe0fSMarek Lindner */ 3628335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 36296b5e971aSSven Eckelmann u8 *src, u8 *dst, 3630335fbe0fSMarek Lindner void *tvlv_value, 36316b5e971aSSven Eckelmann u16 tvlv_value_len) 3632335fbe0fSMarek Lindner { 3633335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data; 36346b5e971aSSven Eckelmann u16 tt_vlan_len, tt_num_entries; 3635335fbe0fSMarek Lindner char tt_flag; 3636335fbe0fSMarek Lindner bool ret; 3637335fbe0fSMarek Lindner 3638335fbe0fSMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 3639335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3640335fbe0fSMarek Lindner 3641335fbe0fSMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 3642335fbe0fSMarek Lindner tvlv_value_len -= sizeof(*tt_data); 3643335fbe0fSMarek Lindner 36447ea7b4a1SAntonio Quartulli tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); 36457ea7b4a1SAntonio Quartulli tt_vlan_len *= ntohs(tt_data->num_vlan); 36467ea7b4a1SAntonio Quartulli 36477ea7b4a1SAntonio Quartulli if (tvlv_value_len < tt_vlan_len) 36487ea7b4a1SAntonio Quartulli return NET_RX_SUCCESS; 36497ea7b4a1SAntonio Quartulli 36507ea7b4a1SAntonio Quartulli tvlv_value_len -= tt_vlan_len; 36517ea7b4a1SAntonio Quartulli tt_num_entries = batadv_tt_entries(tvlv_value_len); 3652335fbe0fSMarek Lindner 3653335fbe0fSMarek Lindner switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { 3654335fbe0fSMarek Lindner case BATADV_TT_REQUEST: 3655335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); 3656335fbe0fSMarek Lindner 3657335fbe0fSMarek Lindner /* If this node cannot provide a TT response the tt_request is 3658335fbe0fSMarek Lindner * forwarded 3659335fbe0fSMarek Lindner */ 3660335fbe0fSMarek Lindner ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); 3661335fbe0fSMarek Lindner if (!ret) { 3662335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 3663335fbe0fSMarek Lindner tt_flag = 'F'; 3664335fbe0fSMarek Lindner else 3665335fbe0fSMarek Lindner tt_flag = '.'; 3666335fbe0fSMarek Lindner 3667335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3668335fbe0fSMarek Lindner "Routing TT_REQUEST to %pM [%c]\n", 3669335fbe0fSMarek Lindner dst, tt_flag); 3670335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 3671335fbe0fSMarek Lindner return NET_RX_DROP; 3672335fbe0fSMarek Lindner } 3673335fbe0fSMarek Lindner break; 3674335fbe0fSMarek Lindner case BATADV_TT_RESPONSE: 3675335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); 3676335fbe0fSMarek Lindner 3677335fbe0fSMarek Lindner if (batadv_is_my_mac(bat_priv, dst)) { 3678335fbe0fSMarek Lindner batadv_handle_tt_response(bat_priv, tt_data, 36797ea7b4a1SAntonio Quartulli src, tt_num_entries); 3680335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3681335fbe0fSMarek Lindner } 3682335fbe0fSMarek Lindner 3683335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 3684335fbe0fSMarek Lindner tt_flag = 'F'; 3685335fbe0fSMarek Lindner else 3686335fbe0fSMarek Lindner tt_flag = '.'; 3687335fbe0fSMarek Lindner 3688335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3689335fbe0fSMarek Lindner "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag); 3690335fbe0fSMarek Lindner 3691335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 3692335fbe0fSMarek Lindner return NET_RX_DROP; 3693335fbe0fSMarek Lindner } 3694335fbe0fSMarek Lindner 3695335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3696335fbe0fSMarek Lindner } 3697335fbe0fSMarek Lindner 3698335fbe0fSMarek Lindner /** 3699122edaa0SMarek Lindner * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container 3700122edaa0SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3701122edaa0SMarek Lindner * @src: mac address of tt tvlv sender 3702122edaa0SMarek Lindner * @dst: mac address of tt tvlv recipient 3703122edaa0SMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 3704122edaa0SMarek Lindner * @tvlv_value_len: tvlv buffer length 3705122edaa0SMarek Lindner * 370662fe710fSSven Eckelmann * Return: NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS 3707122edaa0SMarek Lindner * otherwise. 3708122edaa0SMarek Lindner */ 3709122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 37106b5e971aSSven Eckelmann u8 *src, u8 *dst, 3711122edaa0SMarek Lindner void *tvlv_value, 37126b5e971aSSven Eckelmann u16 tvlv_value_len) 3713122edaa0SMarek Lindner { 3714122edaa0SMarek Lindner struct batadv_tvlv_roam_adv *roaming_adv; 3715122edaa0SMarek Lindner struct batadv_orig_node *orig_node = NULL; 3716122edaa0SMarek Lindner 3717122edaa0SMarek Lindner /* If this node is not the intended recipient of the 3718122edaa0SMarek Lindner * roaming advertisement the packet is forwarded 3719122edaa0SMarek Lindner * (the tvlv API will re-route the packet). 3720122edaa0SMarek Lindner */ 3721122edaa0SMarek Lindner if (!batadv_is_my_mac(bat_priv, dst)) 3722122edaa0SMarek Lindner return NET_RX_DROP; 3723122edaa0SMarek Lindner 3724122edaa0SMarek Lindner if (tvlv_value_len < sizeof(*roaming_adv)) 3725122edaa0SMarek Lindner goto out; 3726122edaa0SMarek Lindner 3727122edaa0SMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, src); 3728122edaa0SMarek Lindner if (!orig_node) 3729122edaa0SMarek Lindner goto out; 3730122edaa0SMarek Lindner 3731122edaa0SMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); 3732122edaa0SMarek Lindner roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; 3733122edaa0SMarek Lindner 3734122edaa0SMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3735122edaa0SMarek Lindner "Received ROAMING_ADV from %pM (client %pM)\n", 3736122edaa0SMarek Lindner src, roaming_adv->client); 3737122edaa0SMarek Lindner 3738122edaa0SMarek Lindner batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, 3739c018ad3dSAntonio Quartulli ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, 3740122edaa0SMarek Lindner atomic_read(&orig_node->last_ttvn) + 1); 3741122edaa0SMarek Lindner 3742122edaa0SMarek Lindner out: 3743122edaa0SMarek Lindner if (orig_node) 3744122edaa0SMarek Lindner batadv_orig_node_free_ref(orig_node); 3745122edaa0SMarek Lindner return NET_RX_SUCCESS; 3746122edaa0SMarek Lindner } 3747122edaa0SMarek Lindner 3748122edaa0SMarek Lindner /** 3749e1bf0c14SMarek Lindner * batadv_tt_init - initialise the translation table internals 3750e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3751e1bf0c14SMarek Lindner * 375262fe710fSSven Eckelmann * Return: 0 on success or negative error number in case of failure. 3753e1bf0c14SMarek Lindner */ 3754e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv) 3755e1bf0c14SMarek Lindner { 3756e1bf0c14SMarek Lindner int ret; 3757e1bf0c14SMarek Lindner 37580eb01568SAntonio Quartulli /* synchronized flags must be remote */ 37590eb01568SAntonio Quartulli BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK)); 37600eb01568SAntonio Quartulli 3761e1bf0c14SMarek Lindner ret = batadv_tt_local_init(bat_priv); 3762e1bf0c14SMarek Lindner if (ret < 0) 3763e1bf0c14SMarek Lindner return ret; 3764e1bf0c14SMarek Lindner 3765e1bf0c14SMarek Lindner ret = batadv_tt_global_init(bat_priv); 3766e1bf0c14SMarek Lindner if (ret < 0) 3767e1bf0c14SMarek Lindner return ret; 3768e1bf0c14SMarek Lindner 3769e1bf0c14SMarek Lindner batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, 3770335fbe0fSMarek Lindner batadv_tt_tvlv_unicast_handler_v1, 3771335fbe0fSMarek Lindner BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); 3772e1bf0c14SMarek Lindner 3773122edaa0SMarek Lindner batadv_tvlv_handler_register(bat_priv, NULL, 3774122edaa0SMarek Lindner batadv_roam_tvlv_unicast_handler_v1, 3775122edaa0SMarek Lindner BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); 3776122edaa0SMarek Lindner 3777e1bf0c14SMarek Lindner INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); 3778e1bf0c14SMarek Lindner queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 3779e1bf0c14SMarek Lindner msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3780e1bf0c14SMarek Lindner 3781e1bf0c14SMarek Lindner return 1; 3782e1bf0c14SMarek Lindner } 378342cb0befSAntonio Quartulli 378442cb0befSAntonio Quartulli /** 378542cb0befSAntonio Quartulli * batadv_tt_global_is_isolated - check if a client is marked as isolated 378642cb0befSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 378742cb0befSAntonio Quartulli * @addr: the mac address of the client 378842cb0befSAntonio Quartulli * @vid: the identifier of the VLAN where this client is connected 378942cb0befSAntonio Quartulli * 379062fe710fSSven Eckelmann * Return: true if the client is marked with the TT_CLIENT_ISOLA flag, false 379142cb0befSAntonio Quartulli * otherwise 379242cb0befSAntonio Quartulli */ 379342cb0befSAntonio Quartulli bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, 37946b5e971aSSven Eckelmann const u8 *addr, unsigned short vid) 379542cb0befSAntonio Quartulli { 379642cb0befSAntonio Quartulli struct batadv_tt_global_entry *tt; 379742cb0befSAntonio Quartulli bool ret; 379842cb0befSAntonio Quartulli 379942cb0befSAntonio Quartulli tt = batadv_tt_global_hash_find(bat_priv, addr, vid); 380042cb0befSAntonio Quartulli if (!tt) 380142cb0befSAntonio Quartulli return false; 380242cb0befSAntonio Quartulli 380342cb0befSAntonio Quartulli ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA; 380442cb0befSAntonio Quartulli 380542cb0befSAntonio Quartulli batadv_tt_global_entry_free_ref(tt); 380642cb0befSAntonio Quartulli 380742cb0befSAntonio Quartulli return ret; 380842cb0befSAntonio Quartulli } 3809