10046b040SSven Eckelmann /* Copyright (C) 2007-2016 B.A.T.M.A.N. contributors: 2c6c8fea2SSven Eckelmann * 335c133a0SAntonio Quartulli * Marek Lindner, Simon Wunderlich, Antonio Quartulli 4c6c8fea2SSven Eckelmann * 5c6c8fea2SSven Eckelmann * This program is free software; you can redistribute it and/or 6c6c8fea2SSven Eckelmann * modify it under the terms of version 2 of the GNU General Public 7c6c8fea2SSven Eckelmann * License as published by the Free Software Foundation. 8c6c8fea2SSven Eckelmann * 9c6c8fea2SSven Eckelmann * This program is distributed in the hope that it will be useful, but 10c6c8fea2SSven Eckelmann * WITHOUT ANY WARRANTY; without even the implied warranty of 11c6c8fea2SSven Eckelmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12c6c8fea2SSven Eckelmann * General Public License for more details. 13c6c8fea2SSven Eckelmann * 14c6c8fea2SSven Eckelmann * You should have received a copy of the GNU General Public License 15ebf38fb7SAntonio Quartulli * along with this program; if not, see <http://www.gnu.org/licenses/>. 16c6c8fea2SSven Eckelmann */ 17c6c8fea2SSven Eckelmann 18c6c8fea2SSven Eckelmann #include "translation-table.h" 191e2c2a4fSSven Eckelmann #include "main.h" 20c6c8fea2SSven Eckelmann 211e2c2a4fSSven Eckelmann #include <linux/atomic.h> 22ac4eebd4SLinus Lüssing #include <linux/bitops.h> 231e2c2a4fSSven Eckelmann #include <linux/bug.h> 241e2c2a4fSSven Eckelmann #include <linux/byteorder/generic.h> 251e2c2a4fSSven Eckelmann #include <linux/compiler.h> 26ced72933SAntonio Quartulli #include <linux/crc32c.h> 271e2c2a4fSSven Eckelmann #include <linux/errno.h> 281e2c2a4fSSven Eckelmann #include <linux/etherdevice.h> 291e2c2a4fSSven Eckelmann #include <linux/fs.h> 301e2c2a4fSSven Eckelmann #include <linux/if_ether.h> 311e2c2a4fSSven Eckelmann #include <linux/jhash.h> 321e2c2a4fSSven Eckelmann #include <linux/jiffies.h> 331e2c2a4fSSven Eckelmann #include <linux/kernel.h> 346e8ef69dSSven Eckelmann #include <linux/kref.h> 351e2c2a4fSSven Eckelmann #include <linux/list.h> 361e2c2a4fSSven Eckelmann #include <linux/lockdep.h> 371e2c2a4fSSven Eckelmann #include <linux/netdevice.h> 381e2c2a4fSSven Eckelmann #include <linux/rculist.h> 391e2c2a4fSSven Eckelmann #include <linux/rcupdate.h> 401e2c2a4fSSven Eckelmann #include <linux/seq_file.h> 411e2c2a4fSSven Eckelmann #include <linux/slab.h> 421e2c2a4fSSven Eckelmann #include <linux/spinlock.h> 431e2c2a4fSSven Eckelmann #include <linux/stddef.h> 441e2c2a4fSSven Eckelmann #include <linux/string.h> 451e2c2a4fSSven Eckelmann #include <linux/workqueue.h> 461e2c2a4fSSven Eckelmann 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 /** 72d15cd622SAntonio Quartulli * batadv_compare_tt - check if two TT entries are the same 73d15cd622SAntonio Quartulli * @node: the list element pointer of the first TT entry 74d15cd622SAntonio Quartulli * @data2: pointer to the tt_common_entry of the second TT entry 7562fe710fSSven Eckelmann * 76d15cd622SAntonio Quartulli * Compare the MAC address and the VLAN ID of the two TT entries and check if 77d15cd622SAntonio Quartulli * they are the same TT client. 784b426b10SSven Eckelmann * Return: true if the two TT clients are the same, false otherwise 7962fe710fSSven Eckelmann */ 804b426b10SSven Eckelmann static bool batadv_compare_tt(const struct hlist_node *node, const void *data2) 817aadf889SMarek Lindner { 8256303d34SSven Eckelmann const void *data1 = container_of(node, struct batadv_tt_common_entry, 83747e4221SSven Eckelmann hash_entry); 844c718958SMarek Lindner const struct batadv_tt_common_entry *tt1 = data1; 854c718958SMarek Lindner const struct batadv_tt_common_entry *tt2 = data2; 867aadf889SMarek Lindner 874c718958SMarek Lindner return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2); 887aadf889SMarek Lindner } 897aadf889SMarek Lindner 90c018ad3dSAntonio Quartulli /** 91c018ad3dSAntonio Quartulli * batadv_choose_tt - return the index of the tt entry in the hash table 92c018ad3dSAntonio Quartulli * @data: pointer to the tt_common_entry object to map 93c018ad3dSAntonio Quartulli * @size: the size of the hash table 94c018ad3dSAntonio Quartulli * 9562fe710fSSven Eckelmann * Return: the hash index where the object represented by 'data' should be 96c018ad3dSAntonio Quartulli * stored at. 97c018ad3dSAntonio Quartulli */ 986b5e971aSSven Eckelmann static inline u32 batadv_choose_tt(const void *data, u32 size) 99c018ad3dSAntonio Quartulli { 100c018ad3dSAntonio Quartulli struct batadv_tt_common_entry *tt; 1016b5e971aSSven Eckelmann u32 hash = 0; 102c018ad3dSAntonio Quartulli 103c018ad3dSAntonio Quartulli tt = (struct batadv_tt_common_entry *)data; 10436fd61cbSSven Eckelmann hash = jhash(&tt->addr, ETH_ALEN, hash); 10536fd61cbSSven Eckelmann hash = jhash(&tt->vid, sizeof(tt->vid), hash); 106c018ad3dSAntonio Quartulli 107c018ad3dSAntonio Quartulli return hash % size; 108c018ad3dSAntonio Quartulli } 109c018ad3dSAntonio Quartulli 110c018ad3dSAntonio Quartulli /** 111c018ad3dSAntonio Quartulli * batadv_tt_hash_find - look for a client in the given hash table 112c018ad3dSAntonio Quartulli * @hash: the hash table to search 113c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 114c018ad3dSAntonio Quartulli * @vid: VLAN identifier 115c018ad3dSAntonio Quartulli * 11662fe710fSSven Eckelmann * Return: a pointer to the tt_common struct belonging to the searched client if 117c018ad3dSAntonio Quartulli * found, NULL otherwise. 118c018ad3dSAntonio Quartulli */ 11956303d34SSven Eckelmann static struct batadv_tt_common_entry * 1206b5e971aSSven Eckelmann batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr, 121c018ad3dSAntonio Quartulli unsigned short vid) 1227aadf889SMarek Lindner { 1237aadf889SMarek Lindner struct hlist_head *head; 124c018ad3dSAntonio Quartulli struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; 1256b5e971aSSven Eckelmann u32 index; 1267aadf889SMarek Lindner 1277aadf889SMarek Lindner if (!hash) 1287aadf889SMarek Lindner return NULL; 1297aadf889SMarek Lindner 1308fdd0153SAntonio Quartulli ether_addr_copy(to_search.addr, addr); 131c018ad3dSAntonio Quartulli to_search.vid = vid; 132c018ad3dSAntonio Quartulli 133c018ad3dSAntonio Quartulli index = batadv_choose_tt(&to_search, hash->size); 1347aadf889SMarek Lindner head = &hash->table[index]; 1357aadf889SMarek Lindner 1367aadf889SMarek Lindner rcu_read_lock(); 137c018ad3dSAntonio Quartulli hlist_for_each_entry_rcu(tt, head, hash_entry) { 138c018ad3dSAntonio Quartulli if (!batadv_compare_eth(tt, addr)) 1397aadf889SMarek Lindner continue; 1407aadf889SMarek Lindner 141c018ad3dSAntonio Quartulli if (tt->vid != vid) 1427683fdc1SAntonio Quartulli continue; 1437683fdc1SAntonio Quartulli 14492dcdf09SSven Eckelmann if (!kref_get_unless_zero(&tt->refcount)) 145c018ad3dSAntonio Quartulli continue; 146c018ad3dSAntonio Quartulli 147c018ad3dSAntonio Quartulli tt_tmp = tt; 1487aadf889SMarek Lindner break; 1497aadf889SMarek Lindner } 1507aadf889SMarek Lindner rcu_read_unlock(); 1517aadf889SMarek Lindner 152c018ad3dSAntonio Quartulli return tt_tmp; 15348100bacSAntonio Quartulli } 15448100bacSAntonio Quartulli 155c018ad3dSAntonio Quartulli /** 156c018ad3dSAntonio Quartulli * batadv_tt_local_hash_find - search the local table for a given client 157c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 158c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 159c018ad3dSAntonio Quartulli * @vid: VLAN identifier 160c018ad3dSAntonio Quartulli * 16162fe710fSSven Eckelmann * Return: a pointer to the corresponding tt_local_entry struct if the client is 162c018ad3dSAntonio Quartulli * found, NULL otherwise. 163c018ad3dSAntonio Quartulli */ 16456303d34SSven Eckelmann static struct batadv_tt_local_entry * 1656b5e971aSSven Eckelmann batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr, 166c018ad3dSAntonio Quartulli unsigned short vid) 16748100bacSAntonio Quartulli { 16856303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 16956303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 17048100bacSAntonio Quartulli 171c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, 172c018ad3dSAntonio Quartulli vid); 17348100bacSAntonio Quartulli if (tt_common_entry) 17448100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 17556303d34SSven Eckelmann struct batadv_tt_local_entry, 17656303d34SSven Eckelmann common); 17748100bacSAntonio Quartulli return tt_local_entry; 1787aadf889SMarek Lindner } 1797aadf889SMarek Lindner 180c018ad3dSAntonio Quartulli /** 181c018ad3dSAntonio Quartulli * batadv_tt_global_hash_find - search the global table for a given client 182c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 183c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 184c018ad3dSAntonio Quartulli * @vid: VLAN identifier 185c018ad3dSAntonio Quartulli * 18662fe710fSSven Eckelmann * Return: a pointer to the corresponding tt_global_entry struct if the client 187c018ad3dSAntonio Quartulli * is found, NULL otherwise. 188c018ad3dSAntonio Quartulli */ 18956303d34SSven Eckelmann static struct batadv_tt_global_entry * 1906b5e971aSSven Eckelmann batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, 191c018ad3dSAntonio Quartulli unsigned short vid) 1927aadf889SMarek Lindner { 19356303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 19456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 1957aadf889SMarek Lindner 196c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, 197c018ad3dSAntonio Quartulli vid); 19848100bacSAntonio Quartulli if (tt_common_entry) 19948100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 20056303d34SSven Eckelmann struct batadv_tt_global_entry, 20156303d34SSven Eckelmann common); 20248100bacSAntonio Quartulli return tt_global_entry; 2037aadf889SMarek Lindner } 2047aadf889SMarek Lindner 20592dcdf09SSven Eckelmann /** 20692dcdf09SSven Eckelmann * batadv_tt_local_entry_release - release tt_local_entry from lists and queue 20792dcdf09SSven Eckelmann * for free after rcu grace period 20892dcdf09SSven Eckelmann * @ref: kref pointer of the nc_node 20992dcdf09SSven Eckelmann */ 21092dcdf09SSven Eckelmann static void batadv_tt_local_entry_release(struct kref *ref) 2117683fdc1SAntonio Quartulli { 21292dcdf09SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 21392dcdf09SSven Eckelmann 21492dcdf09SSven Eckelmann tt_local_entry = container_of(ref, struct batadv_tt_local_entry, 21592dcdf09SSven Eckelmann common.refcount); 21692dcdf09SSven Eckelmann 217a33d970dSSven Eckelmann batadv_softif_vlan_put(tt_local_entry->vlan); 218a33d970dSSven Eckelmann 21948100bacSAntonio Quartulli kfree_rcu(tt_local_entry, common.rcu); 2207683fdc1SAntonio Quartulli } 2217683fdc1SAntonio Quartulli 22221026059SAntonio Quartulli /** 22395c0db90SSven Eckelmann * batadv_tt_local_entry_put - decrement the tt_local_entry refcounter and 22492dcdf09SSven Eckelmann * possibly release it 22592dcdf09SSven Eckelmann * @tt_local_entry: tt_local_entry to be free'd 22692dcdf09SSven Eckelmann */ 22792dcdf09SSven Eckelmann static void 22895c0db90SSven Eckelmann batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry) 22992dcdf09SSven Eckelmann { 23092dcdf09SSven Eckelmann kref_put(&tt_local_entry->common.refcount, 23192dcdf09SSven Eckelmann batadv_tt_local_entry_release); 23292dcdf09SSven Eckelmann } 23392dcdf09SSven Eckelmann 23492dcdf09SSven Eckelmann /** 23592dcdf09SSven Eckelmann * batadv_tt_global_entry_release - release tt_global_entry from lists and queue 23692dcdf09SSven Eckelmann * for free after rcu grace period 23792dcdf09SSven Eckelmann * @ref: kref pointer of the nc_node 23892dcdf09SSven Eckelmann */ 23992dcdf09SSven Eckelmann static void batadv_tt_global_entry_release(struct kref *ref) 24092dcdf09SSven Eckelmann { 24192dcdf09SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 24292dcdf09SSven Eckelmann 24392dcdf09SSven Eckelmann tt_global_entry = container_of(ref, struct batadv_tt_global_entry, 24492dcdf09SSven Eckelmann common.refcount); 24592dcdf09SSven Eckelmann 24692dcdf09SSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 24792dcdf09SSven Eckelmann kfree_rcu(tt_global_entry, common.rcu); 24892dcdf09SSven Eckelmann } 24992dcdf09SSven Eckelmann 25092dcdf09SSven Eckelmann /** 2515dafd8a6SSven Eckelmann * batadv_tt_global_entry_put - decrement the tt_global_entry refcounter and 2525dafd8a6SSven Eckelmann * possibly release it 25392dcdf09SSven Eckelmann * @tt_global_entry: tt_global_entry to be free'd 25421026059SAntonio Quartulli */ 255a513088dSSven Eckelmann static void 2565dafd8a6SSven Eckelmann batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry) 2577683fdc1SAntonio Quartulli { 25892dcdf09SSven Eckelmann kref_put(&tt_global_entry->common.refcount, 25992dcdf09SSven Eckelmann batadv_tt_global_entry_release); 260db08e6e5SSimon Wunderlich } 261db08e6e5SSimon Wunderlich 2621d8ab8d3SLinus Lüssing /** 2631d8ab8d3SLinus Lüssing * batadv_tt_global_hash_count - count the number of orig entries 264d15cd622SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2651d8ab8d3SLinus Lüssing * @addr: the mac address of the client to count entries for 2661d8ab8d3SLinus Lüssing * @vid: VLAN identifier 2671d8ab8d3SLinus Lüssing * 26862fe710fSSven Eckelmann * Return: the number of originators advertising the given address/data 2691d8ab8d3SLinus Lüssing * (excluding ourself). 2701d8ab8d3SLinus Lüssing */ 2711d8ab8d3SLinus Lüssing int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, 2726b5e971aSSven Eckelmann const u8 *addr, unsigned short vid) 2731d8ab8d3SLinus Lüssing { 2741d8ab8d3SLinus Lüssing struct batadv_tt_global_entry *tt_global_entry; 2751d8ab8d3SLinus Lüssing int count; 2761d8ab8d3SLinus Lüssing 2771d8ab8d3SLinus Lüssing tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 2781d8ab8d3SLinus Lüssing if (!tt_global_entry) 2791d8ab8d3SLinus Lüssing return 0; 2801d8ab8d3SLinus Lüssing 2811d8ab8d3SLinus Lüssing count = atomic_read(&tt_global_entry->orig_list_count); 2825dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 2831d8ab8d3SLinus Lüssing 2841d8ab8d3SLinus Lüssing return count; 2851d8ab8d3SLinus Lüssing } 2861d8ab8d3SLinus Lüssing 2877ea7b4a1SAntonio Quartulli /** 2887ea7b4a1SAntonio Quartulli * batadv_tt_local_size_mod - change the size by v of the local table identified 2897ea7b4a1SAntonio Quartulli * by vid 2907ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2917ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier of the sub-table to change 2927ea7b4a1SAntonio Quartulli * @v: the amount to sum to the local table size 2937ea7b4a1SAntonio Quartulli */ 2947ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv, 2957ea7b4a1SAntonio Quartulli unsigned short vid, int v) 2967ea7b4a1SAntonio Quartulli { 2977ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 2987ea7b4a1SAntonio Quartulli 2997ea7b4a1SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 3007ea7b4a1SAntonio Quartulli if (!vlan) 3017ea7b4a1SAntonio Quartulli return; 3027ea7b4a1SAntonio Quartulli 3037ea7b4a1SAntonio Quartulli atomic_add(v, &vlan->tt.num_entries); 3047ea7b4a1SAntonio Quartulli 3059c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 3067ea7b4a1SAntonio Quartulli } 3077ea7b4a1SAntonio Quartulli 3087ea7b4a1SAntonio Quartulli /** 3097ea7b4a1SAntonio Quartulli * batadv_tt_local_size_inc - increase by one the local table size for the given 3107ea7b4a1SAntonio Quartulli * vid 3117ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3127ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3137ea7b4a1SAntonio Quartulli */ 3147ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv, 3157ea7b4a1SAntonio Quartulli unsigned short vid) 3167ea7b4a1SAntonio Quartulli { 3177ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, 1); 3187ea7b4a1SAntonio Quartulli } 3197ea7b4a1SAntonio Quartulli 3207ea7b4a1SAntonio Quartulli /** 3217ea7b4a1SAntonio Quartulli * batadv_tt_local_size_dec - decrease by one the local table size for the given 3227ea7b4a1SAntonio Quartulli * vid 3237ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3247ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3257ea7b4a1SAntonio Quartulli */ 3267ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv, 3277ea7b4a1SAntonio Quartulli unsigned short vid) 3287ea7b4a1SAntonio Quartulli { 3297ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, -1); 3307ea7b4a1SAntonio Quartulli } 3317ea7b4a1SAntonio Quartulli 3327ea7b4a1SAntonio Quartulli /** 333d15cd622SAntonio Quartulli * batadv_tt_global_size_mod - change the size by v of the global table 334d15cd622SAntonio Quartulli * for orig_node identified by vid 335d15cd622SAntonio Quartulli * @orig_node: the originator for which the table has to be modified 3367ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 3377ea7b4a1SAntonio Quartulli * @v: the amount to sum to the global table size 3387ea7b4a1SAntonio Quartulli */ 3397ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, 3407ea7b4a1SAntonio Quartulli unsigned short vid, int v) 3417ea7b4a1SAntonio Quartulli { 3427ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 3437ea7b4a1SAntonio Quartulli 3447ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_new(orig_node, vid); 3457ea7b4a1SAntonio Quartulli if (!vlan) 3467ea7b4a1SAntonio Quartulli return; 3477ea7b4a1SAntonio Quartulli 3487ea7b4a1SAntonio Quartulli if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { 3497ea7b4a1SAntonio Quartulli spin_lock_bh(&orig_node->vlan_list_lock); 3503db15209SSven Eckelmann if (!hlist_unhashed(&vlan->list)) { 351a121048aSMarek Lindner hlist_del_init_rcu(&vlan->list); 35221754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 3537ea7b4a1SAntonio Quartulli } 3543db15209SSven Eckelmann spin_unlock_bh(&orig_node->vlan_list_lock); 3553db15209SSven Eckelmann } 3567ea7b4a1SAntonio Quartulli 35721754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 3587ea7b4a1SAntonio Quartulli } 3597ea7b4a1SAntonio Quartulli 3607ea7b4a1SAntonio Quartulli /** 3617ea7b4a1SAntonio Quartulli * batadv_tt_global_size_inc - increase by one the global table size for the 3627ea7b4a1SAntonio Quartulli * given vid 3637ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 3647ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 3657ea7b4a1SAntonio Quartulli */ 3667ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node, 3677ea7b4a1SAntonio Quartulli unsigned short vid) 3687ea7b4a1SAntonio Quartulli { 3697ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, 1); 3707ea7b4a1SAntonio Quartulli } 3717ea7b4a1SAntonio Quartulli 3727ea7b4a1SAntonio Quartulli /** 3737ea7b4a1SAntonio Quartulli * batadv_tt_global_size_dec - decrease by one the global table size for the 3747ea7b4a1SAntonio Quartulli * given vid 3757ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 3767ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 3777ea7b4a1SAntonio Quartulli */ 3787ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, 3797ea7b4a1SAntonio Quartulli unsigned short vid) 3807ea7b4a1SAntonio Quartulli { 3817ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, -1); 3827ea7b4a1SAntonio Quartulli } 3837ea7b4a1SAntonio Quartulli 38442eff6a6SSven Eckelmann /** 38542eff6a6SSven Eckelmann * batadv_tt_orig_list_entry_release - release tt orig entry from lists and 38642eff6a6SSven Eckelmann * queue for free after rcu grace period 3876e8ef69dSSven Eckelmann * @ref: kref pointer of the tt orig entry 38842eff6a6SSven Eckelmann */ 3896e8ef69dSSven Eckelmann static void batadv_tt_orig_list_entry_release(struct kref *ref) 39042eff6a6SSven Eckelmann { 3916e8ef69dSSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 3926e8ef69dSSven Eckelmann 3936e8ef69dSSven Eckelmann orig_entry = container_of(ref, struct batadv_tt_orig_list_entry, 3946e8ef69dSSven Eckelmann refcount); 3956e8ef69dSSven Eckelmann 3965d967310SSven Eckelmann batadv_orig_node_put(orig_entry->orig_node); 39742eff6a6SSven Eckelmann kfree_rcu(orig_entry, rcu); 39842eff6a6SSven Eckelmann } 39942eff6a6SSven Eckelmann 4006e8ef69dSSven Eckelmann /** 4017e2366c6SSven Eckelmann * batadv_tt_orig_list_entry_put - decrement the tt orig entry refcounter and 4027e2366c6SSven Eckelmann * possibly release it 4036e8ef69dSSven Eckelmann * @orig_entry: tt orig entry to be free'd 4046e8ef69dSSven Eckelmann */ 405a513088dSSven Eckelmann static void 4067e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry) 407db08e6e5SSimon Wunderlich { 4086e8ef69dSSven Eckelmann kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release); 409db08e6e5SSimon Wunderlich } 4107683fdc1SAntonio Quartulli 4113abe4adbSAntonio Quartulli /** 4123abe4adbSAntonio Quartulli * batadv_tt_local_event - store a local TT event (ADD/DEL) 4133abe4adbSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 4143abe4adbSAntonio Quartulli * @tt_local_entry: the TT entry involved in the event 4153abe4adbSAntonio Quartulli * @event_flags: flags to store in the event structure 4163abe4adbSAntonio Quartulli */ 41756303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv, 4183abe4adbSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry, 4196b5e971aSSven Eckelmann u8 event_flags) 420a73105b8SAntonio Quartulli { 42156303d34SSven Eckelmann struct batadv_tt_change_node *tt_change_node, *entry, *safe; 4223abe4adbSAntonio Quartulli struct batadv_tt_common_entry *common = &tt_local_entry->common; 4236b5e971aSSven Eckelmann u8 flags = common->flags | event_flags; 4243b643de5SAntonio Quartulli bool event_removed = false; 4253b643de5SAntonio Quartulli bool del_op_requested, del_op_entry; 426a73105b8SAntonio Quartulli 427a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 428a73105b8SAntonio Quartulli if (!tt_change_node) 429a73105b8SAntonio Quartulli return; 430a73105b8SAntonio Quartulli 431ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 432ca663046SAntonio Quartulli memset(tt_change_node->change.reserved, 0, 433ca663046SAntonio Quartulli sizeof(tt_change_node->change.reserved)); 4348fdd0153SAntonio Quartulli ether_addr_copy(tt_change_node->change.addr, common->addr); 435c018ad3dSAntonio Quartulli tt_change_node->change.vid = htons(common->vid); 436a73105b8SAntonio Quartulli 437acd34afaSSven Eckelmann del_op_requested = flags & BATADV_TT_CLIENT_DEL; 4383b643de5SAntonio Quartulli 4393b643de5SAntonio Quartulli /* check for ADD+DEL or DEL+ADD events */ 440807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 441807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 4423b643de5SAntonio Quartulli list) { 4433abe4adbSAntonio Quartulli if (!batadv_compare_eth(entry->change.addr, common->addr)) 4443b643de5SAntonio Quartulli continue; 4453b643de5SAntonio Quartulli 4463b643de5SAntonio Quartulli /* DEL+ADD in the same orig interval have no effect and can be 4473b643de5SAntonio Quartulli * removed to avoid silly behaviour on the receiver side. The 4483b643de5SAntonio Quartulli * other way around (ADD+DEL) can happen in case of roaming of 4493b643de5SAntonio Quartulli * a client still in the NEW state. Roaming of NEW clients is 4503b643de5SAntonio Quartulli * now possible due to automatically recognition of "temporary" 4513b643de5SAntonio Quartulli * clients 4523b643de5SAntonio Quartulli */ 453acd34afaSSven Eckelmann del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; 4543b643de5SAntonio Quartulli if (!del_op_requested && del_op_entry) 4553b643de5SAntonio Quartulli goto del; 4563b643de5SAntonio Quartulli if (del_op_requested && !del_op_entry) 4573b643de5SAntonio Quartulli goto del; 4583c4f7ab6SAntonio Quartulli 4593c4f7ab6SAntonio Quartulli /* this is a second add in the same originator interval. It 4603c4f7ab6SAntonio Quartulli * means that flags have been changed: update them! 4613c4f7ab6SAntonio Quartulli */ 4623c4f7ab6SAntonio Quartulli if (!del_op_requested && !del_op_entry) 4633c4f7ab6SAntonio Quartulli entry->change.flags = flags; 4643c4f7ab6SAntonio Quartulli 4653b643de5SAntonio Quartulli continue; 4663b643de5SAntonio Quartulli del: 4673b643de5SAntonio Quartulli list_del(&entry->list); 4683b643de5SAntonio Quartulli kfree(entry); 469155e4e12SJesper Juhl kfree(tt_change_node); 4703b643de5SAntonio Quartulli event_removed = true; 4713b643de5SAntonio Quartulli goto unlock; 4723b643de5SAntonio Quartulli } 4733b643de5SAntonio Quartulli 474a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 475807736f6SSven Eckelmann list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list); 4763b643de5SAntonio Quartulli 4773b643de5SAntonio Quartulli unlock: 478807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 479a73105b8SAntonio Quartulli 4803b643de5SAntonio Quartulli if (event_removed) 481807736f6SSven Eckelmann atomic_dec(&bat_priv->tt.local_changes); 4823b643de5SAntonio Quartulli else 483807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.local_changes); 484a73105b8SAntonio Quartulli } 485a73105b8SAntonio Quartulli 486335fbe0fSMarek Lindner /** 487335fbe0fSMarek Lindner * batadv_tt_len - compute length in bytes of given number of tt changes 488335fbe0fSMarek Lindner * @changes_num: number of tt changes 489335fbe0fSMarek Lindner * 49062fe710fSSven Eckelmann * Return: computed length in bytes. 491335fbe0fSMarek Lindner */ 492335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num) 493a73105b8SAntonio Quartulli { 494335fbe0fSMarek Lindner return changes_num * sizeof(struct batadv_tvlv_tt_change); 495a73105b8SAntonio Quartulli } 496a73105b8SAntonio Quartulli 497298e6e68SAntonio Quartulli /** 498298e6e68SAntonio Quartulli * batadv_tt_entries - compute the number of entries fitting in tt_len bytes 499298e6e68SAntonio Quartulli * @tt_len: available space 500298e6e68SAntonio Quartulli * 50162fe710fSSven Eckelmann * Return: the number of entries. 502298e6e68SAntonio Quartulli */ 5036b5e971aSSven Eckelmann static u16 batadv_tt_entries(u16 tt_len) 504298e6e68SAntonio Quartulli { 505298e6e68SAntonio Quartulli return tt_len / batadv_tt_len(1); 506298e6e68SAntonio Quartulli } 507298e6e68SAntonio Quartulli 508a19d3d85SMarek Lindner /** 509a19d3d85SMarek Lindner * batadv_tt_local_table_transmit_size - calculates the local translation table 510a19d3d85SMarek Lindner * size when transmitted over the air 511a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 512a19d3d85SMarek Lindner * 51362fe710fSSven Eckelmann * Return: local translation table size in bytes. 514a19d3d85SMarek Lindner */ 515a19d3d85SMarek Lindner static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) 516a19d3d85SMarek Lindner { 5174f248cffSSven Eckelmann u16 num_vlan = 0; 5184f248cffSSven Eckelmann u16 tt_local_entries = 0; 519a19d3d85SMarek Lindner struct batadv_softif_vlan *vlan; 520a19d3d85SMarek Lindner int hdr_size; 521a19d3d85SMarek Lindner 522a19d3d85SMarek Lindner rcu_read_lock(); 523a19d3d85SMarek Lindner hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 524a19d3d85SMarek Lindner num_vlan++; 525a19d3d85SMarek Lindner tt_local_entries += atomic_read(&vlan->tt.num_entries); 526a19d3d85SMarek Lindner } 527a19d3d85SMarek Lindner rcu_read_unlock(); 528a19d3d85SMarek Lindner 529a19d3d85SMarek Lindner /* header size of tvlv encapsulated tt response payload */ 530a19d3d85SMarek Lindner hdr_size = sizeof(struct batadv_unicast_tvlv_packet); 531a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_hdr); 532a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_tt_data); 533a19d3d85SMarek Lindner hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data); 534a19d3d85SMarek Lindner 535a19d3d85SMarek Lindner return hdr_size + batadv_tt_len(tt_local_entries); 536a19d3d85SMarek Lindner } 537a19d3d85SMarek Lindner 53856303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv) 539c6c8fea2SSven Eckelmann { 540807736f6SSven Eckelmann if (bat_priv->tt.local_hash) 5415346c35eSSven Eckelmann return 0; 542c6c8fea2SSven Eckelmann 543807736f6SSven Eckelmann bat_priv->tt.local_hash = batadv_hash_new(1024); 544c6c8fea2SSven Eckelmann 545807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 5465346c35eSSven Eckelmann return -ENOMEM; 547c6c8fea2SSven Eckelmann 548dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.local_hash, 549dec05074SAntonio Quartulli &batadv_tt_local_hash_lock_class_key); 550dec05074SAntonio Quartulli 5515346c35eSSven Eckelmann return 0; 552c6c8fea2SSven Eckelmann } 553c6c8fea2SSven Eckelmann 554068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv, 555068ee6e2SAntonio Quartulli struct batadv_tt_global_entry *tt_global, 556068ee6e2SAntonio Quartulli const char *message) 557068ee6e2SAntonio Quartulli { 558068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 55916052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 56016052789SAntonio Quartulli tt_global->common.addr, 56116052789SAntonio Quartulli BATADV_PRINT_VID(tt_global->common.vid), message); 562068ee6e2SAntonio Quartulli 563068ee6e2SAntonio Quartulli batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, 564c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_global->common); 5655dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 566068ee6e2SAntonio Quartulli } 567068ee6e2SAntonio Quartulli 568c018ad3dSAntonio Quartulli /** 569c018ad3dSAntonio Quartulli * batadv_tt_local_add - add a new client to the local table or update an 570c018ad3dSAntonio Quartulli * existing client 571c018ad3dSAntonio Quartulli * @soft_iface: netdev struct of the mesh interface 572c018ad3dSAntonio Quartulli * @addr: the mac address of the client to add 573c018ad3dSAntonio Quartulli * @vid: VLAN identifier 574c018ad3dSAntonio Quartulli * @ifindex: index of the interface where the client is connected to (useful to 575c018ad3dSAntonio Quartulli * identify wireless clients) 5769464d071SAntonio Quartulli * @mark: the value contained in the skb->mark field of the received packet (if 5779464d071SAntonio Quartulli * any) 578a19d3d85SMarek Lindner * 57962fe710fSSven Eckelmann * Return: true if the client was successfully added, false otherwise. 580c018ad3dSAntonio Quartulli */ 5816b5e971aSSven Eckelmann bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, 5826b5e971aSSven Eckelmann unsigned short vid, int ifindex, u32 mark) 583c6c8fea2SSven Eckelmann { 58456303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(soft_iface); 585170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local; 586c5caf4efSLinus Lüssing struct batadv_tt_global_entry *tt_global = NULL; 5872cd45a06SAndrew Lunn struct net *net = dev_net(soft_iface); 58835df3b29SAntonio Quartulli struct batadv_softif_vlan *vlan; 5890c69aeccSAntonio Quartulli struct net_device *in_dev = NULL; 590db08e6e5SSimon Wunderlich struct hlist_head *head; 59156303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 592a19d3d85SMarek Lindner int hash_added, table_size, packet_size_max; 5934f248cffSSven Eckelmann bool ret = false; 5944f248cffSSven Eckelmann bool roamed_back = false; 5956b5e971aSSven Eckelmann u8 remote_flags; 5966b5e971aSSven Eckelmann u32 match_mark; 597c6c8fea2SSven Eckelmann 5980c69aeccSAntonio Quartulli if (ifindex != BATADV_NULL_IFINDEX) 5992cd45a06SAndrew Lunn in_dev = dev_get_by_index(net, ifindex); 6000c69aeccSAntonio Quartulli 601c018ad3dSAntonio Quartulli tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); 602c5caf4efSLinus Lüssing 603c5caf4efSLinus Lüssing if (!is_multicast_ether_addr(addr)) 604c018ad3dSAntonio Quartulli tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); 605c6c8fea2SSven Eckelmann 60647c94655SAntonio Quartulli if (tt_local) { 60747c94655SAntonio Quartulli tt_local->last_seen = jiffies; 608068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { 609068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 61016052789SAntonio Quartulli "Re-adding pending client %pM (vid: %d)\n", 61116052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid)); 612068ee6e2SAntonio Quartulli /* whatever the reason why the PENDING flag was set, 613068ee6e2SAntonio Quartulli * this is a client which was enqueued to be removed in 614068ee6e2SAntonio Quartulli * this orig_interval. Since it popped up again, the 615068ee6e2SAntonio Quartulli * flag can be reset like it was never enqueued 616068ee6e2SAntonio Quartulli */ 61747c94655SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; 618068ee6e2SAntonio Quartulli goto add_event; 619068ee6e2SAntonio Quartulli } 620068ee6e2SAntonio Quartulli 621068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { 622068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 62316052789SAntonio Quartulli "Roaming client %pM (vid: %d) came back to its original location\n", 62416052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid)); 625068ee6e2SAntonio Quartulli /* the ROAM flag is set because this client roamed away 626068ee6e2SAntonio Quartulli * and the node got a roaming_advertisement message. Now 627068ee6e2SAntonio Quartulli * that the client popped up again at its original 628068ee6e2SAntonio Quartulli * location such flag can be unset 629068ee6e2SAntonio Quartulli */ 630068ee6e2SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; 631068ee6e2SAntonio Quartulli roamed_back = true; 632068ee6e2SAntonio Quartulli } 633068ee6e2SAntonio Quartulli goto check_roaming; 634c6c8fea2SSven Eckelmann } 635c6c8fea2SSven Eckelmann 636a19d3d85SMarek Lindner /* Ignore the client if we cannot send it in a full table response. */ 637a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 638a19d3d85SMarek Lindner table_size += batadv_tt_len(1); 639a19d3d85SMarek Lindner packet_size_max = atomic_read(&bat_priv->packet_size_max); 640a19d3d85SMarek Lindner if (table_size > packet_size_max) { 641a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 642a19d3d85SMarek Lindner "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n", 643a19d3d85SMarek Lindner table_size, packet_size_max, addr); 644a19d3d85SMarek Lindner goto out; 645a19d3d85SMarek Lindner } 646a19d3d85SMarek Lindner 64747c94655SAntonio Quartulli tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); 64847c94655SAntonio Quartulli if (!tt_local) 6497683fdc1SAntonio Quartulli goto out; 650a73105b8SAntonio Quartulli 65135df3b29SAntonio Quartulli /* increase the refcounter of the related vlan */ 65235df3b29SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 6530b3dd7dfSSimon Wunderlich if (!vlan) { 6540b3dd7dfSSimon Wunderlich net_ratelimited_function(batadv_info, soft_iface, 6550b3dd7dfSSimon Wunderlich "adding TT local entry %pM to non-existent VLAN %d\n", 6560b3dd7dfSSimon Wunderlich addr, BATADV_PRINT_VID(vid)); 657fd7dec25SSven Eckelmann kfree(tt_local); 658fd7dec25SSven Eckelmann tt_local = NULL; 659354136bcSMarek Lindner goto out; 660fd7dec25SSven Eckelmann } 66135df3b29SAntonio Quartulli 66239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 66316052789SAntonio Quartulli "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", 66416052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid), 6656b5e971aSSven Eckelmann (u8)atomic_read(&bat_priv->tt.vn)); 666c6c8fea2SSven Eckelmann 6678fdd0153SAntonio Quartulli ether_addr_copy(tt_local->common.addr, addr); 6688425ec6aSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 6698425ec6aSAntonio Quartulli * a full table response going out before the next ttvn increment 6708425ec6aSAntonio Quartulli * (consistency check) 6718425ec6aSAntonio Quartulli */ 6728425ec6aSAntonio Quartulli tt_local->common.flags = BATADV_TT_CLIENT_NEW; 673c018ad3dSAntonio Quartulli tt_local->common.vid = vid; 6740c69aeccSAntonio Quartulli if (batadv_is_wifi_netdev(in_dev)) 67547c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 67692dcdf09SSven Eckelmann kref_init(&tt_local->common.refcount); 67792dcdf09SSven Eckelmann kref_get(&tt_local->common.refcount); 67847c94655SAntonio Quartulli tt_local->last_seen = jiffies; 67947c94655SAntonio Quartulli tt_local->common.added_at = tt_local->last_seen; 680a33d970dSSven Eckelmann tt_local->vlan = vlan; 681c6c8fea2SSven Eckelmann 682c5caf4efSLinus Lüssing /* the batman interface mac and multicast addresses should never be 683c5caf4efSLinus Lüssing * purged 684c5caf4efSLinus Lüssing */ 685c5caf4efSLinus Lüssing if (batadv_compare_eth(addr, soft_iface->dev_addr) || 686c5caf4efSLinus Lüssing is_multicast_ether_addr(addr)) 68747c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; 688c6c8fea2SSven Eckelmann 689807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, 690c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_local->common, 69147c94655SAntonio Quartulli &tt_local->common.hash_entry); 69280b3f58cSSimon Wunderlich 69380b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 69480b3f58cSSimon Wunderlich /* remove the reference for the hash */ 69595c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local); 6969c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 69780b3f58cSSimon Wunderlich goto out; 69880b3f58cSSimon Wunderlich } 69980b3f58cSSimon Wunderlich 700068ee6e2SAntonio Quartulli add_event: 7013abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 702ff66c975SAntonio Quartulli 703068ee6e2SAntonio Quartulli check_roaming: 704068ee6e2SAntonio Quartulli /* Check whether it is a roaming, but don't do anything if the roaming 705068ee6e2SAntonio Quartulli * process has already been handled 706068ee6e2SAntonio Quartulli */ 707068ee6e2SAntonio Quartulli if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { 708db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 70947c94655SAntonio Quartulli head = &tt_global->orig_list; 710db08e6e5SSimon Wunderlich rcu_read_lock(); 711b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 71247c94655SAntonio Quartulli batadv_send_roam_adv(bat_priv, tt_global->common.addr, 713c018ad3dSAntonio Quartulli tt_global->common.vid, 714db08e6e5SSimon Wunderlich orig_entry->orig_node); 715db08e6e5SSimon Wunderlich } 716db08e6e5SSimon Wunderlich rcu_read_unlock(); 717068ee6e2SAntonio Quartulli if (roamed_back) { 718068ee6e2SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global, 719068ee6e2SAntonio Quartulli "Roaming canceled"); 720068ee6e2SAntonio Quartulli tt_global = NULL; 721068ee6e2SAntonio Quartulli } else { 722db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 723db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 724db08e6e5SSimon Wunderlich */ 72547c94655SAntonio Quartulli tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; 72647c94655SAntonio Quartulli tt_global->roam_at = jiffies; 7277683fdc1SAntonio Quartulli } 728068ee6e2SAntonio Quartulli } 729068ee6e2SAntonio Quartulli 7303c4f7ab6SAntonio Quartulli /* store the current remote flags before altering them. This helps 7313c4f7ab6SAntonio Quartulli * understanding is flags are changing or not 7323c4f7ab6SAntonio Quartulli */ 7333c4f7ab6SAntonio Quartulli remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK; 734a19d3d85SMarek Lindner 7353c4f7ab6SAntonio Quartulli if (batadv_is_wifi_netdev(in_dev)) 7363c4f7ab6SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 7373c4f7ab6SAntonio Quartulli else 7383c4f7ab6SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; 7393c4f7ab6SAntonio Quartulli 7409464d071SAntonio Quartulli /* check the mark in the skb: if it's equal to the configured 7419464d071SAntonio Quartulli * isolation_mark, it means the packet is coming from an isolated 7429464d071SAntonio Quartulli * non-mesh client 7439464d071SAntonio Quartulli */ 7449464d071SAntonio Quartulli match_mark = (mark & bat_priv->isolation_mark_mask); 7459464d071SAntonio Quartulli if (bat_priv->isolation_mark_mask && 7469464d071SAntonio Quartulli match_mark == bat_priv->isolation_mark) 7479464d071SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA; 7489464d071SAntonio Quartulli else 7499464d071SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA; 7509464d071SAntonio Quartulli 7513c4f7ab6SAntonio Quartulli /* if any "dynamic" flag has been modified, resend an ADD event for this 7523c4f7ab6SAntonio Quartulli * entry so that all the nodes can get the new flags 7533c4f7ab6SAntonio Quartulli */ 7543c4f7ab6SAntonio Quartulli if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK)) 7553c4f7ab6SAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 7563c4f7ab6SAntonio Quartulli 7573c4f7ab6SAntonio Quartulli ret = true; 7587683fdc1SAntonio Quartulli out: 7590c69aeccSAntonio Quartulli if (in_dev) 7600c69aeccSAntonio Quartulli dev_put(in_dev); 76147c94655SAntonio Quartulli if (tt_local) 76295c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local); 76347c94655SAntonio Quartulli if (tt_global) 7645dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 765a19d3d85SMarek Lindner return ret; 766c6c8fea2SSven Eckelmann } 767c6c8fea2SSven Eckelmann 768e1bf0c14SMarek Lindner /** 7697ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send 7707ea7b4a1SAntonio Quartulli * within a TT Response directed to another node 7717ea7b4a1SAntonio Quartulli * @orig_node: originator for which the TT data has to be prepared 7727ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 7737ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 7747ea7b4a1SAntonio Quartulli * changed can be stored 7757ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 7767ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire global TT 7777ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 7787ea7b4a1SAntonio Quartulli * reserved bytes 7797ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 7807ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 7817ea7b4a1SAntonio Quartulli * objects, one per active VLAN served by the originator node. 7827ea7b4a1SAntonio Quartulli * 78362fe710fSSven Eckelmann * Return: the size of the allocated buffer or 0 in case of failure. 7847ea7b4a1SAntonio Quartulli */ 7856b5e971aSSven Eckelmann static u16 7867ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, 7877ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 7887ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 7896b5e971aSSven Eckelmann s32 *tt_len) 7907ea7b4a1SAntonio Quartulli { 7914f248cffSSven Eckelmann u16 num_vlan = 0; 7924f248cffSSven Eckelmann u16 num_entries = 0; 7934f248cffSSven Eckelmann u16 change_offset; 7944f248cffSSven Eckelmann u16 tvlv_len; 7957ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 7967ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 7976b5e971aSSven Eckelmann u8 *tt_change_ptr; 7987ea7b4a1SAntonio Quartulli 7997ea7b4a1SAntonio Quartulli rcu_read_lock(); 800d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 8017ea7b4a1SAntonio Quartulli num_vlan++; 8027ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 8037ea7b4a1SAntonio Quartulli } 8047ea7b4a1SAntonio Quartulli 8057ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 8067ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 8077ea7b4a1SAntonio Quartulli 8087ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 8097ea7b4a1SAntonio Quartulli if (*tt_len < 0) 8107ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 8117ea7b4a1SAntonio Quartulli 8127ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 8137ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 8147ea7b4a1SAntonio Quartulli 8157ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 8167ea7b4a1SAntonio Quartulli if (!*tt_data) { 8177ea7b4a1SAntonio Quartulli *tt_len = 0; 8187ea7b4a1SAntonio Quartulli goto out; 8197ea7b4a1SAntonio Quartulli } 8207ea7b4a1SAntonio Quartulli 8217ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 8227ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); 8237ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 8247ea7b4a1SAntonio Quartulli 8257ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 826d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 8277ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 8287ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 8297ea7b4a1SAntonio Quartulli 8307ea7b4a1SAntonio Quartulli tt_vlan++; 8317ea7b4a1SAntonio Quartulli } 8327ea7b4a1SAntonio Quartulli 8336b5e971aSSven Eckelmann tt_change_ptr = (u8 *)*tt_data + change_offset; 8347ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 8357ea7b4a1SAntonio Quartulli 8367ea7b4a1SAntonio Quartulli out: 8377ea7b4a1SAntonio Quartulli rcu_read_unlock(); 8387ea7b4a1SAntonio Quartulli return tvlv_len; 8397ea7b4a1SAntonio Quartulli } 8407ea7b4a1SAntonio Quartulli 8417ea7b4a1SAntonio Quartulli /** 8427ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this 8437ea7b4a1SAntonio Quartulli * node 8447ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 8457ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 8467ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 8477ea7b4a1SAntonio Quartulli * changes can be stored 8487ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 8497ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire local TT 8507ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 8517ea7b4a1SAntonio Quartulli * reserved bytes 8527ea7b4a1SAntonio Quartulli * 8537ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 8547ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 8557ea7b4a1SAntonio Quartulli * objects, one per active VLAN. 8567ea7b4a1SAntonio Quartulli * 85762fe710fSSven Eckelmann * Return: the size of the allocated buffer or 0 in case of failure. 8587ea7b4a1SAntonio Quartulli */ 8596b5e971aSSven Eckelmann static u16 8607ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, 8617ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 8627ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 8636b5e971aSSven Eckelmann s32 *tt_len) 8647ea7b4a1SAntonio Quartulli { 8657ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 8667ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 8674f248cffSSven Eckelmann u16 num_vlan = 0; 8684f248cffSSven Eckelmann u16 num_entries = 0; 8694f248cffSSven Eckelmann u16 tvlv_len; 8706b5e971aSSven Eckelmann u8 *tt_change_ptr; 8717ea7b4a1SAntonio Quartulli int change_offset; 8727ea7b4a1SAntonio Quartulli 8737ea7b4a1SAntonio Quartulli rcu_read_lock(); 8747ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 8757ea7b4a1SAntonio Quartulli num_vlan++; 8767ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 8777ea7b4a1SAntonio Quartulli } 8787ea7b4a1SAntonio Quartulli 8797ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 8807ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 8817ea7b4a1SAntonio Quartulli 8827ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 8837ea7b4a1SAntonio Quartulli if (*tt_len < 0) 8847ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 8857ea7b4a1SAntonio Quartulli 8867ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 8877ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 8887ea7b4a1SAntonio Quartulli 8897ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 8907ea7b4a1SAntonio Quartulli if (!*tt_data) { 8917ea7b4a1SAntonio Quartulli tvlv_len = 0; 8927ea7b4a1SAntonio Quartulli goto out; 8937ea7b4a1SAntonio Quartulli } 8947ea7b4a1SAntonio Quartulli 8957ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 8967ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn); 8977ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 8987ea7b4a1SAntonio Quartulli 8997ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 9007ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 9017ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 9027ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 9037ea7b4a1SAntonio Quartulli 9047ea7b4a1SAntonio Quartulli tt_vlan++; 9057ea7b4a1SAntonio Quartulli } 9067ea7b4a1SAntonio Quartulli 9076b5e971aSSven Eckelmann tt_change_ptr = (u8 *)*tt_data + change_offset; 9087ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 9097ea7b4a1SAntonio Quartulli 9107ea7b4a1SAntonio Quartulli out: 9117ea7b4a1SAntonio Quartulli rcu_read_unlock(); 9127ea7b4a1SAntonio Quartulli return tvlv_len; 9137ea7b4a1SAntonio Quartulli } 9147ea7b4a1SAntonio Quartulli 9157ea7b4a1SAntonio Quartulli /** 916e1bf0c14SMarek Lindner * batadv_tt_tvlv_container_update - update the translation table tvlv container 917e1bf0c14SMarek Lindner * after local tt changes have been committed 918e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 919e1bf0c14SMarek Lindner */ 920e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) 921c6c8fea2SSven Eckelmann { 922e1bf0c14SMarek Lindner struct batadv_tt_change_node *entry, *safe; 923e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 924e1bf0c14SMarek Lindner struct batadv_tvlv_tt_change *tt_change; 9257ea7b4a1SAntonio Quartulli int tt_diff_len, tt_change_len = 0; 9264f248cffSSven Eckelmann int tt_diff_entries_num = 0; 9274f248cffSSven Eckelmann int tt_diff_entries_count = 0; 9286b5e971aSSven Eckelmann u16 tvlv_len; 929c6c8fea2SSven Eckelmann 9307ea7b4a1SAntonio Quartulli tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); 9317ea7b4a1SAntonio Quartulli tt_diff_len = batadv_tt_len(tt_diff_entries_num); 932be9aa4c1SMarek Lindner 933be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 934be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 935be9aa4c1SMarek Lindner */ 936e1bf0c14SMarek Lindner if (tt_diff_len > bat_priv->soft_iface->mtu) 937e1bf0c14SMarek Lindner tt_diff_len = 0; 938be9aa4c1SMarek Lindner 9397ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, 9407ea7b4a1SAntonio Quartulli &tt_change, &tt_diff_len); 9417ea7b4a1SAntonio Quartulli if (!tvlv_len) 942e1bf0c14SMarek Lindner return; 943be9aa4c1SMarek Lindner 944e1bf0c14SMarek Lindner tt_data->flags = BATADV_TT_OGM_DIFF; 945be9aa4c1SMarek Lindner 946e1bf0c14SMarek Lindner if (tt_diff_len == 0) 947e1bf0c14SMarek Lindner goto container_register; 948be9aa4c1SMarek Lindner 949807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 950807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 951c6c8fea2SSven Eckelmann 952807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 953a73105b8SAntonio Quartulli list) { 954e1bf0c14SMarek Lindner if (tt_diff_entries_count < tt_diff_entries_num) { 955e1bf0c14SMarek Lindner memcpy(tt_change + tt_diff_entries_count, 956e1bf0c14SMarek Lindner &entry->change, 957e1bf0c14SMarek Lindner sizeof(struct batadv_tvlv_tt_change)); 958e1bf0c14SMarek Lindner tt_diff_entries_count++; 959c6c8fea2SSven Eckelmann } 960a73105b8SAntonio Quartulli list_del(&entry->list); 961a73105b8SAntonio Quartulli kfree(entry); 962c6c8fea2SSven Eckelmann } 963807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 964c6c8fea2SSven Eckelmann 965a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 966807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 967807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 968807736f6SSven Eckelmann bat_priv->tt.last_changeset_len = 0; 969807736f6SSven Eckelmann bat_priv->tt.last_changeset = NULL; 970e1bf0c14SMarek Lindner tt_change_len = batadv_tt_len(tt_diff_entries_count); 971be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 972e1bf0c14SMarek Lindner if (tt_diff_entries_count > 0) { 973be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 974a73105b8SAntonio Quartulli * instead of providing the diff 975a73105b8SAntonio Quartulli */ 976e1bf0c14SMarek Lindner bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); 977807736f6SSven Eckelmann if (bat_priv->tt.last_changeset) { 978e1bf0c14SMarek Lindner memcpy(bat_priv->tt.last_changeset, 979e1bf0c14SMarek Lindner tt_change, tt_change_len); 980e1bf0c14SMarek Lindner bat_priv->tt.last_changeset_len = tt_diff_len; 981a73105b8SAntonio Quartulli } 982a73105b8SAntonio Quartulli } 983807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 984c6c8fea2SSven Eckelmann 985e1bf0c14SMarek Lindner container_register: 986e1bf0c14SMarek Lindner batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, 9877ea7b4a1SAntonio Quartulli tvlv_len); 988e1bf0c14SMarek Lindner kfree(tt_data); 989c6c8fea2SSven Eckelmann } 990c6c8fea2SSven Eckelmann 99108c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) 992c6c8fea2SSven Eckelmann { 993c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 99456303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 995807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 99656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 99785766a82SAntonio Quartulli struct batadv_tt_local_entry *tt_local; 99856303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 999c6c8fea2SSven Eckelmann struct hlist_head *head; 10007ea7b4a1SAntonio Quartulli unsigned short vid; 10016b5e971aSSven Eckelmann u32 i; 100285766a82SAntonio Quartulli int last_seen_secs; 100385766a82SAntonio Quartulli int last_seen_msecs; 100485766a82SAntonio Quartulli unsigned long last_seen_jiffies; 100585766a82SAntonio Quartulli bool no_purge; 10066b5e971aSSven Eckelmann u16 np_flag = BATADV_TT_CLIENT_NOPURGE; 1007c6c8fea2SSven Eckelmann 100830da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 100930da63a6SMarek Lindner if (!primary_if) 101032ae9b22SMarek Lindner goto out; 1011c6c8fea2SSven Eckelmann 101286ceb360SSven Eckelmann seq_printf(seq, 10137ea7b4a1SAntonio Quartulli "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", 10146b5e971aSSven Eckelmann net_dev->name, (u8)atomic_read(&bat_priv->tt.vn)); 1015925a6f37SAntonio Quartulli seq_puts(seq, 1016925a6f37SAntonio Quartulli " Client VID Flags Last seen (CRC )\n"); 1017c6c8fea2SSven Eckelmann 1018c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1019c6c8fea2SSven Eckelmann head = &hash->table[i]; 1020c6c8fea2SSven Eckelmann 10217aadf889SMarek Lindner rcu_read_lock(); 1022b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 10237aadf889SMarek Lindner head, hash_entry) { 102485766a82SAntonio Quartulli tt_local = container_of(tt_common_entry, 102585766a82SAntonio Quartulli struct batadv_tt_local_entry, 102685766a82SAntonio Quartulli common); 10277ea7b4a1SAntonio Quartulli vid = tt_common_entry->vid; 102885766a82SAntonio Quartulli last_seen_jiffies = jiffies - tt_local->last_seen; 102985766a82SAntonio Quartulli last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 103085766a82SAntonio Quartulli last_seen_secs = last_seen_msecs / 1000; 103185766a82SAntonio Quartulli last_seen_msecs = last_seen_msecs % 1000; 103285766a82SAntonio Quartulli 103385766a82SAntonio Quartulli no_purge = tt_common_entry->flags & np_flag; 10347ea7b4a1SAntonio Quartulli seq_printf(seq, 1035dd24ddb2SAntonio Quartulli " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n", 103648100bacSAntonio Quartulli tt_common_entry->addr, 103716052789SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 1038a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1039a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 104085766a82SAntonio Quartulli no_purge ? 'P' : '.', 1041a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1042a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_NEW) ? 'N' : '.'), 1043a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1044a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_PENDING) ? 'X' : '.'), 1045a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1046a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1047a2f2b6cdSSven Eckelmann ((tt_common_entry->flags & 1048a2f2b6cdSSven Eckelmann BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1049a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_secs, 10507ea7b4a1SAntonio Quartulli no_purge ? 0 : last_seen_msecs, 1051a33d970dSSven Eckelmann tt_local->vlan->tt.crc); 1052c6c8fea2SSven Eckelmann } 10537aadf889SMarek Lindner rcu_read_unlock(); 1054c6c8fea2SSven Eckelmann } 105532ae9b22SMarek Lindner out: 105632ae9b22SMarek Lindner if (primary_if) 105782047ad7SSven Eckelmann batadv_hardif_put(primary_if); 105830da63a6SMarek Lindner return 0; 1059c6c8fea2SSven Eckelmann } 1060c6c8fea2SSven Eckelmann 106156303d34SSven Eckelmann static void 106256303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv, 106356303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry, 10646b5e971aSSven Eckelmann u16 flags, const char *message) 1065c6c8fea2SSven Eckelmann { 10663abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, flags); 1067c6c8fea2SSven Eckelmann 1068015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 1069015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 10709cfc7bd6SSven Eckelmann * response issued before the net ttvn increment (consistency check) 10719cfc7bd6SSven Eckelmann */ 1072acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; 1073c566dbbeSAntonio Quartulli 107439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 107516052789SAntonio Quartulli "Local tt entry (%pM, vid: %d) pending to be removed: %s\n", 107616052789SAntonio Quartulli tt_local_entry->common.addr, 107716052789SAntonio Quartulli BATADV_PRINT_VID(tt_local_entry->common.vid), message); 1078c6c8fea2SSven Eckelmann } 1079c6c8fea2SSven Eckelmann 10807f91d06cSAntonio Quartulli /** 10817f91d06cSAntonio Quartulli * batadv_tt_local_remove - logically remove an entry from the local table 10827f91d06cSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 10837f91d06cSAntonio Quartulli * @addr: the MAC address of the client to remove 1084c018ad3dSAntonio Quartulli * @vid: VLAN identifier 10857f91d06cSAntonio Quartulli * @message: message to append to the log on deletion 10867f91d06cSAntonio Quartulli * @roaming: true if the deletion is due to a roaming event 10877f91d06cSAntonio Quartulli * 108862fe710fSSven Eckelmann * Return: the flags assigned to the local entry before being deleted 10897f91d06cSAntonio Quartulli */ 10906b5e971aSSven Eckelmann u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, 10916b5e971aSSven Eckelmann unsigned short vid, const char *message, 10926b5e971aSSven Eckelmann bool roaming) 1093c6c8fea2SSven Eckelmann { 1094170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 10956b5e971aSSven Eckelmann u16 flags, curr_flags = BATADV_NO_FLAGS; 1096ef72706aSMarek Lindner void *tt_entry_exists; 1097c6c8fea2SSven Eckelmann 1098c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 10997683fdc1SAntonio Quartulli if (!tt_local_entry) 11007683fdc1SAntonio Quartulli goto out; 11017683fdc1SAntonio Quartulli 11027f91d06cSAntonio Quartulli curr_flags = tt_local_entry->common.flags; 11037f91d06cSAntonio Quartulli 1104acd34afaSSven Eckelmann flags = BATADV_TT_CLIENT_DEL; 1105068ee6e2SAntonio Quartulli /* if this global entry addition is due to a roaming, the node has to 1106068ee6e2SAntonio Quartulli * mark the local entry as "roamed" in order to correctly reroute 1107068ee6e2SAntonio Quartulli * packets later 1108068ee6e2SAntonio Quartulli */ 11097c1fd91dSAntonio Quartulli if (roaming) { 1110acd34afaSSven Eckelmann flags |= BATADV_TT_CLIENT_ROAM; 11117c1fd91dSAntonio Quartulli /* mark the local client as ROAMed */ 11127c1fd91dSAntonio Quartulli tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 11137c1fd91dSAntonio Quartulli } 111442d0b044SSven Eckelmann 1115068ee6e2SAntonio Quartulli if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { 1116068ee6e2SAntonio Quartulli batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, 1117068ee6e2SAntonio Quartulli message); 1118068ee6e2SAntonio Quartulli goto out; 1119068ee6e2SAntonio Quartulli } 1120068ee6e2SAntonio Quartulli /* if this client has been added right now, it is possible to 1121068ee6e2SAntonio Quartulli * immediately purge it 1122068ee6e2SAntonio Quartulli */ 11233abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); 1124ef72706aSMarek Lindner 1125ef72706aSMarek Lindner tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, 1126ef72706aSMarek Lindner batadv_compare_tt, 1127ef72706aSMarek Lindner batadv_choose_tt, 1128ef72706aSMarek Lindner &tt_local_entry->common); 1129ef72706aSMarek Lindner if (!tt_entry_exists) 1130ef72706aSMarek Lindner goto out; 1131ef72706aSMarek Lindner 1132ef72706aSMarek Lindner /* extra call to free the local tt entry */ 113395c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 11347f91d06cSAntonio Quartulli 11357683fdc1SAntonio Quartulli out: 11367683fdc1SAntonio Quartulli if (tt_local_entry) 113795c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 11387f91d06cSAntonio Quartulli 11397f91d06cSAntonio Quartulli return curr_flags; 1140c6c8fea2SSven Eckelmann } 1141c6c8fea2SSven Eckelmann 1142a19d3d85SMarek Lindner /** 1143a19d3d85SMarek Lindner * batadv_tt_local_purge_list - purge inactive tt local entries 1144a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1145a19d3d85SMarek Lindner * @head: pointer to the list containing the local tt entries 1146a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1147a19d3d85SMarek Lindner * inactive or not 1148a19d3d85SMarek Lindner */ 114956303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 1150a19d3d85SMarek Lindner struct hlist_head *head, 1151a19d3d85SMarek Lindner int timeout) 1152c6c8fea2SSven Eckelmann { 115356303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 115456303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1155b67bfe0dSSasha Levin struct hlist_node *node_tmp; 1156acd34afaSSven Eckelmann 1157b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, 1158acd34afaSSven Eckelmann hash_entry) { 1159acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common_entry, 116056303d34SSven Eckelmann struct batadv_tt_local_entry, 116156303d34SSven Eckelmann common); 1162acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) 1163acd34afaSSven Eckelmann continue; 1164acd34afaSSven Eckelmann 1165acd34afaSSven Eckelmann /* entry already marked for deletion */ 1166acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 1167acd34afaSSven Eckelmann continue; 1168acd34afaSSven Eckelmann 1169a19d3d85SMarek Lindner if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) 1170acd34afaSSven Eckelmann continue; 1171acd34afaSSven Eckelmann 1172acd34afaSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 1173acd34afaSSven Eckelmann BATADV_TT_CLIENT_DEL, "timed out"); 1174acd34afaSSven Eckelmann } 1175acd34afaSSven Eckelmann } 1176acd34afaSSven Eckelmann 1177a19d3d85SMarek Lindner /** 1178a19d3d85SMarek Lindner * batadv_tt_local_purge - purge inactive tt local entries 1179a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1180a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1181a19d3d85SMarek Lindner * inactive or not 1182a19d3d85SMarek Lindner */ 1183a19d3d85SMarek Lindner static void batadv_tt_local_purge(struct batadv_priv *bat_priv, 1184a19d3d85SMarek Lindner int timeout) 1185acd34afaSSven Eckelmann { 1186807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 1187c6c8fea2SSven Eckelmann struct hlist_head *head; 11887683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 11896b5e971aSSven Eckelmann u32 i; 1190c6c8fea2SSven Eckelmann 1191c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1192c6c8fea2SSven Eckelmann head = &hash->table[i]; 11937683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1194c6c8fea2SSven Eckelmann 11957683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1196a19d3d85SMarek Lindner batadv_tt_local_purge_list(bat_priv, head, timeout); 11977683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1198c6c8fea2SSven Eckelmann } 1199c6c8fea2SSven Eckelmann } 1200c6c8fea2SSven Eckelmann 120156303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) 1202c6c8fea2SSven Eckelmann { 12035bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 1204a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 120556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 120656303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 1207b67bfe0dSSasha Levin struct hlist_node *node_tmp; 12087683fdc1SAntonio Quartulli struct hlist_head *head; 12096b5e971aSSven Eckelmann u32 i; 1210a73105b8SAntonio Quartulli 1211807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 1212c6c8fea2SSven Eckelmann return; 1213c6c8fea2SSven Eckelmann 1214807736f6SSven Eckelmann hash = bat_priv->tt.local_hash; 1215a73105b8SAntonio Quartulli 1216a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1217a73105b8SAntonio Quartulli head = &hash->table[i]; 1218a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 1219a73105b8SAntonio Quartulli 1220a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 1221b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 1222a73105b8SAntonio Quartulli head, hash_entry) { 1223b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 122456303d34SSven Eckelmann tt_local = container_of(tt_common_entry, 122556303d34SSven Eckelmann struct batadv_tt_local_entry, 122648100bacSAntonio Quartulli common); 122735df3b29SAntonio Quartulli 122895c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local); 1229a73105b8SAntonio Quartulli } 1230a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 1231a73105b8SAntonio Quartulli } 1232a73105b8SAntonio Quartulli 12331a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 1234a73105b8SAntonio Quartulli 1235807736f6SSven Eckelmann bat_priv->tt.local_hash = NULL; 1236c6c8fea2SSven Eckelmann } 1237c6c8fea2SSven Eckelmann 123856303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv) 1239c6c8fea2SSven Eckelmann { 1240807736f6SSven Eckelmann if (bat_priv->tt.global_hash) 12415346c35eSSven Eckelmann return 0; 1242c6c8fea2SSven Eckelmann 1243807736f6SSven Eckelmann bat_priv->tt.global_hash = batadv_hash_new(1024); 1244c6c8fea2SSven Eckelmann 1245807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 12465346c35eSSven Eckelmann return -ENOMEM; 1247c6c8fea2SSven Eckelmann 1248dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.global_hash, 1249dec05074SAntonio Quartulli &batadv_tt_global_hash_lock_class_key); 1250dec05074SAntonio Quartulli 12515346c35eSSven Eckelmann return 0; 1252c6c8fea2SSven Eckelmann } 1253c6c8fea2SSven Eckelmann 125456303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) 1255a73105b8SAntonio Quartulli { 125656303d34SSven Eckelmann struct batadv_tt_change_node *entry, *safe; 1257a73105b8SAntonio Quartulli 1258807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 1259a73105b8SAntonio Quartulli 1260807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 1261a73105b8SAntonio Quartulli list) { 1262a73105b8SAntonio Quartulli list_del(&entry->list); 1263a73105b8SAntonio Quartulli kfree(entry); 1264a73105b8SAntonio Quartulli } 1265a73105b8SAntonio Quartulli 1266807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 1267807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 1268a73105b8SAntonio Quartulli } 1269a73105b8SAntonio Quartulli 127062fe710fSSven Eckelmann /** 1271d15cd622SAntonio Quartulli * batadv_tt_global_orig_entry_find - find a TT orig_list_entry 1272d15cd622SAntonio Quartulli * @entry: the TT global entry where the orig_list_entry has to be 1273d15cd622SAntonio Quartulli * extracted from 1274d15cd622SAntonio Quartulli * @orig_node: the originator for which the orig_list_entry has to be found 127562fe710fSSven Eckelmann * 1276d15cd622SAntonio Quartulli * retrieve the orig_tt_list_entry belonging to orig_node from the 1277d657e621SAntonio Quartulli * batadv_tt_global_entry list 1278d657e621SAntonio Quartulli * 127962fe710fSSven Eckelmann * Return: it with an increased refcounter, NULL if not found 1280d657e621SAntonio Quartulli */ 1281d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry * 1282d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, 1283d657e621SAntonio Quartulli const struct batadv_orig_node *orig_node) 1284d657e621SAntonio Quartulli { 1285d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; 1286d657e621SAntonio Quartulli const struct hlist_head *head; 1287d657e621SAntonio Quartulli 1288d657e621SAntonio Quartulli rcu_read_lock(); 1289d657e621SAntonio Quartulli head = &entry->orig_list; 1290b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { 1291d657e621SAntonio Quartulli if (tmp_orig_entry->orig_node != orig_node) 1292d657e621SAntonio Quartulli continue; 12936e8ef69dSSven Eckelmann if (!kref_get_unless_zero(&tmp_orig_entry->refcount)) 1294d657e621SAntonio Quartulli continue; 1295d657e621SAntonio Quartulli 1296d657e621SAntonio Quartulli orig_entry = tmp_orig_entry; 1297d657e621SAntonio Quartulli break; 1298d657e621SAntonio Quartulli } 1299d657e621SAntonio Quartulli rcu_read_unlock(); 1300d657e621SAntonio Quartulli 1301d657e621SAntonio Quartulli return orig_entry; 1302d657e621SAntonio Quartulli } 1303d657e621SAntonio Quartulli 130462fe710fSSven Eckelmann /** 1305d15cd622SAntonio Quartulli * batadv_tt_global_entry_has_orig - check if a TT global entry is also handled 1306d15cd622SAntonio Quartulli * by a given originator 1307d15cd622SAntonio Quartulli * @entry: the TT global entry to check 1308d15cd622SAntonio Quartulli * @orig_node: the originator to search in the list 130962fe710fSSven Eckelmann * 131062fe710fSSven Eckelmann * find out if an orig_node is already in the list of a tt_global_entry. 131162fe710fSSven Eckelmann * 131262fe710fSSven Eckelmann * Return: true if found, false otherwise 1313db08e6e5SSimon Wunderlich */ 131456303d34SSven Eckelmann static bool 131556303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, 131656303d34SSven Eckelmann const struct batadv_orig_node *orig_node) 1317db08e6e5SSimon Wunderlich { 1318d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *orig_entry; 1319db08e6e5SSimon Wunderlich bool found = false; 1320db08e6e5SSimon Wunderlich 1321d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); 1322d657e621SAntonio Quartulli if (orig_entry) { 1323db08e6e5SSimon Wunderlich found = true; 13247e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(orig_entry); 1325db08e6e5SSimon Wunderlich } 1326d657e621SAntonio Quartulli 1327db08e6e5SSimon Wunderlich return found; 1328db08e6e5SSimon Wunderlich } 1329db08e6e5SSimon Wunderlich 1330a513088dSSven Eckelmann static void 1331d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, 133256303d34SSven Eckelmann struct batadv_orig_node *orig_node, int ttvn) 1333db08e6e5SSimon Wunderlich { 133456303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1335db08e6e5SSimon Wunderlich 1336d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); 133730cfd02bSAntonio Quartulli if (orig_entry) { 133830cfd02bSAntonio Quartulli /* refresh the ttvn: the current value could be a bogus one that 133930cfd02bSAntonio Quartulli * was added during a "temporary client detection" 134030cfd02bSAntonio Quartulli */ 134130cfd02bSAntonio Quartulli orig_entry->ttvn = ttvn; 1342d657e621SAntonio Quartulli goto out; 134330cfd02bSAntonio Quartulli } 1344d657e621SAntonio Quartulli 1345db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 1346db08e6e5SSimon Wunderlich if (!orig_entry) 1347d657e621SAntonio Quartulli goto out; 1348db08e6e5SSimon Wunderlich 1349db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 13507c124391SSven Eckelmann kref_get(&orig_node->refcount); 13517ea7b4a1SAntonio Quartulli batadv_tt_global_size_inc(orig_node, tt_global->common.vid); 1352db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 1353db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 13546e8ef69dSSven Eckelmann kref_init(&orig_entry->refcount); 13556e8ef69dSSven Eckelmann kref_get(&orig_entry->refcount); 1356db08e6e5SSimon Wunderlich 1357d657e621SAntonio Quartulli spin_lock_bh(&tt_global->list_lock); 1358db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 1359d657e621SAntonio Quartulli &tt_global->orig_list); 1360d657e621SAntonio Quartulli spin_unlock_bh(&tt_global->list_lock); 13611d8ab8d3SLinus Lüssing atomic_inc(&tt_global->orig_list_count); 13621d8ab8d3SLinus Lüssing 1363d657e621SAntonio Quartulli out: 1364d657e621SAntonio Quartulli if (orig_entry) 13657e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(orig_entry); 1366db08e6e5SSimon Wunderlich } 1367db08e6e5SSimon Wunderlich 1368d4ff40f6SAntonio Quartulli /** 1369d4ff40f6SAntonio Quartulli * batadv_tt_global_add - add a new TT global entry or update an existing one 1370d4ff40f6SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1371d4ff40f6SAntonio Quartulli * @orig_node: the originator announcing the client 1372d4ff40f6SAntonio Quartulli * @tt_addr: the mac address of the non-mesh client 1373c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1374d4ff40f6SAntonio Quartulli * @flags: TT flags that have to be set for this non-mesh client 1375d4ff40f6SAntonio Quartulli * @ttvn: the tt version number ever announcing this non-mesh client 1376d4ff40f6SAntonio Quartulli * 1377d4ff40f6SAntonio Quartulli * Add a new TT global entry for the given originator. If the entry already 1378d4ff40f6SAntonio Quartulli * exists add a new reference to the given originator (a global entry can have 1379d4ff40f6SAntonio Quartulli * references to multiple originators) and adjust the flags attribute to reflect 1380d4ff40f6SAntonio Quartulli * the function argument. 1381d4ff40f6SAntonio Quartulli * If a TT local entry exists for this non-mesh client remove it. 1382d4ff40f6SAntonio Quartulli * 1383d4ff40f6SAntonio Quartulli * The caller must hold orig_node refcount. 13841e5d49fcSAntonio Quartulli * 138562fe710fSSven Eckelmann * Return: true if the new entry has been added, false otherwise 1386d4ff40f6SAntonio Quartulli */ 13871e5d49fcSAntonio Quartulli static bool batadv_tt_global_add(struct batadv_priv *bat_priv, 138856303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1389c018ad3dSAntonio Quartulli const unsigned char *tt_addr, 13906b5e971aSSven Eckelmann unsigned short vid, u16 flags, u8 ttvn) 1391c6c8fea2SSven Eckelmann { 1392170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 1393170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 13941e5d49fcSAntonio Quartulli bool ret = false; 139580b3f58cSSimon Wunderlich int hash_added; 139656303d34SSven Eckelmann struct batadv_tt_common_entry *common; 13976b5e971aSSven Eckelmann u16 local_flags; 1398c6c8fea2SSven Eckelmann 1399cfd4f757SAntonio Quartulli /* ignore global entries from backbone nodes */ 1400cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) 1401cfd4f757SAntonio Quartulli return true; 1402cfd4f757SAntonio Quartulli 1403c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); 1404c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid); 1405068ee6e2SAntonio Quartulli 1406068ee6e2SAntonio Quartulli /* if the node already has a local client for this entry, it has to wait 1407068ee6e2SAntonio Quartulli * for a roaming advertisement instead of manually messing up the global 1408068ee6e2SAntonio Quartulli * table 1409068ee6e2SAntonio Quartulli */ 1410068ee6e2SAntonio Quartulli if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && 1411068ee6e2SAntonio Quartulli !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) 1412068ee6e2SAntonio Quartulli goto out; 1413c6c8fea2SSven Eckelmann 14142dafb49dSAntonio Quartulli if (!tt_global_entry) { 1415d4f44692SAntonio Quartulli tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); 14162dafb49dSAntonio Quartulli if (!tt_global_entry) 14177683fdc1SAntonio Quartulli goto out; 14187683fdc1SAntonio Quartulli 1419c0a55929SSven Eckelmann common = &tt_global_entry->common; 14208fdd0153SAntonio Quartulli ether_addr_copy(common->addr, tt_addr); 1421c018ad3dSAntonio Quartulli common->vid = vid; 1422db08e6e5SSimon Wunderlich 1423d4f44692SAntonio Quartulli common->flags = flags; 1424cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1425fdf79320SAntonio Quartulli /* node must store current time in case of roaming. This is 1426fdf79320SAntonio Quartulli * needed to purge this entry out on timeout (if nobody claims 1427fdf79320SAntonio Quartulli * it) 1428fdf79320SAntonio Quartulli */ 1429fdf79320SAntonio Quartulli if (flags & BATADV_TT_CLIENT_ROAM) 1430fdf79320SAntonio Quartulli tt_global_entry->roam_at = jiffies; 143192dcdf09SSven Eckelmann kref_init(&common->refcount); 143292dcdf09SSven Eckelmann kref_get(&common->refcount); 143330cfd02bSAntonio Quartulli common->added_at = jiffies; 1434db08e6e5SSimon Wunderlich 1435db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 14361d8ab8d3SLinus Lüssing atomic_set(&tt_global_entry->orig_list_count, 0); 1437db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 14387683fdc1SAntonio Quartulli 1439807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.global_hash, 1440a513088dSSven Eckelmann batadv_compare_tt, 1441c018ad3dSAntonio Quartulli batadv_choose_tt, common, 1442a513088dSSven Eckelmann &common->hash_entry); 144380b3f58cSSimon Wunderlich 144480b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 144580b3f58cSSimon Wunderlich /* remove the reference for the hash */ 14465dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 144780b3f58cSSimon Wunderlich goto out_remove; 144880b3f58cSSimon Wunderlich } 1449a73105b8SAntonio Quartulli } else { 1450068ee6e2SAntonio Quartulli common = &tt_global_entry->common; 145130cfd02bSAntonio Quartulli /* If there is already a global entry, we can use this one for 145230cfd02bSAntonio Quartulli * our processing. 1453068ee6e2SAntonio Quartulli * But if we are trying to add a temporary client then here are 1454068ee6e2SAntonio Quartulli * two options at this point: 1455068ee6e2SAntonio Quartulli * 1) the global client is not a temporary client: the global 1456068ee6e2SAntonio Quartulli * client has to be left as it is, temporary information 1457068ee6e2SAntonio Quartulli * should never override any already known client state 1458068ee6e2SAntonio Quartulli * 2) the global client is a temporary client: purge the 1459068ee6e2SAntonio Quartulli * originator list and add the new one orig_entry 146030cfd02bSAntonio Quartulli */ 1461068ee6e2SAntonio Quartulli if (flags & BATADV_TT_CLIENT_TEMP) { 1462068ee6e2SAntonio Quartulli if (!(common->flags & BATADV_TT_CLIENT_TEMP)) 146330cfd02bSAntonio Quartulli goto out; 1464068ee6e2SAntonio Quartulli if (batadv_tt_global_entry_has_orig(tt_global_entry, 1465068ee6e2SAntonio Quartulli orig_node)) 1466068ee6e2SAntonio Quartulli goto out_remove; 1467068ee6e2SAntonio Quartulli batadv_tt_global_del_orig_list(tt_global_entry); 1468068ee6e2SAntonio Quartulli goto add_orig_entry; 1469068ee6e2SAntonio Quartulli } 147030cfd02bSAntonio Quartulli 147130cfd02bSAntonio Quartulli /* if the client was temporary added before receiving the first 1472a6cb3909SSimon Wunderlich * OGM announcing it, we have to clear the TEMP flag. Also, 1473a6cb3909SSimon Wunderlich * remove the previous temporary orig node and re-add it 1474a6cb3909SSimon Wunderlich * if required. If the orig entry changed, the new one which 1475a6cb3909SSimon Wunderlich * is a non-temporary entry is preferred. 147630cfd02bSAntonio Quartulli */ 1477a6cb3909SSimon Wunderlich if (common->flags & BATADV_TT_CLIENT_TEMP) { 1478a6cb3909SSimon Wunderlich batadv_tt_global_del_orig_list(tt_global_entry); 1479068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_TEMP; 1480a6cb3909SSimon Wunderlich } 1481db08e6e5SSimon Wunderlich 1482e9c00136SAntonio Quartulli /* the change can carry possible "attribute" flags like the 1483e9c00136SAntonio Quartulli * TT_CLIENT_WIFI, therefore they have to be copied in the 1484e9c00136SAntonio Quartulli * client entry 1485e9c00136SAntonio Quartulli */ 1486ad7e2c46SSimon Wunderlich common->flags |= flags; 1487e9c00136SAntonio Quartulli 1488acd34afaSSven Eckelmann /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 1489acd34afaSSven Eckelmann * one originator left in the list and we previously received a 1490db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 1491db08e6e5SSimon Wunderlich * 1492db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 1493db08e6e5SSimon Wunderlich * new one. 1494db08e6e5SSimon Wunderlich */ 1495068ee6e2SAntonio Quartulli if (common->flags & BATADV_TT_CLIENT_ROAM) { 1496a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1497068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_ROAM; 1498cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1499c6c8fea2SSven Eckelmann } 1500db08e6e5SSimon Wunderlich } 1501068ee6e2SAntonio Quartulli add_orig_entry: 150230cfd02bSAntonio Quartulli /* add the new orig_entry (if needed) or update it */ 1503d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); 1504db08e6e5SSimon Wunderlich 150539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 150616052789SAntonio Quartulli "Creating new global tt entry: %pM (vid: %d, via %pM)\n", 150716052789SAntonio Quartulli common->addr, BATADV_PRINT_VID(common->vid), 150816052789SAntonio Quartulli orig_node->orig); 15091e5d49fcSAntonio Quartulli ret = true; 1510a73105b8SAntonio Quartulli 151180b3f58cSSimon Wunderlich out_remove: 1512c5caf4efSLinus Lüssing /* Do not remove multicast addresses from the local hash on 1513c5caf4efSLinus Lüssing * global additions 1514c5caf4efSLinus Lüssing */ 1515c5caf4efSLinus Lüssing if (is_multicast_ether_addr(tt_addr)) 1516c5caf4efSLinus Lüssing goto out; 15177f91d06cSAntonio Quartulli 1518c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 1519c018ad3dSAntonio Quartulli local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, 1520acd34afaSSven Eckelmann "global tt received", 1521c1d07431SAntonio Quartulli flags & BATADV_TT_CLIENT_ROAM); 15227f91d06cSAntonio Quartulli tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; 15237f91d06cSAntonio Quartulli 1524068ee6e2SAntonio Quartulli if (!(flags & BATADV_TT_CLIENT_ROAM)) 1525068ee6e2SAntonio Quartulli /* this is a normal global add. Therefore the client is not in a 1526068ee6e2SAntonio Quartulli * roaming state anymore. 1527068ee6e2SAntonio Quartulli */ 1528068ee6e2SAntonio Quartulli tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 1529068ee6e2SAntonio Quartulli 15307683fdc1SAntonio Quartulli out: 15317683fdc1SAntonio Quartulli if (tt_global_entry) 15325dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 1533068ee6e2SAntonio Quartulli if (tt_local_entry) 153495c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 15357683fdc1SAntonio Quartulli return ret; 1536c6c8fea2SSven Eckelmann } 1537c6c8fea2SSven Eckelmann 15381b371d13SSimon Wunderlich /** 15391b371d13SSimon Wunderlich * batadv_transtable_best_orig - Get best originator list entry from tt entry 15404627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1541981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be analyzed 1542981d8900SSven Eckelmann * 1543981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 154462fe710fSSven Eckelmann * Return: best originator list entry or NULL on errors. 1545981d8900SSven Eckelmann */ 1546981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry * 15474627456aSAntonio Quartulli batadv_transtable_best_orig(struct batadv_priv *bat_priv, 15484627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry) 1549981d8900SSven Eckelmann { 15504627456aSAntonio Quartulli struct batadv_neigh_node *router, *best_router = NULL; 15514627456aSAntonio Quartulli struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; 1552981d8900SSven Eckelmann struct hlist_head *head; 1553981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; 1554981d8900SSven Eckelmann 1555981d8900SSven Eckelmann head = &tt_global_entry->orig_list; 1556b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 15577351a482SSimon Wunderlich router = batadv_orig_router_get(orig_entry->orig_node, 15587351a482SSimon Wunderlich BATADV_IF_DEFAULT); 1559981d8900SSven Eckelmann if (!router) 1560981d8900SSven Eckelmann continue; 1561981d8900SSven Eckelmann 15624627456aSAntonio Quartulli if (best_router && 156389652331SSimon Wunderlich bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, 156489652331SSimon Wunderlich best_router, BATADV_IF_DEFAULT) <= 0) { 156525bb2509SSven Eckelmann batadv_neigh_node_put(router); 15664627456aSAntonio Quartulli continue; 1567981d8900SSven Eckelmann } 1568981d8900SSven Eckelmann 15694627456aSAntonio Quartulli /* release the refcount for the "old" best */ 15704627456aSAntonio Quartulli if (best_router) 157125bb2509SSven Eckelmann batadv_neigh_node_put(best_router); 15724627456aSAntonio Quartulli 15734627456aSAntonio Quartulli best_entry = orig_entry; 15744627456aSAntonio Quartulli best_router = router; 1575981d8900SSven Eckelmann } 1576981d8900SSven Eckelmann 15774627456aSAntonio Quartulli if (best_router) 157825bb2509SSven Eckelmann batadv_neigh_node_put(best_router); 15794627456aSAntonio Quartulli 1580981d8900SSven Eckelmann return best_entry; 1581981d8900SSven Eckelmann } 1582981d8900SSven Eckelmann 15831b371d13SSimon Wunderlich /** 15841b371d13SSimon Wunderlich * batadv_tt_global_print_entry - print all orig nodes who announce the address 1585981d8900SSven Eckelmann * for this global entry 15864627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1587981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be printed 1588981d8900SSven Eckelmann * @seq: debugfs table seq_file struct 1589981d8900SSven Eckelmann * 1590981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 1591db08e6e5SSimon Wunderlich */ 1592a513088dSSven Eckelmann static void 15934627456aSAntonio Quartulli batadv_tt_global_print_entry(struct batadv_priv *bat_priv, 15944627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry, 1595db08e6e5SSimon Wunderlich struct seq_file *seq) 1596db08e6e5SSimon Wunderlich { 1597981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry; 159856303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 15997ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 16007ea7b4a1SAntonio Quartulli struct hlist_head *head; 16016b5e971aSSven Eckelmann u8 last_ttvn; 16026b5e971aSSven Eckelmann u16 flags; 1603db08e6e5SSimon Wunderlich 1604db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 1605981d8900SSven Eckelmann flags = tt_common_entry->flags; 1606981d8900SSven Eckelmann 16074627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 1608981d8900SSven Eckelmann if (best_entry) { 16097ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(best_entry->orig_node, 16107ea7b4a1SAntonio Quartulli tt_common_entry->vid); 16117ea7b4a1SAntonio Quartulli if (!vlan) { 16127ea7b4a1SAntonio Quartulli seq_printf(seq, 16137ea7b4a1SAntonio Quartulli " * Cannot retrieve VLAN %d for originator %pM\n", 16147ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 16157ea7b4a1SAntonio Quartulli best_entry->orig_node->orig); 16167ea7b4a1SAntonio Quartulli goto print_list; 16177ea7b4a1SAntonio Quartulli } 16187ea7b4a1SAntonio Quartulli 1619981d8900SSven Eckelmann last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); 1620f9d8a537SAntonio Quartulli seq_printf(seq, 1621dd24ddb2SAntonio Quartulli " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1622981d8900SSven Eckelmann '*', tt_global_entry->common.addr, 162316052789SAntonio Quartulli BATADV_PRINT_VID(tt_global_entry->common.vid), 1624981d8900SSven Eckelmann best_entry->ttvn, best_entry->orig_node->orig, 16257ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1626a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 1627a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1628a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1629a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.')); 16307ea7b4a1SAntonio Quartulli 163121754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 1632981d8900SSven Eckelmann } 1633db08e6e5SSimon Wunderlich 16347ea7b4a1SAntonio Quartulli print_list: 1635db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1636db08e6e5SSimon Wunderlich 1637b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1638981d8900SSven Eckelmann if (best_entry == orig_entry) 1639981d8900SSven Eckelmann continue; 1640981d8900SSven Eckelmann 16417ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, 16427ea7b4a1SAntonio Quartulli tt_common_entry->vid); 16437ea7b4a1SAntonio Quartulli if (!vlan) { 16447ea7b4a1SAntonio Quartulli seq_printf(seq, 16457ea7b4a1SAntonio Quartulli " + Cannot retrieve VLAN %d for originator %pM\n", 16467ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 16477ea7b4a1SAntonio Quartulli orig_entry->orig_node->orig); 16487ea7b4a1SAntonio Quartulli continue; 16497ea7b4a1SAntonio Quartulli } 16507ea7b4a1SAntonio Quartulli 1651db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 165216052789SAntonio Quartulli seq_printf(seq, 1653dd24ddb2SAntonio Quartulli " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1654981d8900SSven Eckelmann '+', tt_global_entry->common.addr, 165516052789SAntonio Quartulli BATADV_PRINT_VID(tt_global_entry->common.vid), 1656981d8900SSven Eckelmann orig_entry->ttvn, orig_entry->orig_node->orig, 16577ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1658a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ROAM) ? 'R' : '.'), 1659a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_WIFI) ? 'W' : '.'), 1660a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), 1661a2f2b6cdSSven Eckelmann ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.')); 16627ea7b4a1SAntonio Quartulli 166321754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 1664db08e6e5SSimon Wunderlich } 1665db08e6e5SSimon Wunderlich } 1666db08e6e5SSimon Wunderlich 166708c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 1668c6c8fea2SSven Eckelmann { 1669c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 167056303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 1671807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 167256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 167356303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 167456303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 1675c6c8fea2SSven Eckelmann struct hlist_head *head; 16766b5e971aSSven Eckelmann u32 i; 1677c6c8fea2SSven Eckelmann 167830da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 167930da63a6SMarek Lindner if (!primary_if) 168032ae9b22SMarek Lindner goto out; 1681c6c8fea2SSven Eckelmann 16822dafb49dSAntonio Quartulli seq_printf(seq, 16832dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 1684c6c8fea2SSven Eckelmann net_dev->name); 1685925a6f37SAntonio Quartulli seq_puts(seq, 1686925a6f37SAntonio Quartulli " Client VID (TTVN) Originator (Curr TTVN) (CRC ) Flags\n"); 1687c6c8fea2SSven Eckelmann 1688c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1689c6c8fea2SSven Eckelmann head = &hash->table[i]; 1690c6c8fea2SSven Eckelmann 16917aadf889SMarek Lindner rcu_read_lock(); 1692b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 16937aadf889SMarek Lindner head, hash_entry) { 169456303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 169556303d34SSven Eckelmann struct batadv_tt_global_entry, 169648100bacSAntonio Quartulli common); 16974627456aSAntonio Quartulli batadv_tt_global_print_entry(bat_priv, tt_global, seq); 1698c6c8fea2SSven Eckelmann } 16997aadf889SMarek Lindner rcu_read_unlock(); 1700c6c8fea2SSven Eckelmann } 170132ae9b22SMarek Lindner out: 170232ae9b22SMarek Lindner if (primary_if) 170382047ad7SSven Eckelmann batadv_hardif_put(primary_if); 170430da63a6SMarek Lindner return 0; 1705c6c8fea2SSven Eckelmann } 1706c6c8fea2SSven Eckelmann 17071d8ab8d3SLinus Lüssing /** 1708433ff98fSMarek Lindner * _batadv_tt_global_del_orig_entry - remove and free an orig_entry 17091d8ab8d3SLinus Lüssing * @tt_global_entry: the global entry to remove the orig_entry from 17101d8ab8d3SLinus Lüssing * @orig_entry: the orig entry to remove and free 17111d8ab8d3SLinus Lüssing * 17121d8ab8d3SLinus Lüssing * Remove an orig_entry from its list in the given tt_global_entry and 17131d8ab8d3SLinus Lüssing * free this orig_entry afterwards. 1714433ff98fSMarek Lindner * 1715433ff98fSMarek Lindner * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is 1716433ff98fSMarek Lindner * part of a list. 17171d8ab8d3SLinus Lüssing */ 17181d8ab8d3SLinus Lüssing static void 1719433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, 17201d8ab8d3SLinus Lüssing struct batadv_tt_orig_list_entry *orig_entry) 17211d8ab8d3SLinus Lüssing { 17222c72d655SSven Eckelmann lockdep_assert_held(&tt_global_entry->list_lock); 17232c72d655SSven Eckelmann 17241d8ab8d3SLinus Lüssing batadv_tt_global_size_dec(orig_entry->orig_node, 17251d8ab8d3SLinus Lüssing tt_global_entry->common.vid); 17261d8ab8d3SLinus Lüssing atomic_dec(&tt_global_entry->orig_list_count); 1727433ff98fSMarek Lindner /* requires holding tt_global_entry->list_lock and orig_entry->list 1728433ff98fSMarek Lindner * being part of a list 1729433ff98fSMarek Lindner */ 17301d8ab8d3SLinus Lüssing hlist_del_rcu(&orig_entry->list); 17317e2366c6SSven Eckelmann batadv_tt_orig_list_entry_put(orig_entry); 17321d8ab8d3SLinus Lüssing } 17331d8ab8d3SLinus Lüssing 1734db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 1735a513088dSSven Eckelmann static void 173656303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) 1737db08e6e5SSimon Wunderlich { 1738db08e6e5SSimon Wunderlich struct hlist_head *head; 1739b67bfe0dSSasha Levin struct hlist_node *safe; 174056303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1741db08e6e5SSimon Wunderlich 1742db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1743db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 17441d8ab8d3SLinus Lüssing hlist_for_each_entry_safe(orig_entry, safe, head, list) 1745433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); 1746db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1747db08e6e5SSimon Wunderlich } 1748db08e6e5SSimon Wunderlich 17491d8ab8d3SLinus Lüssing /** 17501d8ab8d3SLinus Lüssing * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry 17511d8ab8d3SLinus Lüssing * @bat_priv: the bat priv with all the soft interface information 17521d8ab8d3SLinus Lüssing * @tt_global_entry: the global entry to remove the orig_node from 17531d8ab8d3SLinus Lüssing * @orig_node: the originator announcing the client 17541d8ab8d3SLinus Lüssing * @message: message to append to the log on deletion 17551d8ab8d3SLinus Lüssing * 17561d8ab8d3SLinus Lüssing * Remove the given orig_node and its according orig_entry from the given 17571d8ab8d3SLinus Lüssing * global tt entry. 17581d8ab8d3SLinus Lüssing */ 1759a513088dSSven Eckelmann static void 17601d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, 176156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 176256303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1763db08e6e5SSimon Wunderlich const char *message) 1764db08e6e5SSimon Wunderlich { 1765db08e6e5SSimon Wunderlich struct hlist_head *head; 1766b67bfe0dSSasha Levin struct hlist_node *safe; 176756303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 176816052789SAntonio Quartulli unsigned short vid; 1769db08e6e5SSimon Wunderlich 1770db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1771db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1772b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1773db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 177416052789SAntonio Quartulli vid = tt_global_entry->common.vid; 177539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 177616052789SAntonio Quartulli "Deleting %pM from global tt entry %pM (vid: %d): %s\n", 17771eda58bfSSven Eckelmann orig_node->orig, 177816052789SAntonio Quartulli tt_global_entry->common.addr, 177916052789SAntonio Quartulli BATADV_PRINT_VID(vid), message); 1780433ff98fSMarek Lindner _batadv_tt_global_del_orig_entry(tt_global_entry, 17811d8ab8d3SLinus Lüssing orig_entry); 1782db08e6e5SSimon Wunderlich } 1783db08e6e5SSimon Wunderlich } 1784db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1785db08e6e5SSimon Wunderlich } 1786db08e6e5SSimon Wunderlich 1787db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 1788acd34afaSSven Eckelmann * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the 1789acd34afaSSven Eckelmann * timer, otherwise we simply remove the originator scheduled for deletion. 1790db08e6e5SSimon Wunderlich */ 1791a513088dSSven Eckelmann static void 179256303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, 179356303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 179456303d34SSven Eckelmann struct batadv_orig_node *orig_node, 179556303d34SSven Eckelmann const char *message) 1796db08e6e5SSimon Wunderlich { 1797db08e6e5SSimon Wunderlich bool last_entry = true; 1798db08e6e5SSimon Wunderlich struct hlist_head *head; 179956303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1800db08e6e5SSimon Wunderlich 1801db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 1802db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 1803db08e6e5SSimon Wunderlich */ 1804db08e6e5SSimon Wunderlich 1805db08e6e5SSimon Wunderlich rcu_read_lock(); 1806db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1807b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1808db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 1809db08e6e5SSimon Wunderlich last_entry = false; 1810db08e6e5SSimon Wunderlich break; 1811db08e6e5SSimon Wunderlich } 1812db08e6e5SSimon Wunderlich } 1813db08e6e5SSimon Wunderlich rcu_read_unlock(); 1814db08e6e5SSimon Wunderlich 1815db08e6e5SSimon Wunderlich if (last_entry) { 1816db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 1817acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 1818db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 1819db08e6e5SSimon Wunderlich } else 1820db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 1821db08e6e5SSimon Wunderlich * one and can still use the other one. 1822db08e6e5SSimon Wunderlich */ 18231d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 1824db08e6e5SSimon Wunderlich orig_node, message); 1825db08e6e5SSimon Wunderlich } 1826db08e6e5SSimon Wunderlich 1827c018ad3dSAntonio Quartulli /** 1828c018ad3dSAntonio Quartulli * batadv_tt_global_del - remove a client from the global table 1829c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1830c018ad3dSAntonio Quartulli * @orig_node: an originator serving this client 1831c018ad3dSAntonio Quartulli * @addr: the mac address of the client 1832c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1833c018ad3dSAntonio Quartulli * @message: a message explaining the reason for deleting the client to print 1834c018ad3dSAntonio Quartulli * for debugging purpose 1835c018ad3dSAntonio Quartulli * @roaming: true if the deletion has been triggered by a roaming event 1836c018ad3dSAntonio Quartulli */ 183756303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv, 183856303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1839c018ad3dSAntonio Quartulli const unsigned char *addr, unsigned short vid, 1840cc47f66eSAntonio Quartulli const char *message, bool roaming) 1841a73105b8SAntonio Quartulli { 1842170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 184356303d34SSven Eckelmann struct batadv_tt_local_entry *local_entry = NULL; 1844a73105b8SAntonio Quartulli 1845c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 1846db08e6e5SSimon Wunderlich if (!tt_global_entry) 18477683fdc1SAntonio Quartulli goto out; 1848a73105b8SAntonio Quartulli 1849db08e6e5SSimon Wunderlich if (!roaming) { 18501d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 1851a513088dSSven Eckelmann orig_node, message); 185292f90f56SSven Eckelmann 1853db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 1854be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, 1855db08e6e5SSimon Wunderlich message); 1856db08e6e5SSimon Wunderlich 1857cc47f66eSAntonio Quartulli goto out; 1858cc47f66eSAntonio Quartulli } 185992f90f56SSven Eckelmann 1860db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 1861db08e6e5SSimon Wunderlich * event, there are two possibilities: 1862db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 1863db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 1864acd34afaSSven Eckelmann * it with BATADV_TT_CLIENT_ROAM, we start a timer and we 1865db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 1866db08e6e5SSimon Wunderlich * the entry is purged. 1867db08e6e5SSimon Wunderlich * 1868db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 1869db08e6e5SSimon Wunderlich * the originator. 1870db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 18719cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 18729cfc7bd6SSven Eckelmann */ 1873a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 1874c018ad3dSAntonio Quartulli tt_global_entry->common.addr, 1875c018ad3dSAntonio Quartulli vid); 1876a513088dSSven Eckelmann if (local_entry) { 1877db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 1878a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1879be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, message); 1880db08e6e5SSimon Wunderlich } else 1881db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 1882a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 1883a513088dSSven Eckelmann orig_node, message); 1884db08e6e5SSimon Wunderlich 1885cc47f66eSAntonio Quartulli out: 18867683fdc1SAntonio Quartulli if (tt_global_entry) 18875dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 1888a513088dSSven Eckelmann if (local_entry) 188995c0db90SSven Eckelmann batadv_tt_local_entry_put(local_entry); 1890a73105b8SAntonio Quartulli } 1891a73105b8SAntonio Quartulli 189295fb130dSAntonio Quartulli /** 189395fb130dSAntonio Quartulli * batadv_tt_global_del_orig - remove all the TT global entries belonging to the 189495fb130dSAntonio Quartulli * given originator matching the provided vid 189595fb130dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 189695fb130dSAntonio Quartulli * @orig_node: the originator owning the entries to remove 189795fb130dSAntonio Quartulli * @match_vid: the VLAN identifier to match. If negative all the entries will be 189895fb130dSAntonio Quartulli * removed 189995fb130dSAntonio Quartulli * @message: debug message to print as "reason" 190095fb130dSAntonio Quartulli */ 190156303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, 190256303d34SSven Eckelmann struct batadv_orig_node *orig_node, 19036b5e971aSSven Eckelmann s32 match_vid, 190456303d34SSven Eckelmann const char *message) 1905c6c8fea2SSven Eckelmann { 190656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 190756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 19086b5e971aSSven Eckelmann u32 i; 1909807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 1910b67bfe0dSSasha Levin struct hlist_node *safe; 1911a73105b8SAntonio Quartulli struct hlist_head *head; 19127683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 191316052789SAntonio Quartulli unsigned short vid; 1914c6c8fea2SSven Eckelmann 19156e801494SSimon Wunderlich if (!hash) 19166e801494SSimon Wunderlich return; 19176e801494SSimon Wunderlich 1918a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1919a73105b8SAntonio Quartulli head = &hash->table[i]; 19207683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1921c6c8fea2SSven Eckelmann 19227683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1923b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, safe, 1924a73105b8SAntonio Quartulli head, hash_entry) { 192595fb130dSAntonio Quartulli /* remove only matching entries */ 192695fb130dSAntonio Quartulli if (match_vid >= 0 && tt_common_entry->vid != match_vid) 192795fb130dSAntonio Quartulli continue; 192895fb130dSAntonio Quartulli 192956303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 193056303d34SSven Eckelmann struct batadv_tt_global_entry, 193148100bacSAntonio Quartulli common); 1932db08e6e5SSimon Wunderlich 19331d8ab8d3SLinus Lüssing batadv_tt_global_del_orig_node(bat_priv, tt_global, 1934db08e6e5SSimon Wunderlich orig_node, message); 1935db08e6e5SSimon Wunderlich 193656303d34SSven Eckelmann if (hlist_empty(&tt_global->orig_list)) { 193716052789SAntonio Quartulli vid = tt_global->common.vid; 193839c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 193916052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 194016052789SAntonio Quartulli tt_global->common.addr, 194116052789SAntonio Quartulli BATADV_PRINT_VID(vid), message); 1942b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 19435dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 1944c6c8fea2SSven Eckelmann } 1945a73105b8SAntonio Quartulli } 19467683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 19477683fdc1SAntonio Quartulli } 1948ac4eebd4SLinus Lüssing clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); 1949c6c8fea2SSven Eckelmann } 1950c6c8fea2SSven Eckelmann 195130cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, 195230cfd02bSAntonio Quartulli char **msg) 1953cc47f66eSAntonio Quartulli { 195430cfd02bSAntonio Quartulli bool purge = false; 195530cfd02bSAntonio Quartulli unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; 195630cfd02bSAntonio Quartulli unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; 1957cc47f66eSAntonio Quartulli 195830cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && 195930cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { 196030cfd02bSAntonio Quartulli purge = true; 196130cfd02bSAntonio Quartulli *msg = "Roaming timeout\n"; 196242d0b044SSven Eckelmann } 196342d0b044SSven Eckelmann 196430cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) && 196530cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) { 196630cfd02bSAntonio Quartulli purge = true; 196730cfd02bSAntonio Quartulli *msg = "Temporary client timeout\n"; 196830cfd02bSAntonio Quartulli } 196930cfd02bSAntonio Quartulli 197030cfd02bSAntonio Quartulli return purge; 197130cfd02bSAntonio Quartulli } 197230cfd02bSAntonio Quartulli 197330cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv) 197442d0b044SSven Eckelmann { 1975807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 197642d0b044SSven Eckelmann struct hlist_head *head; 1977b67bfe0dSSasha Levin struct hlist_node *node_tmp; 197842d0b044SSven Eckelmann spinlock_t *list_lock; /* protects write access to the hash lists */ 19796b5e971aSSven Eckelmann u32 i; 198030cfd02bSAntonio Quartulli char *msg = NULL; 198130cfd02bSAntonio Quartulli struct batadv_tt_common_entry *tt_common; 198230cfd02bSAntonio Quartulli struct batadv_tt_global_entry *tt_global; 198342d0b044SSven Eckelmann 198442d0b044SSven Eckelmann for (i = 0; i < hash->size; i++) { 198542d0b044SSven Eckelmann head = &hash->table[i]; 198642d0b044SSven Eckelmann list_lock = &hash->list_locks[i]; 198742d0b044SSven Eckelmann 198842d0b044SSven Eckelmann spin_lock_bh(list_lock); 1989b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 199030cfd02bSAntonio Quartulli hash_entry) { 199130cfd02bSAntonio Quartulli tt_global = container_of(tt_common, 199230cfd02bSAntonio Quartulli struct batadv_tt_global_entry, 199330cfd02bSAntonio Quartulli common); 199430cfd02bSAntonio Quartulli 199530cfd02bSAntonio Quartulli if (!batadv_tt_global_to_purge(tt_global, &msg)) 199630cfd02bSAntonio Quartulli continue; 199730cfd02bSAntonio Quartulli 199830cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 199916052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 200016052789SAntonio Quartulli tt_global->common.addr, 200116052789SAntonio Quartulli BATADV_PRINT_VID(tt_global->common.vid), 200216052789SAntonio Quartulli msg); 200330cfd02bSAntonio Quartulli 2004b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 200530cfd02bSAntonio Quartulli 20065dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 200730cfd02bSAntonio Quartulli } 20087683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 2009cc47f66eSAntonio Quartulli } 2010cc47f66eSAntonio Quartulli } 2011cc47f66eSAntonio Quartulli 201256303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) 2013c6c8fea2SSven Eckelmann { 20145bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 20157683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 201656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 201756303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 2018b67bfe0dSSasha Levin struct hlist_node *node_tmp; 20197683fdc1SAntonio Quartulli struct hlist_head *head; 20206b5e971aSSven Eckelmann u32 i; 20217683fdc1SAntonio Quartulli 2022807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 2023c6c8fea2SSven Eckelmann return; 2024c6c8fea2SSven Eckelmann 2025807736f6SSven Eckelmann hash = bat_priv->tt.global_hash; 20267683fdc1SAntonio Quartulli 20277683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 20287683fdc1SAntonio Quartulli head = &hash->table[i]; 20297683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 20307683fdc1SAntonio Quartulli 20317683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 2032b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 20337683fdc1SAntonio Quartulli head, hash_entry) { 2034b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 203556303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 203656303d34SSven Eckelmann struct batadv_tt_global_entry, 203748100bacSAntonio Quartulli common); 20385dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global); 20397683fdc1SAntonio Quartulli } 20407683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 20417683fdc1SAntonio Quartulli } 20427683fdc1SAntonio Quartulli 20431a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 20447683fdc1SAntonio Quartulli 2045807736f6SSven Eckelmann bat_priv->tt.global_hash = NULL; 2046c6c8fea2SSven Eckelmann } 2047c6c8fea2SSven Eckelmann 204856303d34SSven Eckelmann static bool 204956303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, 205056303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry) 205159b699cdSAntonio Quartulli { 205259b699cdSAntonio Quartulli bool ret = false; 205359b699cdSAntonio Quartulli 2054acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && 2055acd34afaSSven Eckelmann tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) 205659b699cdSAntonio Quartulli ret = true; 205759b699cdSAntonio Quartulli 20582d2fcc2aSAntonio Quartulli /* check if the two clients are marked as isolated */ 20592d2fcc2aSAntonio Quartulli if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA && 20602d2fcc2aSAntonio Quartulli tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA) 20612d2fcc2aSAntonio Quartulli ret = true; 20622d2fcc2aSAntonio Quartulli 206359b699cdSAntonio Quartulli return ret; 206459b699cdSAntonio Quartulli } 206559b699cdSAntonio Quartulli 2066c018ad3dSAntonio Quartulli /** 2067c018ad3dSAntonio Quartulli * batadv_transtable_search - get the mesh destination for a given client 2068c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2069c018ad3dSAntonio Quartulli * @src: mac address of the source client 2070c018ad3dSAntonio Quartulli * @addr: mac address of the destination client 2071c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2072c018ad3dSAntonio Quartulli * 207362fe710fSSven Eckelmann * Return: a pointer to the originator that was selected as destination in the 2074c018ad3dSAntonio Quartulli * mesh for contacting the client 'addr', NULL otherwise. 2075c018ad3dSAntonio Quartulli * In case of multiple originators serving the same client, the function returns 2076c018ad3dSAntonio Quartulli * the best one (best in terms of metric towards the destination node). 2077c018ad3dSAntonio Quartulli * 2078c018ad3dSAntonio Quartulli * If the two clients are AP isolated the function returns NULL. 2079c018ad3dSAntonio Quartulli */ 208056303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, 20816b5e971aSSven Eckelmann const u8 *src, 20826b5e971aSSven Eckelmann const u8 *addr, 2083c018ad3dSAntonio Quartulli unsigned short vid) 2084c6c8fea2SSven Eckelmann { 208556303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 208656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 208756303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 2088981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *best_entry; 2089c6c8fea2SSven Eckelmann 2090eceb22aeSAntonio Quartulli if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) { 2091c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); 2092068ee6e2SAntonio Quartulli if (!tt_local_entry || 2093068ee6e2SAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) 20943d393e47SAntonio Quartulli goto out; 20953d393e47SAntonio Quartulli } 20967aadf889SMarek Lindner 2097c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 20982dafb49dSAntonio Quartulli if (!tt_global_entry) 20997b36e8eeSMarek Lindner goto out; 2100c6c8fea2SSven Eckelmann 21013d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 21029cfc7bd6SSven Eckelmann * isolation 21039cfc7bd6SSven Eckelmann */ 2104a513088dSSven Eckelmann if (tt_local_entry && 2105a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 21063d393e47SAntonio Quartulli goto out; 21073d393e47SAntonio Quartulli 2108db08e6e5SSimon Wunderlich rcu_read_lock(); 21094627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 2110db08e6e5SSimon Wunderlich /* found anything? */ 2111981d8900SSven Eckelmann if (best_entry) 2112981d8900SSven Eckelmann orig_node = best_entry->orig_node; 21137c124391SSven Eckelmann if (orig_node && !kref_get_unless_zero(&orig_node->refcount)) 2114db08e6e5SSimon Wunderlich orig_node = NULL; 2115db08e6e5SSimon Wunderlich rcu_read_unlock(); 2116981d8900SSven Eckelmann 21177b36e8eeSMarek Lindner out: 21183d393e47SAntonio Quartulli if (tt_global_entry) 21195dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 21203d393e47SAntonio Quartulli if (tt_local_entry) 212195c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 21223d393e47SAntonio Quartulli 21237b36e8eeSMarek Lindner return orig_node; 2124c6c8fea2SSven Eckelmann } 2125a73105b8SAntonio Quartulli 2126ced72933SAntonio Quartulli /** 2127ced72933SAntonio Quartulli * batadv_tt_global_crc - calculates the checksum of the local table belonging 2128ced72933SAntonio Quartulli * to the given orig_node 2129ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 21300ffa9e8dSAntonio Quartulli * @orig_node: originator for which the CRC should be computed 21317ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 21320ffa9e8dSAntonio Quartulli * 21330ffa9e8dSAntonio Quartulli * This function computes the checksum for the global table corresponding to a 21340ffa9e8dSAntonio Quartulli * specific originator. In particular, the checksum is computed as follows: For 21350ffa9e8dSAntonio Quartulli * each client connected to the originator the CRC32C of the MAC address and the 21360ffa9e8dSAntonio Quartulli * VID is computed and then all the CRC32Cs of the various clients are xor'ed 21370ffa9e8dSAntonio Quartulli * together. 21380ffa9e8dSAntonio Quartulli * 21390ffa9e8dSAntonio Quartulli * The idea behind is that CRC32C should be used as much as possible in order to 21400ffa9e8dSAntonio Quartulli * produce a unique hash of the table, but since the order which is used to feed 21410ffa9e8dSAntonio Quartulli * the CRC32C function affects the result and since every node in the network 21420ffa9e8dSAntonio Quartulli * probably sorts the clients differently, the hash function cannot be directly 21430ffa9e8dSAntonio Quartulli * computed over the entire table. Hence the CRC32C is used only on 21440ffa9e8dSAntonio Quartulli * the single client entry, while all the results are then xor'ed together 21450ffa9e8dSAntonio Quartulli * because the XOR operation can combine them all while trying to reduce the 21460ffa9e8dSAntonio Quartulli * noise as much as possible. 21470ffa9e8dSAntonio Quartulli * 214862fe710fSSven Eckelmann * Return: the checksum of the global table of a given originator. 2149ced72933SAntonio Quartulli */ 21506b5e971aSSven Eckelmann static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv, 21517ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node, 21527ea7b4a1SAntonio Quartulli unsigned short vid) 2153a73105b8SAntonio Quartulli { 2154807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 215556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 215656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 2157a73105b8SAntonio Quartulli struct hlist_head *head; 21586b5e971aSSven Eckelmann u32 i, crc_tmp, crc = 0; 21596b5e971aSSven Eckelmann u8 flags; 2160a30e22caSAntonio Quartulli __be16 tmp_vid; 2161a73105b8SAntonio Quartulli 2162a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2163a73105b8SAntonio Quartulli head = &hash->table[i]; 2164a73105b8SAntonio Quartulli 2165a73105b8SAntonio Quartulli rcu_read_lock(); 2166b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 216756303d34SSven Eckelmann tt_global = container_of(tt_common, 216856303d34SSven Eckelmann struct batadv_tt_global_entry, 216948100bacSAntonio Quartulli common); 21707ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 21717ea7b4a1SAntonio Quartulli * VLAN identified by the vid passed as parameter 21727ea7b4a1SAntonio Quartulli */ 21737ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 21747ea7b4a1SAntonio Quartulli continue; 21757ea7b4a1SAntonio Quartulli 2176cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 2177cc47f66eSAntonio Quartulli * consistency only. They don't have to be 2178cc47f66eSAntonio Quartulli * taken into account while computing the 2179db08e6e5SSimon Wunderlich * global crc 2180db08e6e5SSimon Wunderlich */ 2181acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 2182cc47f66eSAntonio Quartulli continue; 218330cfd02bSAntonio Quartulli /* Temporary clients have not been announced yet, so 218430cfd02bSAntonio Quartulli * they have to be skipped while computing the global 218530cfd02bSAntonio Quartulli * crc 218630cfd02bSAntonio Quartulli */ 218730cfd02bSAntonio Quartulli if (tt_common->flags & BATADV_TT_CLIENT_TEMP) 218830cfd02bSAntonio Quartulli continue; 2189db08e6e5SSimon Wunderlich 2190db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 2191db08e6e5SSimon Wunderlich * originator 2192db08e6e5SSimon Wunderlich */ 219356303d34SSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global, 2194db08e6e5SSimon Wunderlich orig_node)) 2195db08e6e5SSimon Wunderlich continue; 2196db08e6e5SSimon Wunderlich 2197a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2198a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2199a30e22caSAntonio Quartulli */ 2200a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2201a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 22020eb01568SAntonio Quartulli 22030eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 22040eb01568SAntonio Quartulli * among nodes 22050eb01568SAntonio Quartulli */ 22060eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 22070eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 22080eb01568SAntonio Quartulli 22090ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2210a73105b8SAntonio Quartulli } 2211a73105b8SAntonio Quartulli rcu_read_unlock(); 2212a73105b8SAntonio Quartulli } 2213a73105b8SAntonio Quartulli 2214ced72933SAntonio Quartulli return crc; 2215a73105b8SAntonio Quartulli } 2216a73105b8SAntonio Quartulli 2217ced72933SAntonio Quartulli /** 2218ced72933SAntonio Quartulli * batadv_tt_local_crc - calculates the checksum of the local table 2219ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 22207ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 22210ffa9e8dSAntonio Quartulli * 22220ffa9e8dSAntonio Quartulli * For details about the computation, please refer to the documentation for 22230ffa9e8dSAntonio Quartulli * batadv_tt_global_crc(). 22240ffa9e8dSAntonio Quartulli * 222562fe710fSSven Eckelmann * Return: the checksum of the local table 2226ced72933SAntonio Quartulli */ 22276b5e971aSSven Eckelmann static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv, 22287ea7b4a1SAntonio Quartulli unsigned short vid) 2229a73105b8SAntonio Quartulli { 2230807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 223156303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 2232a73105b8SAntonio Quartulli struct hlist_head *head; 22336b5e971aSSven Eckelmann u32 i, crc_tmp, crc = 0; 22346b5e971aSSven Eckelmann u8 flags; 2235a30e22caSAntonio Quartulli __be16 tmp_vid; 2236a73105b8SAntonio Quartulli 2237a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2238a73105b8SAntonio Quartulli head = &hash->table[i]; 2239a73105b8SAntonio Quartulli 2240a73105b8SAntonio Quartulli rcu_read_lock(); 2241b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 22427ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 22437ea7b4a1SAntonio Quartulli * VLAN identified by vid 22447ea7b4a1SAntonio Quartulli */ 22457ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 22467ea7b4a1SAntonio Quartulli continue; 22477ea7b4a1SAntonio Quartulli 2248058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 22499cfc7bd6SSven Eckelmann * account while computing the CRC 22509cfc7bd6SSven Eckelmann */ 2251acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_NEW) 2252058d0e26SAntonio Quartulli continue; 2253ced72933SAntonio Quartulli 2254a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2255a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2256a30e22caSAntonio Quartulli */ 2257a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2258a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 22590eb01568SAntonio Quartulli 22600eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 22610eb01568SAntonio Quartulli * among nodes 22620eb01568SAntonio Quartulli */ 22630eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 22640eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 22650eb01568SAntonio Quartulli 22660ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2267a73105b8SAntonio Quartulli } 2268a73105b8SAntonio Quartulli rcu_read_unlock(); 2269a73105b8SAntonio Quartulli } 2270a73105b8SAntonio Quartulli 2271ced72933SAntonio Quartulli return crc; 2272a73105b8SAntonio Quartulli } 2273a73105b8SAntonio Quartulli 227456303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) 2275a73105b8SAntonio Quartulli { 22767c26a53bSMarek Lindner struct batadv_tt_req_node *node; 22777c26a53bSMarek Lindner struct hlist_node *safe; 2278a73105b8SAntonio Quartulli 2279807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2280a73105b8SAntonio Quartulli 22817c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 22827c26a53bSMarek Lindner hlist_del_init(&node->list); 2283a73105b8SAntonio Quartulli kfree(node); 2284a73105b8SAntonio Quartulli } 2285a73105b8SAntonio Quartulli 2286807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2287a73105b8SAntonio Quartulli } 2288a73105b8SAntonio Quartulli 228956303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, 229056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2291e8cf234aSAntonio Quartulli const void *tt_buff, 22926b5e971aSSven Eckelmann u16 tt_buff_len) 2293a73105b8SAntonio Quartulli { 2294a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 22959cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 22969cfc7bd6SSven Eckelmann */ 2297a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2298a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 2299a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2300a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2301a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 2302a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 2303a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 2304a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 2305a73105b8SAntonio Quartulli } 2306a73105b8SAntonio Quartulli } 2307a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2308a73105b8SAntonio Quartulli } 2309a73105b8SAntonio Quartulli 231056303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv) 2311a73105b8SAntonio Quartulli { 23127c26a53bSMarek Lindner struct batadv_tt_req_node *node; 23137c26a53bSMarek Lindner struct hlist_node *safe; 2314a73105b8SAntonio Quartulli 2315807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 23167c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 231742d0b044SSven Eckelmann if (batadv_has_timed_out(node->issued_at, 231842d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) { 23197c26a53bSMarek Lindner hlist_del_init(&node->list); 2320a73105b8SAntonio Quartulli kfree(node); 2321a73105b8SAntonio Quartulli } 2322a73105b8SAntonio Quartulli } 2323807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2324a73105b8SAntonio Quartulli } 2325a73105b8SAntonio Quartulli 2326383b8636SMarek Lindner /** 2327383b8636SMarek Lindner * batadv_tt_req_node_new - search and possibly create a tt_req_node object 2328383b8636SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2329383b8636SMarek Lindner * @orig_node: orig node this request is being issued for 2330383b8636SMarek Lindner * 233162fe710fSSven Eckelmann * Return: the pointer to the new tt_req_node struct if no request 2332383b8636SMarek Lindner * has already been issued for this orig_node, NULL otherwise. 23339cfc7bd6SSven Eckelmann */ 233456303d34SSven Eckelmann static struct batadv_tt_req_node * 2335383b8636SMarek Lindner batadv_tt_req_node_new(struct batadv_priv *bat_priv, 233656303d34SSven Eckelmann struct batadv_orig_node *orig_node) 2337a73105b8SAntonio Quartulli { 233856303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 2339a73105b8SAntonio Quartulli 2340807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 23417c26a53bSMarek Lindner hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { 23421eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 23431eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 234442d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) 2345a73105b8SAntonio Quartulli goto unlock; 2346a73105b8SAntonio Quartulli } 2347a73105b8SAntonio Quartulli 2348a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 2349a73105b8SAntonio Quartulli if (!tt_req_node) 2350a73105b8SAntonio Quartulli goto unlock; 2351a73105b8SAntonio Quartulli 23528fdd0153SAntonio Quartulli ether_addr_copy(tt_req_node->addr, orig_node->orig); 2353a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 2354a73105b8SAntonio Quartulli 23557c26a53bSMarek Lindner hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list); 2356a73105b8SAntonio Quartulli unlock: 2357807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2358a73105b8SAntonio Quartulli return tt_req_node; 2359a73105b8SAntonio Quartulli } 2360a73105b8SAntonio Quartulli 2361335fbe0fSMarek Lindner /** 2362335fbe0fSMarek Lindner * batadv_tt_local_valid - verify that given tt entry is a valid one 2363335fbe0fSMarek Lindner * @entry_ptr: to be checked local tt entry 2364335fbe0fSMarek Lindner * @data_ptr: not used but definition required to satisfy the callback prototype 2365335fbe0fSMarek Lindner * 23664b426b10SSven Eckelmann * Return: true if the entry is a valid, false otherwise. 2367335fbe0fSMarek Lindner */ 23684b426b10SSven Eckelmann static bool batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) 2369058d0e26SAntonio Quartulli { 237056303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 2371058d0e26SAntonio Quartulli 2372acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) 23734b426b10SSven Eckelmann return false; 23744b426b10SSven Eckelmann return true; 2375058d0e26SAntonio Quartulli } 2376058d0e26SAntonio Quartulli 23774b426b10SSven Eckelmann static bool batadv_tt_global_valid(const void *entry_ptr, 2378a513088dSSven Eckelmann const void *data_ptr) 2379a73105b8SAntonio Quartulli { 238056303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 238156303d34SSven Eckelmann const struct batadv_tt_global_entry *tt_global_entry; 238256303d34SSven Eckelmann const struct batadv_orig_node *orig_node = data_ptr; 2383a73105b8SAntonio Quartulli 238430cfd02bSAntonio Quartulli if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || 238530cfd02bSAntonio Quartulli tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) 23864b426b10SSven Eckelmann return false; 2387cc47f66eSAntonio Quartulli 238856303d34SSven Eckelmann tt_global_entry = container_of(tt_common_entry, 238956303d34SSven Eckelmann struct batadv_tt_global_entry, 239048100bacSAntonio Quartulli common); 239148100bacSAntonio Quartulli 2392a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 2393a73105b8SAntonio Quartulli } 2394a73105b8SAntonio Quartulli 2395335fbe0fSMarek Lindner /** 23967ea7b4a1SAntonio Quartulli * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the 23977ea7b4a1SAntonio Quartulli * specified tt hash 2398335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2399335fbe0fSMarek Lindner * @hash: hash table containing the tt entries 2400335fbe0fSMarek Lindner * @tt_len: expected tvlv tt data buffer length in number of bytes 24017ea7b4a1SAntonio Quartulli * @tvlv_buff: pointer to the buffer to fill with the TT data 2402335fbe0fSMarek Lindner * @valid_cb: function to filter tt change entries 2403335fbe0fSMarek Lindner * @cb_data: data passed to the filter function as argument 2404335fbe0fSMarek Lindner */ 24057ea7b4a1SAntonio Quartulli static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, 24067ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash, 24076b5e971aSSven Eckelmann void *tvlv_buff, u16 tt_len, 24084b426b10SSven Eckelmann bool (*valid_cb)(const void *, 24094b426b10SSven Eckelmann const void *), 2410a73105b8SAntonio Quartulli void *cb_data) 2411a73105b8SAntonio Quartulli { 241256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 2413335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 2414a73105b8SAntonio Quartulli struct hlist_head *head; 24156b5e971aSSven Eckelmann u16 tt_tot, tt_num_entries = 0; 24166b5e971aSSven Eckelmann u32 i; 2417a73105b8SAntonio Quartulli 2418298e6e68SAntonio Quartulli tt_tot = batadv_tt_entries(tt_len); 24197ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; 2420a73105b8SAntonio Quartulli 2421a73105b8SAntonio Quartulli rcu_read_lock(); 2422a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2423a73105b8SAntonio Quartulli head = &hash->table[i]; 2424a73105b8SAntonio Quartulli 2425b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 2426a73105b8SAntonio Quartulli head, hash_entry) { 2427335fbe0fSMarek Lindner if (tt_tot == tt_num_entries) 2428a73105b8SAntonio Quartulli break; 2429a73105b8SAntonio Quartulli 243048100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 2431a73105b8SAntonio Quartulli continue; 2432a73105b8SAntonio Quartulli 24338fdd0153SAntonio Quartulli ether_addr_copy(tt_change->addr, tt_common_entry->addr); 243427b37ebfSAntonio Quartulli tt_change->flags = tt_common_entry->flags; 2435c018ad3dSAntonio Quartulli tt_change->vid = htons(tt_common_entry->vid); 2436ca663046SAntonio Quartulli memset(tt_change->reserved, 0, 2437ca663046SAntonio Quartulli sizeof(tt_change->reserved)); 2438a73105b8SAntonio Quartulli 2439335fbe0fSMarek Lindner tt_num_entries++; 2440a73105b8SAntonio Quartulli tt_change++; 2441a73105b8SAntonio Quartulli } 2442a73105b8SAntonio Quartulli } 2443a73105b8SAntonio Quartulli rcu_read_unlock(); 24447ea7b4a1SAntonio Quartulli } 2445a73105b8SAntonio Quartulli 24467ea7b4a1SAntonio Quartulli /** 24477ea7b4a1SAntonio Quartulli * batadv_tt_global_check_crc - check if all the CRCs are correct 24487ea7b4a1SAntonio Quartulli * @orig_node: originator for which the CRCs have to be checked 24497ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN entry 24507ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 24517ea7b4a1SAntonio Quartulli * 245262fe710fSSven Eckelmann * Return: true if all the received CRCs match the locally stored ones, false 24537ea7b4a1SAntonio Quartulli * otherwise 24547ea7b4a1SAntonio Quartulli */ 24557ea7b4a1SAntonio Quartulli static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, 24567ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 24576b5e971aSSven Eckelmann u16 num_vlan) 24587ea7b4a1SAntonio Quartulli { 24597ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; 24607ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 2461c169c59dSSimon Wunderlich int i, orig_num_vlan; 24626b5e971aSSven Eckelmann u32 crc; 24637ea7b4a1SAntonio Quartulli 24647ea7b4a1SAntonio Quartulli /* check if each received CRC matches the locally stored one */ 24657ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 24667ea7b4a1SAntonio Quartulli tt_vlan_tmp = tt_vlan + i; 24677ea7b4a1SAntonio Quartulli 24687ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't check 24697ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 24707ea7b4a1SAntonio Quartulli */ 24717ea7b4a1SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, 2472cfd4f757SAntonio Quartulli orig_node->orig, 2473cfd4f757SAntonio Quartulli ntohs(tt_vlan_tmp->vid))) 24747ea7b4a1SAntonio Quartulli continue; 24757ea7b4a1SAntonio Quartulli 24767ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_node, 24777ea7b4a1SAntonio Quartulli ntohs(tt_vlan_tmp->vid)); 24787ea7b4a1SAntonio Quartulli if (!vlan) 24797ea7b4a1SAntonio Quartulli return false; 24807ea7b4a1SAntonio Quartulli 248191c2b1a9SAntonio Quartulli crc = vlan->tt.crc; 248221754e25SSven Eckelmann batadv_orig_node_vlan_put(vlan); 248391c2b1a9SAntonio Quartulli 248491c2b1a9SAntonio Quartulli if (crc != ntohl(tt_vlan_tmp->crc)) 24857ea7b4a1SAntonio Quartulli return false; 24867ea7b4a1SAntonio Quartulli } 24877ea7b4a1SAntonio Quartulli 2488c169c59dSSimon Wunderlich /* check if any excess VLANs exist locally for the originator 2489c169c59dSSimon Wunderlich * which are not mentioned in the TVLV from the originator. 2490c169c59dSSimon Wunderlich */ 2491c169c59dSSimon Wunderlich rcu_read_lock(); 2492c169c59dSSimon Wunderlich orig_num_vlan = 0; 2493c169c59dSSimon Wunderlich hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) 2494c169c59dSSimon Wunderlich orig_num_vlan++; 2495c169c59dSSimon Wunderlich rcu_read_unlock(); 2496c169c59dSSimon Wunderlich 2497c169c59dSSimon Wunderlich if (orig_num_vlan > num_vlan) 2498c169c59dSSimon Wunderlich return false; 2499c169c59dSSimon Wunderlich 25007ea7b4a1SAntonio Quartulli return true; 25017ea7b4a1SAntonio Quartulli } 25027ea7b4a1SAntonio Quartulli 25037ea7b4a1SAntonio Quartulli /** 25047ea7b4a1SAntonio Quartulli * batadv_tt_local_update_crc - update all the local CRCs 25057ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 25067ea7b4a1SAntonio Quartulli */ 25077ea7b4a1SAntonio Quartulli static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) 25087ea7b4a1SAntonio Quartulli { 25097ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 25107ea7b4a1SAntonio Quartulli 25117ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 25127ea7b4a1SAntonio Quartulli rcu_read_lock(); 25137ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 25147ea7b4a1SAntonio Quartulli vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); 25157ea7b4a1SAntonio Quartulli } 25167ea7b4a1SAntonio Quartulli rcu_read_unlock(); 25177ea7b4a1SAntonio Quartulli } 25187ea7b4a1SAntonio Quartulli 25197ea7b4a1SAntonio Quartulli /** 25207ea7b4a1SAntonio Quartulli * batadv_tt_global_update_crc - update all the global CRCs for this orig_node 25217ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 25227ea7b4a1SAntonio Quartulli * @orig_node: the orig_node for which the CRCs have to be updated 25237ea7b4a1SAntonio Quartulli */ 25247ea7b4a1SAntonio Quartulli static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, 25257ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node) 25267ea7b4a1SAntonio Quartulli { 25277ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 25286b5e971aSSven Eckelmann u32 crc; 25297ea7b4a1SAntonio Quartulli 25307ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 25317ea7b4a1SAntonio Quartulli rcu_read_lock(); 2532d0fa4f3fSMarek Lindner hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 25337ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't compute 25347ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 25357ea7b4a1SAntonio Quartulli */ 2536cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, 2537cfd4f757SAntonio Quartulli vlan->vid)) 25387ea7b4a1SAntonio Quartulli continue; 25397ea7b4a1SAntonio Quartulli 25407ea7b4a1SAntonio Quartulli crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); 25417ea7b4a1SAntonio Quartulli vlan->tt.crc = crc; 25427ea7b4a1SAntonio Quartulli } 25437ea7b4a1SAntonio Quartulli rcu_read_unlock(); 2544a73105b8SAntonio Quartulli } 2545a73105b8SAntonio Quartulli 2546ced72933SAntonio Quartulli /** 2547ced72933SAntonio Quartulli * batadv_send_tt_request - send a TT Request message to a given node 2548ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2549ced72933SAntonio Quartulli * @dst_orig_node: the destination of the message 2550ced72933SAntonio Quartulli * @ttvn: the version number that the source of the message is looking for 25517ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN object to request 25527ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 2553ced72933SAntonio Quartulli * @full_table: ask for the entire translation table if true, while only for the 2554ced72933SAntonio Quartulli * last TT diff otherwise 2555d15cd622SAntonio Quartulli * 2556d15cd622SAntonio Quartulli * Return: true if the TT Request was sent, false otherwise 2557ced72933SAntonio Quartulli */ 25584b426b10SSven Eckelmann static bool batadv_send_tt_request(struct batadv_priv *bat_priv, 255956303d34SSven Eckelmann struct batadv_orig_node *dst_orig_node, 25606b5e971aSSven Eckelmann u8 ttvn, 25617ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 25626b5e971aSSven Eckelmann u16 num_vlan, bool full_table) 2563a73105b8SAntonio Quartulli { 2564335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 256556303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node = NULL; 25667ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_req; 25677ea7b4a1SAntonio Quartulli struct batadv_hard_iface *primary_if; 2568335fbe0fSMarek Lindner bool ret = false; 25697ea7b4a1SAntonio Quartulli int i, size; 2570a73105b8SAntonio Quartulli 2571e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2572a73105b8SAntonio Quartulli if (!primary_if) 2573a73105b8SAntonio Quartulli goto out; 2574a73105b8SAntonio Quartulli 2575a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 25769cfc7bd6SSven Eckelmann * reply from the same orig_node yet 25779cfc7bd6SSven Eckelmann */ 2578383b8636SMarek Lindner tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node); 2579a73105b8SAntonio Quartulli if (!tt_req_node) 2580a73105b8SAntonio Quartulli goto out; 2581a73105b8SAntonio Quartulli 25827ea7b4a1SAntonio Quartulli size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; 25837ea7b4a1SAntonio Quartulli tvlv_tt_data = kzalloc(size, GFP_ATOMIC); 2584335fbe0fSMarek Lindner if (!tvlv_tt_data) 2585a73105b8SAntonio Quartulli goto out; 2586a73105b8SAntonio Quartulli 2587335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_REQUEST; 2588335fbe0fSMarek Lindner tvlv_tt_data->ttvn = ttvn; 25897ea7b4a1SAntonio Quartulli tvlv_tt_data->num_vlan = htons(num_vlan); 25907ea7b4a1SAntonio Quartulli 25917ea7b4a1SAntonio Quartulli /* send all the CRCs within the request. This is needed by intermediate 25927ea7b4a1SAntonio Quartulli * nodes to ensure they have the correct table before replying 25937ea7b4a1SAntonio Quartulli */ 25947ea7b4a1SAntonio Quartulli tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); 25957ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 25967ea7b4a1SAntonio Quartulli tt_vlan_req->vid = tt_vlan->vid; 25977ea7b4a1SAntonio Quartulli tt_vlan_req->crc = tt_vlan->crc; 25987ea7b4a1SAntonio Quartulli 25997ea7b4a1SAntonio Quartulli tt_vlan_req++; 26007ea7b4a1SAntonio Quartulli tt_vlan++; 26017ea7b4a1SAntonio Quartulli } 2602a73105b8SAntonio Quartulli 2603a73105b8SAntonio Quartulli if (full_table) 2604335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2605a73105b8SAntonio Quartulli 2606bb351ba0SMartin Hundebøll batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", 2607335fbe0fSMarek Lindner dst_orig_node->orig, full_table ? 'F' : '.'); 2608a73105b8SAntonio Quartulli 2609d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); 2610335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 2611335fbe0fSMarek Lindner dst_orig_node->orig, BATADV_TVLV_TT, 1, 26127ea7b4a1SAntonio Quartulli tvlv_tt_data, size); 2613335fbe0fSMarek Lindner ret = true; 2614a73105b8SAntonio Quartulli 2615a73105b8SAntonio Quartulli out: 2616a73105b8SAntonio Quartulli if (primary_if) 261782047ad7SSven Eckelmann batadv_hardif_put(primary_if); 2618a73105b8SAntonio Quartulli if (ret && tt_req_node) { 2619807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 26207c26a53bSMarek Lindner /* hlist_del_init() verifies tt_req_node still is in the list */ 26217c26a53bSMarek Lindner hlist_del_init(&tt_req_node->list); 2622807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2623a73105b8SAntonio Quartulli kfree(tt_req_node); 2624a73105b8SAntonio Quartulli } 2625335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2626a73105b8SAntonio Quartulli return ret; 2627a73105b8SAntonio Quartulli } 2628a73105b8SAntonio Quartulli 2629335fbe0fSMarek Lindner /** 2630335fbe0fSMarek Lindner * batadv_send_other_tt_response - send reply to tt request concerning another 2631335fbe0fSMarek Lindner * node's translation table 2632335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2633335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2634335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2635335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 2636335fbe0fSMarek Lindner * 263762fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2638335fbe0fSMarek Lindner */ 2639335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, 2640335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 26416b5e971aSSven Eckelmann u8 *req_src, u8 *req_dst) 2642a73105b8SAntonio Quartulli { 2643170173bfSSven Eckelmann struct batadv_orig_node *req_dst_orig_node; 264456303d34SSven Eckelmann struct batadv_orig_node *res_dst_orig_node = NULL; 26457ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 2646335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 26477ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 2648335fbe0fSMarek Lindner bool ret = false, full_table; 26496b5e971aSSven Eckelmann u8 orig_ttvn, req_ttvn; 26506b5e971aSSven Eckelmann u16 tvlv_len; 26516b5e971aSSven Eckelmann s32 tt_len; 2652a73105b8SAntonio Quartulli 265339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 265486ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 2655335fbe0fSMarek Lindner req_src, tt_data->ttvn, req_dst, 2656a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 2657a73105b8SAntonio Quartulli 2658a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 2659335fbe0fSMarek Lindner req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); 2660a73105b8SAntonio Quartulli if (!req_dst_orig_node) 2661a73105b8SAntonio Quartulli goto out; 2662a73105b8SAntonio Quartulli 2663335fbe0fSMarek Lindner res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); 2664a73105b8SAntonio Quartulli if (!res_dst_orig_node) 2665a73105b8SAntonio Quartulli goto out; 2666a73105b8SAntonio Quartulli 26676b5e971aSSven Eckelmann orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn); 2668335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 2669a73105b8SAntonio Quartulli 26707ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 2671335fbe0fSMarek Lindner /* this node doesn't have the requested data */ 2672a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 26737ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, 26747ea7b4a1SAntonio Quartulli ntohs(tt_data->num_vlan))) 2675a73105b8SAntonio Quartulli goto out; 2676a73105b8SAntonio Quartulli 2677015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 2678335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || 2679a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 2680a73105b8SAntonio Quartulli full_table = true; 2681a73105b8SAntonio Quartulli else 2682a73105b8SAntonio Quartulli full_table = false; 2683a73105b8SAntonio Quartulli 2684335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 2685335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 26869cfc7bd6SSven Eckelmann */ 2687a73105b8SAntonio Quartulli if (!full_table) { 2688a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 2689a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 2690a73105b8SAntonio Quartulli 26917ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 26927ea7b4a1SAntonio Quartulli &tvlv_tt_data, 26937ea7b4a1SAntonio Quartulli &tt_change, 26947ea7b4a1SAntonio Quartulli &tt_len); 26957ea7b4a1SAntonio Quartulli if (!tt_len) 2696a73105b8SAntonio Quartulli goto unlock; 2697a73105b8SAntonio Quartulli 2698a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 26997ea7b4a1SAntonio Quartulli memcpy(tt_change, req_dst_orig_node->tt_buff, 2700a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 2701a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 2702a73105b8SAntonio Quartulli } else { 27037ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 27047ea7b4a1SAntonio Quartulli * in the initial part 27057ea7b4a1SAntonio Quartulli */ 27067ea7b4a1SAntonio Quartulli tt_len = -1; 27077ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 27087ea7b4a1SAntonio Quartulli &tvlv_tt_data, 27097ea7b4a1SAntonio Quartulli &tt_change, 27107ea7b4a1SAntonio Quartulli &tt_len); 27117ea7b4a1SAntonio Quartulli if (!tt_len) 27127ea7b4a1SAntonio Quartulli goto out; 2713a73105b8SAntonio Quartulli 27147ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 27157ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, 27167ea7b4a1SAntonio Quartulli tt_change, tt_len, 2717a513088dSSven Eckelmann batadv_tt_global_valid, 2718a73105b8SAntonio Quartulli req_dst_orig_node); 2719a73105b8SAntonio Quartulli } 2720a73105b8SAntonio Quartulli 2721a19d3d85SMarek Lindner /* Don't send the response, if larger than fragmented packet. */ 2722a19d3d85SMarek Lindner tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len; 2723a19d3d85SMarek Lindner if (tt_len > atomic_read(&bat_priv->packet_size_max)) { 2724a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, bat_priv->soft_iface, 2725a19d3d85SMarek Lindner "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n", 2726a19d3d85SMarek Lindner res_dst_orig_node->orig); 2727a19d3d85SMarek Lindner goto out; 2728a19d3d85SMarek Lindner } 2729a19d3d85SMarek Lindner 2730335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2731335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 2732a73105b8SAntonio Quartulli 2733a73105b8SAntonio Quartulli if (full_table) 2734335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2735a73105b8SAntonio Quartulli 273639c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2737335fbe0fSMarek Lindner "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n", 2738335fbe0fSMarek Lindner res_dst_orig_node->orig, req_dst_orig_node->orig, 2739335fbe0fSMarek Lindner full_table ? 'F' : '.', req_ttvn); 2740a73105b8SAntonio Quartulli 2741d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 2742f8214865SMartin Hundebøll 2743335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, 27447ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 27457ea7b4a1SAntonio Quartulli tvlv_len); 2746e91ecfc6SMartin Hundebøll 2747335fbe0fSMarek Lindner ret = true; 2748a73105b8SAntonio Quartulli goto out; 2749a73105b8SAntonio Quartulli 2750a73105b8SAntonio Quartulli unlock: 2751a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 2752a73105b8SAntonio Quartulli 2753a73105b8SAntonio Quartulli out: 2754a73105b8SAntonio Quartulli if (res_dst_orig_node) 27555d967310SSven Eckelmann batadv_orig_node_put(res_dst_orig_node); 2756a73105b8SAntonio Quartulli if (req_dst_orig_node) 27575d967310SSven Eckelmann batadv_orig_node_put(req_dst_orig_node); 2758335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2759a73105b8SAntonio Quartulli return ret; 2760a73105b8SAntonio Quartulli } 276196412690SSven Eckelmann 2762335fbe0fSMarek Lindner /** 2763335fbe0fSMarek Lindner * batadv_send_my_tt_response - send reply to tt request concerning this node's 2764335fbe0fSMarek Lindner * translation table 2765335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2766335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2767335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2768335fbe0fSMarek Lindner * 276962fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2770335fbe0fSMarek Lindner */ 2771335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, 2772335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 27736b5e971aSSven Eckelmann u8 *req_src) 2774a73105b8SAntonio Quartulli { 2775335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 277656303d34SSven Eckelmann struct batadv_hard_iface *primary_if = NULL; 27777ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 27787ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node; 27796b5e971aSSven Eckelmann u8 my_ttvn, req_ttvn; 27806b5e971aSSven Eckelmann u16 tvlv_len; 2781a73105b8SAntonio Quartulli bool full_table; 27826b5e971aSSven Eckelmann s32 tt_len; 2783a73105b8SAntonio Quartulli 278439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 278586ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 2786335fbe0fSMarek Lindner req_src, tt_data->ttvn, 2787a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 2788a73105b8SAntonio Quartulli 2789a70a9aa9SAntonio Quartulli spin_lock_bh(&bat_priv->tt.commit_lock); 2790a73105b8SAntonio Quartulli 27916b5e971aSSven Eckelmann my_ttvn = (u8)atomic_read(&bat_priv->tt.vn); 2792335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 2793a73105b8SAntonio Quartulli 2794335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, req_src); 2795a73105b8SAntonio Quartulli if (!orig_node) 2796a73105b8SAntonio Quartulli goto out; 2797a73105b8SAntonio Quartulli 2798e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2799a73105b8SAntonio Quartulli if (!primary_if) 2800a73105b8SAntonio Quartulli goto out; 2801a73105b8SAntonio Quartulli 2802a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 28039cfc7bd6SSven Eckelmann * is too big send the whole local translation table 28049cfc7bd6SSven Eckelmann */ 2805335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || 2806807736f6SSven Eckelmann !bat_priv->tt.last_changeset) 2807a73105b8SAntonio Quartulli full_table = true; 2808a73105b8SAntonio Quartulli else 2809a73105b8SAntonio Quartulli full_table = false; 2810a73105b8SAntonio Quartulli 2811335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 2812335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 28139cfc7bd6SSven Eckelmann */ 2814a73105b8SAntonio Quartulli if (!full_table) { 2815807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 2816a73105b8SAntonio Quartulli 28177ea7b4a1SAntonio Quartulli tt_len = bat_priv->tt.last_changeset_len; 28187ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 28197ea7b4a1SAntonio Quartulli &tvlv_tt_data, 28207ea7b4a1SAntonio Quartulli &tt_change, 28217ea7b4a1SAntonio Quartulli &tt_len); 28227ea7b4a1SAntonio Quartulli if (!tt_len) 2823a73105b8SAntonio Quartulli goto unlock; 2824a73105b8SAntonio Quartulli 2825335fbe0fSMarek Lindner /* Copy the last orig_node's OGM buffer */ 28267ea7b4a1SAntonio Quartulli memcpy(tt_change, bat_priv->tt.last_changeset, 2827807736f6SSven Eckelmann bat_priv->tt.last_changeset_len); 2828807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2829a73105b8SAntonio Quartulli } else { 28306b5e971aSSven Eckelmann req_ttvn = (u8)atomic_read(&bat_priv->tt.vn); 2831a73105b8SAntonio Quartulli 28327ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 28337ea7b4a1SAntonio Quartulli * in the initial part 28347ea7b4a1SAntonio Quartulli */ 28357ea7b4a1SAntonio Quartulli tt_len = -1; 28367ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 28377ea7b4a1SAntonio Quartulli &tvlv_tt_data, 28387ea7b4a1SAntonio Quartulli &tt_change, 28397ea7b4a1SAntonio Quartulli &tt_len); 28407ea7b4a1SAntonio Quartulli if (!tt_len) 2841a73105b8SAntonio Quartulli goto out; 28427ea7b4a1SAntonio Quartulli 28437ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 28447ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, 28457ea7b4a1SAntonio Quartulli tt_change, tt_len, 28467ea7b4a1SAntonio Quartulli batadv_tt_local_valid, NULL); 2847a73105b8SAntonio Quartulli } 2848a73105b8SAntonio Quartulli 2849335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2850335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 2851a73105b8SAntonio Quartulli 2852a73105b8SAntonio Quartulli if (full_table) 2853335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2854a73105b8SAntonio Quartulli 285539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2856335fbe0fSMarek Lindner "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n", 2857335fbe0fSMarek Lindner orig_node->orig, full_table ? 'F' : '.', req_ttvn); 2858a73105b8SAntonio Quartulli 2859d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 2860f8214865SMartin Hundebøll 2861335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 28627ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 28637ea7b4a1SAntonio Quartulli tvlv_len); 2864335fbe0fSMarek Lindner 2865a73105b8SAntonio Quartulli goto out; 2866a73105b8SAntonio Quartulli 2867a73105b8SAntonio Quartulli unlock: 2868807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2869a73105b8SAntonio Quartulli out: 2870a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 2871a73105b8SAntonio Quartulli if (orig_node) 28725d967310SSven Eckelmann batadv_orig_node_put(orig_node); 2873a73105b8SAntonio Quartulli if (primary_if) 287482047ad7SSven Eckelmann batadv_hardif_put(primary_if); 2875335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2876335fbe0fSMarek Lindner /* The packet was for this host, so it doesn't need to be re-routed */ 2877a73105b8SAntonio Quartulli return true; 2878a73105b8SAntonio Quartulli } 2879a73105b8SAntonio Quartulli 2880335fbe0fSMarek Lindner /** 2881335fbe0fSMarek Lindner * batadv_send_tt_response - send reply to tt request 2882335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2883335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2884335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2885335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 2886335fbe0fSMarek Lindner * 288762fe710fSSven Eckelmann * Return: true if tt request reply was sent, false otherwise. 2888335fbe0fSMarek Lindner */ 2889335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv, 2890335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 28916b5e971aSSven Eckelmann u8 *req_src, u8 *req_dst) 2892a73105b8SAntonio Quartulli { 2893cfd4f757SAntonio Quartulli if (batadv_is_my_mac(bat_priv, req_dst)) 2894335fbe0fSMarek Lindner return batadv_send_my_tt_response(bat_priv, tt_data, req_src); 289524820df1SAntonio Quartulli return batadv_send_other_tt_response(bat_priv, tt_data, req_src, 289624820df1SAntonio Quartulli req_dst); 2897a73105b8SAntonio Quartulli } 2898a73105b8SAntonio Quartulli 289956303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, 290056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2901335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change, 29026b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn) 2903a73105b8SAntonio Quartulli { 2904a73105b8SAntonio Quartulli int i; 2905a513088dSSven Eckelmann int roams; 2906a73105b8SAntonio Quartulli 2907a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 2908acd34afaSSven Eckelmann if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { 2909acd34afaSSven Eckelmann roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; 2910a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 2911a73105b8SAntonio Quartulli (tt_change + i)->addr, 2912c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 2913cc47f66eSAntonio Quartulli "tt removed by changes", 2914a513088dSSven Eckelmann roams); 291508c36d3eSSven Eckelmann } else { 291608c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 2917d4f44692SAntonio Quartulli (tt_change + i)->addr, 2918c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 2919d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 2920a73105b8SAntonio Quartulli /* In case of problem while storing a 2921a73105b8SAntonio Quartulli * global_entry, we stop the updating 2922a73105b8SAntonio Quartulli * procedure without committing the 2923a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 2924a73105b8SAntonio Quartulli * corrupted data on tt_request 2925a73105b8SAntonio Quartulli */ 2926a73105b8SAntonio Quartulli return; 2927a73105b8SAntonio Quartulli } 292808c36d3eSSven Eckelmann } 2929ac4eebd4SLinus Lüssing set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); 2930a73105b8SAntonio Quartulli } 2931a73105b8SAntonio Quartulli 293256303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, 29337ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 29346b5e971aSSven Eckelmann u8 ttvn, u8 *resp_src, 29356b5e971aSSven Eckelmann u16 num_entries) 2936a73105b8SAntonio Quartulli { 2937170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 2938a73105b8SAntonio Quartulli 2939335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 2940a73105b8SAntonio Quartulli if (!orig_node) 2941a73105b8SAntonio Quartulli goto out; 2942a73105b8SAntonio Quartulli 2943a73105b8SAntonio Quartulli /* Purge the old table first.. */ 294495fb130dSAntonio Quartulli batadv_tt_global_del_orig(bat_priv, orig_node, -1, 294595fb130dSAntonio Quartulli "Received full table"); 2946a73105b8SAntonio Quartulli 29477ea7b4a1SAntonio Quartulli _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, 29487ea7b4a1SAntonio Quartulli ttvn); 2949a73105b8SAntonio Quartulli 2950a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2951a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2952a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2953a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 2954a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2955a73105b8SAntonio Quartulli 29567ea7b4a1SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2957a73105b8SAntonio Quartulli 2958a73105b8SAntonio Quartulli out: 2959a73105b8SAntonio Quartulli if (orig_node) 29605d967310SSven Eckelmann batadv_orig_node_put(orig_node); 2961a73105b8SAntonio Quartulli } 2962a73105b8SAntonio Quartulli 296356303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv, 296456303d34SSven Eckelmann struct batadv_orig_node *orig_node, 29656b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn, 2966335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change) 2967a73105b8SAntonio Quartulli { 2968a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 2969a513088dSSven Eckelmann tt_num_changes, ttvn); 2970a73105b8SAntonio Quartulli 2971e8cf234aSAntonio Quartulli batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, 2972e8cf234aSAntonio Quartulli batadv_tt_len(tt_num_changes)); 2973a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2974a73105b8SAntonio Quartulli } 2975a73105b8SAntonio Quartulli 2976c018ad3dSAntonio Quartulli /** 2977c018ad3dSAntonio Quartulli * batadv_is_my_client - check if a client is served by the local node 2978c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 29793f68785eSAntonio Quartulli * @addr: the mac address of the client to check 2980c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2981c018ad3dSAntonio Quartulli * 298262fe710fSSven Eckelmann * Return: true if the client is served by this node, false otherwise. 2983c018ad3dSAntonio Quartulli */ 29846b5e971aSSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr, 2985c018ad3dSAntonio Quartulli unsigned short vid) 2986a73105b8SAntonio Quartulli { 2987170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 29887683fdc1SAntonio Quartulli bool ret = false; 2989a73105b8SAntonio Quartulli 2990c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 29917683fdc1SAntonio Quartulli if (!tt_local_entry) 29927683fdc1SAntonio Quartulli goto out; 2993058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 29949cfc7bd6SSven Eckelmann * consistency purpose) 29959cfc7bd6SSven Eckelmann */ 29967c1fd91dSAntonio Quartulli if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) || 29977c1fd91dSAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM)) 2998058d0e26SAntonio Quartulli goto out; 29997683fdc1SAntonio Quartulli ret = true; 30007683fdc1SAntonio Quartulli out: 3001a73105b8SAntonio Quartulli if (tt_local_entry) 300295c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 30037683fdc1SAntonio Quartulli return ret; 3004a73105b8SAntonio Quartulli } 3005a73105b8SAntonio Quartulli 3006335fbe0fSMarek Lindner /** 3007335fbe0fSMarek Lindner * batadv_handle_tt_response - process incoming tt reply 3008335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3009335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 3010335fbe0fSMarek Lindner * @resp_src: mac address of tt reply sender 3011335fbe0fSMarek Lindner * @num_entries: number of tt change entries appended to the tt data 3012335fbe0fSMarek Lindner */ 3013335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv, 3014335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 30156b5e971aSSven Eckelmann u8 *resp_src, u16 num_entries) 3016a73105b8SAntonio Quartulli { 30177c26a53bSMarek Lindner struct batadv_tt_req_node *node; 30187c26a53bSMarek Lindner struct hlist_node *safe; 301956303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 3020335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 30216b5e971aSSven Eckelmann u8 *tvlv_ptr = (u8 *)tt_data; 30226b5e971aSSven Eckelmann u16 change_offset; 3023a73105b8SAntonio Quartulli 302439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 302586ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 3026335fbe0fSMarek Lindner resp_src, tt_data->ttvn, num_entries, 3027a2f2b6cdSSven Eckelmann ((tt_data->flags & BATADV_TT_FULL_TABLE) ? 'F' : '.')); 3028a73105b8SAntonio Quartulli 3029335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 3030a73105b8SAntonio Quartulli if (!orig_node) 3031a73105b8SAntonio Quartulli goto out; 3032a73105b8SAntonio Quartulli 3033a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 3034a70a9aa9SAntonio Quartulli 30357ea7b4a1SAntonio Quartulli change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); 30367ea7b4a1SAntonio Quartulli change_offset *= ntohs(tt_data->num_vlan); 30377ea7b4a1SAntonio Quartulli change_offset += sizeof(*tt_data); 30387ea7b4a1SAntonio Quartulli tvlv_ptr += change_offset; 30397ea7b4a1SAntonio Quartulli 30407ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; 3041335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) { 30427ea7b4a1SAntonio Quartulli batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, 30437ea7b4a1SAntonio Quartulli resp_src, num_entries); 304496412690SSven Eckelmann } else { 3045335fbe0fSMarek Lindner batadv_tt_update_changes(bat_priv, orig_node, num_entries, 3046335fbe0fSMarek Lindner tt_data->ttvn, tt_change); 304796412690SSven Eckelmann } 3048a73105b8SAntonio Quartulli 3049a70a9aa9SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 30507ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3051a70a9aa9SAntonio Quartulli 3052a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3053a70a9aa9SAntonio Quartulli 3054a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 3055807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 30567c26a53bSMarek Lindner hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 3057335fbe0fSMarek Lindner if (!batadv_compare_eth(node->addr, resp_src)) 3058a73105b8SAntonio Quartulli continue; 30597c26a53bSMarek Lindner hlist_del_init(&node->list); 3060a73105b8SAntonio Quartulli kfree(node); 3061a73105b8SAntonio Quartulli } 30627ea7b4a1SAntonio Quartulli 3063807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 3064a73105b8SAntonio Quartulli out: 3065a73105b8SAntonio Quartulli if (orig_node) 30665d967310SSven Eckelmann batadv_orig_node_put(orig_node); 3067a73105b8SAntonio Quartulli } 3068a73105b8SAntonio Quartulli 306956303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) 3070a73105b8SAntonio Quartulli { 307156303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 3072a73105b8SAntonio Quartulli 3073807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3074a73105b8SAntonio Quartulli 3075807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 3076cc47f66eSAntonio Quartulli list_del(&node->list); 3077cc47f66eSAntonio Quartulli kfree(node); 3078cc47f66eSAntonio Quartulli } 3079cc47f66eSAntonio Quartulli 3080807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3081cc47f66eSAntonio Quartulli } 3082cc47f66eSAntonio Quartulli 308356303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) 3084cc47f66eSAntonio Quartulli { 308556303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 3086cc47f66eSAntonio Quartulli 3087807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3088807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 308942d0b044SSven Eckelmann if (!batadv_has_timed_out(node->first_time, 309042d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 3091cc47f66eSAntonio Quartulli continue; 3092cc47f66eSAntonio Quartulli 3093cc47f66eSAntonio Quartulli list_del(&node->list); 3094cc47f66eSAntonio Quartulli kfree(node); 3095cc47f66eSAntonio Quartulli } 3096807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3097cc47f66eSAntonio Quartulli } 3098cc47f66eSAntonio Quartulli 309962fe710fSSven Eckelmann /** 3100d15cd622SAntonio Quartulli * batadv_tt_check_roam_count - check if a client has roamed too frequently 3101d15cd622SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3102d15cd622SAntonio Quartulli * @client: mac address of the roaming client 310362fe710fSSven Eckelmann * 310462fe710fSSven Eckelmann * This function checks whether the client already reached the 3105cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 3106cc47f66eSAntonio Quartulli * will not be sent. 3107cc47f66eSAntonio Quartulli * 310862fe710fSSven Eckelmann * Return: true if the ROAMING_ADV can be sent, false otherwise 31099cfc7bd6SSven Eckelmann */ 31106b5e971aSSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client) 3111cc47f66eSAntonio Quartulli { 311256303d34SSven Eckelmann struct batadv_tt_roam_node *tt_roam_node; 3113cc47f66eSAntonio Quartulli bool ret = false; 3114cc47f66eSAntonio Quartulli 3115807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 3116cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 31179cfc7bd6SSven Eckelmann * reply from the same orig_node yet 31189cfc7bd6SSven Eckelmann */ 3119807736f6SSven Eckelmann list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) { 31201eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 3121cc47f66eSAntonio Quartulli continue; 3122cc47f66eSAntonio Quartulli 31231eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 312442d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 3125cc47f66eSAntonio Quartulli continue; 3126cc47f66eSAntonio Quartulli 31273e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 3128cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 3129cc47f66eSAntonio Quartulli goto unlock; 3130cc47f66eSAntonio Quartulli ret = true; 3131cc47f66eSAntonio Quartulli break; 3132cc47f66eSAntonio Quartulli } 3133cc47f66eSAntonio Quartulli 3134cc47f66eSAntonio Quartulli if (!ret) { 3135cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 3136cc47f66eSAntonio Quartulli if (!tt_roam_node) 3137cc47f66eSAntonio Quartulli goto unlock; 3138cc47f66eSAntonio Quartulli 3139cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 314042d0b044SSven Eckelmann atomic_set(&tt_roam_node->counter, 314142d0b044SSven Eckelmann BATADV_ROAMING_MAX_COUNT - 1); 31428fdd0153SAntonio Quartulli ether_addr_copy(tt_roam_node->addr, client); 3143cc47f66eSAntonio Quartulli 3144807736f6SSven Eckelmann list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); 3145cc47f66eSAntonio Quartulli ret = true; 3146cc47f66eSAntonio Quartulli } 3147cc47f66eSAntonio Quartulli 3148cc47f66eSAntonio Quartulli unlock: 3149807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 3150cc47f66eSAntonio Quartulli return ret; 3151cc47f66eSAntonio Quartulli } 3152cc47f66eSAntonio Quartulli 3153c018ad3dSAntonio Quartulli /** 3154c018ad3dSAntonio Quartulli * batadv_send_roam_adv - send a roaming advertisement message 3155c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3156c018ad3dSAntonio Quartulli * @client: mac address of the roaming client 3157c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3158c018ad3dSAntonio Quartulli * @orig_node: message destination 3159c018ad3dSAntonio Quartulli * 3160c018ad3dSAntonio Quartulli * Send a ROAMING_ADV message to the node which was previously serving this 3161c018ad3dSAntonio Quartulli * client. This is done to inform the node that from now on all traffic destined 3162c018ad3dSAntonio Quartulli * for this particular roamed client has to be forwarded to the sender of the 3163c018ad3dSAntonio Quartulli * roaming message. 3164c018ad3dSAntonio Quartulli */ 31656b5e971aSSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, 3166c018ad3dSAntonio Quartulli unsigned short vid, 316756303d34SSven Eckelmann struct batadv_orig_node *orig_node) 3168cc47f66eSAntonio Quartulli { 316956303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 3170122edaa0SMarek Lindner struct batadv_tvlv_roam_adv tvlv_roam; 3171122edaa0SMarek Lindner 3172122edaa0SMarek Lindner primary_if = batadv_primary_if_get_selected(bat_priv); 3173122edaa0SMarek Lindner if (!primary_if) 3174122edaa0SMarek Lindner goto out; 3175cc47f66eSAntonio Quartulli 3176cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 31779cfc7bd6SSven Eckelmann * already roamed to us too many times 31789cfc7bd6SSven Eckelmann */ 3179a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 3180cc47f66eSAntonio Quartulli goto out; 3181cc47f66eSAntonio Quartulli 318239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 318316052789SAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n", 318416052789SAntonio Quartulli orig_node->orig, client, BATADV_PRINT_VID(vid)); 3185cc47f66eSAntonio Quartulli 3186d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); 3187f8214865SMartin Hundebøll 3188122edaa0SMarek Lindner memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); 3189c018ad3dSAntonio Quartulli tvlv_roam.vid = htons(vid); 3190122edaa0SMarek Lindner 3191122edaa0SMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 3192122edaa0SMarek Lindner orig_node->orig, BATADV_TVLV_ROAM, 1, 3193122edaa0SMarek Lindner &tvlv_roam, sizeof(tvlv_roam)); 3194cc47f66eSAntonio Quartulli 3195cc47f66eSAntonio Quartulli out: 3196122edaa0SMarek Lindner if (primary_if) 319782047ad7SSven Eckelmann batadv_hardif_put(primary_if); 3198a73105b8SAntonio Quartulli } 3199a73105b8SAntonio Quartulli 3200a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 3201a73105b8SAntonio Quartulli { 320256303d34SSven Eckelmann struct delayed_work *delayed_work; 3203807736f6SSven Eckelmann struct batadv_priv_tt *priv_tt; 320456303d34SSven Eckelmann struct batadv_priv *bat_priv; 320556303d34SSven Eckelmann 32064ba4bc0fSGeliang Tang delayed_work = to_delayed_work(work); 3207807736f6SSven Eckelmann priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 3208807736f6SSven Eckelmann bat_priv = container_of(priv_tt, struct batadv_priv, tt); 3209a73105b8SAntonio Quartulli 3210a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT); 321130cfd02bSAntonio Quartulli batadv_tt_global_purge(bat_priv); 3212a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 3213a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 3214a73105b8SAntonio Quartulli 321572414442SAntonio Quartulli queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 321672414442SAntonio Quartulli msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3217a73105b8SAntonio Quartulli } 3218cc47f66eSAntonio Quartulli 321956303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv) 3220cc47f66eSAntonio Quartulli { 3221e1bf0c14SMarek Lindner batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); 3222e1bf0c14SMarek Lindner batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); 3223e1bf0c14SMarek Lindner 3224807736f6SSven Eckelmann cancel_delayed_work_sync(&bat_priv->tt.work); 3225cc47f66eSAntonio Quartulli 3226a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 3227a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 3228a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 3229a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 3230a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 3231cc47f66eSAntonio Quartulli 3232807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 3233cc47f66eSAntonio Quartulli } 3234058d0e26SAntonio Quartulli 32357ea7b4a1SAntonio Quartulli /** 32367ea7b4a1SAntonio Quartulli * batadv_tt_local_set_flags - set or unset the specified flags on the local 32377ea7b4a1SAntonio Quartulli * table and possibly count them in the TT size 32387ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 32397ea7b4a1SAntonio Quartulli * @flags: the flag to switch 32407ea7b4a1SAntonio Quartulli * @enable: whether to set or unset the flag 32417ea7b4a1SAntonio Quartulli * @count: whether to increase the TT size by the number of changed entries 32429cfc7bd6SSven Eckelmann */ 32436b5e971aSSven Eckelmann static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags, 32446b5e971aSSven Eckelmann bool enable, bool count) 3245058d0e26SAntonio Quartulli { 32467ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash = bat_priv->tt.local_hash; 32477ea7b4a1SAntonio Quartulli struct batadv_tt_common_entry *tt_common_entry; 32486b5e971aSSven Eckelmann u16 changed_num = 0; 3249058d0e26SAntonio Quartulli struct hlist_head *head; 32506b5e971aSSven Eckelmann u32 i; 3251058d0e26SAntonio Quartulli 3252058d0e26SAntonio Quartulli if (!hash) 32537ea7b4a1SAntonio Quartulli return; 3254058d0e26SAntonio Quartulli 3255058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3256058d0e26SAntonio Quartulli head = &hash->table[i]; 3257058d0e26SAntonio Quartulli 3258058d0e26SAntonio Quartulli rcu_read_lock(); 3259b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 3260058d0e26SAntonio Quartulli head, hash_entry) { 3261697f2531SAntonio Quartulli if (enable) { 3262697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 3263697f2531SAntonio Quartulli continue; 3264697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 3265697f2531SAntonio Quartulli } else { 326648100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 326731901264SAntonio Quartulli continue; 326848100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 3269697f2531SAntonio Quartulli } 3270697f2531SAntonio Quartulli changed_num++; 32717ea7b4a1SAntonio Quartulli 32727ea7b4a1SAntonio Quartulli if (!count) 32737ea7b4a1SAntonio Quartulli continue; 32747ea7b4a1SAntonio Quartulli 32757ea7b4a1SAntonio Quartulli batadv_tt_local_size_inc(bat_priv, 32767ea7b4a1SAntonio Quartulli tt_common_entry->vid); 3277058d0e26SAntonio Quartulli } 3278058d0e26SAntonio Quartulli rcu_read_unlock(); 3279058d0e26SAntonio Quartulli } 3280058d0e26SAntonio Quartulli } 3281058d0e26SAntonio Quartulli 3282acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ 328356303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) 3284058d0e26SAntonio Quartulli { 3285807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 328656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 328756303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 3288b67bfe0dSSasha Levin struct hlist_node *node_tmp; 3289058d0e26SAntonio Quartulli struct hlist_head *head; 3290058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 32916b5e971aSSven Eckelmann u32 i; 3292058d0e26SAntonio Quartulli 3293058d0e26SAntonio Quartulli if (!hash) 3294058d0e26SAntonio Quartulli return; 3295058d0e26SAntonio Quartulli 3296058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3297058d0e26SAntonio Quartulli head = &hash->table[i]; 3298058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 3299058d0e26SAntonio Quartulli 3300058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 3301b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 3302acd34afaSSven Eckelmann hash_entry) { 3303acd34afaSSven Eckelmann if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) 3304058d0e26SAntonio Quartulli continue; 3305058d0e26SAntonio Quartulli 330639c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 330716052789SAntonio Quartulli "Deleting local tt entry (%pM, vid: %d): pending\n", 330816052789SAntonio Quartulli tt_common->addr, 330916052789SAntonio Quartulli BATADV_PRINT_VID(tt_common->vid)); 3310058d0e26SAntonio Quartulli 33117ea7b4a1SAntonio Quartulli batadv_tt_local_size_dec(bat_priv, tt_common->vid); 3312b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 331356303d34SSven Eckelmann tt_local = container_of(tt_common, 331456303d34SSven Eckelmann struct batadv_tt_local_entry, 331548100bacSAntonio Quartulli common); 331635df3b29SAntonio Quartulli 331795c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local); 3318058d0e26SAntonio Quartulli } 3319058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 3320058d0e26SAntonio Quartulli } 3321058d0e26SAntonio Quartulli } 3322058d0e26SAntonio Quartulli 3323e1bf0c14SMarek Lindner /** 3324a19d3d85SMarek Lindner * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes 3325a19d3d85SMarek Lindner * which have been queued in the time since the last commit 3326e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3327a19d3d85SMarek Lindner * 3328a19d3d85SMarek Lindner * Caller must hold tt->commit_lock. 3329e1bf0c14SMarek Lindner */ 3330a19d3d85SMarek Lindner static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) 3331058d0e26SAntonio Quartulli { 33325274cd68SSven Eckelmann lockdep_assert_held(&bat_priv->tt.commit_lock); 33335274cd68SSven Eckelmann 3334c5caf4efSLinus Lüssing /* Update multicast addresses in local translation table */ 3335c5caf4efSLinus Lüssing batadv_mcast_mla_update(bat_priv); 3336c5caf4efSLinus Lüssing 3337e1bf0c14SMarek Lindner if (atomic_read(&bat_priv->tt.local_changes) < 1) { 3338e1bf0c14SMarek Lindner if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 3339e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3340a19d3d85SMarek Lindner return; 3341e1bf0c14SMarek Lindner } 3342be9aa4c1SMarek Lindner 33437ea7b4a1SAntonio Quartulli batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); 3344be9aa4c1SMarek Lindner 3345a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 33467ea7b4a1SAntonio Quartulli batadv_tt_local_update_crc(bat_priv); 3347058d0e26SAntonio Quartulli 3348058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 3349807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.vn); 335039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 33511eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 33526b5e971aSSven Eckelmann (u8)atomic_read(&bat_priv->tt.vn)); 3353be9aa4c1SMarek Lindner 3354be9aa4c1SMarek Lindner /* reset the sending counter */ 3355807736f6SSven Eckelmann atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 3356e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3357a19d3d85SMarek Lindner } 3358a70a9aa9SAntonio Quartulli 3359a19d3d85SMarek Lindner /** 3360a19d3d85SMarek Lindner * batadv_tt_local_commit_changes - commit all pending local tt changes which 3361a19d3d85SMarek Lindner * have been queued in the time since the last commit 3362a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3363a19d3d85SMarek Lindner */ 3364a19d3d85SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) 3365a19d3d85SMarek Lindner { 3366a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3367a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3368a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 3369058d0e26SAntonio Quartulli } 337059b699cdSAntonio Quartulli 33716b5e971aSSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, 33726b5e971aSSven Eckelmann unsigned short vid) 337359b699cdSAntonio Quartulli { 337456303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 337556303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 3376b8cbd81dSAntonio Quartulli struct batadv_softif_vlan *vlan; 33775870adc6SMarek Lindner bool ret = false; 337859b699cdSAntonio Quartulli 3379b8cbd81dSAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 3380e087f34fSMarkus Elfring if (!vlan) 3381e087f34fSMarkus Elfring return false; 3382e087f34fSMarkus Elfring 3383e087f34fSMarkus Elfring if (!atomic_read(&vlan->ap_isolation)) 33845870adc6SMarek Lindner goto out; 338559b699cdSAntonio Quartulli 3386b8cbd81dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); 338759b699cdSAntonio Quartulli if (!tt_local_entry) 338859b699cdSAntonio Quartulli goto out; 338959b699cdSAntonio Quartulli 3390b8cbd81dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); 339159b699cdSAntonio Quartulli if (!tt_global_entry) 339259b699cdSAntonio Quartulli goto out; 339359b699cdSAntonio Quartulli 33941f129fefSAntonio Quartulli if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 339559b699cdSAntonio Quartulli goto out; 339659b699cdSAntonio Quartulli 33975870adc6SMarek Lindner ret = true; 339859b699cdSAntonio Quartulli 339959b699cdSAntonio Quartulli out: 34009c3bf081SSven Eckelmann batadv_softif_vlan_put(vlan); 340159b699cdSAntonio Quartulli if (tt_global_entry) 34025dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 340359b699cdSAntonio Quartulli if (tt_local_entry) 340495c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 340559b699cdSAntonio Quartulli return ret; 340659b699cdSAntonio Quartulli } 3407a943cac1SMarek Lindner 3408e1bf0c14SMarek Lindner /** 3409e1bf0c14SMarek Lindner * batadv_tt_update_orig - update global translation table with new tt 3410e1bf0c14SMarek Lindner * information received via ogms 3411e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3412e51f0397SSven Eckelmann * @orig_node: the orig_node of the ogm 3413e51f0397SSven Eckelmann * @tt_buff: pointer to the first tvlv VLAN entry 34147ea7b4a1SAntonio Quartulli * @tt_num_vlan: number of tvlv VLAN entries 34157ea7b4a1SAntonio Quartulli * @tt_change: pointer to the first entry in the TT buffer 3416e1bf0c14SMarek Lindner * @tt_num_changes: number of tt changes inside the tt buffer 3417e1bf0c14SMarek Lindner * @ttvn: translation table version number of this changeset 3418e1bf0c14SMarek Lindner */ 3419e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv, 342056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 34216b5e971aSSven Eckelmann const void *tt_buff, u16 tt_num_vlan, 34227ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 34236b5e971aSSven Eckelmann u16 tt_num_changes, u8 ttvn) 3424a943cac1SMarek Lindner { 34256b5e971aSSven Eckelmann u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); 34267ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 3427a943cac1SMarek Lindner bool full_table = true; 3428e17931d1SLinus Lüssing bool has_tt_init; 3429a943cac1SMarek Lindner 34307ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; 3431ac4eebd4SLinus Lüssing has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT, 3432ac4eebd4SLinus Lüssing &orig_node->capa_initialized); 3433e17931d1SLinus Lüssing 343417071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 34359cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 34369cfc7bd6SSven Eckelmann */ 3437e17931d1SLinus Lüssing if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) { 3438a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 343942d0b044SSven Eckelmann * because they have already been sent BATADV_TT_OGM_APPEND_MAX 344042d0b044SSven Eckelmann * times. 34419cfc7bd6SSven Eckelmann * In this case send a tt request 34429cfc7bd6SSven Eckelmann */ 3443a943cac1SMarek Lindner if (!tt_num_changes) { 3444a943cac1SMarek Lindner full_table = false; 3445a943cac1SMarek Lindner goto request_table; 3446a943cac1SMarek Lindner } 3447a943cac1SMarek Lindner 3448a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 3449a70a9aa9SAntonio Quartulli 3450a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 345196412690SSven Eckelmann ttvn, tt_change); 3452a943cac1SMarek Lindner 3453a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 3454a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 34559cfc7bd6SSven Eckelmann * in the global table 34569cfc7bd6SSven Eckelmann */ 34577ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3458a943cac1SMarek Lindner 3459a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3460a70a9aa9SAntonio Quartulli 3461a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 3462a943cac1SMarek Lindner * because a single value could represent different states 3463a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 3464a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 3465a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 3466a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 3467a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 34689cfc7bd6SSven Eckelmann * inconsistency 34699cfc7bd6SSven Eckelmann */ 34707ea7b4a1SAntonio Quartulli if (!batadv_tt_global_check_crc(orig_node, tt_vlan, 34717ea7b4a1SAntonio Quartulli tt_num_vlan)) 3472a943cac1SMarek Lindner goto request_table; 3473a943cac1SMarek Lindner } else { 3474a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 34759cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 34769cfc7bd6SSven Eckelmann */ 3477e17931d1SLinus Lüssing if (!has_tt_init || ttvn != orig_ttvn || 34787ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(orig_node, tt_vlan, 34797ea7b4a1SAntonio Quartulli tt_num_vlan)) { 3480a943cac1SMarek Lindner request_table: 348139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 34827ea7b4a1SAntonio Quartulli "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n", 34837ea7b4a1SAntonio Quartulli orig_node->orig, ttvn, orig_ttvn, 34847ea7b4a1SAntonio Quartulli tt_num_changes); 3485a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 34867ea7b4a1SAntonio Quartulli tt_vlan, tt_num_vlan, 34877ea7b4a1SAntonio Quartulli full_table); 3488a943cac1SMarek Lindner return; 3489a943cac1SMarek Lindner } 3490a943cac1SMarek Lindner } 3491a943cac1SMarek Lindner } 34923275e7ccSAntonio Quartulli 3493c018ad3dSAntonio Quartulli /** 3494c018ad3dSAntonio Quartulli * batadv_tt_global_client_is_roaming - check if a client is marked as roaming 3495c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3496c018ad3dSAntonio Quartulli * @addr: the mac address of the client to check 3497c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3498c018ad3dSAntonio Quartulli * 349962fe710fSSven Eckelmann * Return: true if we know that the client has moved from its old originator 3500c018ad3dSAntonio Quartulli * to another one. This entry is still kept for consistency purposes and will be 3501c018ad3dSAntonio Quartulli * deleted later by a DEL or because of timeout 35023275e7ccSAntonio Quartulli */ 350356303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, 35046b5e971aSSven Eckelmann u8 *addr, unsigned short vid) 35053275e7ccSAntonio Quartulli { 350656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 35073275e7ccSAntonio Quartulli bool ret = false; 35083275e7ccSAntonio Quartulli 3509c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 35103275e7ccSAntonio Quartulli if (!tt_global_entry) 35113275e7ccSAntonio Quartulli goto out; 35123275e7ccSAntonio Quartulli 3513c1d07431SAntonio Quartulli ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; 35145dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt_global_entry); 35153275e7ccSAntonio Quartulli out: 35163275e7ccSAntonio Quartulli return ret; 35173275e7ccSAntonio Quartulli } 351830cfd02bSAntonio Quartulli 35197c1fd91dSAntonio Quartulli /** 35207c1fd91dSAntonio Quartulli * batadv_tt_local_client_is_roaming - tells whether the client is roaming 35217c1fd91dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3522c018ad3dSAntonio Quartulli * @addr: the mac address of the local client to query 3523c018ad3dSAntonio Quartulli * @vid: VLAN identifier 35247c1fd91dSAntonio Quartulli * 352562fe710fSSven Eckelmann * Return: true if the local client is known to be roaming (it is not served by 35267c1fd91dSAntonio Quartulli * this node anymore) or not. If yes, the client is still present in the table 35277c1fd91dSAntonio Quartulli * to keep the latter consistent with the node TTVN 35287c1fd91dSAntonio Quartulli */ 35297c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, 35306b5e971aSSven Eckelmann u8 *addr, unsigned short vid) 35317c1fd91dSAntonio Quartulli { 35327c1fd91dSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry; 35337c1fd91dSAntonio Quartulli bool ret = false; 35347c1fd91dSAntonio Quartulli 3535c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 35367c1fd91dSAntonio Quartulli if (!tt_local_entry) 35377c1fd91dSAntonio Quartulli goto out; 35387c1fd91dSAntonio Quartulli 35397c1fd91dSAntonio Quartulli ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; 354095c0db90SSven Eckelmann batadv_tt_local_entry_put(tt_local_entry); 35417c1fd91dSAntonio Quartulli out: 35427c1fd91dSAntonio Quartulli return ret; 35437c1fd91dSAntonio Quartulli } 35447c1fd91dSAntonio Quartulli 354530cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, 354630cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 3547c018ad3dSAntonio Quartulli const unsigned char *addr, 354816052789SAntonio Quartulli unsigned short vid) 354930cfd02bSAntonio Quartulli { 355030cfd02bSAntonio Quartulli bool ret = false; 355130cfd02bSAntonio Quartulli 355216052789SAntonio Quartulli if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, 355330cfd02bSAntonio Quartulli BATADV_TT_CLIENT_TEMP, 355430cfd02bSAntonio Quartulli atomic_read(&orig_node->last_ttvn))) 355530cfd02bSAntonio Quartulli goto out; 355630cfd02bSAntonio Quartulli 355730cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 355816052789SAntonio Quartulli "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n", 355916052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid), orig_node->orig); 356030cfd02bSAntonio Quartulli ret = true; 356130cfd02bSAntonio Quartulli out: 356230cfd02bSAntonio Quartulli return ret; 356330cfd02bSAntonio Quartulli } 3564e1bf0c14SMarek Lindner 3565e1bf0c14SMarek Lindner /** 3566a19d3d85SMarek Lindner * batadv_tt_local_resize_to_mtu - resize the local translation table fit the 3567a19d3d85SMarek Lindner * maximum packet size that can be transported through the mesh 3568a19d3d85SMarek Lindner * @soft_iface: netdev struct of the mesh interface 3569a19d3d85SMarek Lindner * 3570a19d3d85SMarek Lindner * Remove entries older than 'timeout' and half timeout if more entries need 3571a19d3d85SMarek Lindner * to be removed. 3572a19d3d85SMarek Lindner */ 3573a19d3d85SMarek Lindner void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface) 3574a19d3d85SMarek Lindner { 3575a19d3d85SMarek Lindner struct batadv_priv *bat_priv = netdev_priv(soft_iface); 3576a19d3d85SMarek Lindner int packet_size_max = atomic_read(&bat_priv->packet_size_max); 3577a19d3d85SMarek Lindner int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; 3578a19d3d85SMarek Lindner bool reduced = false; 3579a19d3d85SMarek Lindner 3580a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3581a19d3d85SMarek Lindner 3582a19d3d85SMarek Lindner while (true) { 3583a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 3584a19d3d85SMarek Lindner if (packet_size_max >= table_size) 3585a19d3d85SMarek Lindner break; 3586a19d3d85SMarek Lindner 3587a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, timeout); 3588a19d3d85SMarek Lindner batadv_tt_local_purge_pending_clients(bat_priv); 3589a19d3d85SMarek Lindner 3590a19d3d85SMarek Lindner timeout /= 2; 3591a19d3d85SMarek Lindner reduced = true; 3592a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 3593a19d3d85SMarek Lindner "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n", 3594a19d3d85SMarek Lindner packet_size_max); 3595a19d3d85SMarek Lindner } 3596a19d3d85SMarek Lindner 3597a19d3d85SMarek Lindner /* commit these changes immediately, to avoid synchronization problem 3598a19d3d85SMarek Lindner * with the TTVN 3599a19d3d85SMarek Lindner */ 3600a19d3d85SMarek Lindner if (reduced) 3601a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3602a19d3d85SMarek Lindner 3603a19d3d85SMarek Lindner spin_unlock_bh(&bat_priv->tt.commit_lock); 3604a19d3d85SMarek Lindner } 3605a19d3d85SMarek Lindner 3606a19d3d85SMarek Lindner /** 3607e1bf0c14SMarek Lindner * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container 3608e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3609e1bf0c14SMarek Lindner * @orig: the orig_node of the ogm 3610e1bf0c14SMarek Lindner * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 3611e1bf0c14SMarek Lindner * @tvlv_value: tvlv buffer containing the gateway data 3612e1bf0c14SMarek Lindner * @tvlv_value_len: tvlv buffer length 3613e1bf0c14SMarek Lindner */ 3614e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 3615e1bf0c14SMarek Lindner struct batadv_orig_node *orig, 36166b5e971aSSven Eckelmann u8 flags, void *tvlv_value, 36176b5e971aSSven Eckelmann u16 tvlv_value_len) 3618e1bf0c14SMarek Lindner { 36197ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 36207ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 3621e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 36226b5e971aSSven Eckelmann u16 num_entries, num_vlan; 3623e1bf0c14SMarek Lindner 3624e1bf0c14SMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 3625e1bf0c14SMarek Lindner return; 3626e1bf0c14SMarek Lindner 3627e1bf0c14SMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 3628e1bf0c14SMarek Lindner tvlv_value_len -= sizeof(*tt_data); 3629e1bf0c14SMarek Lindner 36307ea7b4a1SAntonio Quartulli num_vlan = ntohs(tt_data->num_vlan); 36317ea7b4a1SAntonio Quartulli 36327ea7b4a1SAntonio Quartulli if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) 36337ea7b4a1SAntonio Quartulli return; 36347ea7b4a1SAntonio Quartulli 36357ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 36367ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); 36377ea7b4a1SAntonio Quartulli tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; 36387ea7b4a1SAntonio Quartulli 3639298e6e68SAntonio Quartulli num_entries = batadv_tt_entries(tvlv_value_len); 3640e1bf0c14SMarek Lindner 36417ea7b4a1SAntonio Quartulli batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, 36427ea7b4a1SAntonio Quartulli num_entries, tt_data->ttvn); 3643e1bf0c14SMarek Lindner } 3644e1bf0c14SMarek Lindner 3645e1bf0c14SMarek Lindner /** 3646335fbe0fSMarek Lindner * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv 3647335fbe0fSMarek Lindner * container 3648335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3649335fbe0fSMarek Lindner * @src: mac address of tt tvlv sender 3650335fbe0fSMarek Lindner * @dst: mac address of tt tvlv recipient 3651335fbe0fSMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 3652335fbe0fSMarek Lindner * @tvlv_value_len: tvlv buffer length 3653335fbe0fSMarek Lindner * 365462fe710fSSven Eckelmann * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS 3655335fbe0fSMarek Lindner * otherwise. 3656335fbe0fSMarek Lindner */ 3657335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 36586b5e971aSSven Eckelmann u8 *src, u8 *dst, 3659335fbe0fSMarek Lindner void *tvlv_value, 36606b5e971aSSven Eckelmann u16 tvlv_value_len) 3661335fbe0fSMarek Lindner { 3662335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data; 36636b5e971aSSven Eckelmann u16 tt_vlan_len, tt_num_entries; 3664335fbe0fSMarek Lindner char tt_flag; 3665335fbe0fSMarek Lindner bool ret; 3666335fbe0fSMarek Lindner 3667335fbe0fSMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 3668335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3669335fbe0fSMarek Lindner 3670335fbe0fSMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 3671335fbe0fSMarek Lindner tvlv_value_len -= sizeof(*tt_data); 3672335fbe0fSMarek Lindner 36737ea7b4a1SAntonio Quartulli tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); 36747ea7b4a1SAntonio Quartulli tt_vlan_len *= ntohs(tt_data->num_vlan); 36757ea7b4a1SAntonio Quartulli 36767ea7b4a1SAntonio Quartulli if (tvlv_value_len < tt_vlan_len) 36777ea7b4a1SAntonio Quartulli return NET_RX_SUCCESS; 36787ea7b4a1SAntonio Quartulli 36797ea7b4a1SAntonio Quartulli tvlv_value_len -= tt_vlan_len; 36807ea7b4a1SAntonio Quartulli tt_num_entries = batadv_tt_entries(tvlv_value_len); 3681335fbe0fSMarek Lindner 3682335fbe0fSMarek Lindner switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { 3683335fbe0fSMarek Lindner case BATADV_TT_REQUEST: 3684335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); 3685335fbe0fSMarek Lindner 3686335fbe0fSMarek Lindner /* If this node cannot provide a TT response the tt_request is 3687335fbe0fSMarek Lindner * forwarded 3688335fbe0fSMarek Lindner */ 3689335fbe0fSMarek Lindner ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); 3690335fbe0fSMarek Lindner if (!ret) { 3691335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 3692335fbe0fSMarek Lindner tt_flag = 'F'; 3693335fbe0fSMarek Lindner else 3694335fbe0fSMarek Lindner tt_flag = '.'; 3695335fbe0fSMarek Lindner 3696335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3697335fbe0fSMarek Lindner "Routing TT_REQUEST to %pM [%c]\n", 3698335fbe0fSMarek Lindner dst, tt_flag); 3699335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 3700335fbe0fSMarek Lindner return NET_RX_DROP; 3701335fbe0fSMarek Lindner } 3702335fbe0fSMarek Lindner break; 3703335fbe0fSMarek Lindner case BATADV_TT_RESPONSE: 3704335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); 3705335fbe0fSMarek Lindner 3706335fbe0fSMarek Lindner if (batadv_is_my_mac(bat_priv, dst)) { 3707335fbe0fSMarek Lindner batadv_handle_tt_response(bat_priv, tt_data, 37087ea7b4a1SAntonio Quartulli src, tt_num_entries); 3709335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3710335fbe0fSMarek Lindner } 3711335fbe0fSMarek Lindner 3712335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 3713335fbe0fSMarek Lindner tt_flag = 'F'; 3714335fbe0fSMarek Lindner else 3715335fbe0fSMarek Lindner tt_flag = '.'; 3716335fbe0fSMarek Lindner 3717335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3718335fbe0fSMarek Lindner "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag); 3719335fbe0fSMarek Lindner 3720335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 3721335fbe0fSMarek Lindner return NET_RX_DROP; 3722335fbe0fSMarek Lindner } 3723335fbe0fSMarek Lindner 3724335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3725335fbe0fSMarek Lindner } 3726335fbe0fSMarek Lindner 3727335fbe0fSMarek Lindner /** 3728122edaa0SMarek Lindner * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container 3729122edaa0SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3730122edaa0SMarek Lindner * @src: mac address of tt tvlv sender 3731122edaa0SMarek Lindner * @dst: mac address of tt tvlv recipient 3732122edaa0SMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 3733122edaa0SMarek Lindner * @tvlv_value_len: tvlv buffer length 3734122edaa0SMarek Lindner * 373562fe710fSSven Eckelmann * Return: NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS 3736122edaa0SMarek Lindner * otherwise. 3737122edaa0SMarek Lindner */ 3738122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 37396b5e971aSSven Eckelmann u8 *src, u8 *dst, 3740122edaa0SMarek Lindner void *tvlv_value, 37416b5e971aSSven Eckelmann u16 tvlv_value_len) 3742122edaa0SMarek Lindner { 3743122edaa0SMarek Lindner struct batadv_tvlv_roam_adv *roaming_adv; 3744122edaa0SMarek Lindner struct batadv_orig_node *orig_node = NULL; 3745122edaa0SMarek Lindner 3746122edaa0SMarek Lindner /* If this node is not the intended recipient of the 3747122edaa0SMarek Lindner * roaming advertisement the packet is forwarded 3748122edaa0SMarek Lindner * (the tvlv API will re-route the packet). 3749122edaa0SMarek Lindner */ 3750122edaa0SMarek Lindner if (!batadv_is_my_mac(bat_priv, dst)) 3751122edaa0SMarek Lindner return NET_RX_DROP; 3752122edaa0SMarek Lindner 3753122edaa0SMarek Lindner if (tvlv_value_len < sizeof(*roaming_adv)) 3754122edaa0SMarek Lindner goto out; 3755122edaa0SMarek Lindner 3756122edaa0SMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, src); 3757122edaa0SMarek Lindner if (!orig_node) 3758122edaa0SMarek Lindner goto out; 3759122edaa0SMarek Lindner 3760122edaa0SMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); 3761122edaa0SMarek Lindner roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; 3762122edaa0SMarek Lindner 3763122edaa0SMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3764122edaa0SMarek Lindner "Received ROAMING_ADV from %pM (client %pM)\n", 3765122edaa0SMarek Lindner src, roaming_adv->client); 3766122edaa0SMarek Lindner 3767122edaa0SMarek Lindner batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, 3768c018ad3dSAntonio Quartulli ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, 3769122edaa0SMarek Lindner atomic_read(&orig_node->last_ttvn) + 1); 3770122edaa0SMarek Lindner 3771122edaa0SMarek Lindner out: 3772122edaa0SMarek Lindner if (orig_node) 37735d967310SSven Eckelmann batadv_orig_node_put(orig_node); 3774122edaa0SMarek Lindner return NET_RX_SUCCESS; 3775122edaa0SMarek Lindner } 3776122edaa0SMarek Lindner 3777122edaa0SMarek Lindner /** 3778e1bf0c14SMarek Lindner * batadv_tt_init - initialise the translation table internals 3779e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3780e1bf0c14SMarek Lindner * 378162fe710fSSven Eckelmann * Return: 0 on success or negative error number in case of failure. 3782e1bf0c14SMarek Lindner */ 3783e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv) 3784e1bf0c14SMarek Lindner { 3785e1bf0c14SMarek Lindner int ret; 3786e1bf0c14SMarek Lindner 37870eb01568SAntonio Quartulli /* synchronized flags must be remote */ 37880eb01568SAntonio Quartulli BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK)); 37890eb01568SAntonio Quartulli 3790e1bf0c14SMarek Lindner ret = batadv_tt_local_init(bat_priv); 3791e1bf0c14SMarek Lindner if (ret < 0) 3792e1bf0c14SMarek Lindner return ret; 3793e1bf0c14SMarek Lindner 3794e1bf0c14SMarek Lindner ret = batadv_tt_global_init(bat_priv); 3795e1bf0c14SMarek Lindner if (ret < 0) 3796e1bf0c14SMarek Lindner return ret; 3797e1bf0c14SMarek Lindner 3798e1bf0c14SMarek Lindner batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, 3799335fbe0fSMarek Lindner batadv_tt_tvlv_unicast_handler_v1, 3800335fbe0fSMarek Lindner BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); 3801e1bf0c14SMarek Lindner 3802122edaa0SMarek Lindner batadv_tvlv_handler_register(bat_priv, NULL, 3803122edaa0SMarek Lindner batadv_roam_tvlv_unicast_handler_v1, 3804122edaa0SMarek Lindner BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); 3805122edaa0SMarek Lindner 3806e1bf0c14SMarek Lindner INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); 3807e1bf0c14SMarek Lindner queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 3808e1bf0c14SMarek Lindner msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3809e1bf0c14SMarek Lindner 3810e1bf0c14SMarek Lindner return 1; 3811e1bf0c14SMarek Lindner } 381242cb0befSAntonio Quartulli 381342cb0befSAntonio Quartulli /** 381442cb0befSAntonio Quartulli * batadv_tt_global_is_isolated - check if a client is marked as isolated 381542cb0befSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 381642cb0befSAntonio Quartulli * @addr: the mac address of the client 381742cb0befSAntonio Quartulli * @vid: the identifier of the VLAN where this client is connected 381842cb0befSAntonio Quartulli * 381962fe710fSSven Eckelmann * Return: true if the client is marked with the TT_CLIENT_ISOLA flag, false 382042cb0befSAntonio Quartulli * otherwise 382142cb0befSAntonio Quartulli */ 382242cb0befSAntonio Quartulli bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, 38236b5e971aSSven Eckelmann const u8 *addr, unsigned short vid) 382442cb0befSAntonio Quartulli { 382542cb0befSAntonio Quartulli struct batadv_tt_global_entry *tt; 382642cb0befSAntonio Quartulli bool ret; 382742cb0befSAntonio Quartulli 382842cb0befSAntonio Quartulli tt = batadv_tt_global_hash_find(bat_priv, addr, vid); 382942cb0befSAntonio Quartulli if (!tt) 383042cb0befSAntonio Quartulli return false; 383142cb0befSAntonio Quartulli 383242cb0befSAntonio Quartulli ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA; 383342cb0befSAntonio Quartulli 38345dafd8a6SSven Eckelmann batadv_tt_global_entry_put(tt); 383542cb0befSAntonio Quartulli 383642cb0befSAntonio Quartulli return ret; 383742cb0befSAntonio Quartulli } 3838