1e19f9759SSimon Wunderlich /* Copyright (C) 2007-2014 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 "main.h" 19c6c8fea2SSven Eckelmann #include "translation-table.h" 20c6c8fea2SSven Eckelmann #include "soft-interface.h" 2132ae9b22SMarek Lindner #include "hard-interface.h" 22a73105b8SAntonio Quartulli #include "send.h" 23c6c8fea2SSven Eckelmann #include "hash.h" 24c6c8fea2SSven Eckelmann #include "originator.h" 25a73105b8SAntonio Quartulli #include "routing.h" 2620ff9d59SSimon Wunderlich #include "bridge_loop_avoidance.h" 27c6c8fea2SSven Eckelmann 28ced72933SAntonio Quartulli #include <linux/crc32c.h> 29a73105b8SAntonio Quartulli 30dec05074SAntonio Quartulli /* hash class keys */ 31dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_local_hash_lock_class_key; 32dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_global_hash_lock_class_key; 33dec05074SAntonio Quartulli 3456303d34SSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, 35c018ad3dSAntonio Quartulli unsigned short vid, 3656303d34SSven Eckelmann struct batadv_orig_node *orig_node); 37a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work); 38a513088dSSven Eckelmann static void 3956303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); 4030cfd02bSAntonio Quartulli static void batadv_tt_global_del(struct batadv_priv *bat_priv, 4130cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 4230cfd02bSAntonio Quartulli const unsigned char *addr, 43c018ad3dSAntonio Quartulli unsigned short vid, const char *message, 44c018ad3dSAntonio Quartulli bool roaming); 45c6c8fea2SSven Eckelmann 467aadf889SMarek Lindner /* returns 1 if they are the same mac addr */ 47a513088dSSven Eckelmann static int batadv_compare_tt(const struct hlist_node *node, const void *data2) 487aadf889SMarek Lindner { 4956303d34SSven Eckelmann const void *data1 = container_of(node, struct batadv_tt_common_entry, 50747e4221SSven Eckelmann hash_entry); 517aadf889SMarek Lindner 52323813edSdingtianhong return batadv_compare_eth(data1, data2); 537aadf889SMarek Lindner } 547aadf889SMarek Lindner 55c018ad3dSAntonio Quartulli /** 56c018ad3dSAntonio Quartulli * batadv_choose_tt - return the index of the tt entry in the hash table 57c018ad3dSAntonio Quartulli * @data: pointer to the tt_common_entry object to map 58c018ad3dSAntonio Quartulli * @size: the size of the hash table 59c018ad3dSAntonio Quartulli * 60c018ad3dSAntonio Quartulli * Returns the hash index where the object represented by 'data' should be 61c018ad3dSAntonio Quartulli * stored at. 62c018ad3dSAntonio Quartulli */ 63c018ad3dSAntonio Quartulli static inline uint32_t batadv_choose_tt(const void *data, uint32_t size) 64c018ad3dSAntonio Quartulli { 65c018ad3dSAntonio Quartulli struct batadv_tt_common_entry *tt; 66c018ad3dSAntonio Quartulli uint32_t hash = 0; 67c018ad3dSAntonio Quartulli 68c018ad3dSAntonio Quartulli tt = (struct batadv_tt_common_entry *)data; 69c018ad3dSAntonio Quartulli hash = batadv_hash_bytes(hash, &tt->addr, ETH_ALEN); 70c018ad3dSAntonio Quartulli hash = batadv_hash_bytes(hash, &tt->vid, sizeof(tt->vid)); 71c018ad3dSAntonio Quartulli 72c018ad3dSAntonio Quartulli hash += (hash << 3); 73c018ad3dSAntonio Quartulli hash ^= (hash >> 11); 74c018ad3dSAntonio Quartulli hash += (hash << 15); 75c018ad3dSAntonio Quartulli 76c018ad3dSAntonio Quartulli return hash % size; 77c018ad3dSAntonio Quartulli } 78c018ad3dSAntonio Quartulli 79c018ad3dSAntonio Quartulli /** 80c018ad3dSAntonio Quartulli * batadv_tt_hash_find - look for a client in the given hash table 81c018ad3dSAntonio Quartulli * @hash: the hash table to search 82c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 83c018ad3dSAntonio Quartulli * @vid: VLAN identifier 84c018ad3dSAntonio Quartulli * 85c018ad3dSAntonio Quartulli * Returns a pointer to the tt_common struct belonging to the searched client if 86c018ad3dSAntonio Quartulli * found, NULL otherwise. 87c018ad3dSAntonio Quartulli */ 8856303d34SSven Eckelmann static struct batadv_tt_common_entry * 89c018ad3dSAntonio Quartulli batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr, 90c018ad3dSAntonio Quartulli unsigned short vid) 917aadf889SMarek Lindner { 927aadf889SMarek Lindner struct hlist_head *head; 93c018ad3dSAntonio Quartulli struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; 94c90681b8SAntonio Quartulli uint32_t index; 957aadf889SMarek Lindner 967aadf889SMarek Lindner if (!hash) 977aadf889SMarek Lindner return NULL; 987aadf889SMarek Lindner 998fdd0153SAntonio Quartulli ether_addr_copy(to_search.addr, addr); 100c018ad3dSAntonio Quartulli to_search.vid = vid; 101c018ad3dSAntonio Quartulli 102c018ad3dSAntonio Quartulli index = batadv_choose_tt(&to_search, hash->size); 1037aadf889SMarek Lindner head = &hash->table[index]; 1047aadf889SMarek Lindner 1057aadf889SMarek Lindner rcu_read_lock(); 106c018ad3dSAntonio Quartulli hlist_for_each_entry_rcu(tt, head, hash_entry) { 107c018ad3dSAntonio Quartulli if (!batadv_compare_eth(tt, addr)) 1087aadf889SMarek Lindner continue; 1097aadf889SMarek Lindner 110c018ad3dSAntonio Quartulli if (tt->vid != vid) 1117683fdc1SAntonio Quartulli continue; 1127683fdc1SAntonio Quartulli 113c018ad3dSAntonio Quartulli if (!atomic_inc_not_zero(&tt->refcount)) 114c018ad3dSAntonio Quartulli continue; 115c018ad3dSAntonio Quartulli 116c018ad3dSAntonio Quartulli tt_tmp = tt; 1177aadf889SMarek Lindner break; 1187aadf889SMarek Lindner } 1197aadf889SMarek Lindner rcu_read_unlock(); 1207aadf889SMarek Lindner 121c018ad3dSAntonio Quartulli return tt_tmp; 12248100bacSAntonio Quartulli } 12348100bacSAntonio Quartulli 124c018ad3dSAntonio Quartulli /** 125c018ad3dSAntonio Quartulli * batadv_tt_local_hash_find - search the local table for a given client 126c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 127c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 128c018ad3dSAntonio Quartulli * @vid: VLAN identifier 129c018ad3dSAntonio Quartulli * 130c018ad3dSAntonio Quartulli * Returns a pointer to the corresponding tt_local_entry struct if the client is 131c018ad3dSAntonio Quartulli * found, NULL otherwise. 132c018ad3dSAntonio Quartulli */ 13356303d34SSven Eckelmann static struct batadv_tt_local_entry * 134c018ad3dSAntonio Quartulli batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, 135c018ad3dSAntonio Quartulli unsigned short vid) 13648100bacSAntonio Quartulli { 13756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 13856303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 13948100bacSAntonio Quartulli 140c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, 141c018ad3dSAntonio Quartulli vid); 14248100bacSAntonio Quartulli if (tt_common_entry) 14348100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 14456303d34SSven Eckelmann struct batadv_tt_local_entry, 14556303d34SSven Eckelmann common); 14648100bacSAntonio Quartulli return tt_local_entry; 1477aadf889SMarek Lindner } 1487aadf889SMarek Lindner 149c018ad3dSAntonio Quartulli /** 150c018ad3dSAntonio Quartulli * batadv_tt_global_hash_find - search the global table for a given client 151c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 152c018ad3dSAntonio Quartulli * @addr: the mac address of the client to look for 153c018ad3dSAntonio Quartulli * @vid: VLAN identifier 154c018ad3dSAntonio Quartulli * 155c018ad3dSAntonio Quartulli * Returns a pointer to the corresponding tt_global_entry struct if the client 156c018ad3dSAntonio Quartulli * is found, NULL otherwise. 157c018ad3dSAntonio Quartulli */ 15856303d34SSven Eckelmann static struct batadv_tt_global_entry * 159c018ad3dSAntonio Quartulli batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, 160c018ad3dSAntonio Quartulli unsigned short vid) 1617aadf889SMarek Lindner { 16256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 16356303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 1647aadf889SMarek Lindner 165c018ad3dSAntonio Quartulli tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, 166c018ad3dSAntonio Quartulli vid); 16748100bacSAntonio Quartulli if (tt_common_entry) 16848100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 16956303d34SSven Eckelmann struct batadv_tt_global_entry, 17056303d34SSven Eckelmann common); 17148100bacSAntonio Quartulli return tt_global_entry; 1727aadf889SMarek Lindner } 1737aadf889SMarek Lindner 174a513088dSSven Eckelmann static void 17556303d34SSven Eckelmann batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry) 1767683fdc1SAntonio Quartulli { 17748100bacSAntonio Quartulli if (atomic_dec_and_test(&tt_local_entry->common.refcount)) 17848100bacSAntonio Quartulli kfree_rcu(tt_local_entry, common.rcu); 1797683fdc1SAntonio Quartulli } 1807683fdc1SAntonio Quartulli 18121026059SAntonio Quartulli /** 18221026059SAntonio Quartulli * batadv_tt_global_entry_free_ref - decrement the refcounter for a 18321026059SAntonio Quartulli * tt_global_entry and possibly free it 18421026059SAntonio Quartulli * @tt_global_entry: the object to free 18521026059SAntonio Quartulli */ 186a513088dSSven Eckelmann static void 18756303d34SSven Eckelmann batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) 1887683fdc1SAntonio Quartulli { 189db08e6e5SSimon Wunderlich if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { 190a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 19121026059SAntonio Quartulli kfree_rcu(tt_global_entry, common.rcu); 1927683fdc1SAntonio Quartulli } 193db08e6e5SSimon Wunderlich } 194db08e6e5SSimon Wunderlich 195a513088dSSven Eckelmann static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) 196db08e6e5SSimon Wunderlich { 19756303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 198db08e6e5SSimon Wunderlich 19956303d34SSven Eckelmann orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu); 20072822225SLinus Lüssing 20172822225SLinus Lüssing /* We are in an rcu callback here, therefore we cannot use 20272822225SLinus Lüssing * batadv_orig_node_free_ref() and its call_rcu(): 20372822225SLinus Lüssing * An rcu_barrier() wouldn't wait for that to finish 20472822225SLinus Lüssing */ 20572822225SLinus Lüssing batadv_orig_node_free_ref_now(orig_entry->orig_node); 206db08e6e5SSimon Wunderlich kfree(orig_entry); 207db08e6e5SSimon Wunderlich } 208db08e6e5SSimon Wunderlich 2097ea7b4a1SAntonio Quartulli /** 2107ea7b4a1SAntonio Quartulli * batadv_tt_local_size_mod - change the size by v of the local table identified 2117ea7b4a1SAntonio Quartulli * by vid 2127ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2137ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier of the sub-table to change 2147ea7b4a1SAntonio Quartulli * @v: the amount to sum to the local table size 2157ea7b4a1SAntonio Quartulli */ 2167ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv, 2177ea7b4a1SAntonio Quartulli unsigned short vid, int v) 2187ea7b4a1SAntonio Quartulli { 2197ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 2207ea7b4a1SAntonio Quartulli 2217ea7b4a1SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 2227ea7b4a1SAntonio Quartulli if (!vlan) 2237ea7b4a1SAntonio Quartulli return; 2247ea7b4a1SAntonio Quartulli 2257ea7b4a1SAntonio Quartulli atomic_add(v, &vlan->tt.num_entries); 2267ea7b4a1SAntonio Quartulli 2277ea7b4a1SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 2287ea7b4a1SAntonio Quartulli } 2297ea7b4a1SAntonio Quartulli 2307ea7b4a1SAntonio Quartulli /** 2317ea7b4a1SAntonio Quartulli * batadv_tt_local_size_inc - increase by one the local table size for the given 2327ea7b4a1SAntonio Quartulli * vid 2337ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2347ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 2357ea7b4a1SAntonio Quartulli */ 2367ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv, 2377ea7b4a1SAntonio Quartulli unsigned short vid) 2387ea7b4a1SAntonio Quartulli { 2397ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, 1); 2407ea7b4a1SAntonio Quartulli } 2417ea7b4a1SAntonio Quartulli 2427ea7b4a1SAntonio Quartulli /** 2437ea7b4a1SAntonio Quartulli * batadv_tt_local_size_dec - decrease by one the local table size for the given 2447ea7b4a1SAntonio Quartulli * vid 2457ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2467ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 2477ea7b4a1SAntonio Quartulli */ 2487ea7b4a1SAntonio Quartulli static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv, 2497ea7b4a1SAntonio Quartulli unsigned short vid) 2507ea7b4a1SAntonio Quartulli { 2517ea7b4a1SAntonio Quartulli batadv_tt_local_size_mod(bat_priv, vid, -1); 2527ea7b4a1SAntonio Quartulli } 2537ea7b4a1SAntonio Quartulli 2547ea7b4a1SAntonio Quartulli /** 2557ea7b4a1SAntonio Quartulli * batadv_tt_global_size_mod - change the size by v of the local table 2567ea7b4a1SAntonio Quartulli * identified by vid 2577ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2587ea7b4a1SAntonio Quartulli * @vid: the VLAN identifier 2597ea7b4a1SAntonio Quartulli * @v: the amount to sum to the global table size 2607ea7b4a1SAntonio Quartulli */ 2617ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, 2627ea7b4a1SAntonio Quartulli unsigned short vid, int v) 2637ea7b4a1SAntonio Quartulli { 2647ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 2657ea7b4a1SAntonio Quartulli 2667ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_new(orig_node, vid); 2677ea7b4a1SAntonio Quartulli if (!vlan) 2687ea7b4a1SAntonio Quartulli return; 2697ea7b4a1SAntonio Quartulli 2707ea7b4a1SAntonio Quartulli if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { 2717ea7b4a1SAntonio Quartulli spin_lock_bh(&orig_node->vlan_list_lock); 2727ea7b4a1SAntonio Quartulli list_del_rcu(&vlan->list); 2737ea7b4a1SAntonio Quartulli spin_unlock_bh(&orig_node->vlan_list_lock); 2747ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 2757ea7b4a1SAntonio Quartulli } 2767ea7b4a1SAntonio Quartulli 2777ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 2787ea7b4a1SAntonio Quartulli } 2797ea7b4a1SAntonio Quartulli 2807ea7b4a1SAntonio Quartulli /** 2817ea7b4a1SAntonio Quartulli * batadv_tt_global_size_inc - increase by one the global table size for the 2827ea7b4a1SAntonio Quartulli * given vid 2837ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 2847ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 2857ea7b4a1SAntonio Quartulli */ 2867ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node, 2877ea7b4a1SAntonio Quartulli unsigned short vid) 2887ea7b4a1SAntonio Quartulli { 2897ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, 1); 2907ea7b4a1SAntonio Quartulli } 2917ea7b4a1SAntonio Quartulli 2927ea7b4a1SAntonio Quartulli /** 2937ea7b4a1SAntonio Quartulli * batadv_tt_global_size_dec - decrease by one the global table size for the 2947ea7b4a1SAntonio Quartulli * given vid 2957ea7b4a1SAntonio Quartulli * @orig_node: the originator which global table size has to be decreased 2967ea7b4a1SAntonio Quartulli * @vid: the vlan identifier 2977ea7b4a1SAntonio Quartulli */ 2987ea7b4a1SAntonio Quartulli static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, 2997ea7b4a1SAntonio Quartulli unsigned short vid) 3007ea7b4a1SAntonio Quartulli { 3017ea7b4a1SAntonio Quartulli batadv_tt_global_size_mod(orig_node, vid, -1); 3027ea7b4a1SAntonio Quartulli } 3037ea7b4a1SAntonio Quartulli 304a513088dSSven Eckelmann static void 30556303d34SSven Eckelmann batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) 306db08e6e5SSimon Wunderlich { 307d657e621SAntonio Quartulli if (!atomic_dec_and_test(&orig_entry->refcount)) 308d657e621SAntonio Quartulli return; 3097ea7b4a1SAntonio Quartulli 310a513088dSSven Eckelmann call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); 311db08e6e5SSimon Wunderlich } 3127683fdc1SAntonio Quartulli 3133abe4adbSAntonio Quartulli /** 3143abe4adbSAntonio Quartulli * batadv_tt_local_event - store a local TT event (ADD/DEL) 3153abe4adbSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3163abe4adbSAntonio Quartulli * @tt_local_entry: the TT entry involved in the event 3173abe4adbSAntonio Quartulli * @event_flags: flags to store in the event structure 3183abe4adbSAntonio Quartulli */ 31956303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv, 3203abe4adbSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry, 3213abe4adbSAntonio Quartulli uint8_t event_flags) 322a73105b8SAntonio Quartulli { 32356303d34SSven Eckelmann struct batadv_tt_change_node *tt_change_node, *entry, *safe; 3243abe4adbSAntonio Quartulli struct batadv_tt_common_entry *common = &tt_local_entry->common; 3253abe4adbSAntonio Quartulli uint8_t flags = common->flags | event_flags; 3263b643de5SAntonio Quartulli bool event_removed = false; 3273b643de5SAntonio Quartulli bool del_op_requested, del_op_entry; 328a73105b8SAntonio Quartulli 329a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 330a73105b8SAntonio Quartulli if (!tt_change_node) 331a73105b8SAntonio Quartulli return; 332a73105b8SAntonio Quartulli 333ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 334ca663046SAntonio Quartulli memset(tt_change_node->change.reserved, 0, 335ca663046SAntonio Quartulli sizeof(tt_change_node->change.reserved)); 3368fdd0153SAntonio Quartulli ether_addr_copy(tt_change_node->change.addr, common->addr); 337c018ad3dSAntonio Quartulli tt_change_node->change.vid = htons(common->vid); 338a73105b8SAntonio Quartulli 339acd34afaSSven Eckelmann del_op_requested = flags & BATADV_TT_CLIENT_DEL; 3403b643de5SAntonio Quartulli 3413b643de5SAntonio Quartulli /* check for ADD+DEL or DEL+ADD events */ 342807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 343807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 3443b643de5SAntonio Quartulli list) { 3453abe4adbSAntonio Quartulli if (!batadv_compare_eth(entry->change.addr, common->addr)) 3463b643de5SAntonio Quartulli continue; 3473b643de5SAntonio Quartulli 3483b643de5SAntonio Quartulli /* DEL+ADD in the same orig interval have no effect and can be 3493b643de5SAntonio Quartulli * removed to avoid silly behaviour on the receiver side. The 3503b643de5SAntonio Quartulli * other way around (ADD+DEL) can happen in case of roaming of 3513b643de5SAntonio Quartulli * a client still in the NEW state. Roaming of NEW clients is 3523b643de5SAntonio Quartulli * now possible due to automatically recognition of "temporary" 3533b643de5SAntonio Quartulli * clients 3543b643de5SAntonio Quartulli */ 355acd34afaSSven Eckelmann del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; 3563b643de5SAntonio Quartulli if (!del_op_requested && del_op_entry) 3573b643de5SAntonio Quartulli goto del; 3583b643de5SAntonio Quartulli if (del_op_requested && !del_op_entry) 3593b643de5SAntonio Quartulli goto del; 3603c4f7ab6SAntonio Quartulli 3613c4f7ab6SAntonio Quartulli /* this is a second add in the same originator interval. It 3623c4f7ab6SAntonio Quartulli * means that flags have been changed: update them! 3633c4f7ab6SAntonio Quartulli */ 3643c4f7ab6SAntonio Quartulli if (!del_op_requested && !del_op_entry) 3653c4f7ab6SAntonio Quartulli entry->change.flags = flags; 3663c4f7ab6SAntonio Quartulli 3673b643de5SAntonio Quartulli continue; 3683b643de5SAntonio Quartulli del: 3693b643de5SAntonio Quartulli list_del(&entry->list); 3703b643de5SAntonio Quartulli kfree(entry); 371155e4e12SJesper Juhl kfree(tt_change_node); 3723b643de5SAntonio Quartulli event_removed = true; 3733b643de5SAntonio Quartulli goto unlock; 3743b643de5SAntonio Quartulli } 3753b643de5SAntonio Quartulli 376a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 377807736f6SSven Eckelmann list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list); 3783b643de5SAntonio Quartulli 3793b643de5SAntonio Quartulli unlock: 380807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 381a73105b8SAntonio Quartulli 3823b643de5SAntonio Quartulli if (event_removed) 383807736f6SSven Eckelmann atomic_dec(&bat_priv->tt.local_changes); 3843b643de5SAntonio Quartulli else 385807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.local_changes); 386a73105b8SAntonio Quartulli } 387a73105b8SAntonio Quartulli 388335fbe0fSMarek Lindner /** 389335fbe0fSMarek Lindner * batadv_tt_len - compute length in bytes of given number of tt changes 390335fbe0fSMarek Lindner * @changes_num: number of tt changes 391335fbe0fSMarek Lindner * 392335fbe0fSMarek Lindner * Returns computed length in bytes. 393335fbe0fSMarek Lindner */ 394335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num) 395a73105b8SAntonio Quartulli { 396335fbe0fSMarek Lindner return changes_num * sizeof(struct batadv_tvlv_tt_change); 397a73105b8SAntonio Quartulli } 398a73105b8SAntonio Quartulli 399298e6e68SAntonio Quartulli /** 400298e6e68SAntonio Quartulli * batadv_tt_entries - compute the number of entries fitting in tt_len bytes 401298e6e68SAntonio Quartulli * @tt_len: available space 402298e6e68SAntonio Quartulli * 403298e6e68SAntonio Quartulli * Returns the number of entries. 404298e6e68SAntonio Quartulli */ 405298e6e68SAntonio Quartulli static uint16_t batadv_tt_entries(uint16_t tt_len) 406298e6e68SAntonio Quartulli { 407298e6e68SAntonio Quartulli return tt_len / batadv_tt_len(1); 408298e6e68SAntonio Quartulli } 409298e6e68SAntonio Quartulli 410a19d3d85SMarek Lindner /** 411a19d3d85SMarek Lindner * batadv_tt_local_table_transmit_size - calculates the local translation table 412a19d3d85SMarek Lindner * size when transmitted over the air 413a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 414a19d3d85SMarek Lindner * 415a19d3d85SMarek Lindner * Returns local translation table size in bytes. 416a19d3d85SMarek Lindner */ 417a19d3d85SMarek Lindner static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) 418a19d3d85SMarek Lindner { 419a19d3d85SMarek Lindner uint16_t num_vlan = 0, tt_local_entries = 0; 420a19d3d85SMarek Lindner struct batadv_softif_vlan *vlan; 421a19d3d85SMarek Lindner int hdr_size; 422a19d3d85SMarek Lindner 423a19d3d85SMarek Lindner rcu_read_lock(); 424a19d3d85SMarek Lindner hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 425a19d3d85SMarek Lindner num_vlan++; 426a19d3d85SMarek Lindner tt_local_entries += atomic_read(&vlan->tt.num_entries); 427a19d3d85SMarek Lindner } 428a19d3d85SMarek Lindner rcu_read_unlock(); 429a19d3d85SMarek Lindner 430a19d3d85SMarek Lindner /* header size of tvlv encapsulated tt response payload */ 431a19d3d85SMarek Lindner hdr_size = sizeof(struct batadv_unicast_tvlv_packet); 432a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_hdr); 433a19d3d85SMarek Lindner hdr_size += sizeof(struct batadv_tvlv_tt_data); 434a19d3d85SMarek Lindner hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data); 435a19d3d85SMarek Lindner 436a19d3d85SMarek Lindner return hdr_size + batadv_tt_len(tt_local_entries); 437a19d3d85SMarek Lindner } 438a19d3d85SMarek Lindner 43956303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv) 440c6c8fea2SSven Eckelmann { 441807736f6SSven Eckelmann if (bat_priv->tt.local_hash) 4425346c35eSSven Eckelmann return 0; 443c6c8fea2SSven Eckelmann 444807736f6SSven Eckelmann bat_priv->tt.local_hash = batadv_hash_new(1024); 445c6c8fea2SSven Eckelmann 446807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 4475346c35eSSven Eckelmann return -ENOMEM; 448c6c8fea2SSven Eckelmann 449dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.local_hash, 450dec05074SAntonio Quartulli &batadv_tt_local_hash_lock_class_key); 451dec05074SAntonio Quartulli 4525346c35eSSven Eckelmann return 0; 453c6c8fea2SSven Eckelmann } 454c6c8fea2SSven Eckelmann 455068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv, 456068ee6e2SAntonio Quartulli struct batadv_tt_global_entry *tt_global, 457068ee6e2SAntonio Quartulli const char *message) 458068ee6e2SAntonio Quartulli { 459068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 46016052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 46116052789SAntonio Quartulli tt_global->common.addr, 46216052789SAntonio Quartulli BATADV_PRINT_VID(tt_global->common.vid), message); 463068ee6e2SAntonio Quartulli 464068ee6e2SAntonio Quartulli batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, 465c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_global->common); 466068ee6e2SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 467068ee6e2SAntonio Quartulli } 468068ee6e2SAntonio Quartulli 469c018ad3dSAntonio Quartulli /** 470c018ad3dSAntonio Quartulli * batadv_tt_local_add - add a new client to the local table or update an 471c018ad3dSAntonio Quartulli * existing client 472c018ad3dSAntonio Quartulli * @soft_iface: netdev struct of the mesh interface 473c018ad3dSAntonio Quartulli * @addr: the mac address of the client to add 474c018ad3dSAntonio Quartulli * @vid: VLAN identifier 475c018ad3dSAntonio Quartulli * @ifindex: index of the interface where the client is connected to (useful to 476c018ad3dSAntonio Quartulli * identify wireless clients) 4779464d071SAntonio Quartulli * @mark: the value contained in the skb->mark field of the received packet (if 4789464d071SAntonio Quartulli * any) 479a19d3d85SMarek Lindner * 480a19d3d85SMarek Lindner * Returns true if the client was successfully added, false otherwise. 481c018ad3dSAntonio Quartulli */ 482a19d3d85SMarek Lindner bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 4839464d071SAntonio Quartulli unsigned short vid, int ifindex, uint32_t mark) 484c6c8fea2SSven Eckelmann { 48556303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(soft_iface); 486170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local; 487170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global; 4880c69aeccSAntonio Quartulli struct net_device *in_dev = NULL; 489db08e6e5SSimon Wunderlich struct hlist_head *head; 49056303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 491a19d3d85SMarek Lindner int hash_added, table_size, packet_size_max; 492a19d3d85SMarek Lindner bool ret = false, roamed_back = false; 4933c4f7ab6SAntonio Quartulli uint8_t remote_flags; 4949464d071SAntonio Quartulli uint32_t match_mark; 495c6c8fea2SSven Eckelmann 4960c69aeccSAntonio Quartulli if (ifindex != BATADV_NULL_IFINDEX) 4970c69aeccSAntonio Quartulli in_dev = dev_get_by_index(&init_net, ifindex); 4980c69aeccSAntonio Quartulli 499c018ad3dSAntonio Quartulli tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); 500c018ad3dSAntonio Quartulli tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); 501c6c8fea2SSven Eckelmann 50247c94655SAntonio Quartulli if (tt_local) { 50347c94655SAntonio Quartulli tt_local->last_seen = jiffies; 504068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { 505068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 50616052789SAntonio Quartulli "Re-adding pending client %pM (vid: %d)\n", 50716052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid)); 508068ee6e2SAntonio Quartulli /* whatever the reason why the PENDING flag was set, 509068ee6e2SAntonio Quartulli * this is a client which was enqueued to be removed in 510068ee6e2SAntonio Quartulli * this orig_interval. Since it popped up again, the 511068ee6e2SAntonio Quartulli * flag can be reset like it was never enqueued 512068ee6e2SAntonio Quartulli */ 51347c94655SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; 514068ee6e2SAntonio Quartulli goto add_event; 515068ee6e2SAntonio Quartulli } 516068ee6e2SAntonio Quartulli 517068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { 518068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 51916052789SAntonio Quartulli "Roaming client %pM (vid: %d) came back to its original location\n", 52016052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid)); 521068ee6e2SAntonio Quartulli /* the ROAM flag is set because this client roamed away 522068ee6e2SAntonio Quartulli * and the node got a roaming_advertisement message. Now 523068ee6e2SAntonio Quartulli * that the client popped up again at its original 524068ee6e2SAntonio Quartulli * location such flag can be unset 525068ee6e2SAntonio Quartulli */ 526068ee6e2SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; 527068ee6e2SAntonio Quartulli roamed_back = true; 528068ee6e2SAntonio Quartulli } 529068ee6e2SAntonio Quartulli goto check_roaming; 530c6c8fea2SSven Eckelmann } 531c6c8fea2SSven Eckelmann 532a19d3d85SMarek Lindner /* Ignore the client if we cannot send it in a full table response. */ 533a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 534a19d3d85SMarek Lindner table_size += batadv_tt_len(1); 535a19d3d85SMarek Lindner packet_size_max = atomic_read(&bat_priv->packet_size_max); 536a19d3d85SMarek Lindner if (table_size > packet_size_max) { 537a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 538a19d3d85SMarek Lindner "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n", 539a19d3d85SMarek Lindner table_size, packet_size_max, addr); 540a19d3d85SMarek Lindner goto out; 541a19d3d85SMarek Lindner } 542a19d3d85SMarek Lindner 54347c94655SAntonio Quartulli tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); 54447c94655SAntonio Quartulli if (!tt_local) 5457683fdc1SAntonio Quartulli goto out; 546a73105b8SAntonio Quartulli 54739c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 54816052789SAntonio Quartulli "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", 54916052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid), 550807736f6SSven Eckelmann (uint8_t)atomic_read(&bat_priv->tt.vn)); 551c6c8fea2SSven Eckelmann 5528fdd0153SAntonio Quartulli ether_addr_copy(tt_local->common.addr, addr); 5538425ec6aSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 5548425ec6aSAntonio Quartulli * a full table response going out before the next ttvn increment 5558425ec6aSAntonio Quartulli * (consistency check) 5568425ec6aSAntonio Quartulli */ 5578425ec6aSAntonio Quartulli tt_local->common.flags = BATADV_TT_CLIENT_NEW; 558c018ad3dSAntonio Quartulli tt_local->common.vid = vid; 5590c69aeccSAntonio Quartulli if (batadv_is_wifi_netdev(in_dev)) 56047c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 56147c94655SAntonio Quartulli atomic_set(&tt_local->common.refcount, 2); 56247c94655SAntonio Quartulli tt_local->last_seen = jiffies; 56347c94655SAntonio Quartulli tt_local->common.added_at = tt_local->last_seen; 564c6c8fea2SSven Eckelmann 565c6c8fea2SSven Eckelmann /* the batman interface mac address should never be purged */ 5661eda58bfSSven Eckelmann if (batadv_compare_eth(addr, soft_iface->dev_addr)) 56747c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; 568c6c8fea2SSven Eckelmann 569807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, 570c018ad3dSAntonio Quartulli batadv_choose_tt, &tt_local->common, 57147c94655SAntonio Quartulli &tt_local->common.hash_entry); 57280b3f58cSSimon Wunderlich 57380b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 57480b3f58cSSimon Wunderlich /* remove the reference for the hash */ 57547c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 57680b3f58cSSimon Wunderlich goto out; 57780b3f58cSSimon Wunderlich } 57880b3f58cSSimon Wunderlich 579068ee6e2SAntonio Quartulli add_event: 5803abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 581ff66c975SAntonio Quartulli 582068ee6e2SAntonio Quartulli check_roaming: 583068ee6e2SAntonio Quartulli /* Check whether it is a roaming, but don't do anything if the roaming 584068ee6e2SAntonio Quartulli * process has already been handled 585068ee6e2SAntonio Quartulli */ 586068ee6e2SAntonio Quartulli if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { 587db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 58847c94655SAntonio Quartulli head = &tt_global->orig_list; 589db08e6e5SSimon Wunderlich rcu_read_lock(); 590b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 59147c94655SAntonio Quartulli batadv_send_roam_adv(bat_priv, tt_global->common.addr, 592c018ad3dSAntonio Quartulli tt_global->common.vid, 593db08e6e5SSimon Wunderlich orig_entry->orig_node); 594db08e6e5SSimon Wunderlich } 595db08e6e5SSimon Wunderlich rcu_read_unlock(); 596068ee6e2SAntonio Quartulli if (roamed_back) { 597068ee6e2SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global, 598068ee6e2SAntonio Quartulli "Roaming canceled"); 599068ee6e2SAntonio Quartulli tt_global = NULL; 600068ee6e2SAntonio Quartulli } else { 601db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 602db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 603db08e6e5SSimon Wunderlich */ 60447c94655SAntonio Quartulli tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; 60547c94655SAntonio Quartulli tt_global->roam_at = jiffies; 6067683fdc1SAntonio Quartulli } 607068ee6e2SAntonio Quartulli } 608068ee6e2SAntonio Quartulli 6093c4f7ab6SAntonio Quartulli /* store the current remote flags before altering them. This helps 6103c4f7ab6SAntonio Quartulli * understanding is flags are changing or not 6113c4f7ab6SAntonio Quartulli */ 6123c4f7ab6SAntonio Quartulli remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK; 613a19d3d85SMarek Lindner 6143c4f7ab6SAntonio Quartulli if (batadv_is_wifi_netdev(in_dev)) 6153c4f7ab6SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 6163c4f7ab6SAntonio Quartulli else 6173c4f7ab6SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; 6183c4f7ab6SAntonio Quartulli 6199464d071SAntonio Quartulli /* check the mark in the skb: if it's equal to the configured 6209464d071SAntonio Quartulli * isolation_mark, it means the packet is coming from an isolated 6219464d071SAntonio Quartulli * non-mesh client 6229464d071SAntonio Quartulli */ 6239464d071SAntonio Quartulli match_mark = (mark & bat_priv->isolation_mark_mask); 6249464d071SAntonio Quartulli if (bat_priv->isolation_mark_mask && 6259464d071SAntonio Quartulli match_mark == bat_priv->isolation_mark) 6269464d071SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA; 6279464d071SAntonio Quartulli else 6289464d071SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA; 6299464d071SAntonio Quartulli 6303c4f7ab6SAntonio Quartulli /* if any "dynamic" flag has been modified, resend an ADD event for this 6313c4f7ab6SAntonio Quartulli * entry so that all the nodes can get the new flags 6323c4f7ab6SAntonio Quartulli */ 6333c4f7ab6SAntonio Quartulli if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK)) 6343c4f7ab6SAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 6353c4f7ab6SAntonio Quartulli 6363c4f7ab6SAntonio Quartulli ret = true; 6377683fdc1SAntonio Quartulli out: 6380c69aeccSAntonio Quartulli if (in_dev) 6390c69aeccSAntonio Quartulli dev_put(in_dev); 64047c94655SAntonio Quartulli if (tt_local) 64147c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 64247c94655SAntonio Quartulli if (tt_global) 64347c94655SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 644a19d3d85SMarek Lindner return ret; 645c6c8fea2SSven Eckelmann } 646c6c8fea2SSven Eckelmann 647e1bf0c14SMarek Lindner /** 6487ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send 6497ea7b4a1SAntonio Quartulli * within a TT Response directed to another node 6507ea7b4a1SAntonio Quartulli * @orig_node: originator for which the TT data has to be prepared 6517ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 6527ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 6537ea7b4a1SAntonio Quartulli * changed can be stored 6547ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 6557ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire global TT 6567ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 6577ea7b4a1SAntonio Quartulli * reserved bytes 6587ea7b4a1SAntonio Quartulli 6597ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 6607ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 6617ea7b4a1SAntonio Quartulli * objects, one per active VLAN served by the originator node. 6627ea7b4a1SAntonio Quartulli * 6637ea7b4a1SAntonio Quartulli * Return the size of the allocated buffer or 0 in case of failure. 6647ea7b4a1SAntonio Quartulli */ 6657ea7b4a1SAntonio Quartulli static uint16_t 6667ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, 6677ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 6687ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 6697ea7b4a1SAntonio Quartulli int32_t *tt_len) 6707ea7b4a1SAntonio Quartulli { 6717ea7b4a1SAntonio Quartulli uint16_t num_vlan = 0, num_entries = 0, change_offset, tvlv_len; 6727ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 6737ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 6747ea7b4a1SAntonio Quartulli uint8_t *tt_change_ptr; 6757ea7b4a1SAntonio Quartulli 6767ea7b4a1SAntonio Quartulli rcu_read_lock(); 6777ea7b4a1SAntonio Quartulli list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 6787ea7b4a1SAntonio Quartulli num_vlan++; 6797ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 6807ea7b4a1SAntonio Quartulli } 6817ea7b4a1SAntonio Quartulli 6827ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 6837ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 6847ea7b4a1SAntonio Quartulli 6857ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 6867ea7b4a1SAntonio Quartulli if (*tt_len < 0) 6877ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 6887ea7b4a1SAntonio Quartulli 6897ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 6907ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 6917ea7b4a1SAntonio Quartulli 6927ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 6937ea7b4a1SAntonio Quartulli if (!*tt_data) { 6947ea7b4a1SAntonio Quartulli *tt_len = 0; 6957ea7b4a1SAntonio Quartulli goto out; 6967ea7b4a1SAntonio Quartulli } 6977ea7b4a1SAntonio Quartulli 6987ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 6997ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); 7007ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 7017ea7b4a1SAntonio Quartulli 7027ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 7037ea7b4a1SAntonio Quartulli list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 7047ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 7057ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 7067ea7b4a1SAntonio Quartulli 7077ea7b4a1SAntonio Quartulli tt_vlan++; 7087ea7b4a1SAntonio Quartulli } 7097ea7b4a1SAntonio Quartulli 7107ea7b4a1SAntonio Quartulli tt_change_ptr = (uint8_t *)*tt_data + change_offset; 7117ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 7127ea7b4a1SAntonio Quartulli 7137ea7b4a1SAntonio Quartulli out: 7147ea7b4a1SAntonio Quartulli rcu_read_unlock(); 7157ea7b4a1SAntonio Quartulli return tvlv_len; 7167ea7b4a1SAntonio Quartulli } 7177ea7b4a1SAntonio Quartulli 7187ea7b4a1SAntonio Quartulli /** 7197ea7b4a1SAntonio Quartulli * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this 7207ea7b4a1SAntonio Quartulli * node 7217ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 7227ea7b4a1SAntonio Quartulli * @tt_data: uninitialised pointer to the address of the TVLV buffer 7237ea7b4a1SAntonio Quartulli * @tt_change: uninitialised pointer to the address of the area where the TT 7247ea7b4a1SAntonio Quartulli * changes can be stored 7257ea7b4a1SAntonio Quartulli * @tt_len: pointer to the length to reserve to the tt_change. if -1 this 7267ea7b4a1SAntonio Quartulli * function reserves the amount of space needed to send the entire local TT 7277ea7b4a1SAntonio Quartulli * table. In case of success the value is updated with the real amount of 7287ea7b4a1SAntonio Quartulli * reserved bytes 7297ea7b4a1SAntonio Quartulli * 7307ea7b4a1SAntonio Quartulli * Allocate the needed amount of memory for the entire TT TVLV and write its 7317ea7b4a1SAntonio Quartulli * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data 7327ea7b4a1SAntonio Quartulli * objects, one per active VLAN. 7337ea7b4a1SAntonio Quartulli * 7347ea7b4a1SAntonio Quartulli * Return the size of the allocated buffer or 0 in case of failure. 7357ea7b4a1SAntonio Quartulli */ 7367ea7b4a1SAntonio Quartulli static uint16_t 7377ea7b4a1SAntonio Quartulli batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, 7387ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_data **tt_data, 7397ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change **tt_change, 7407ea7b4a1SAntonio Quartulli int32_t *tt_len) 7417ea7b4a1SAntonio Quartulli { 7427ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 7437ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 7447ea7b4a1SAntonio Quartulli uint16_t num_vlan = 0, num_entries = 0, tvlv_len; 7457ea7b4a1SAntonio Quartulli uint8_t *tt_change_ptr; 7467ea7b4a1SAntonio Quartulli int change_offset; 7477ea7b4a1SAntonio Quartulli 7487ea7b4a1SAntonio Quartulli rcu_read_lock(); 7497ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 7507ea7b4a1SAntonio Quartulli num_vlan++; 7517ea7b4a1SAntonio Quartulli num_entries += atomic_read(&vlan->tt.num_entries); 7527ea7b4a1SAntonio Quartulli } 7537ea7b4a1SAntonio Quartulli 7547ea7b4a1SAntonio Quartulli change_offset = sizeof(**tt_data); 7557ea7b4a1SAntonio Quartulli change_offset += num_vlan * sizeof(*tt_vlan); 7567ea7b4a1SAntonio Quartulli 7577ea7b4a1SAntonio Quartulli /* if tt_len is negative, allocate the space needed by the full table */ 7587ea7b4a1SAntonio Quartulli if (*tt_len < 0) 7597ea7b4a1SAntonio Quartulli *tt_len = batadv_tt_len(num_entries); 7607ea7b4a1SAntonio Quartulli 7617ea7b4a1SAntonio Quartulli tvlv_len = *tt_len; 7627ea7b4a1SAntonio Quartulli tvlv_len += change_offset; 7637ea7b4a1SAntonio Quartulli 7647ea7b4a1SAntonio Quartulli *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); 7657ea7b4a1SAntonio Quartulli if (!*tt_data) { 7667ea7b4a1SAntonio Quartulli tvlv_len = 0; 7677ea7b4a1SAntonio Quartulli goto out; 7687ea7b4a1SAntonio Quartulli } 7697ea7b4a1SAntonio Quartulli 7707ea7b4a1SAntonio Quartulli (*tt_data)->flags = BATADV_NO_FLAGS; 7717ea7b4a1SAntonio Quartulli (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn); 7727ea7b4a1SAntonio Quartulli (*tt_data)->num_vlan = htons(num_vlan); 7737ea7b4a1SAntonio Quartulli 7747ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); 7757ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 7767ea7b4a1SAntonio Quartulli tt_vlan->vid = htons(vlan->vid); 7777ea7b4a1SAntonio Quartulli tt_vlan->crc = htonl(vlan->tt.crc); 7787ea7b4a1SAntonio Quartulli 7797ea7b4a1SAntonio Quartulli tt_vlan++; 7807ea7b4a1SAntonio Quartulli } 7817ea7b4a1SAntonio Quartulli 7827ea7b4a1SAntonio Quartulli tt_change_ptr = (uint8_t *)*tt_data + change_offset; 7837ea7b4a1SAntonio Quartulli *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; 7847ea7b4a1SAntonio Quartulli 7857ea7b4a1SAntonio Quartulli out: 7867ea7b4a1SAntonio Quartulli rcu_read_unlock(); 7877ea7b4a1SAntonio Quartulli return tvlv_len; 7887ea7b4a1SAntonio Quartulli } 7897ea7b4a1SAntonio Quartulli 7907ea7b4a1SAntonio Quartulli /** 791e1bf0c14SMarek Lindner * batadv_tt_tvlv_container_update - update the translation table tvlv container 792e1bf0c14SMarek Lindner * after local tt changes have been committed 793e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 794e1bf0c14SMarek Lindner */ 795e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) 796c6c8fea2SSven Eckelmann { 797e1bf0c14SMarek Lindner struct batadv_tt_change_node *entry, *safe; 798e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 799e1bf0c14SMarek Lindner struct batadv_tvlv_tt_change *tt_change; 8007ea7b4a1SAntonio Quartulli int tt_diff_len, tt_change_len = 0; 801e1bf0c14SMarek Lindner int tt_diff_entries_num = 0, tt_diff_entries_count = 0; 8027ea7b4a1SAntonio Quartulli uint16_t tvlv_len; 803c6c8fea2SSven Eckelmann 8047ea7b4a1SAntonio Quartulli tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); 8057ea7b4a1SAntonio Quartulli tt_diff_len = batadv_tt_len(tt_diff_entries_num); 806be9aa4c1SMarek Lindner 807be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 808be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 809be9aa4c1SMarek Lindner */ 810e1bf0c14SMarek Lindner if (tt_diff_len > bat_priv->soft_iface->mtu) 811e1bf0c14SMarek Lindner tt_diff_len = 0; 812be9aa4c1SMarek Lindner 8137ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, 8147ea7b4a1SAntonio Quartulli &tt_change, &tt_diff_len); 8157ea7b4a1SAntonio Quartulli if (!tvlv_len) 816e1bf0c14SMarek Lindner return; 817be9aa4c1SMarek Lindner 818e1bf0c14SMarek Lindner tt_data->flags = BATADV_TT_OGM_DIFF; 819be9aa4c1SMarek Lindner 820e1bf0c14SMarek Lindner if (tt_diff_len == 0) 821e1bf0c14SMarek Lindner goto container_register; 822be9aa4c1SMarek Lindner 823807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 824807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 825c6c8fea2SSven Eckelmann 826807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 827a73105b8SAntonio Quartulli list) { 828e1bf0c14SMarek Lindner if (tt_diff_entries_count < tt_diff_entries_num) { 829e1bf0c14SMarek Lindner memcpy(tt_change + tt_diff_entries_count, 830e1bf0c14SMarek Lindner &entry->change, 831e1bf0c14SMarek Lindner sizeof(struct batadv_tvlv_tt_change)); 832e1bf0c14SMarek Lindner tt_diff_entries_count++; 833c6c8fea2SSven Eckelmann } 834a73105b8SAntonio Quartulli list_del(&entry->list); 835a73105b8SAntonio Quartulli kfree(entry); 836c6c8fea2SSven Eckelmann } 837807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 838c6c8fea2SSven Eckelmann 839a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 840807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 841807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 842807736f6SSven Eckelmann bat_priv->tt.last_changeset_len = 0; 843807736f6SSven Eckelmann bat_priv->tt.last_changeset = NULL; 844e1bf0c14SMarek Lindner tt_change_len = batadv_tt_len(tt_diff_entries_count); 845be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 846e1bf0c14SMarek Lindner if (tt_diff_entries_count > 0) { 847be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 848a73105b8SAntonio Quartulli * instead of providing the diff 849a73105b8SAntonio Quartulli */ 850e1bf0c14SMarek Lindner bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); 851807736f6SSven Eckelmann if (bat_priv->tt.last_changeset) { 852e1bf0c14SMarek Lindner memcpy(bat_priv->tt.last_changeset, 853e1bf0c14SMarek Lindner tt_change, tt_change_len); 854e1bf0c14SMarek Lindner bat_priv->tt.last_changeset_len = tt_diff_len; 855a73105b8SAntonio Quartulli } 856a73105b8SAntonio Quartulli } 857807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 858c6c8fea2SSven Eckelmann 859e1bf0c14SMarek Lindner container_register: 860e1bf0c14SMarek Lindner batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, 8617ea7b4a1SAntonio Quartulli tvlv_len); 862e1bf0c14SMarek Lindner kfree(tt_data); 863c6c8fea2SSven Eckelmann } 864c6c8fea2SSven Eckelmann 86508c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) 866c6c8fea2SSven Eckelmann { 867c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 86856303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 869807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 87056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 87185766a82SAntonio Quartulli struct batadv_tt_local_entry *tt_local; 87256303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 8737ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 874c6c8fea2SSven Eckelmann struct hlist_head *head; 8757ea7b4a1SAntonio Quartulli unsigned short vid; 876c90681b8SAntonio Quartulli uint32_t i; 87785766a82SAntonio Quartulli int last_seen_secs; 87885766a82SAntonio Quartulli int last_seen_msecs; 87985766a82SAntonio Quartulli unsigned long last_seen_jiffies; 88085766a82SAntonio Quartulli bool no_purge; 88185766a82SAntonio Quartulli uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE; 882c6c8fea2SSven Eckelmann 88330da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 88430da63a6SMarek Lindner if (!primary_if) 88532ae9b22SMarek Lindner goto out; 886c6c8fea2SSven Eckelmann 88786ceb360SSven Eckelmann seq_printf(seq, 8887ea7b4a1SAntonio Quartulli "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", 8897ea7b4a1SAntonio Quartulli net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn)); 890dd24ddb2SAntonio Quartulli seq_printf(seq, " %-13s %s %-8s %-9s (%-10s)\n", "Client", "VID", 8917ea7b4a1SAntonio Quartulli "Flags", "Last seen", "CRC"); 892c6c8fea2SSven Eckelmann 893c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 894c6c8fea2SSven Eckelmann head = &hash->table[i]; 895c6c8fea2SSven Eckelmann 8967aadf889SMarek Lindner rcu_read_lock(); 897b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 8987aadf889SMarek Lindner head, hash_entry) { 89985766a82SAntonio Quartulli tt_local = container_of(tt_common_entry, 90085766a82SAntonio Quartulli struct batadv_tt_local_entry, 90185766a82SAntonio Quartulli common); 9027ea7b4a1SAntonio Quartulli vid = tt_common_entry->vid; 90385766a82SAntonio Quartulli last_seen_jiffies = jiffies - tt_local->last_seen; 90485766a82SAntonio Quartulli last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 90585766a82SAntonio Quartulli last_seen_secs = last_seen_msecs / 1000; 90685766a82SAntonio Quartulli last_seen_msecs = last_seen_msecs % 1000; 90785766a82SAntonio Quartulli 90885766a82SAntonio Quartulli no_purge = tt_common_entry->flags & np_flag; 90985766a82SAntonio Quartulli 9107ea7b4a1SAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 9117ea7b4a1SAntonio Quartulli if (!vlan) { 9127ea7b4a1SAntonio Quartulli seq_printf(seq, "Cannot retrieve VLAN %d\n", 9137ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(vid)); 9147ea7b4a1SAntonio Quartulli continue; 9157ea7b4a1SAntonio Quartulli } 9167ea7b4a1SAntonio Quartulli 9177ea7b4a1SAntonio Quartulli seq_printf(seq, 918dd24ddb2SAntonio Quartulli " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n", 91948100bacSAntonio Quartulli tt_common_entry->addr, 92016052789SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 92148100bacSAntonio Quartulli (tt_common_entry->flags & 922acd34afaSSven Eckelmann BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 92385766a82SAntonio Quartulli no_purge ? 'P' : '.', 92448100bacSAntonio Quartulli (tt_common_entry->flags & 925acd34afaSSven Eckelmann BATADV_TT_CLIENT_NEW ? 'N' : '.'), 92648100bacSAntonio Quartulli (tt_common_entry->flags & 927acd34afaSSven Eckelmann BATADV_TT_CLIENT_PENDING ? 'X' : '.'), 92848100bacSAntonio Quartulli (tt_common_entry->flags & 92985766a82SAntonio Quartulli BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 930dd24ddb2SAntonio Quartulli (tt_common_entry->flags & 931dd24ddb2SAntonio Quartulli BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), 932a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_secs, 9337ea7b4a1SAntonio Quartulli no_purge ? 0 : last_seen_msecs, 9347ea7b4a1SAntonio Quartulli vlan->tt.crc); 9357ea7b4a1SAntonio Quartulli 9367ea7b4a1SAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 937c6c8fea2SSven Eckelmann } 9387aadf889SMarek Lindner rcu_read_unlock(); 939c6c8fea2SSven Eckelmann } 94032ae9b22SMarek Lindner out: 94132ae9b22SMarek Lindner if (primary_if) 942e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 94330da63a6SMarek Lindner return 0; 944c6c8fea2SSven Eckelmann } 945c6c8fea2SSven Eckelmann 94656303d34SSven Eckelmann static void 94756303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv, 94856303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry, 949c566dbbeSAntonio Quartulli uint16_t flags, const char *message) 950c6c8fea2SSven Eckelmann { 9513abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, flags); 952c6c8fea2SSven Eckelmann 953015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 954015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 9559cfc7bd6SSven Eckelmann * response issued before the net ttvn increment (consistency check) 9569cfc7bd6SSven Eckelmann */ 957acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; 958c566dbbeSAntonio Quartulli 95939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 96016052789SAntonio Quartulli "Local tt entry (%pM, vid: %d) pending to be removed: %s\n", 96116052789SAntonio Quartulli tt_local_entry->common.addr, 96216052789SAntonio Quartulli BATADV_PRINT_VID(tt_local_entry->common.vid), message); 963c6c8fea2SSven Eckelmann } 964c6c8fea2SSven Eckelmann 9657f91d06cSAntonio Quartulli /** 9667f91d06cSAntonio Quartulli * batadv_tt_local_remove - logically remove an entry from the local table 9677f91d06cSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 9687f91d06cSAntonio Quartulli * @addr: the MAC address of the client to remove 969c018ad3dSAntonio Quartulli * @vid: VLAN identifier 9707f91d06cSAntonio Quartulli * @message: message to append to the log on deletion 9717f91d06cSAntonio Quartulli * @roaming: true if the deletion is due to a roaming event 9727f91d06cSAntonio Quartulli * 9737f91d06cSAntonio Quartulli * Returns the flags assigned to the local entry before being deleted 9747f91d06cSAntonio Quartulli */ 9757f91d06cSAntonio Quartulli uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, 976c018ad3dSAntonio Quartulli const uint8_t *addr, unsigned short vid, 977c018ad3dSAntonio Quartulli const char *message, bool roaming) 978c6c8fea2SSven Eckelmann { 979170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 9807f91d06cSAntonio Quartulli uint16_t flags, curr_flags = BATADV_NO_FLAGS; 981c6c8fea2SSven Eckelmann 982c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 9837683fdc1SAntonio Quartulli if (!tt_local_entry) 9847683fdc1SAntonio Quartulli goto out; 9857683fdc1SAntonio Quartulli 9867f91d06cSAntonio Quartulli curr_flags = tt_local_entry->common.flags; 9877f91d06cSAntonio Quartulli 988acd34afaSSven Eckelmann flags = BATADV_TT_CLIENT_DEL; 989068ee6e2SAntonio Quartulli /* if this global entry addition is due to a roaming, the node has to 990068ee6e2SAntonio Quartulli * mark the local entry as "roamed" in order to correctly reroute 991068ee6e2SAntonio Quartulli * packets later 992068ee6e2SAntonio Quartulli */ 9937c1fd91dSAntonio Quartulli if (roaming) { 994acd34afaSSven Eckelmann flags |= BATADV_TT_CLIENT_ROAM; 9957c1fd91dSAntonio Quartulli /* mark the local client as ROAMed */ 9967c1fd91dSAntonio Quartulli tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 9977c1fd91dSAntonio Quartulli } 99842d0b044SSven Eckelmann 999068ee6e2SAntonio Quartulli if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { 1000068ee6e2SAntonio Quartulli batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, 1001068ee6e2SAntonio Quartulli message); 1002068ee6e2SAntonio Quartulli goto out; 1003068ee6e2SAntonio Quartulli } 1004068ee6e2SAntonio Quartulli /* if this client has been added right now, it is possible to 1005068ee6e2SAntonio Quartulli * immediately purge it 1006068ee6e2SAntonio Quartulli */ 10073abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); 1008068ee6e2SAntonio Quartulli hlist_del_rcu(&tt_local_entry->common.hash_entry); 1009068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 10107f91d06cSAntonio Quartulli 10117683fdc1SAntonio Quartulli out: 10127683fdc1SAntonio Quartulli if (tt_local_entry) 1013a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 10147f91d06cSAntonio Quartulli 10157f91d06cSAntonio Quartulli return curr_flags; 1016c6c8fea2SSven Eckelmann } 1017c6c8fea2SSven Eckelmann 1018a19d3d85SMarek Lindner /** 1019a19d3d85SMarek Lindner * batadv_tt_local_purge_list - purge inactive tt local entries 1020a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1021a19d3d85SMarek Lindner * @head: pointer to the list containing the local tt entries 1022a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1023a19d3d85SMarek Lindner * inactive or not 1024a19d3d85SMarek Lindner */ 102556303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 1026a19d3d85SMarek Lindner struct hlist_head *head, 1027a19d3d85SMarek Lindner int timeout) 1028c6c8fea2SSven Eckelmann { 102956303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 103056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1031b67bfe0dSSasha Levin struct hlist_node *node_tmp; 1032acd34afaSSven Eckelmann 1033b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, 1034acd34afaSSven Eckelmann hash_entry) { 1035acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common_entry, 103656303d34SSven Eckelmann struct batadv_tt_local_entry, 103756303d34SSven Eckelmann common); 1038acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) 1039acd34afaSSven Eckelmann continue; 1040acd34afaSSven Eckelmann 1041acd34afaSSven Eckelmann /* entry already marked for deletion */ 1042acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 1043acd34afaSSven Eckelmann continue; 1044acd34afaSSven Eckelmann 1045a19d3d85SMarek Lindner if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) 1046acd34afaSSven Eckelmann continue; 1047acd34afaSSven Eckelmann 1048acd34afaSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 1049acd34afaSSven Eckelmann BATADV_TT_CLIENT_DEL, "timed out"); 1050acd34afaSSven Eckelmann } 1051acd34afaSSven Eckelmann } 1052acd34afaSSven Eckelmann 1053a19d3d85SMarek Lindner /** 1054a19d3d85SMarek Lindner * batadv_tt_local_purge - purge inactive tt local entries 1055a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1056a19d3d85SMarek Lindner * @timeout: parameter deciding whether a given tt local entry is considered 1057a19d3d85SMarek Lindner * inactive or not 1058a19d3d85SMarek Lindner */ 1059a19d3d85SMarek Lindner static void batadv_tt_local_purge(struct batadv_priv *bat_priv, 1060a19d3d85SMarek Lindner int timeout) 1061acd34afaSSven Eckelmann { 1062807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 1063c6c8fea2SSven Eckelmann struct hlist_head *head; 10647683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 1065c90681b8SAntonio Quartulli uint32_t i; 1066c6c8fea2SSven Eckelmann 1067c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1068c6c8fea2SSven Eckelmann head = &hash->table[i]; 10697683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1070c6c8fea2SSven Eckelmann 10717683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1072a19d3d85SMarek Lindner batadv_tt_local_purge_list(bat_priv, head, timeout); 10737683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1074c6c8fea2SSven Eckelmann } 1075c6c8fea2SSven Eckelmann } 1076c6c8fea2SSven Eckelmann 107756303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) 1078c6c8fea2SSven Eckelmann { 10795bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 1080a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 108156303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 108256303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 1083b67bfe0dSSasha Levin struct hlist_node *node_tmp; 10847683fdc1SAntonio Quartulli struct hlist_head *head; 1085c90681b8SAntonio Quartulli uint32_t i; 1086a73105b8SAntonio Quartulli 1087807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 1088c6c8fea2SSven Eckelmann return; 1089c6c8fea2SSven Eckelmann 1090807736f6SSven Eckelmann hash = bat_priv->tt.local_hash; 1091a73105b8SAntonio Quartulli 1092a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1093a73105b8SAntonio Quartulli head = &hash->table[i]; 1094a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 1095a73105b8SAntonio Quartulli 1096a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 1097b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 1098a73105b8SAntonio Quartulli head, hash_entry) { 1099b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 110056303d34SSven Eckelmann tt_local = container_of(tt_common_entry, 110156303d34SSven Eckelmann struct batadv_tt_local_entry, 110248100bacSAntonio Quartulli common); 110356303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 1104a73105b8SAntonio Quartulli } 1105a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 1106a73105b8SAntonio Quartulli } 1107a73105b8SAntonio Quartulli 11081a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 1109a73105b8SAntonio Quartulli 1110807736f6SSven Eckelmann bat_priv->tt.local_hash = NULL; 1111c6c8fea2SSven Eckelmann } 1112c6c8fea2SSven Eckelmann 111356303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv) 1114c6c8fea2SSven Eckelmann { 1115807736f6SSven Eckelmann if (bat_priv->tt.global_hash) 11165346c35eSSven Eckelmann return 0; 1117c6c8fea2SSven Eckelmann 1118807736f6SSven Eckelmann bat_priv->tt.global_hash = batadv_hash_new(1024); 1119c6c8fea2SSven Eckelmann 1120807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 11215346c35eSSven Eckelmann return -ENOMEM; 1122c6c8fea2SSven Eckelmann 1123dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.global_hash, 1124dec05074SAntonio Quartulli &batadv_tt_global_hash_lock_class_key); 1125dec05074SAntonio Quartulli 11265346c35eSSven Eckelmann return 0; 1127c6c8fea2SSven Eckelmann } 1128c6c8fea2SSven Eckelmann 112956303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) 1130a73105b8SAntonio Quartulli { 113156303d34SSven Eckelmann struct batadv_tt_change_node *entry, *safe; 1132a73105b8SAntonio Quartulli 1133807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 1134a73105b8SAntonio Quartulli 1135807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 1136a73105b8SAntonio Quartulli list) { 1137a73105b8SAntonio Quartulli list_del(&entry->list); 1138a73105b8SAntonio Quartulli kfree(entry); 1139a73105b8SAntonio Quartulli } 1140a73105b8SAntonio Quartulli 1141807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 1142807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 1143a73105b8SAntonio Quartulli } 1144a73105b8SAntonio Quartulli 1145d657e621SAntonio Quartulli /* retrieves the orig_tt_list_entry belonging to orig_node from the 1146d657e621SAntonio Quartulli * batadv_tt_global_entry list 1147d657e621SAntonio Quartulli * 1148d657e621SAntonio Quartulli * returns it with an increased refcounter, NULL if not found 1149d657e621SAntonio Quartulli */ 1150d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry * 1151d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, 1152d657e621SAntonio Quartulli const struct batadv_orig_node *orig_node) 1153d657e621SAntonio Quartulli { 1154d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; 1155d657e621SAntonio Quartulli const struct hlist_head *head; 1156d657e621SAntonio Quartulli 1157d657e621SAntonio Quartulli rcu_read_lock(); 1158d657e621SAntonio Quartulli head = &entry->orig_list; 1159b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { 1160d657e621SAntonio Quartulli if (tmp_orig_entry->orig_node != orig_node) 1161d657e621SAntonio Quartulli continue; 1162d657e621SAntonio Quartulli if (!atomic_inc_not_zero(&tmp_orig_entry->refcount)) 1163d657e621SAntonio Quartulli continue; 1164d657e621SAntonio Quartulli 1165d657e621SAntonio Quartulli orig_entry = tmp_orig_entry; 1166d657e621SAntonio Quartulli break; 1167d657e621SAntonio Quartulli } 1168d657e621SAntonio Quartulli rcu_read_unlock(); 1169d657e621SAntonio Quartulli 1170d657e621SAntonio Quartulli return orig_entry; 1171d657e621SAntonio Quartulli } 1172d657e621SAntonio Quartulli 1173db08e6e5SSimon Wunderlich /* find out if an orig_node is already in the list of a tt_global_entry. 1174d657e621SAntonio Quartulli * returns true if found, false otherwise 1175db08e6e5SSimon Wunderlich */ 117656303d34SSven Eckelmann static bool 117756303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, 117856303d34SSven Eckelmann const struct batadv_orig_node *orig_node) 1179db08e6e5SSimon Wunderlich { 1180d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *orig_entry; 1181db08e6e5SSimon Wunderlich bool found = false; 1182db08e6e5SSimon Wunderlich 1183d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); 1184d657e621SAntonio Quartulli if (orig_entry) { 1185db08e6e5SSimon Wunderlich found = true; 1186d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 1187db08e6e5SSimon Wunderlich } 1188d657e621SAntonio Quartulli 1189db08e6e5SSimon Wunderlich return found; 1190db08e6e5SSimon Wunderlich } 1191db08e6e5SSimon Wunderlich 1192a513088dSSven Eckelmann static void 1193d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, 119456303d34SSven Eckelmann struct batadv_orig_node *orig_node, int ttvn) 1195db08e6e5SSimon Wunderlich { 119656303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1197db08e6e5SSimon Wunderlich 1198d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); 119930cfd02bSAntonio Quartulli if (orig_entry) { 120030cfd02bSAntonio Quartulli /* refresh the ttvn: the current value could be a bogus one that 120130cfd02bSAntonio Quartulli * was added during a "temporary client detection" 120230cfd02bSAntonio Quartulli */ 120330cfd02bSAntonio Quartulli orig_entry->ttvn = ttvn; 1204d657e621SAntonio Quartulli goto out; 120530cfd02bSAntonio Quartulli } 1206d657e621SAntonio Quartulli 1207db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 1208db08e6e5SSimon Wunderlich if (!orig_entry) 1209d657e621SAntonio Quartulli goto out; 1210db08e6e5SSimon Wunderlich 1211db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 1212db08e6e5SSimon Wunderlich atomic_inc(&orig_node->refcount); 12137ea7b4a1SAntonio Quartulli batadv_tt_global_size_inc(orig_node, tt_global->common.vid); 1214db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 1215db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 1216d657e621SAntonio Quartulli atomic_set(&orig_entry->refcount, 2); 1217db08e6e5SSimon Wunderlich 1218d657e621SAntonio Quartulli spin_lock_bh(&tt_global->list_lock); 1219db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 1220d657e621SAntonio Quartulli &tt_global->orig_list); 1221d657e621SAntonio Quartulli spin_unlock_bh(&tt_global->list_lock); 1222d657e621SAntonio Quartulli out: 1223d657e621SAntonio Quartulli if (orig_entry) 1224d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 1225db08e6e5SSimon Wunderlich } 1226db08e6e5SSimon Wunderlich 1227d4ff40f6SAntonio Quartulli /** 1228d4ff40f6SAntonio Quartulli * batadv_tt_global_add - add a new TT global entry or update an existing one 1229d4ff40f6SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1230d4ff40f6SAntonio Quartulli * @orig_node: the originator announcing the client 1231d4ff40f6SAntonio Quartulli * @tt_addr: the mac address of the non-mesh client 1232c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1233d4ff40f6SAntonio Quartulli * @flags: TT flags that have to be set for this non-mesh client 1234d4ff40f6SAntonio Quartulli * @ttvn: the tt version number ever announcing this non-mesh client 1235d4ff40f6SAntonio Quartulli * 1236d4ff40f6SAntonio Quartulli * Add a new TT global entry for the given originator. If the entry already 1237d4ff40f6SAntonio Quartulli * exists add a new reference to the given originator (a global entry can have 1238d4ff40f6SAntonio Quartulli * references to multiple originators) and adjust the flags attribute to reflect 1239d4ff40f6SAntonio Quartulli * the function argument. 1240d4ff40f6SAntonio Quartulli * If a TT local entry exists for this non-mesh client remove it. 1241d4ff40f6SAntonio Quartulli * 1242d4ff40f6SAntonio Quartulli * The caller must hold orig_node refcount. 12431e5d49fcSAntonio Quartulli * 12441e5d49fcSAntonio Quartulli * Return true if the new entry has been added, false otherwise 1245d4ff40f6SAntonio Quartulli */ 12461e5d49fcSAntonio Quartulli static bool batadv_tt_global_add(struct batadv_priv *bat_priv, 124756303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1248c018ad3dSAntonio Quartulli const unsigned char *tt_addr, 1249c018ad3dSAntonio Quartulli unsigned short vid, uint16_t flags, 1250d4f44692SAntonio Quartulli uint8_t ttvn) 1251c6c8fea2SSven Eckelmann { 1252170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 1253170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 12541e5d49fcSAntonio Quartulli bool ret = false; 125580b3f58cSSimon Wunderlich int hash_added; 125656303d34SSven Eckelmann struct batadv_tt_common_entry *common; 12577f91d06cSAntonio Quartulli uint16_t local_flags; 1258c6c8fea2SSven Eckelmann 1259cfd4f757SAntonio Quartulli /* ignore global entries from backbone nodes */ 1260cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) 1261cfd4f757SAntonio Quartulli return true; 1262cfd4f757SAntonio Quartulli 1263c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); 1264c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid); 1265068ee6e2SAntonio Quartulli 1266068ee6e2SAntonio Quartulli /* if the node already has a local client for this entry, it has to wait 1267068ee6e2SAntonio Quartulli * for a roaming advertisement instead of manually messing up the global 1268068ee6e2SAntonio Quartulli * table 1269068ee6e2SAntonio Quartulli */ 1270068ee6e2SAntonio Quartulli if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && 1271068ee6e2SAntonio Quartulli !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) 1272068ee6e2SAntonio Quartulli goto out; 1273c6c8fea2SSven Eckelmann 12742dafb49dSAntonio Quartulli if (!tt_global_entry) { 1275d4f44692SAntonio Quartulli tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); 12762dafb49dSAntonio Quartulli if (!tt_global_entry) 12777683fdc1SAntonio Quartulli goto out; 12787683fdc1SAntonio Quartulli 1279c0a55929SSven Eckelmann common = &tt_global_entry->common; 12808fdd0153SAntonio Quartulli ether_addr_copy(common->addr, tt_addr); 1281c018ad3dSAntonio Quartulli common->vid = vid; 1282db08e6e5SSimon Wunderlich 1283d4f44692SAntonio Quartulli common->flags = flags; 1284cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1285fdf79320SAntonio Quartulli /* node must store current time in case of roaming. This is 1286fdf79320SAntonio Quartulli * needed to purge this entry out on timeout (if nobody claims 1287fdf79320SAntonio Quartulli * it) 1288fdf79320SAntonio Quartulli */ 1289fdf79320SAntonio Quartulli if (flags & BATADV_TT_CLIENT_ROAM) 1290fdf79320SAntonio Quartulli tt_global_entry->roam_at = jiffies; 1291c0a55929SSven Eckelmann atomic_set(&common->refcount, 2); 129230cfd02bSAntonio Quartulli common->added_at = jiffies; 1293db08e6e5SSimon Wunderlich 1294db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 1295db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 12967683fdc1SAntonio Quartulli 1297807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.global_hash, 1298a513088dSSven Eckelmann batadv_compare_tt, 1299c018ad3dSAntonio Quartulli batadv_choose_tt, common, 1300a513088dSSven Eckelmann &common->hash_entry); 130180b3f58cSSimon Wunderlich 130280b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 130380b3f58cSSimon Wunderlich /* remove the reference for the hash */ 1304a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 130580b3f58cSSimon Wunderlich goto out_remove; 130680b3f58cSSimon Wunderlich } 1307a73105b8SAntonio Quartulli } else { 1308068ee6e2SAntonio Quartulli common = &tt_global_entry->common; 130930cfd02bSAntonio Quartulli /* If there is already a global entry, we can use this one for 131030cfd02bSAntonio Quartulli * our processing. 1311068ee6e2SAntonio Quartulli * But if we are trying to add a temporary client then here are 1312068ee6e2SAntonio Quartulli * two options at this point: 1313068ee6e2SAntonio Quartulli * 1) the global client is not a temporary client: the global 1314068ee6e2SAntonio Quartulli * client has to be left as it is, temporary information 1315068ee6e2SAntonio Quartulli * should never override any already known client state 1316068ee6e2SAntonio Quartulli * 2) the global client is a temporary client: purge the 1317068ee6e2SAntonio Quartulli * originator list and add the new one orig_entry 131830cfd02bSAntonio Quartulli */ 1319068ee6e2SAntonio Quartulli if (flags & BATADV_TT_CLIENT_TEMP) { 1320068ee6e2SAntonio Quartulli if (!(common->flags & BATADV_TT_CLIENT_TEMP)) 132130cfd02bSAntonio Quartulli goto out; 1322068ee6e2SAntonio Quartulli if (batadv_tt_global_entry_has_orig(tt_global_entry, 1323068ee6e2SAntonio Quartulli orig_node)) 1324068ee6e2SAntonio Quartulli goto out_remove; 1325068ee6e2SAntonio Quartulli batadv_tt_global_del_orig_list(tt_global_entry); 1326068ee6e2SAntonio Quartulli goto add_orig_entry; 1327068ee6e2SAntonio Quartulli } 132830cfd02bSAntonio Quartulli 132930cfd02bSAntonio Quartulli /* if the client was temporary added before receiving the first 133030cfd02bSAntonio Quartulli * OGM announcing it, we have to clear the TEMP flag 133130cfd02bSAntonio Quartulli */ 1332068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_TEMP; 1333db08e6e5SSimon Wunderlich 1334e9c00136SAntonio Quartulli /* the change can carry possible "attribute" flags like the 1335e9c00136SAntonio Quartulli * TT_CLIENT_WIFI, therefore they have to be copied in the 1336e9c00136SAntonio Quartulli * client entry 1337e9c00136SAntonio Quartulli */ 1338e9c00136SAntonio Quartulli tt_global_entry->common.flags |= flags; 1339e9c00136SAntonio Quartulli 1340acd34afaSSven Eckelmann /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 1341acd34afaSSven Eckelmann * one originator left in the list and we previously received a 1342db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 1343db08e6e5SSimon Wunderlich * 1344db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 1345db08e6e5SSimon Wunderlich * new one. 1346db08e6e5SSimon Wunderlich */ 1347068ee6e2SAntonio Quartulli if (common->flags & BATADV_TT_CLIENT_ROAM) { 1348a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1349068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_ROAM; 1350cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 1351c6c8fea2SSven Eckelmann } 1352db08e6e5SSimon Wunderlich } 1353068ee6e2SAntonio Quartulli add_orig_entry: 135430cfd02bSAntonio Quartulli /* add the new orig_entry (if needed) or update it */ 1355d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); 1356db08e6e5SSimon Wunderlich 135739c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 135816052789SAntonio Quartulli "Creating new global tt entry: %pM (vid: %d, via %pM)\n", 135916052789SAntonio Quartulli common->addr, BATADV_PRINT_VID(common->vid), 136016052789SAntonio Quartulli orig_node->orig); 13611e5d49fcSAntonio Quartulli ret = true; 1362a73105b8SAntonio Quartulli 136380b3f58cSSimon Wunderlich out_remove: 13647f91d06cSAntonio Quartulli 1365c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 1366c018ad3dSAntonio Quartulli local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, 1367acd34afaSSven Eckelmann "global tt received", 1368c1d07431SAntonio Quartulli flags & BATADV_TT_CLIENT_ROAM); 13697f91d06cSAntonio Quartulli tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; 13707f91d06cSAntonio Quartulli 1371068ee6e2SAntonio Quartulli if (!(flags & BATADV_TT_CLIENT_ROAM)) 1372068ee6e2SAntonio Quartulli /* this is a normal global add. Therefore the client is not in a 1373068ee6e2SAntonio Quartulli * roaming state anymore. 1374068ee6e2SAntonio Quartulli */ 1375068ee6e2SAntonio Quartulli tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 1376068ee6e2SAntonio Quartulli 13777683fdc1SAntonio Quartulli out: 13787683fdc1SAntonio Quartulli if (tt_global_entry) 1379a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1380068ee6e2SAntonio Quartulli if (tt_local_entry) 1381068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 13827683fdc1SAntonio Quartulli return ret; 1383c6c8fea2SSven Eckelmann } 1384c6c8fea2SSven Eckelmann 13851b371d13SSimon Wunderlich /** 13861b371d13SSimon Wunderlich * batadv_transtable_best_orig - Get best originator list entry from tt entry 13874627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1388981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be analyzed 1389981d8900SSven Eckelmann * 1390981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 1391981d8900SSven Eckelmann * Returns best originator list entry or NULL on errors. 1392981d8900SSven Eckelmann */ 1393981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry * 13944627456aSAntonio Quartulli batadv_transtable_best_orig(struct batadv_priv *bat_priv, 13954627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry) 1396981d8900SSven Eckelmann { 13974627456aSAntonio Quartulli struct batadv_neigh_node *router, *best_router = NULL; 13984627456aSAntonio Quartulli struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; 1399981d8900SSven Eckelmann struct hlist_head *head; 1400981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; 1401981d8900SSven Eckelmann 1402981d8900SSven Eckelmann head = &tt_global_entry->orig_list; 1403b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 14047351a482SSimon Wunderlich router = batadv_orig_router_get(orig_entry->orig_node, 14057351a482SSimon Wunderlich BATADV_IF_DEFAULT); 1406981d8900SSven Eckelmann if (!router) 1407981d8900SSven Eckelmann continue; 1408981d8900SSven Eckelmann 14094627456aSAntonio Quartulli if (best_router && 141089652331SSimon Wunderlich bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, 141189652331SSimon Wunderlich best_router, BATADV_IF_DEFAULT) <= 0) { 14124627456aSAntonio Quartulli batadv_neigh_node_free_ref(router); 14134627456aSAntonio Quartulli continue; 1414981d8900SSven Eckelmann } 1415981d8900SSven Eckelmann 14164627456aSAntonio Quartulli /* release the refcount for the "old" best */ 14174627456aSAntonio Quartulli if (best_router) 14184627456aSAntonio Quartulli batadv_neigh_node_free_ref(best_router); 14194627456aSAntonio Quartulli 14204627456aSAntonio Quartulli best_entry = orig_entry; 14214627456aSAntonio Quartulli best_router = router; 1422981d8900SSven Eckelmann } 1423981d8900SSven Eckelmann 14244627456aSAntonio Quartulli if (best_router) 14254627456aSAntonio Quartulli batadv_neigh_node_free_ref(best_router); 14264627456aSAntonio Quartulli 1427981d8900SSven Eckelmann return best_entry; 1428981d8900SSven Eckelmann } 1429981d8900SSven Eckelmann 14301b371d13SSimon Wunderlich /** 14311b371d13SSimon Wunderlich * batadv_tt_global_print_entry - print all orig nodes who announce the address 1432981d8900SSven Eckelmann * for this global entry 14334627456aSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1434981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be printed 1435981d8900SSven Eckelmann * @seq: debugfs table seq_file struct 1436981d8900SSven Eckelmann * 1437981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 1438db08e6e5SSimon Wunderlich */ 1439a513088dSSven Eckelmann static void 14404627456aSAntonio Quartulli batadv_tt_global_print_entry(struct batadv_priv *bat_priv, 14414627456aSAntonio Quartulli struct batadv_tt_global_entry *tt_global_entry, 1442db08e6e5SSimon Wunderlich struct seq_file *seq) 1443db08e6e5SSimon Wunderlich { 1444981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry; 144556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 14467ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 14477ea7b4a1SAntonio Quartulli struct hlist_head *head; 1448db08e6e5SSimon Wunderlich uint8_t last_ttvn; 14497ea7b4a1SAntonio Quartulli uint16_t flags; 1450db08e6e5SSimon Wunderlich 1451db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 1452981d8900SSven Eckelmann flags = tt_common_entry->flags; 1453981d8900SSven Eckelmann 14544627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 1455981d8900SSven Eckelmann if (best_entry) { 14567ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(best_entry->orig_node, 14577ea7b4a1SAntonio Quartulli tt_common_entry->vid); 14587ea7b4a1SAntonio Quartulli if (!vlan) { 14597ea7b4a1SAntonio Quartulli seq_printf(seq, 14607ea7b4a1SAntonio Quartulli " * Cannot retrieve VLAN %d for originator %pM\n", 14617ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 14627ea7b4a1SAntonio Quartulli best_entry->orig_node->orig); 14637ea7b4a1SAntonio Quartulli goto print_list; 14647ea7b4a1SAntonio Quartulli } 14657ea7b4a1SAntonio Quartulli 1466981d8900SSven Eckelmann last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); 1467f9d8a537SAntonio Quartulli seq_printf(seq, 1468dd24ddb2SAntonio Quartulli " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1469981d8900SSven Eckelmann '*', tt_global_entry->common.addr, 147016052789SAntonio Quartulli BATADV_PRINT_VID(tt_global_entry->common.vid), 1471981d8900SSven Eckelmann best_entry->ttvn, best_entry->orig_node->orig, 14727ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1473981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 1474981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 1475dd24ddb2SAntonio Quartulli (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), 1476981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); 14777ea7b4a1SAntonio Quartulli 14787ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 1479981d8900SSven Eckelmann } 1480db08e6e5SSimon Wunderlich 14817ea7b4a1SAntonio Quartulli print_list: 1482db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1483db08e6e5SSimon Wunderlich 1484b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1485981d8900SSven Eckelmann if (best_entry == orig_entry) 1486981d8900SSven Eckelmann continue; 1487981d8900SSven Eckelmann 14887ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, 14897ea7b4a1SAntonio Quartulli tt_common_entry->vid); 14907ea7b4a1SAntonio Quartulli if (!vlan) { 14917ea7b4a1SAntonio Quartulli seq_printf(seq, 14927ea7b4a1SAntonio Quartulli " + Cannot retrieve VLAN %d for originator %pM\n", 14937ea7b4a1SAntonio Quartulli BATADV_PRINT_VID(tt_common_entry->vid), 14947ea7b4a1SAntonio Quartulli orig_entry->orig_node->orig); 14957ea7b4a1SAntonio Quartulli continue; 14967ea7b4a1SAntonio Quartulli } 14977ea7b4a1SAntonio Quartulli 1498db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 149916052789SAntonio Quartulli seq_printf(seq, 1500dd24ddb2SAntonio Quartulli " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n", 1501981d8900SSven Eckelmann '+', tt_global_entry->common.addr, 150216052789SAntonio Quartulli BATADV_PRINT_VID(tt_global_entry->common.vid), 1503981d8900SSven Eckelmann orig_entry->ttvn, orig_entry->orig_node->orig, 15047ea7b4a1SAntonio Quartulli last_ttvn, vlan->tt.crc, 1505acd34afaSSven Eckelmann (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 150630cfd02bSAntonio Quartulli (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 1507dd24ddb2SAntonio Quartulli (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), 150830cfd02bSAntonio Quartulli (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); 15097ea7b4a1SAntonio Quartulli 15107ea7b4a1SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 1511db08e6e5SSimon Wunderlich } 1512db08e6e5SSimon Wunderlich } 1513db08e6e5SSimon Wunderlich 151408c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 1515c6c8fea2SSven Eckelmann { 1516c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 151756303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 1518807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 151956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 152056303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 152156303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 1522c6c8fea2SSven Eckelmann struct hlist_head *head; 1523c90681b8SAntonio Quartulli uint32_t i; 1524c6c8fea2SSven Eckelmann 152530da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 152630da63a6SMarek Lindner if (!primary_if) 152732ae9b22SMarek Lindner goto out; 1528c6c8fea2SSven Eckelmann 15292dafb49dSAntonio Quartulli seq_printf(seq, 15302dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 1531c6c8fea2SSven Eckelmann net_dev->name); 153216052789SAntonio Quartulli seq_printf(seq, " %-13s %s %s %-15s %s (%-10s) %s\n", 153316052789SAntonio Quartulli "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)", 153416052789SAntonio Quartulli "CRC", "Flags"); 1535c6c8fea2SSven Eckelmann 1536c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1537c6c8fea2SSven Eckelmann head = &hash->table[i]; 1538c6c8fea2SSven Eckelmann 15397aadf889SMarek Lindner rcu_read_lock(); 1540b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 15417aadf889SMarek Lindner head, hash_entry) { 154256303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 154356303d34SSven Eckelmann struct batadv_tt_global_entry, 154448100bacSAntonio Quartulli common); 15454627456aSAntonio Quartulli batadv_tt_global_print_entry(bat_priv, tt_global, seq); 1546c6c8fea2SSven Eckelmann } 15477aadf889SMarek Lindner rcu_read_unlock(); 1548c6c8fea2SSven Eckelmann } 154932ae9b22SMarek Lindner out: 155032ae9b22SMarek Lindner if (primary_if) 1551e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 155230da63a6SMarek Lindner return 0; 1553c6c8fea2SSven Eckelmann } 1554c6c8fea2SSven Eckelmann 1555db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 1556a513088dSSven Eckelmann static void 155756303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) 1558db08e6e5SSimon Wunderlich { 1559db08e6e5SSimon Wunderlich struct hlist_head *head; 1560b67bfe0dSSasha Levin struct hlist_node *safe; 156156303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1562db08e6e5SSimon Wunderlich 1563db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1564db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1565b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1566b67bfe0dSSasha Levin hlist_del_rcu(&orig_entry->list); 15677ea7b4a1SAntonio Quartulli batadv_tt_global_size_dec(orig_entry->orig_node, 15687ea7b4a1SAntonio Quartulli tt_global_entry->common.vid); 1569a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 1570db08e6e5SSimon Wunderlich } 1571db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1572db08e6e5SSimon Wunderlich } 1573db08e6e5SSimon Wunderlich 1574a513088dSSven Eckelmann static void 157556303d34SSven Eckelmann batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, 157656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 157756303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1578db08e6e5SSimon Wunderlich const char *message) 1579db08e6e5SSimon Wunderlich { 1580db08e6e5SSimon Wunderlich struct hlist_head *head; 1581b67bfe0dSSasha Levin struct hlist_node *safe; 158256303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 158316052789SAntonio Quartulli unsigned short vid; 1584db08e6e5SSimon Wunderlich 1585db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1586db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1587b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1588db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 158916052789SAntonio Quartulli vid = tt_global_entry->common.vid; 159039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 159116052789SAntonio Quartulli "Deleting %pM from global tt entry %pM (vid: %d): %s\n", 15921eda58bfSSven Eckelmann orig_node->orig, 159316052789SAntonio Quartulli tt_global_entry->common.addr, 159416052789SAntonio Quartulli BATADV_PRINT_VID(vid), message); 1595b67bfe0dSSasha Levin hlist_del_rcu(&orig_entry->list); 15967ea7b4a1SAntonio Quartulli batadv_tt_global_size_dec(orig_node, 15977ea7b4a1SAntonio Quartulli tt_global_entry->common.vid); 1598a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 1599db08e6e5SSimon Wunderlich } 1600db08e6e5SSimon Wunderlich } 1601db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1602db08e6e5SSimon Wunderlich } 1603db08e6e5SSimon Wunderlich 1604db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 1605acd34afaSSven Eckelmann * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the 1606acd34afaSSven Eckelmann * timer, otherwise we simply remove the originator scheduled for deletion. 1607db08e6e5SSimon Wunderlich */ 1608a513088dSSven Eckelmann static void 160956303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, 161056303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 161156303d34SSven Eckelmann struct batadv_orig_node *orig_node, 161256303d34SSven Eckelmann const char *message) 1613db08e6e5SSimon Wunderlich { 1614db08e6e5SSimon Wunderlich bool last_entry = true; 1615db08e6e5SSimon Wunderlich struct hlist_head *head; 161656303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1617db08e6e5SSimon Wunderlich 1618db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 1619db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 1620db08e6e5SSimon Wunderlich */ 1621db08e6e5SSimon Wunderlich 1622db08e6e5SSimon Wunderlich rcu_read_lock(); 1623db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1624b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1625db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 1626db08e6e5SSimon Wunderlich last_entry = false; 1627db08e6e5SSimon Wunderlich break; 1628db08e6e5SSimon Wunderlich } 1629db08e6e5SSimon Wunderlich } 1630db08e6e5SSimon Wunderlich rcu_read_unlock(); 1631db08e6e5SSimon Wunderlich 1632db08e6e5SSimon Wunderlich if (last_entry) { 1633db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 1634acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 1635db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 1636db08e6e5SSimon Wunderlich } else 1637db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 1638db08e6e5SSimon Wunderlich * one and can still use the other one. 1639db08e6e5SSimon Wunderlich */ 1640a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 1641db08e6e5SSimon Wunderlich orig_node, message); 1642db08e6e5SSimon Wunderlich } 1643db08e6e5SSimon Wunderlich 1644c018ad3dSAntonio Quartulli /** 1645c018ad3dSAntonio Quartulli * batadv_tt_global_del - remove a client from the global table 1646c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1647c018ad3dSAntonio Quartulli * @orig_node: an originator serving this client 1648c018ad3dSAntonio Quartulli * @addr: the mac address of the client 1649c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1650c018ad3dSAntonio Quartulli * @message: a message explaining the reason for deleting the client to print 1651c018ad3dSAntonio Quartulli * for debugging purpose 1652c018ad3dSAntonio Quartulli * @roaming: true if the deletion has been triggered by a roaming event 1653c018ad3dSAntonio Quartulli */ 165456303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv, 165556303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1656c018ad3dSAntonio Quartulli const unsigned char *addr, unsigned short vid, 1657cc47f66eSAntonio Quartulli const char *message, bool roaming) 1658a73105b8SAntonio Quartulli { 1659170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 166056303d34SSven Eckelmann struct batadv_tt_local_entry *local_entry = NULL; 1661a73105b8SAntonio Quartulli 1662c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 1663db08e6e5SSimon Wunderlich if (!tt_global_entry) 16647683fdc1SAntonio Quartulli goto out; 1665a73105b8SAntonio Quartulli 1666db08e6e5SSimon Wunderlich if (!roaming) { 1667a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 1668a513088dSSven Eckelmann orig_node, message); 166992f90f56SSven Eckelmann 1670db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 1671be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, 1672db08e6e5SSimon Wunderlich message); 1673db08e6e5SSimon Wunderlich 1674cc47f66eSAntonio Quartulli goto out; 1675cc47f66eSAntonio Quartulli } 167692f90f56SSven Eckelmann 1677db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 1678db08e6e5SSimon Wunderlich * event, there are two possibilities: 1679db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 1680db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 1681acd34afaSSven Eckelmann * it with BATADV_TT_CLIENT_ROAM, we start a timer and we 1682db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 1683db08e6e5SSimon Wunderlich * the entry is purged. 1684db08e6e5SSimon Wunderlich * 1685db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 1686db08e6e5SSimon Wunderlich * the originator. 1687db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 16889cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 16899cfc7bd6SSven Eckelmann */ 1690a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 1691c018ad3dSAntonio Quartulli tt_global_entry->common.addr, 1692c018ad3dSAntonio Quartulli vid); 1693a513088dSSven Eckelmann if (local_entry) { 1694db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 1695a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1696be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, message); 1697db08e6e5SSimon Wunderlich } else 1698db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 1699a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 1700a513088dSSven Eckelmann orig_node, message); 1701db08e6e5SSimon Wunderlich 170292f90f56SSven Eckelmann 1703cc47f66eSAntonio Quartulli out: 17047683fdc1SAntonio Quartulli if (tt_global_entry) 1705a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1706a513088dSSven Eckelmann if (local_entry) 1707a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(local_entry); 1708a73105b8SAntonio Quartulli } 1709a73105b8SAntonio Quartulli 171095fb130dSAntonio Quartulli /** 171195fb130dSAntonio Quartulli * batadv_tt_global_del_orig - remove all the TT global entries belonging to the 171295fb130dSAntonio Quartulli * given originator matching the provided vid 171395fb130dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 171495fb130dSAntonio Quartulli * @orig_node: the originator owning the entries to remove 171595fb130dSAntonio Quartulli * @match_vid: the VLAN identifier to match. If negative all the entries will be 171695fb130dSAntonio Quartulli * removed 171795fb130dSAntonio Quartulli * @message: debug message to print as "reason" 171895fb130dSAntonio Quartulli */ 171956303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, 172056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 172195fb130dSAntonio Quartulli int32_t match_vid, 172256303d34SSven Eckelmann const char *message) 1723c6c8fea2SSven Eckelmann { 172456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 172556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1726c90681b8SAntonio Quartulli uint32_t i; 1727807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 1728b67bfe0dSSasha Levin struct hlist_node *safe; 1729a73105b8SAntonio Quartulli struct hlist_head *head; 17307683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 173116052789SAntonio Quartulli unsigned short vid; 1732c6c8fea2SSven Eckelmann 17336e801494SSimon Wunderlich if (!hash) 17346e801494SSimon Wunderlich return; 17356e801494SSimon Wunderlich 1736a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1737a73105b8SAntonio Quartulli head = &hash->table[i]; 17387683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1739c6c8fea2SSven Eckelmann 17407683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1741b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, safe, 1742a73105b8SAntonio Quartulli head, hash_entry) { 174395fb130dSAntonio Quartulli /* remove only matching entries */ 174495fb130dSAntonio Quartulli if (match_vid >= 0 && tt_common_entry->vid != match_vid) 174595fb130dSAntonio Quartulli continue; 174695fb130dSAntonio Quartulli 174756303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 174856303d34SSven Eckelmann struct batadv_tt_global_entry, 174948100bacSAntonio Quartulli common); 1750db08e6e5SSimon Wunderlich 175156303d34SSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global, 1752db08e6e5SSimon Wunderlich orig_node, message); 1753db08e6e5SSimon Wunderlich 175456303d34SSven Eckelmann if (hlist_empty(&tt_global->orig_list)) { 175516052789SAntonio Quartulli vid = tt_global->common.vid; 175639c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 175716052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 175816052789SAntonio Quartulli tt_global->common.addr, 175916052789SAntonio Quartulli BATADV_PRINT_VID(vid), message); 1760b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 176156303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 1762c6c8fea2SSven Eckelmann } 1763a73105b8SAntonio Quartulli } 17647683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 17657683fdc1SAntonio Quartulli } 176617071578SAntonio Quartulli orig_node->tt_initialised = false; 1767c6c8fea2SSven Eckelmann } 1768c6c8fea2SSven Eckelmann 176930cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, 177030cfd02bSAntonio Quartulli char **msg) 1771cc47f66eSAntonio Quartulli { 177230cfd02bSAntonio Quartulli bool purge = false; 177330cfd02bSAntonio Quartulli unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; 177430cfd02bSAntonio Quartulli unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; 1775cc47f66eSAntonio Quartulli 177630cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && 177730cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { 177830cfd02bSAntonio Quartulli purge = true; 177930cfd02bSAntonio Quartulli *msg = "Roaming timeout\n"; 178042d0b044SSven Eckelmann } 178142d0b044SSven Eckelmann 178230cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) && 178330cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) { 178430cfd02bSAntonio Quartulli purge = true; 178530cfd02bSAntonio Quartulli *msg = "Temporary client timeout\n"; 178630cfd02bSAntonio Quartulli } 178730cfd02bSAntonio Quartulli 178830cfd02bSAntonio Quartulli return purge; 178930cfd02bSAntonio Quartulli } 179030cfd02bSAntonio Quartulli 179130cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv) 179242d0b044SSven Eckelmann { 1793807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 179442d0b044SSven Eckelmann struct hlist_head *head; 1795b67bfe0dSSasha Levin struct hlist_node *node_tmp; 179642d0b044SSven Eckelmann spinlock_t *list_lock; /* protects write access to the hash lists */ 179742d0b044SSven Eckelmann uint32_t i; 179830cfd02bSAntonio Quartulli char *msg = NULL; 179930cfd02bSAntonio Quartulli struct batadv_tt_common_entry *tt_common; 180030cfd02bSAntonio Quartulli struct batadv_tt_global_entry *tt_global; 180142d0b044SSven Eckelmann 180242d0b044SSven Eckelmann for (i = 0; i < hash->size; i++) { 180342d0b044SSven Eckelmann head = &hash->table[i]; 180442d0b044SSven Eckelmann list_lock = &hash->list_locks[i]; 180542d0b044SSven Eckelmann 180642d0b044SSven Eckelmann spin_lock_bh(list_lock); 1807b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 180830cfd02bSAntonio Quartulli hash_entry) { 180930cfd02bSAntonio Quartulli tt_global = container_of(tt_common, 181030cfd02bSAntonio Quartulli struct batadv_tt_global_entry, 181130cfd02bSAntonio Quartulli common); 181230cfd02bSAntonio Quartulli 181330cfd02bSAntonio Quartulli if (!batadv_tt_global_to_purge(tt_global, &msg)) 181430cfd02bSAntonio Quartulli continue; 181530cfd02bSAntonio Quartulli 181630cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 181716052789SAntonio Quartulli "Deleting global tt entry %pM (vid: %d): %s\n", 181816052789SAntonio Quartulli tt_global->common.addr, 181916052789SAntonio Quartulli BATADV_PRINT_VID(tt_global->common.vid), 182016052789SAntonio Quartulli msg); 182130cfd02bSAntonio Quartulli 1822b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 182330cfd02bSAntonio Quartulli 182430cfd02bSAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 182530cfd02bSAntonio Quartulli } 18267683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1827cc47f66eSAntonio Quartulli } 1828cc47f66eSAntonio Quartulli } 1829cc47f66eSAntonio Quartulli 183056303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) 1831c6c8fea2SSven Eckelmann { 18325bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 18337683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 183456303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 183556303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 1836b67bfe0dSSasha Levin struct hlist_node *node_tmp; 18377683fdc1SAntonio Quartulli struct hlist_head *head; 1838c90681b8SAntonio Quartulli uint32_t i; 18397683fdc1SAntonio Quartulli 1840807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 1841c6c8fea2SSven Eckelmann return; 1842c6c8fea2SSven Eckelmann 1843807736f6SSven Eckelmann hash = bat_priv->tt.global_hash; 18447683fdc1SAntonio Quartulli 18457683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 18467683fdc1SAntonio Quartulli head = &hash->table[i]; 18477683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 18487683fdc1SAntonio Quartulli 18497683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1850b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 18517683fdc1SAntonio Quartulli head, hash_entry) { 1852b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 185356303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 185456303d34SSven Eckelmann struct batadv_tt_global_entry, 185548100bacSAntonio Quartulli common); 185656303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 18577683fdc1SAntonio Quartulli } 18587683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 18597683fdc1SAntonio Quartulli } 18607683fdc1SAntonio Quartulli 18611a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 18627683fdc1SAntonio Quartulli 1863807736f6SSven Eckelmann bat_priv->tt.global_hash = NULL; 1864c6c8fea2SSven Eckelmann } 1865c6c8fea2SSven Eckelmann 186656303d34SSven Eckelmann static bool 186756303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, 186856303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry) 186959b699cdSAntonio Quartulli { 187059b699cdSAntonio Quartulli bool ret = false; 187159b699cdSAntonio Quartulli 1872acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && 1873acd34afaSSven Eckelmann tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) 187459b699cdSAntonio Quartulli ret = true; 187559b699cdSAntonio Quartulli 18762d2fcc2aSAntonio Quartulli /* check if the two clients are marked as isolated */ 18772d2fcc2aSAntonio Quartulli if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA && 18782d2fcc2aSAntonio Quartulli tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA) 18792d2fcc2aSAntonio Quartulli ret = true; 18802d2fcc2aSAntonio Quartulli 188159b699cdSAntonio Quartulli return ret; 188259b699cdSAntonio Quartulli } 188359b699cdSAntonio Quartulli 1884c018ad3dSAntonio Quartulli /** 1885c018ad3dSAntonio Quartulli * batadv_transtable_search - get the mesh destination for a given client 1886c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1887c018ad3dSAntonio Quartulli * @src: mac address of the source client 1888c018ad3dSAntonio Quartulli * @addr: mac address of the destination client 1889c018ad3dSAntonio Quartulli * @vid: VLAN identifier 1890c018ad3dSAntonio Quartulli * 1891c018ad3dSAntonio Quartulli * Returns a pointer to the originator that was selected as destination in the 1892c018ad3dSAntonio Quartulli * mesh for contacting the client 'addr', NULL otherwise. 1893c018ad3dSAntonio Quartulli * In case of multiple originators serving the same client, the function returns 1894c018ad3dSAntonio Quartulli * the best one (best in terms of metric towards the destination node). 1895c018ad3dSAntonio Quartulli * 1896c018ad3dSAntonio Quartulli * If the two clients are AP isolated the function returns NULL. 1897c018ad3dSAntonio Quartulli */ 189856303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, 189908c36d3eSSven Eckelmann const uint8_t *src, 1900c018ad3dSAntonio Quartulli const uint8_t *addr, 1901c018ad3dSAntonio Quartulli unsigned short vid) 1902c6c8fea2SSven Eckelmann { 190356303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 190456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 190556303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 1906981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *best_entry; 1907c6c8fea2SSven Eckelmann 1908eceb22aeSAntonio Quartulli if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) { 1909c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); 1910068ee6e2SAntonio Quartulli if (!tt_local_entry || 1911068ee6e2SAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) 19123d393e47SAntonio Quartulli goto out; 19133d393e47SAntonio Quartulli } 19147aadf889SMarek Lindner 1915c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 19162dafb49dSAntonio Quartulli if (!tt_global_entry) 19177b36e8eeSMarek Lindner goto out; 1918c6c8fea2SSven Eckelmann 19193d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 19209cfc7bd6SSven Eckelmann * isolation 19219cfc7bd6SSven Eckelmann */ 1922a513088dSSven Eckelmann if (tt_local_entry && 1923a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 19243d393e47SAntonio Quartulli goto out; 19253d393e47SAntonio Quartulli 1926db08e6e5SSimon Wunderlich rcu_read_lock(); 19274627456aSAntonio Quartulli best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); 1928db08e6e5SSimon Wunderlich /* found anything? */ 1929981d8900SSven Eckelmann if (best_entry) 1930981d8900SSven Eckelmann orig_node = best_entry->orig_node; 1931db08e6e5SSimon Wunderlich if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) 1932db08e6e5SSimon Wunderlich orig_node = NULL; 1933db08e6e5SSimon Wunderlich rcu_read_unlock(); 1934981d8900SSven Eckelmann 19357b36e8eeSMarek Lindner out: 19363d393e47SAntonio Quartulli if (tt_global_entry) 1937a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 19383d393e47SAntonio Quartulli if (tt_local_entry) 1939a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 19403d393e47SAntonio Quartulli 19417b36e8eeSMarek Lindner return orig_node; 1942c6c8fea2SSven Eckelmann } 1943a73105b8SAntonio Quartulli 1944ced72933SAntonio Quartulli /** 1945ced72933SAntonio Quartulli * batadv_tt_global_crc - calculates the checksum of the local table belonging 1946ced72933SAntonio Quartulli * to the given orig_node 1947ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 19480ffa9e8dSAntonio Quartulli * @orig_node: originator for which the CRC should be computed 19497ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 19500ffa9e8dSAntonio Quartulli * 19510ffa9e8dSAntonio Quartulli * This function computes the checksum for the global table corresponding to a 19520ffa9e8dSAntonio Quartulli * specific originator. In particular, the checksum is computed as follows: For 19530ffa9e8dSAntonio Quartulli * each client connected to the originator the CRC32C of the MAC address and the 19540ffa9e8dSAntonio Quartulli * VID is computed and then all the CRC32Cs of the various clients are xor'ed 19550ffa9e8dSAntonio Quartulli * together. 19560ffa9e8dSAntonio Quartulli * 19570ffa9e8dSAntonio Quartulli * The idea behind is that CRC32C should be used as much as possible in order to 19580ffa9e8dSAntonio Quartulli * produce a unique hash of the table, but since the order which is used to feed 19590ffa9e8dSAntonio Quartulli * the CRC32C function affects the result and since every node in the network 19600ffa9e8dSAntonio Quartulli * probably sorts the clients differently, the hash function cannot be directly 19610ffa9e8dSAntonio Quartulli * computed over the entire table. Hence the CRC32C is used only on 19620ffa9e8dSAntonio Quartulli * the single client entry, while all the results are then xor'ed together 19630ffa9e8dSAntonio Quartulli * because the XOR operation can combine them all while trying to reduce the 19640ffa9e8dSAntonio Quartulli * noise as much as possible. 19650ffa9e8dSAntonio Quartulli * 19660ffa9e8dSAntonio Quartulli * Returns the checksum of the global table of a given originator. 1967ced72933SAntonio Quartulli */ 1968ced72933SAntonio Quartulli static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, 19697ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node, 19707ea7b4a1SAntonio Quartulli unsigned short vid) 1971a73105b8SAntonio Quartulli { 1972807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 197356303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 197456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 1975a73105b8SAntonio Quartulli struct hlist_head *head; 19760ffa9e8dSAntonio Quartulli uint32_t i, crc_tmp, crc = 0; 19770eb01568SAntonio Quartulli uint8_t flags; 1978a30e22caSAntonio Quartulli __be16 tmp_vid; 1979a73105b8SAntonio Quartulli 1980a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1981a73105b8SAntonio Quartulli head = &hash->table[i]; 1982a73105b8SAntonio Quartulli 1983a73105b8SAntonio Quartulli rcu_read_lock(); 1984b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 198556303d34SSven Eckelmann tt_global = container_of(tt_common, 198656303d34SSven Eckelmann struct batadv_tt_global_entry, 198748100bacSAntonio Quartulli common); 19887ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 19897ea7b4a1SAntonio Quartulli * VLAN identified by the vid passed as parameter 19907ea7b4a1SAntonio Quartulli */ 19917ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 19927ea7b4a1SAntonio Quartulli continue; 19937ea7b4a1SAntonio Quartulli 1994cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 1995cc47f66eSAntonio Quartulli * consistency only. They don't have to be 1996cc47f66eSAntonio Quartulli * taken into account while computing the 1997db08e6e5SSimon Wunderlich * global crc 1998db08e6e5SSimon Wunderlich */ 1999acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 2000cc47f66eSAntonio Quartulli continue; 200130cfd02bSAntonio Quartulli /* Temporary clients have not been announced yet, so 200230cfd02bSAntonio Quartulli * they have to be skipped while computing the global 200330cfd02bSAntonio Quartulli * crc 200430cfd02bSAntonio Quartulli */ 200530cfd02bSAntonio Quartulli if (tt_common->flags & BATADV_TT_CLIENT_TEMP) 200630cfd02bSAntonio Quartulli continue; 2007db08e6e5SSimon Wunderlich 2008db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 2009db08e6e5SSimon Wunderlich * originator 2010db08e6e5SSimon Wunderlich */ 201156303d34SSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global, 2012db08e6e5SSimon Wunderlich orig_node)) 2013db08e6e5SSimon Wunderlich continue; 2014db08e6e5SSimon Wunderlich 2015a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2016a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2017a30e22caSAntonio Quartulli */ 2018a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2019a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 20200eb01568SAntonio Quartulli 20210eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 20220eb01568SAntonio Quartulli * among nodes 20230eb01568SAntonio Quartulli */ 20240eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 20250eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 20260eb01568SAntonio Quartulli 20270ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2028a73105b8SAntonio Quartulli } 2029a73105b8SAntonio Quartulli rcu_read_unlock(); 2030a73105b8SAntonio Quartulli } 2031a73105b8SAntonio Quartulli 2032ced72933SAntonio Quartulli return crc; 2033a73105b8SAntonio Quartulli } 2034a73105b8SAntonio Quartulli 2035ced72933SAntonio Quartulli /** 2036ced72933SAntonio Quartulli * batadv_tt_local_crc - calculates the checksum of the local table 2037ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 20387ea7b4a1SAntonio Quartulli * @vid: VLAN identifier for which the CRC32 has to be computed 20390ffa9e8dSAntonio Quartulli * 20400ffa9e8dSAntonio Quartulli * For details about the computation, please refer to the documentation for 20410ffa9e8dSAntonio Quartulli * batadv_tt_global_crc(). 20420ffa9e8dSAntonio Quartulli * 20430ffa9e8dSAntonio Quartulli * Returns the checksum of the local table 2044ced72933SAntonio Quartulli */ 20457ea7b4a1SAntonio Quartulli static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, 20467ea7b4a1SAntonio Quartulli unsigned short vid) 2047a73105b8SAntonio Quartulli { 2048807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 204956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 2050a73105b8SAntonio Quartulli struct hlist_head *head; 20510ffa9e8dSAntonio Quartulli uint32_t i, crc_tmp, crc = 0; 20520eb01568SAntonio Quartulli uint8_t flags; 2053a30e22caSAntonio Quartulli __be16 tmp_vid; 2054a73105b8SAntonio Quartulli 2055a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2056a73105b8SAntonio Quartulli head = &hash->table[i]; 2057a73105b8SAntonio Quartulli 2058a73105b8SAntonio Quartulli rcu_read_lock(); 2059b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 20607ea7b4a1SAntonio Quartulli /* compute the CRC only for entries belonging to the 20617ea7b4a1SAntonio Quartulli * VLAN identified by vid 20627ea7b4a1SAntonio Quartulli */ 20637ea7b4a1SAntonio Quartulli if (tt_common->vid != vid) 20647ea7b4a1SAntonio Quartulli continue; 20657ea7b4a1SAntonio Quartulli 2066058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 20679cfc7bd6SSven Eckelmann * account while computing the CRC 20689cfc7bd6SSven Eckelmann */ 2069acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_NEW) 2070058d0e26SAntonio Quartulli continue; 2071ced72933SAntonio Quartulli 2072a30e22caSAntonio Quartulli /* use network order to read the VID: this ensures that 2073a30e22caSAntonio Quartulli * every node reads the bytes in the same order. 2074a30e22caSAntonio Quartulli */ 2075a30e22caSAntonio Quartulli tmp_vid = htons(tt_common->vid); 2076a30e22caSAntonio Quartulli crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); 20770eb01568SAntonio Quartulli 20780eb01568SAntonio Quartulli /* compute the CRC on flags that have to be kept in sync 20790eb01568SAntonio Quartulli * among nodes 20800eb01568SAntonio Quartulli */ 20810eb01568SAntonio Quartulli flags = tt_common->flags & BATADV_TT_SYNC_MASK; 20820eb01568SAntonio Quartulli crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); 20830eb01568SAntonio Quartulli 20840ffa9e8dSAntonio Quartulli crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); 2085a73105b8SAntonio Quartulli } 2086a73105b8SAntonio Quartulli rcu_read_unlock(); 2087a73105b8SAntonio Quartulli } 2088a73105b8SAntonio Quartulli 2089ced72933SAntonio Quartulli return crc; 2090a73105b8SAntonio Quartulli } 2091a73105b8SAntonio Quartulli 209256303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) 2093a73105b8SAntonio Quartulli { 209456303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 2095a73105b8SAntonio Quartulli 2096807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2097a73105b8SAntonio Quartulli 2098807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 2099a73105b8SAntonio Quartulli list_del(&node->list); 2100a73105b8SAntonio Quartulli kfree(node); 2101a73105b8SAntonio Quartulli } 2102a73105b8SAntonio Quartulli 2103807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2104a73105b8SAntonio Quartulli } 2105a73105b8SAntonio Quartulli 210656303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, 210756303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2108e8cf234aSAntonio Quartulli const void *tt_buff, 2109e8cf234aSAntonio Quartulli uint16_t tt_buff_len) 2110a73105b8SAntonio Quartulli { 2111a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 21129cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 21139cfc7bd6SSven Eckelmann */ 2114a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2115a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 2116a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2117a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2118a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 2119a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 2120a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 2121a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 2122a73105b8SAntonio Quartulli } 2123a73105b8SAntonio Quartulli } 2124a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2125a73105b8SAntonio Quartulli } 2126a73105b8SAntonio Quartulli 212756303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv) 2128a73105b8SAntonio Quartulli { 212956303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 2130a73105b8SAntonio Quartulli 2131807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2132807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 213342d0b044SSven Eckelmann if (batadv_has_timed_out(node->issued_at, 213442d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) { 2135a73105b8SAntonio Quartulli list_del(&node->list); 2136a73105b8SAntonio Quartulli kfree(node); 2137a73105b8SAntonio Quartulli } 2138a73105b8SAntonio Quartulli } 2139807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2140a73105b8SAntonio Quartulli } 2141a73105b8SAntonio Quartulli 2142a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 21439cfc7bd6SSven Eckelmann * has already been issued for this orig_node, NULL otherwise 21449cfc7bd6SSven Eckelmann */ 214556303d34SSven Eckelmann static struct batadv_tt_req_node * 214656303d34SSven Eckelmann batadv_new_tt_req_node(struct batadv_priv *bat_priv, 214756303d34SSven Eckelmann struct batadv_orig_node *orig_node) 2148a73105b8SAntonio Quartulli { 214956303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 2150a73105b8SAntonio Quartulli 2151807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2152807736f6SSven Eckelmann list_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { 21531eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 21541eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 215542d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) 2156a73105b8SAntonio Quartulli goto unlock; 2157a73105b8SAntonio Quartulli } 2158a73105b8SAntonio Quartulli 2159a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 2160a73105b8SAntonio Quartulli if (!tt_req_node) 2161a73105b8SAntonio Quartulli goto unlock; 2162a73105b8SAntonio Quartulli 21638fdd0153SAntonio Quartulli ether_addr_copy(tt_req_node->addr, orig_node->orig); 2164a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 2165a73105b8SAntonio Quartulli 2166807736f6SSven Eckelmann list_add(&tt_req_node->list, &bat_priv->tt.req_list); 2167a73105b8SAntonio Quartulli unlock: 2168807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2169a73105b8SAntonio Quartulli return tt_req_node; 2170a73105b8SAntonio Quartulli } 2171a73105b8SAntonio Quartulli 2172335fbe0fSMarek Lindner /** 2173335fbe0fSMarek Lindner * batadv_tt_local_valid - verify that given tt entry is a valid one 2174335fbe0fSMarek Lindner * @entry_ptr: to be checked local tt entry 2175335fbe0fSMarek Lindner * @data_ptr: not used but definition required to satisfy the callback prototype 2176335fbe0fSMarek Lindner * 2177335fbe0fSMarek Lindner * Returns 1 if the entry is a valid, 0 otherwise. 2178335fbe0fSMarek Lindner */ 2179335fbe0fSMarek Lindner static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) 2180058d0e26SAntonio Quartulli { 218156303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 2182058d0e26SAntonio Quartulli 2183acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) 2184058d0e26SAntonio Quartulli return 0; 2185058d0e26SAntonio Quartulli return 1; 2186058d0e26SAntonio Quartulli } 2187058d0e26SAntonio Quartulli 2188a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr, 2189a513088dSSven Eckelmann const void *data_ptr) 2190a73105b8SAntonio Quartulli { 219156303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 219256303d34SSven Eckelmann const struct batadv_tt_global_entry *tt_global_entry; 219356303d34SSven Eckelmann const struct batadv_orig_node *orig_node = data_ptr; 2194a73105b8SAntonio Quartulli 219530cfd02bSAntonio Quartulli if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || 219630cfd02bSAntonio Quartulli tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) 2197cc47f66eSAntonio Quartulli return 0; 2198cc47f66eSAntonio Quartulli 219956303d34SSven Eckelmann tt_global_entry = container_of(tt_common_entry, 220056303d34SSven Eckelmann struct batadv_tt_global_entry, 220148100bacSAntonio Quartulli common); 220248100bacSAntonio Quartulli 2203a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 2204a73105b8SAntonio Quartulli } 2205a73105b8SAntonio Quartulli 2206335fbe0fSMarek Lindner /** 22077ea7b4a1SAntonio Quartulli * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the 22087ea7b4a1SAntonio Quartulli * specified tt hash 2209335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2210335fbe0fSMarek Lindner * @hash: hash table containing the tt entries 2211335fbe0fSMarek Lindner * @tt_len: expected tvlv tt data buffer length in number of bytes 22127ea7b4a1SAntonio Quartulli * @tvlv_buff: pointer to the buffer to fill with the TT data 2213335fbe0fSMarek Lindner * @valid_cb: function to filter tt change entries 2214335fbe0fSMarek Lindner * @cb_data: data passed to the filter function as argument 2215335fbe0fSMarek Lindner */ 22167ea7b4a1SAntonio Quartulli static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, 22177ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash, 22187ea7b4a1SAntonio Quartulli void *tvlv_buff, uint16_t tt_len, 2219a513088dSSven Eckelmann int (*valid_cb)(const void *, const void *), 2220a73105b8SAntonio Quartulli void *cb_data) 2221a73105b8SAntonio Quartulli { 222256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 2223335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 2224a73105b8SAntonio Quartulli struct hlist_head *head; 2225335fbe0fSMarek Lindner uint16_t tt_tot, tt_num_entries = 0; 2226c90681b8SAntonio Quartulli uint32_t i; 2227a73105b8SAntonio Quartulli 2228298e6e68SAntonio Quartulli tt_tot = batadv_tt_entries(tt_len); 22297ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; 2230a73105b8SAntonio Quartulli 2231a73105b8SAntonio Quartulli rcu_read_lock(); 2232a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2233a73105b8SAntonio Quartulli head = &hash->table[i]; 2234a73105b8SAntonio Quartulli 2235b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 2236a73105b8SAntonio Quartulli head, hash_entry) { 2237335fbe0fSMarek Lindner if (tt_tot == tt_num_entries) 2238a73105b8SAntonio Quartulli break; 2239a73105b8SAntonio Quartulli 224048100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 2241a73105b8SAntonio Quartulli continue; 2242a73105b8SAntonio Quartulli 22438fdd0153SAntonio Quartulli ether_addr_copy(tt_change->addr, tt_common_entry->addr); 224427b37ebfSAntonio Quartulli tt_change->flags = tt_common_entry->flags; 2245c018ad3dSAntonio Quartulli tt_change->vid = htons(tt_common_entry->vid); 2246ca663046SAntonio Quartulli memset(tt_change->reserved, 0, 2247ca663046SAntonio Quartulli sizeof(tt_change->reserved)); 2248a73105b8SAntonio Quartulli 2249335fbe0fSMarek Lindner tt_num_entries++; 2250a73105b8SAntonio Quartulli tt_change++; 2251a73105b8SAntonio Quartulli } 2252a73105b8SAntonio Quartulli } 2253a73105b8SAntonio Quartulli rcu_read_unlock(); 22547ea7b4a1SAntonio Quartulli } 2255a73105b8SAntonio Quartulli 22567ea7b4a1SAntonio Quartulli /** 22577ea7b4a1SAntonio Quartulli * batadv_tt_global_check_crc - check if all the CRCs are correct 22587ea7b4a1SAntonio Quartulli * @orig_node: originator for which the CRCs have to be checked 22597ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN entry 22607ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 22617ea7b4a1SAntonio Quartulli * @create: if true, create VLAN objects if not found 22627ea7b4a1SAntonio Quartulli * 22637ea7b4a1SAntonio Quartulli * Return true if all the received CRCs match the locally stored ones, false 22647ea7b4a1SAntonio Quartulli * otherwise 22657ea7b4a1SAntonio Quartulli */ 22667ea7b4a1SAntonio Quartulli static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, 22677ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 22687ea7b4a1SAntonio Quartulli uint16_t num_vlan) 22697ea7b4a1SAntonio Quartulli { 22707ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; 22717ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 227291c2b1a9SAntonio Quartulli uint32_t crc; 22737ea7b4a1SAntonio Quartulli int i; 22747ea7b4a1SAntonio Quartulli 22757ea7b4a1SAntonio Quartulli /* check if each received CRC matches the locally stored one */ 22767ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 22777ea7b4a1SAntonio Quartulli tt_vlan_tmp = tt_vlan + i; 22787ea7b4a1SAntonio Quartulli 22797ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't check 22807ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 22817ea7b4a1SAntonio Quartulli */ 22827ea7b4a1SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, 2283cfd4f757SAntonio Quartulli orig_node->orig, 2284cfd4f757SAntonio Quartulli ntohs(tt_vlan_tmp->vid))) 22857ea7b4a1SAntonio Quartulli continue; 22867ea7b4a1SAntonio Quartulli 22877ea7b4a1SAntonio Quartulli vlan = batadv_orig_node_vlan_get(orig_node, 22887ea7b4a1SAntonio Quartulli ntohs(tt_vlan_tmp->vid)); 22897ea7b4a1SAntonio Quartulli if (!vlan) 22907ea7b4a1SAntonio Quartulli return false; 22917ea7b4a1SAntonio Quartulli 229291c2b1a9SAntonio Quartulli crc = vlan->tt.crc; 229391c2b1a9SAntonio Quartulli batadv_orig_node_vlan_free_ref(vlan); 229491c2b1a9SAntonio Quartulli 229591c2b1a9SAntonio Quartulli if (crc != ntohl(tt_vlan_tmp->crc)) 22967ea7b4a1SAntonio Quartulli return false; 22977ea7b4a1SAntonio Quartulli } 22987ea7b4a1SAntonio Quartulli 22997ea7b4a1SAntonio Quartulli return true; 23007ea7b4a1SAntonio Quartulli } 23017ea7b4a1SAntonio Quartulli 23027ea7b4a1SAntonio Quartulli /** 23037ea7b4a1SAntonio Quartulli * batadv_tt_local_update_crc - update all the local CRCs 23047ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 23057ea7b4a1SAntonio Quartulli */ 23067ea7b4a1SAntonio Quartulli static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) 23077ea7b4a1SAntonio Quartulli { 23087ea7b4a1SAntonio Quartulli struct batadv_softif_vlan *vlan; 23097ea7b4a1SAntonio Quartulli 23107ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 23117ea7b4a1SAntonio Quartulli rcu_read_lock(); 23127ea7b4a1SAntonio Quartulli hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 23137ea7b4a1SAntonio Quartulli vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); 23147ea7b4a1SAntonio Quartulli } 23157ea7b4a1SAntonio Quartulli rcu_read_unlock(); 23167ea7b4a1SAntonio Quartulli } 23177ea7b4a1SAntonio Quartulli 23187ea7b4a1SAntonio Quartulli /** 23197ea7b4a1SAntonio Quartulli * batadv_tt_global_update_crc - update all the global CRCs for this orig_node 23207ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 23217ea7b4a1SAntonio Quartulli * @orig_node: the orig_node for which the CRCs have to be updated 23227ea7b4a1SAntonio Quartulli */ 23237ea7b4a1SAntonio Quartulli static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, 23247ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node) 23257ea7b4a1SAntonio Quartulli { 23267ea7b4a1SAntonio Quartulli struct batadv_orig_node_vlan *vlan; 23277ea7b4a1SAntonio Quartulli uint32_t crc; 23287ea7b4a1SAntonio Quartulli 23297ea7b4a1SAntonio Quartulli /* recompute the global CRC for each VLAN */ 23307ea7b4a1SAntonio Quartulli rcu_read_lock(); 23317ea7b4a1SAntonio Quartulli list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { 23327ea7b4a1SAntonio Quartulli /* if orig_node is a backbone node for this VLAN, don't compute 23337ea7b4a1SAntonio Quartulli * the CRC as we ignore all the global entries over it 23347ea7b4a1SAntonio Quartulli */ 2335cfd4f757SAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, 2336cfd4f757SAntonio Quartulli vlan->vid)) 23377ea7b4a1SAntonio Quartulli continue; 23387ea7b4a1SAntonio Quartulli 23397ea7b4a1SAntonio Quartulli crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); 23407ea7b4a1SAntonio Quartulli vlan->tt.crc = crc; 23417ea7b4a1SAntonio Quartulli } 23427ea7b4a1SAntonio Quartulli rcu_read_unlock(); 2343a73105b8SAntonio Quartulli } 2344a73105b8SAntonio Quartulli 2345ced72933SAntonio Quartulli /** 2346ced72933SAntonio Quartulli * batadv_send_tt_request - send a TT Request message to a given node 2347ced72933SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2348ced72933SAntonio Quartulli * @dst_orig_node: the destination of the message 2349ced72933SAntonio Quartulli * @ttvn: the version number that the source of the message is looking for 23507ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN object to request 23517ea7b4a1SAntonio Quartulli * @num_vlan: number of tvlv VLAN entries 2352ced72933SAntonio Quartulli * @full_table: ask for the entire translation table if true, while only for the 2353ced72933SAntonio Quartulli * last TT diff otherwise 2354ced72933SAntonio Quartulli */ 235556303d34SSven Eckelmann static int batadv_send_tt_request(struct batadv_priv *bat_priv, 235656303d34SSven Eckelmann struct batadv_orig_node *dst_orig_node, 23577ea7b4a1SAntonio Quartulli uint8_t ttvn, 23587ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan, 23597ea7b4a1SAntonio Quartulli uint16_t num_vlan, bool full_table) 2360a73105b8SAntonio Quartulli { 2361335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 236256303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node = NULL; 23637ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan_req; 23647ea7b4a1SAntonio Quartulli struct batadv_hard_iface *primary_if; 2365335fbe0fSMarek Lindner bool ret = false; 23667ea7b4a1SAntonio Quartulli int i, size; 2367a73105b8SAntonio Quartulli 2368e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2369a73105b8SAntonio Quartulli if (!primary_if) 2370a73105b8SAntonio Quartulli goto out; 2371a73105b8SAntonio Quartulli 2372a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 23739cfc7bd6SSven Eckelmann * reply from the same orig_node yet 23749cfc7bd6SSven Eckelmann */ 2375a513088dSSven Eckelmann tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node); 2376a73105b8SAntonio Quartulli if (!tt_req_node) 2377a73105b8SAntonio Quartulli goto out; 2378a73105b8SAntonio Quartulli 23797ea7b4a1SAntonio Quartulli size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; 23807ea7b4a1SAntonio Quartulli tvlv_tt_data = kzalloc(size, GFP_ATOMIC); 2381335fbe0fSMarek Lindner if (!tvlv_tt_data) 2382a73105b8SAntonio Quartulli goto out; 2383a73105b8SAntonio Quartulli 2384335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_REQUEST; 2385335fbe0fSMarek Lindner tvlv_tt_data->ttvn = ttvn; 23867ea7b4a1SAntonio Quartulli tvlv_tt_data->num_vlan = htons(num_vlan); 23877ea7b4a1SAntonio Quartulli 23887ea7b4a1SAntonio Quartulli /* send all the CRCs within the request. This is needed by intermediate 23897ea7b4a1SAntonio Quartulli * nodes to ensure they have the correct table before replying 23907ea7b4a1SAntonio Quartulli */ 23917ea7b4a1SAntonio Quartulli tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); 23927ea7b4a1SAntonio Quartulli for (i = 0; i < num_vlan; i++) { 23937ea7b4a1SAntonio Quartulli tt_vlan_req->vid = tt_vlan->vid; 23947ea7b4a1SAntonio Quartulli tt_vlan_req->crc = tt_vlan->crc; 23957ea7b4a1SAntonio Quartulli 23967ea7b4a1SAntonio Quartulli tt_vlan_req++; 23977ea7b4a1SAntonio Quartulli tt_vlan++; 23987ea7b4a1SAntonio Quartulli } 2399a73105b8SAntonio Quartulli 2400a73105b8SAntonio Quartulli if (full_table) 2401335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2402a73105b8SAntonio Quartulli 2403bb351ba0SMartin Hundebøll batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", 2404335fbe0fSMarek Lindner dst_orig_node->orig, full_table ? 'F' : '.'); 2405a73105b8SAntonio Quartulli 2406d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); 2407335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 2408335fbe0fSMarek Lindner dst_orig_node->orig, BATADV_TVLV_TT, 1, 24097ea7b4a1SAntonio Quartulli tvlv_tt_data, size); 2410335fbe0fSMarek Lindner ret = true; 2411a73105b8SAntonio Quartulli 2412a73105b8SAntonio Quartulli out: 2413a73105b8SAntonio Quartulli if (primary_if) 2414e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 2415a73105b8SAntonio Quartulli if (ret && tt_req_node) { 2416807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2417a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 2418807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2419a73105b8SAntonio Quartulli kfree(tt_req_node); 2420a73105b8SAntonio Quartulli } 2421335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2422a73105b8SAntonio Quartulli return ret; 2423a73105b8SAntonio Quartulli } 2424a73105b8SAntonio Quartulli 2425335fbe0fSMarek Lindner /** 2426335fbe0fSMarek Lindner * batadv_send_other_tt_response - send reply to tt request concerning another 2427335fbe0fSMarek Lindner * node's translation table 2428335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2429335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2430335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2431335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 2432335fbe0fSMarek Lindner * 2433335fbe0fSMarek Lindner * Returns true if tt request reply was sent, false otherwise. 2434335fbe0fSMarek Lindner */ 2435335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, 2436335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 2437335fbe0fSMarek Lindner uint8_t *req_src, uint8_t *req_dst) 2438a73105b8SAntonio Quartulli { 2439170173bfSSven Eckelmann struct batadv_orig_node *req_dst_orig_node; 244056303d34SSven Eckelmann struct batadv_orig_node *res_dst_orig_node = NULL; 24417ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 2442335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 24437ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 2444335fbe0fSMarek Lindner bool ret = false, full_table; 24457ea7b4a1SAntonio Quartulli uint8_t orig_ttvn, req_ttvn; 24467ea7b4a1SAntonio Quartulli uint16_t tvlv_len; 24477ea7b4a1SAntonio Quartulli int32_t tt_len; 2448a73105b8SAntonio Quartulli 244939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 245086ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 2451335fbe0fSMarek Lindner req_src, tt_data->ttvn, req_dst, 2452335fbe0fSMarek Lindner (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 2453a73105b8SAntonio Quartulli 2454a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 2455335fbe0fSMarek Lindner req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); 2456a73105b8SAntonio Quartulli if (!req_dst_orig_node) 2457a73105b8SAntonio Quartulli goto out; 2458a73105b8SAntonio Quartulli 2459335fbe0fSMarek Lindner res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); 2460a73105b8SAntonio Quartulli if (!res_dst_orig_node) 2461a73105b8SAntonio Quartulli goto out; 2462a73105b8SAntonio Quartulli 2463a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 2464335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 2465a73105b8SAntonio Quartulli 24667ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 2467335fbe0fSMarek Lindner /* this node doesn't have the requested data */ 2468a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 24697ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, 24707ea7b4a1SAntonio Quartulli ntohs(tt_data->num_vlan))) 2471a73105b8SAntonio Quartulli goto out; 2472a73105b8SAntonio Quartulli 2473015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 2474335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || 2475a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 2476a73105b8SAntonio Quartulli full_table = true; 2477a73105b8SAntonio Quartulli else 2478a73105b8SAntonio Quartulli full_table = false; 2479a73105b8SAntonio Quartulli 2480335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 2481335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 24829cfc7bd6SSven Eckelmann */ 2483a73105b8SAntonio Quartulli if (!full_table) { 2484a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 2485a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 2486a73105b8SAntonio Quartulli 24877ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 24887ea7b4a1SAntonio Quartulli &tvlv_tt_data, 24897ea7b4a1SAntonio Quartulli &tt_change, 24907ea7b4a1SAntonio Quartulli &tt_len); 24917ea7b4a1SAntonio Quartulli if (!tt_len) 2492a73105b8SAntonio Quartulli goto unlock; 2493a73105b8SAntonio Quartulli 2494a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 24957ea7b4a1SAntonio Quartulli memcpy(tt_change, req_dst_orig_node->tt_buff, 2496a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 2497a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 2498a73105b8SAntonio Quartulli } else { 24997ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 25007ea7b4a1SAntonio Quartulli * in the initial part 25017ea7b4a1SAntonio Quartulli */ 25027ea7b4a1SAntonio Quartulli tt_len = -1; 25037ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, 25047ea7b4a1SAntonio Quartulli &tvlv_tt_data, 25057ea7b4a1SAntonio Quartulli &tt_change, 25067ea7b4a1SAntonio Quartulli &tt_len); 25077ea7b4a1SAntonio Quartulli if (!tt_len) 25087ea7b4a1SAntonio Quartulli goto out; 2509a73105b8SAntonio Quartulli 25107ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 25117ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, 25127ea7b4a1SAntonio Quartulli tt_change, tt_len, 2513a513088dSSven Eckelmann batadv_tt_global_valid, 2514a73105b8SAntonio Quartulli req_dst_orig_node); 2515a73105b8SAntonio Quartulli } 2516a73105b8SAntonio Quartulli 2517a19d3d85SMarek Lindner /* Don't send the response, if larger than fragmented packet. */ 2518a19d3d85SMarek Lindner tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len; 2519a19d3d85SMarek Lindner if (tt_len > atomic_read(&bat_priv->packet_size_max)) { 2520a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, bat_priv->soft_iface, 2521a19d3d85SMarek Lindner "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n", 2522a19d3d85SMarek Lindner res_dst_orig_node->orig); 2523a19d3d85SMarek Lindner goto out; 2524a19d3d85SMarek Lindner } 2525a19d3d85SMarek Lindner 2526335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2527335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 2528a73105b8SAntonio Quartulli 2529a73105b8SAntonio Quartulli if (full_table) 2530335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2531a73105b8SAntonio Quartulli 253239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2533335fbe0fSMarek Lindner "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n", 2534335fbe0fSMarek Lindner res_dst_orig_node->orig, req_dst_orig_node->orig, 2535335fbe0fSMarek Lindner full_table ? 'F' : '.', req_ttvn); 2536a73105b8SAntonio Quartulli 2537d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 2538f8214865SMartin Hundebøll 2539335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, 25407ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 25417ea7b4a1SAntonio Quartulli tvlv_len); 2542e91ecfc6SMartin Hundebøll 2543335fbe0fSMarek Lindner ret = true; 2544a73105b8SAntonio Quartulli goto out; 2545a73105b8SAntonio Quartulli 2546a73105b8SAntonio Quartulli unlock: 2547a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 2548a73105b8SAntonio Quartulli 2549a73105b8SAntonio Quartulli out: 2550a73105b8SAntonio Quartulli if (res_dst_orig_node) 25517d211efcSSven Eckelmann batadv_orig_node_free_ref(res_dst_orig_node); 2552a73105b8SAntonio Quartulli if (req_dst_orig_node) 25537d211efcSSven Eckelmann batadv_orig_node_free_ref(req_dst_orig_node); 2554335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2555a73105b8SAntonio Quartulli return ret; 2556a73105b8SAntonio Quartulli } 255796412690SSven Eckelmann 2558335fbe0fSMarek Lindner /** 2559335fbe0fSMarek Lindner * batadv_send_my_tt_response - send reply to tt request concerning this node's 2560335fbe0fSMarek Lindner * translation table 2561335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2562335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2563335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2564335fbe0fSMarek Lindner * 2565335fbe0fSMarek Lindner * Returns true if tt request reply was sent, false otherwise. 2566335fbe0fSMarek Lindner */ 2567335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, 2568335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 2569335fbe0fSMarek Lindner uint8_t *req_src) 2570a73105b8SAntonio Quartulli { 2571335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 257256303d34SSven Eckelmann struct batadv_hard_iface *primary_if = NULL; 25737ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 25747ea7b4a1SAntonio Quartulli struct batadv_orig_node *orig_node; 2575335fbe0fSMarek Lindner uint8_t my_ttvn, req_ttvn; 25767ea7b4a1SAntonio Quartulli uint16_t tvlv_len; 2577a73105b8SAntonio Quartulli bool full_table; 25787ea7b4a1SAntonio Quartulli int32_t tt_len; 2579a73105b8SAntonio Quartulli 258039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 258186ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 2582335fbe0fSMarek Lindner req_src, tt_data->ttvn, 2583335fbe0fSMarek Lindner (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 2584a73105b8SAntonio Quartulli 2585a70a9aa9SAntonio Quartulli spin_lock_bh(&bat_priv->tt.commit_lock); 2586a73105b8SAntonio Quartulli 2587807736f6SSven Eckelmann my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); 2588335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 2589a73105b8SAntonio Quartulli 2590335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, req_src); 2591a73105b8SAntonio Quartulli if (!orig_node) 2592a73105b8SAntonio Quartulli goto out; 2593a73105b8SAntonio Quartulli 2594e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2595a73105b8SAntonio Quartulli if (!primary_if) 2596a73105b8SAntonio Quartulli goto out; 2597a73105b8SAntonio Quartulli 2598a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 25999cfc7bd6SSven Eckelmann * is too big send the whole local translation table 26009cfc7bd6SSven Eckelmann */ 2601335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || 2602807736f6SSven Eckelmann !bat_priv->tt.last_changeset) 2603a73105b8SAntonio Quartulli full_table = true; 2604a73105b8SAntonio Quartulli else 2605a73105b8SAntonio Quartulli full_table = false; 2606a73105b8SAntonio Quartulli 2607335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 2608335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 26099cfc7bd6SSven Eckelmann */ 2610a73105b8SAntonio Quartulli if (!full_table) { 2611807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 2612a73105b8SAntonio Quartulli 26137ea7b4a1SAntonio Quartulli tt_len = bat_priv->tt.last_changeset_len; 26147ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 26157ea7b4a1SAntonio Quartulli &tvlv_tt_data, 26167ea7b4a1SAntonio Quartulli &tt_change, 26177ea7b4a1SAntonio Quartulli &tt_len); 26187ea7b4a1SAntonio Quartulli if (!tt_len) 2619a73105b8SAntonio Quartulli goto unlock; 2620a73105b8SAntonio Quartulli 2621335fbe0fSMarek Lindner /* Copy the last orig_node's OGM buffer */ 26227ea7b4a1SAntonio Quartulli memcpy(tt_change, bat_priv->tt.last_changeset, 2623807736f6SSven Eckelmann bat_priv->tt.last_changeset_len); 2624807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2625a73105b8SAntonio Quartulli } else { 2626335fbe0fSMarek Lindner req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); 2627a73105b8SAntonio Quartulli 26287ea7b4a1SAntonio Quartulli /* allocate the tvlv, put the tt_data and all the tt_vlan_data 26297ea7b4a1SAntonio Quartulli * in the initial part 26307ea7b4a1SAntonio Quartulli */ 26317ea7b4a1SAntonio Quartulli tt_len = -1; 26327ea7b4a1SAntonio Quartulli tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, 26337ea7b4a1SAntonio Quartulli &tvlv_tt_data, 26347ea7b4a1SAntonio Quartulli &tt_change, 26357ea7b4a1SAntonio Quartulli &tt_len); 26367ea7b4a1SAntonio Quartulli if (!tt_len) 2637a73105b8SAntonio Quartulli goto out; 26387ea7b4a1SAntonio Quartulli 26397ea7b4a1SAntonio Quartulli /* fill the rest of the tvlv with the real TT entries */ 26407ea7b4a1SAntonio Quartulli batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, 26417ea7b4a1SAntonio Quartulli tt_change, tt_len, 26427ea7b4a1SAntonio Quartulli batadv_tt_local_valid, NULL); 2643a73105b8SAntonio Quartulli } 2644a73105b8SAntonio Quartulli 2645335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2646335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 2647a73105b8SAntonio Quartulli 2648a73105b8SAntonio Quartulli if (full_table) 2649335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 2650a73105b8SAntonio Quartulli 265139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2652335fbe0fSMarek Lindner "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n", 2653335fbe0fSMarek Lindner orig_node->orig, full_table ? 'F' : '.', req_ttvn); 2654a73105b8SAntonio Quartulli 2655d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 2656f8214865SMartin Hundebøll 2657335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 26587ea7b4a1SAntonio Quartulli req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, 26597ea7b4a1SAntonio Quartulli tvlv_len); 2660335fbe0fSMarek Lindner 2661a73105b8SAntonio Quartulli goto out; 2662a73105b8SAntonio Quartulli 2663a73105b8SAntonio Quartulli unlock: 2664807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2665a73105b8SAntonio Quartulli out: 2666a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 2667a73105b8SAntonio Quartulli if (orig_node) 26687d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2669a73105b8SAntonio Quartulli if (primary_if) 2670e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 2671335fbe0fSMarek Lindner kfree(tvlv_tt_data); 2672335fbe0fSMarek Lindner /* The packet was for this host, so it doesn't need to be re-routed */ 2673a73105b8SAntonio Quartulli return true; 2674a73105b8SAntonio Quartulli } 2675a73105b8SAntonio Quartulli 2676335fbe0fSMarek Lindner /** 2677335fbe0fSMarek Lindner * batadv_send_tt_response - send reply to tt request 2678335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2679335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2680335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 2681335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 2682335fbe0fSMarek Lindner * 2683335fbe0fSMarek Lindner * Returns true if tt request reply was sent, false otherwise. 2684335fbe0fSMarek Lindner */ 2685335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv, 2686335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 2687335fbe0fSMarek Lindner uint8_t *req_src, uint8_t *req_dst) 2688a73105b8SAntonio Quartulli { 2689cfd4f757SAntonio Quartulli if (batadv_is_my_mac(bat_priv, req_dst)) 2690335fbe0fSMarek Lindner return batadv_send_my_tt_response(bat_priv, tt_data, req_src); 2691cfd4f757SAntonio Quartulli else 2692335fbe0fSMarek Lindner return batadv_send_other_tt_response(bat_priv, tt_data, 2693335fbe0fSMarek Lindner req_src, req_dst); 2694a73105b8SAntonio Quartulli } 2695a73105b8SAntonio Quartulli 269656303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, 269756303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2698335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change, 2699a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 2700a73105b8SAntonio Quartulli { 2701a73105b8SAntonio Quartulli int i; 2702a513088dSSven Eckelmann int roams; 2703a73105b8SAntonio Quartulli 2704a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 2705acd34afaSSven Eckelmann if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { 2706acd34afaSSven Eckelmann roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; 2707a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 2708a73105b8SAntonio Quartulli (tt_change + i)->addr, 2709c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 2710cc47f66eSAntonio Quartulli "tt removed by changes", 2711a513088dSSven Eckelmann roams); 271208c36d3eSSven Eckelmann } else { 271308c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 2714d4f44692SAntonio Quartulli (tt_change + i)->addr, 2715c018ad3dSAntonio Quartulli ntohs((tt_change + i)->vid), 2716d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 2717a73105b8SAntonio Quartulli /* In case of problem while storing a 2718a73105b8SAntonio Quartulli * global_entry, we stop the updating 2719a73105b8SAntonio Quartulli * procedure without committing the 2720a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 2721a73105b8SAntonio Quartulli * corrupted data on tt_request 2722a73105b8SAntonio Quartulli */ 2723a73105b8SAntonio Quartulli return; 2724a73105b8SAntonio Quartulli } 272508c36d3eSSven Eckelmann } 272617071578SAntonio Quartulli orig_node->tt_initialised = true; 2727a73105b8SAntonio Quartulli } 2728a73105b8SAntonio Quartulli 272956303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, 27307ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 27317ea7b4a1SAntonio Quartulli uint8_t ttvn, uint8_t *resp_src, 27327ea7b4a1SAntonio Quartulli uint16_t num_entries) 2733a73105b8SAntonio Quartulli { 2734170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 2735a73105b8SAntonio Quartulli 2736335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 2737a73105b8SAntonio Quartulli if (!orig_node) 2738a73105b8SAntonio Quartulli goto out; 2739a73105b8SAntonio Quartulli 2740a73105b8SAntonio Quartulli /* Purge the old table first.. */ 274195fb130dSAntonio Quartulli batadv_tt_global_del_orig(bat_priv, orig_node, -1, 274295fb130dSAntonio Quartulli "Received full table"); 2743a73105b8SAntonio Quartulli 27447ea7b4a1SAntonio Quartulli _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, 27457ea7b4a1SAntonio Quartulli ttvn); 2746a73105b8SAntonio Quartulli 2747a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2748a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2749a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2750a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 2751a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2752a73105b8SAntonio Quartulli 27537ea7b4a1SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2754a73105b8SAntonio Quartulli 2755a73105b8SAntonio Quartulli out: 2756a73105b8SAntonio Quartulli if (orig_node) 27577d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2758a73105b8SAntonio Quartulli } 2759a73105b8SAntonio Quartulli 276056303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv, 276156303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2762a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 2763335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change) 2764a73105b8SAntonio Quartulli { 2765a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 2766a513088dSSven Eckelmann tt_num_changes, ttvn); 2767a73105b8SAntonio Quartulli 2768e8cf234aSAntonio Quartulli batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, 2769e8cf234aSAntonio Quartulli batadv_tt_len(tt_num_changes)); 2770a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2771a73105b8SAntonio Quartulli } 2772a73105b8SAntonio Quartulli 2773c018ad3dSAntonio Quartulli /** 2774c018ad3dSAntonio Quartulli * batadv_is_my_client - check if a client is served by the local node 2775c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2776c018ad3dSAntonio Quartulli * @addr: the mac adress of the client to check 2777c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2778c018ad3dSAntonio Quartulli * 2779c018ad3dSAntonio Quartulli * Returns true if the client is served by this node, false otherwise. 2780c018ad3dSAntonio Quartulli */ 2781c018ad3dSAntonio Quartulli bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, 2782c018ad3dSAntonio Quartulli unsigned short vid) 2783a73105b8SAntonio Quartulli { 2784170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 27857683fdc1SAntonio Quartulli bool ret = false; 2786a73105b8SAntonio Quartulli 2787c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 27887683fdc1SAntonio Quartulli if (!tt_local_entry) 27897683fdc1SAntonio Quartulli goto out; 2790058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 27919cfc7bd6SSven Eckelmann * consistency purpose) 27929cfc7bd6SSven Eckelmann */ 27937c1fd91dSAntonio Quartulli if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) || 27947c1fd91dSAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM)) 2795058d0e26SAntonio Quartulli goto out; 27967683fdc1SAntonio Quartulli ret = true; 27977683fdc1SAntonio Quartulli out: 2798a73105b8SAntonio Quartulli if (tt_local_entry) 2799a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 28007683fdc1SAntonio Quartulli return ret; 2801a73105b8SAntonio Quartulli } 2802a73105b8SAntonio Quartulli 2803335fbe0fSMarek Lindner /** 2804335fbe0fSMarek Lindner * batadv_handle_tt_response - process incoming tt reply 2805335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2806335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2807335fbe0fSMarek Lindner * @resp_src: mac address of tt reply sender 2808335fbe0fSMarek Lindner * @num_entries: number of tt change entries appended to the tt data 2809335fbe0fSMarek Lindner */ 2810335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv, 2811335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 2812335fbe0fSMarek Lindner uint8_t *resp_src, uint16_t num_entries) 2813a73105b8SAntonio Quartulli { 281456303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 281556303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 2816335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 28177ea7b4a1SAntonio Quartulli uint8_t *tvlv_ptr = (uint8_t *)tt_data; 28187ea7b4a1SAntonio Quartulli uint16_t change_offset; 2819a73105b8SAntonio Quartulli 282039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 282186ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 2822335fbe0fSMarek Lindner resp_src, tt_data->ttvn, num_entries, 2823335fbe0fSMarek Lindner (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 2824a73105b8SAntonio Quartulli 2825335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 2826a73105b8SAntonio Quartulli if (!orig_node) 2827a73105b8SAntonio Quartulli goto out; 2828a73105b8SAntonio Quartulli 2829a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 2830a70a9aa9SAntonio Quartulli 28317ea7b4a1SAntonio Quartulli change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); 28327ea7b4a1SAntonio Quartulli change_offset *= ntohs(tt_data->num_vlan); 28337ea7b4a1SAntonio Quartulli change_offset += sizeof(*tt_data); 28347ea7b4a1SAntonio Quartulli tvlv_ptr += change_offset; 28357ea7b4a1SAntonio Quartulli 28367ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; 2837335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) { 28387ea7b4a1SAntonio Quartulli batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, 28397ea7b4a1SAntonio Quartulli resp_src, num_entries); 284096412690SSven Eckelmann } else { 2841335fbe0fSMarek Lindner batadv_tt_update_changes(bat_priv, orig_node, num_entries, 2842335fbe0fSMarek Lindner tt_data->ttvn, tt_change); 284396412690SSven Eckelmann } 2844a73105b8SAntonio Quartulli 2845a70a9aa9SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 28467ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 2847a70a9aa9SAntonio Quartulli 2848a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 2849a70a9aa9SAntonio Quartulli 2850a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 2851807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2852807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 2853335fbe0fSMarek Lindner if (!batadv_compare_eth(node->addr, resp_src)) 2854a73105b8SAntonio Quartulli continue; 2855a73105b8SAntonio Quartulli list_del(&node->list); 2856a73105b8SAntonio Quartulli kfree(node); 2857a73105b8SAntonio Quartulli } 28587ea7b4a1SAntonio Quartulli 2859807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2860a73105b8SAntonio Quartulli out: 2861a73105b8SAntonio Quartulli if (orig_node) 28627d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2863a73105b8SAntonio Quartulli } 2864a73105b8SAntonio Quartulli 286556303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) 2866a73105b8SAntonio Quartulli { 286756303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 2868a73105b8SAntonio Quartulli 2869807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2870a73105b8SAntonio Quartulli 2871807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 2872cc47f66eSAntonio Quartulli list_del(&node->list); 2873cc47f66eSAntonio Quartulli kfree(node); 2874cc47f66eSAntonio Quartulli } 2875cc47f66eSAntonio Quartulli 2876807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2877cc47f66eSAntonio Quartulli } 2878cc47f66eSAntonio Quartulli 287956303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) 2880cc47f66eSAntonio Quartulli { 288156303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 2882cc47f66eSAntonio Quartulli 2883807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2884807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 288542d0b044SSven Eckelmann if (!batadv_has_timed_out(node->first_time, 288642d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 2887cc47f66eSAntonio Quartulli continue; 2888cc47f66eSAntonio Quartulli 2889cc47f66eSAntonio Quartulli list_del(&node->list); 2890cc47f66eSAntonio Quartulli kfree(node); 2891cc47f66eSAntonio Quartulli } 2892807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2893cc47f66eSAntonio Quartulli } 2894cc47f66eSAntonio Quartulli 2895cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 2896cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 2897cc47f66eSAntonio Quartulli * will not be sent. 2898cc47f66eSAntonio Quartulli * 28999cfc7bd6SSven Eckelmann * returns true if the ROAMING_ADV can be sent, false otherwise 29009cfc7bd6SSven Eckelmann */ 290156303d34SSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, 2902cc47f66eSAntonio Quartulli uint8_t *client) 2903cc47f66eSAntonio Quartulli { 290456303d34SSven Eckelmann struct batadv_tt_roam_node *tt_roam_node; 2905cc47f66eSAntonio Quartulli bool ret = false; 2906cc47f66eSAntonio Quartulli 2907807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2908cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 29099cfc7bd6SSven Eckelmann * reply from the same orig_node yet 29109cfc7bd6SSven Eckelmann */ 2911807736f6SSven Eckelmann list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) { 29121eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 2913cc47f66eSAntonio Quartulli continue; 2914cc47f66eSAntonio Quartulli 29151eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 291642d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 2917cc47f66eSAntonio Quartulli continue; 2918cc47f66eSAntonio Quartulli 29193e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 2920cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 2921cc47f66eSAntonio Quartulli goto unlock; 2922cc47f66eSAntonio Quartulli ret = true; 2923cc47f66eSAntonio Quartulli break; 2924cc47f66eSAntonio Quartulli } 2925cc47f66eSAntonio Quartulli 2926cc47f66eSAntonio Quartulli if (!ret) { 2927cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 2928cc47f66eSAntonio Quartulli if (!tt_roam_node) 2929cc47f66eSAntonio Quartulli goto unlock; 2930cc47f66eSAntonio Quartulli 2931cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 293242d0b044SSven Eckelmann atomic_set(&tt_roam_node->counter, 293342d0b044SSven Eckelmann BATADV_ROAMING_MAX_COUNT - 1); 29348fdd0153SAntonio Quartulli ether_addr_copy(tt_roam_node->addr, client); 2935cc47f66eSAntonio Quartulli 2936807736f6SSven Eckelmann list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); 2937cc47f66eSAntonio Quartulli ret = true; 2938cc47f66eSAntonio Quartulli } 2939cc47f66eSAntonio Quartulli 2940cc47f66eSAntonio Quartulli unlock: 2941807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2942cc47f66eSAntonio Quartulli return ret; 2943cc47f66eSAntonio Quartulli } 2944cc47f66eSAntonio Quartulli 2945c018ad3dSAntonio Quartulli /** 2946c018ad3dSAntonio Quartulli * batadv_send_roam_adv - send a roaming advertisement message 2947c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 2948c018ad3dSAntonio Quartulli * @client: mac address of the roaming client 2949c018ad3dSAntonio Quartulli * @vid: VLAN identifier 2950c018ad3dSAntonio Quartulli * @orig_node: message destination 2951c018ad3dSAntonio Quartulli * 2952c018ad3dSAntonio Quartulli * Send a ROAMING_ADV message to the node which was previously serving this 2953c018ad3dSAntonio Quartulli * client. This is done to inform the node that from now on all traffic destined 2954c018ad3dSAntonio Quartulli * for this particular roamed client has to be forwarded to the sender of the 2955c018ad3dSAntonio Quartulli * roaming message. 2956c018ad3dSAntonio Quartulli */ 295756303d34SSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, 2958c018ad3dSAntonio Quartulli unsigned short vid, 295956303d34SSven Eckelmann struct batadv_orig_node *orig_node) 2960cc47f66eSAntonio Quartulli { 296156303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 2962122edaa0SMarek Lindner struct batadv_tvlv_roam_adv tvlv_roam; 2963122edaa0SMarek Lindner 2964122edaa0SMarek Lindner primary_if = batadv_primary_if_get_selected(bat_priv); 2965122edaa0SMarek Lindner if (!primary_if) 2966122edaa0SMarek Lindner goto out; 2967cc47f66eSAntonio Quartulli 2968cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 29699cfc7bd6SSven Eckelmann * already roamed to us too many times 29709cfc7bd6SSven Eckelmann */ 2971a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 2972cc47f66eSAntonio Quartulli goto out; 2973cc47f66eSAntonio Quartulli 297439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 297516052789SAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n", 297616052789SAntonio Quartulli orig_node->orig, client, BATADV_PRINT_VID(vid)); 2977cc47f66eSAntonio Quartulli 2978d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); 2979f8214865SMartin Hundebøll 2980122edaa0SMarek Lindner memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); 2981c018ad3dSAntonio Quartulli tvlv_roam.vid = htons(vid); 2982122edaa0SMarek Lindner 2983122edaa0SMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 2984122edaa0SMarek Lindner orig_node->orig, BATADV_TVLV_ROAM, 1, 2985122edaa0SMarek Lindner &tvlv_roam, sizeof(tvlv_roam)); 2986cc47f66eSAntonio Quartulli 2987cc47f66eSAntonio Quartulli out: 2988122edaa0SMarek Lindner if (primary_if) 2989122edaa0SMarek Lindner batadv_hardif_free_ref(primary_if); 2990a73105b8SAntonio Quartulli } 2991a73105b8SAntonio Quartulli 2992a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 2993a73105b8SAntonio Quartulli { 299456303d34SSven Eckelmann struct delayed_work *delayed_work; 2995807736f6SSven Eckelmann struct batadv_priv_tt *priv_tt; 299656303d34SSven Eckelmann struct batadv_priv *bat_priv; 299756303d34SSven Eckelmann 299856303d34SSven Eckelmann delayed_work = container_of(work, struct delayed_work, work); 2999807736f6SSven Eckelmann priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 3000807736f6SSven Eckelmann bat_priv = container_of(priv_tt, struct batadv_priv, tt); 3001a73105b8SAntonio Quartulli 3002a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT); 300330cfd02bSAntonio Quartulli batadv_tt_global_purge(bat_priv); 3004a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 3005a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 3006a73105b8SAntonio Quartulli 300772414442SAntonio Quartulli queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 300872414442SAntonio Quartulli msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3009a73105b8SAntonio Quartulli } 3010cc47f66eSAntonio Quartulli 301156303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv) 3012cc47f66eSAntonio Quartulli { 3013e1bf0c14SMarek Lindner batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); 3014e1bf0c14SMarek Lindner batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); 3015e1bf0c14SMarek Lindner 3016807736f6SSven Eckelmann cancel_delayed_work_sync(&bat_priv->tt.work); 3017cc47f66eSAntonio Quartulli 3018a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 3019a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 3020a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 3021a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 3022a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 3023cc47f66eSAntonio Quartulli 3024807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 3025cc47f66eSAntonio Quartulli } 3026058d0e26SAntonio Quartulli 30277ea7b4a1SAntonio Quartulli /** 30287ea7b4a1SAntonio Quartulli * batadv_tt_local_set_flags - set or unset the specified flags on the local 30297ea7b4a1SAntonio Quartulli * table and possibly count them in the TT size 30307ea7b4a1SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 30317ea7b4a1SAntonio Quartulli * @flags: the flag to switch 30327ea7b4a1SAntonio Quartulli * @enable: whether to set or unset the flag 30337ea7b4a1SAntonio Quartulli * @count: whether to increase the TT size by the number of changed entries 30349cfc7bd6SSven Eckelmann */ 30357ea7b4a1SAntonio Quartulli static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, 30367ea7b4a1SAntonio Quartulli uint16_t flags, bool enable, bool count) 3037058d0e26SAntonio Quartulli { 30387ea7b4a1SAntonio Quartulli struct batadv_hashtable *hash = bat_priv->tt.local_hash; 30397ea7b4a1SAntonio Quartulli struct batadv_tt_common_entry *tt_common_entry; 3040697f2531SAntonio Quartulli uint16_t changed_num = 0; 3041058d0e26SAntonio Quartulli struct hlist_head *head; 30427ea7b4a1SAntonio Quartulli uint32_t i; 3043058d0e26SAntonio Quartulli 3044058d0e26SAntonio Quartulli if (!hash) 30457ea7b4a1SAntonio Quartulli return; 3046058d0e26SAntonio Quartulli 3047058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3048058d0e26SAntonio Quartulli head = &hash->table[i]; 3049058d0e26SAntonio Quartulli 3050058d0e26SAntonio Quartulli rcu_read_lock(); 3051b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 3052058d0e26SAntonio Quartulli head, hash_entry) { 3053697f2531SAntonio Quartulli if (enable) { 3054697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 3055697f2531SAntonio Quartulli continue; 3056697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 3057697f2531SAntonio Quartulli } else { 305848100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 305931901264SAntonio Quartulli continue; 306048100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 3061697f2531SAntonio Quartulli } 3062697f2531SAntonio Quartulli changed_num++; 30637ea7b4a1SAntonio Quartulli 30647ea7b4a1SAntonio Quartulli if (!count) 30657ea7b4a1SAntonio Quartulli continue; 30667ea7b4a1SAntonio Quartulli 30677ea7b4a1SAntonio Quartulli batadv_tt_local_size_inc(bat_priv, 30687ea7b4a1SAntonio Quartulli tt_common_entry->vid); 3069058d0e26SAntonio Quartulli } 3070058d0e26SAntonio Quartulli rcu_read_unlock(); 3071058d0e26SAntonio Quartulli } 3072058d0e26SAntonio Quartulli } 3073058d0e26SAntonio Quartulli 3074acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ 307556303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) 3076058d0e26SAntonio Quartulli { 3077807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 307856303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 307956303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 3080b67bfe0dSSasha Levin struct hlist_node *node_tmp; 3081058d0e26SAntonio Quartulli struct hlist_head *head; 3082058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 3083c90681b8SAntonio Quartulli uint32_t i; 3084058d0e26SAntonio Quartulli 3085058d0e26SAntonio Quartulli if (!hash) 3086058d0e26SAntonio Quartulli return; 3087058d0e26SAntonio Quartulli 3088058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 3089058d0e26SAntonio Quartulli head = &hash->table[i]; 3090058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 3091058d0e26SAntonio Quartulli 3092058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 3093b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 3094acd34afaSSven Eckelmann hash_entry) { 3095acd34afaSSven Eckelmann if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) 3096058d0e26SAntonio Quartulli continue; 3097058d0e26SAntonio Quartulli 309839c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 309916052789SAntonio Quartulli "Deleting local tt entry (%pM, vid: %d): pending\n", 310016052789SAntonio Quartulli tt_common->addr, 310116052789SAntonio Quartulli BATADV_PRINT_VID(tt_common->vid)); 3102058d0e26SAntonio Quartulli 31037ea7b4a1SAntonio Quartulli batadv_tt_local_size_dec(bat_priv, tt_common->vid); 3104b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 310556303d34SSven Eckelmann tt_local = container_of(tt_common, 310656303d34SSven Eckelmann struct batadv_tt_local_entry, 310748100bacSAntonio Quartulli common); 310856303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 3109058d0e26SAntonio Quartulli } 3110058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 3111058d0e26SAntonio Quartulli } 3112058d0e26SAntonio Quartulli } 3113058d0e26SAntonio Quartulli 3114e1bf0c14SMarek Lindner /** 3115a19d3d85SMarek Lindner * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes 3116a19d3d85SMarek Lindner * which have been queued in the time since the last commit 3117e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3118a19d3d85SMarek Lindner * 3119a19d3d85SMarek Lindner * Caller must hold tt->commit_lock. 3120e1bf0c14SMarek Lindner */ 3121a19d3d85SMarek Lindner static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) 3122058d0e26SAntonio Quartulli { 3123e1bf0c14SMarek Lindner if (atomic_read(&bat_priv->tt.local_changes) < 1) { 3124e1bf0c14SMarek Lindner if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 3125e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3126a19d3d85SMarek Lindner return; 3127e1bf0c14SMarek Lindner } 3128be9aa4c1SMarek Lindner 31297ea7b4a1SAntonio Quartulli batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); 3130be9aa4c1SMarek Lindner 3131a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 31327ea7b4a1SAntonio Quartulli batadv_tt_local_update_crc(bat_priv); 3133058d0e26SAntonio Quartulli 3134058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 3135807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.vn); 313639c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 31371eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 3138807736f6SSven Eckelmann (uint8_t)atomic_read(&bat_priv->tt.vn)); 3139be9aa4c1SMarek Lindner 3140be9aa4c1SMarek Lindner /* reset the sending counter */ 3141807736f6SSven Eckelmann atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 3142e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 3143a19d3d85SMarek Lindner } 3144a70a9aa9SAntonio Quartulli 3145a19d3d85SMarek Lindner /** 3146a19d3d85SMarek Lindner * batadv_tt_local_commit_changes - commit all pending local tt changes which 3147a19d3d85SMarek Lindner * have been queued in the time since the last commit 3148a19d3d85SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3149a19d3d85SMarek Lindner */ 3150a19d3d85SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) 3151a19d3d85SMarek Lindner { 3152a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3153a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3154a70a9aa9SAntonio Quartulli spin_unlock_bh(&bat_priv->tt.commit_lock); 3155058d0e26SAntonio Quartulli } 315659b699cdSAntonio Quartulli 315756303d34SSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, 3158b8cbd81dSAntonio Quartulli uint8_t *dst, unsigned short vid) 315959b699cdSAntonio Quartulli { 316056303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 316156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 3162b8cbd81dSAntonio Quartulli struct batadv_softif_vlan *vlan; 31635870adc6SMarek Lindner bool ret = false; 316459b699cdSAntonio Quartulli 3165b8cbd81dSAntonio Quartulli vlan = batadv_softif_vlan_get(bat_priv, vid); 3166b8cbd81dSAntonio Quartulli if (!vlan || !atomic_read(&vlan->ap_isolation)) 31675870adc6SMarek Lindner goto out; 316859b699cdSAntonio Quartulli 3169b8cbd81dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); 317059b699cdSAntonio Quartulli if (!tt_local_entry) 317159b699cdSAntonio Quartulli goto out; 317259b699cdSAntonio Quartulli 3173b8cbd81dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); 317459b699cdSAntonio Quartulli if (!tt_global_entry) 317559b699cdSAntonio Quartulli goto out; 317659b699cdSAntonio Quartulli 31771f129fefSAntonio Quartulli if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 317859b699cdSAntonio Quartulli goto out; 317959b699cdSAntonio Quartulli 31805870adc6SMarek Lindner ret = true; 318159b699cdSAntonio Quartulli 318259b699cdSAntonio Quartulli out: 3183b8cbd81dSAntonio Quartulli if (vlan) 3184b8cbd81dSAntonio Quartulli batadv_softif_vlan_free_ref(vlan); 318559b699cdSAntonio Quartulli if (tt_global_entry) 3186a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 318759b699cdSAntonio Quartulli if (tt_local_entry) 3188a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 318959b699cdSAntonio Quartulli return ret; 319059b699cdSAntonio Quartulli } 3191a943cac1SMarek Lindner 3192e1bf0c14SMarek Lindner /** 3193e1bf0c14SMarek Lindner * batadv_tt_update_orig - update global translation table with new tt 3194e1bf0c14SMarek Lindner * information received via ogms 3195e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3196e1bf0c14SMarek Lindner * @orig: the orig_node of the ogm 31977ea7b4a1SAntonio Quartulli * @tt_vlan: pointer to the first tvlv VLAN entry 31987ea7b4a1SAntonio Quartulli * @tt_num_vlan: number of tvlv VLAN entries 31997ea7b4a1SAntonio Quartulli * @tt_change: pointer to the first entry in the TT buffer 3200e1bf0c14SMarek Lindner * @tt_num_changes: number of tt changes inside the tt buffer 3201e1bf0c14SMarek Lindner * @ttvn: translation table version number of this changeset 3202ced72933SAntonio Quartulli * @tt_crc: crc32 checksum of orig node's translation table 3203e1bf0c14SMarek Lindner */ 3204e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv, 320556303d34SSven Eckelmann struct batadv_orig_node *orig_node, 32067ea7b4a1SAntonio Quartulli const void *tt_buff, uint16_t tt_num_vlan, 32077ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change, 32087ea7b4a1SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 3209a943cac1SMarek Lindner { 3210a943cac1SMarek Lindner uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); 32117ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 3212a943cac1SMarek Lindner bool full_table = true; 3213a943cac1SMarek Lindner 32147ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; 321517071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 32169cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 32179cfc7bd6SSven Eckelmann */ 321817071578SAntonio Quartulli if ((!orig_node->tt_initialised && ttvn == 1) || 321917071578SAntonio Quartulli ttvn - orig_ttvn == 1) { 3220a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 322142d0b044SSven Eckelmann * because they have already been sent BATADV_TT_OGM_APPEND_MAX 322242d0b044SSven Eckelmann * times. 32239cfc7bd6SSven Eckelmann * In this case send a tt request 32249cfc7bd6SSven Eckelmann */ 3225a943cac1SMarek Lindner if (!tt_num_changes) { 3226a943cac1SMarek Lindner full_table = false; 3227a943cac1SMarek Lindner goto request_table; 3228a943cac1SMarek Lindner } 3229a943cac1SMarek Lindner 3230a70a9aa9SAntonio Quartulli spin_lock_bh(&orig_node->tt_lock); 3231a70a9aa9SAntonio Quartulli 3232a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 323396412690SSven Eckelmann ttvn, tt_change); 3234a943cac1SMarek Lindner 3235a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 3236a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 32379cfc7bd6SSven Eckelmann * in the global table 32389cfc7bd6SSven Eckelmann */ 32397ea7b4a1SAntonio Quartulli batadv_tt_global_update_crc(bat_priv, orig_node); 3240a943cac1SMarek Lindner 3241a70a9aa9SAntonio Quartulli spin_unlock_bh(&orig_node->tt_lock); 3242a70a9aa9SAntonio Quartulli 3243a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 3244a943cac1SMarek Lindner * because a single value could represent different states 3245a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 3246a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 3247a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 3248a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 3249a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 32509cfc7bd6SSven Eckelmann * inconsistency 32519cfc7bd6SSven Eckelmann */ 32527ea7b4a1SAntonio Quartulli if (!batadv_tt_global_check_crc(orig_node, tt_vlan, 32537ea7b4a1SAntonio Quartulli tt_num_vlan)) 3254a943cac1SMarek Lindner goto request_table; 3255a943cac1SMarek Lindner } else { 3256a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 32579cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 32589cfc7bd6SSven Eckelmann */ 325917071578SAntonio Quartulli if (!orig_node->tt_initialised || ttvn != orig_ttvn || 32607ea7b4a1SAntonio Quartulli !batadv_tt_global_check_crc(orig_node, tt_vlan, 32617ea7b4a1SAntonio Quartulli tt_num_vlan)) { 3262a943cac1SMarek Lindner request_table: 326339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 32647ea7b4a1SAntonio Quartulli "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n", 32657ea7b4a1SAntonio Quartulli orig_node->orig, ttvn, orig_ttvn, 32667ea7b4a1SAntonio Quartulli tt_num_changes); 3267a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 32687ea7b4a1SAntonio Quartulli tt_vlan, tt_num_vlan, 32697ea7b4a1SAntonio Quartulli full_table); 3270a943cac1SMarek Lindner return; 3271a943cac1SMarek Lindner } 3272a943cac1SMarek Lindner } 3273a943cac1SMarek Lindner } 32743275e7ccSAntonio Quartulli 3275c018ad3dSAntonio Quartulli /** 3276c018ad3dSAntonio Quartulli * batadv_tt_global_client_is_roaming - check if a client is marked as roaming 3277c018ad3dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3278c018ad3dSAntonio Quartulli * @addr: the mac address of the client to check 3279c018ad3dSAntonio Quartulli * @vid: VLAN identifier 3280c018ad3dSAntonio Quartulli * 3281c018ad3dSAntonio Quartulli * Returns true if we know that the client has moved from its old originator 3282c018ad3dSAntonio Quartulli * to another one. This entry is still kept for consistency purposes and will be 3283c018ad3dSAntonio Quartulli * deleted later by a DEL or because of timeout 32843275e7ccSAntonio Quartulli */ 328556303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, 3286c018ad3dSAntonio Quartulli uint8_t *addr, unsigned short vid) 32873275e7ccSAntonio Quartulli { 328856303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 32893275e7ccSAntonio Quartulli bool ret = false; 32903275e7ccSAntonio Quartulli 3291c018ad3dSAntonio Quartulli tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 32923275e7ccSAntonio Quartulli if (!tt_global_entry) 32933275e7ccSAntonio Quartulli goto out; 32943275e7ccSAntonio Quartulli 3295c1d07431SAntonio Quartulli ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; 3296a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 32973275e7ccSAntonio Quartulli out: 32983275e7ccSAntonio Quartulli return ret; 32993275e7ccSAntonio Quartulli } 330030cfd02bSAntonio Quartulli 33017c1fd91dSAntonio Quartulli /** 33027c1fd91dSAntonio Quartulli * batadv_tt_local_client_is_roaming - tells whether the client is roaming 33037c1fd91dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 3304c018ad3dSAntonio Quartulli * @addr: the mac address of the local client to query 3305c018ad3dSAntonio Quartulli * @vid: VLAN identifier 33067c1fd91dSAntonio Quartulli * 33077c1fd91dSAntonio Quartulli * Returns true if the local client is known to be roaming (it is not served by 33087c1fd91dSAntonio Quartulli * this node anymore) or not. If yes, the client is still present in the table 33097c1fd91dSAntonio Quartulli * to keep the latter consistent with the node TTVN 33107c1fd91dSAntonio Quartulli */ 33117c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, 3312c018ad3dSAntonio Quartulli uint8_t *addr, unsigned short vid) 33137c1fd91dSAntonio Quartulli { 33147c1fd91dSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry; 33157c1fd91dSAntonio Quartulli bool ret = false; 33167c1fd91dSAntonio Quartulli 3317c018ad3dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); 33187c1fd91dSAntonio Quartulli if (!tt_local_entry) 33197c1fd91dSAntonio Quartulli goto out; 33207c1fd91dSAntonio Quartulli 33217c1fd91dSAntonio Quartulli ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; 33227c1fd91dSAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 33237c1fd91dSAntonio Quartulli out: 33247c1fd91dSAntonio Quartulli return ret; 33257c1fd91dSAntonio Quartulli } 33267c1fd91dSAntonio Quartulli 332730cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, 332830cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 3329c018ad3dSAntonio Quartulli const unsigned char *addr, 333016052789SAntonio Quartulli unsigned short vid) 333130cfd02bSAntonio Quartulli { 333230cfd02bSAntonio Quartulli bool ret = false; 333330cfd02bSAntonio Quartulli 333416052789SAntonio Quartulli if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, 333530cfd02bSAntonio Quartulli BATADV_TT_CLIENT_TEMP, 333630cfd02bSAntonio Quartulli atomic_read(&orig_node->last_ttvn))) 333730cfd02bSAntonio Quartulli goto out; 333830cfd02bSAntonio Quartulli 333930cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 334016052789SAntonio Quartulli "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n", 334116052789SAntonio Quartulli addr, BATADV_PRINT_VID(vid), orig_node->orig); 334230cfd02bSAntonio Quartulli ret = true; 334330cfd02bSAntonio Quartulli out: 334430cfd02bSAntonio Quartulli return ret; 334530cfd02bSAntonio Quartulli } 3346e1bf0c14SMarek Lindner 3347e1bf0c14SMarek Lindner /** 3348a19d3d85SMarek Lindner * batadv_tt_local_resize_to_mtu - resize the local translation table fit the 3349a19d3d85SMarek Lindner * maximum packet size that can be transported through the mesh 3350a19d3d85SMarek Lindner * @soft_iface: netdev struct of the mesh interface 3351a19d3d85SMarek Lindner * 3352a19d3d85SMarek Lindner * Remove entries older than 'timeout' and half timeout if more entries need 3353a19d3d85SMarek Lindner * to be removed. 3354a19d3d85SMarek Lindner */ 3355a19d3d85SMarek Lindner void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface) 3356a19d3d85SMarek Lindner { 3357a19d3d85SMarek Lindner struct batadv_priv *bat_priv = netdev_priv(soft_iface); 3358a19d3d85SMarek Lindner int packet_size_max = atomic_read(&bat_priv->packet_size_max); 3359a19d3d85SMarek Lindner int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; 3360a19d3d85SMarek Lindner bool reduced = false; 3361a19d3d85SMarek Lindner 3362a19d3d85SMarek Lindner spin_lock_bh(&bat_priv->tt.commit_lock); 3363a19d3d85SMarek Lindner 3364a19d3d85SMarek Lindner while (true) { 3365a19d3d85SMarek Lindner table_size = batadv_tt_local_table_transmit_size(bat_priv); 3366a19d3d85SMarek Lindner if (packet_size_max >= table_size) 3367a19d3d85SMarek Lindner break; 3368a19d3d85SMarek Lindner 3369a19d3d85SMarek Lindner batadv_tt_local_purge(bat_priv, timeout); 3370a19d3d85SMarek Lindner batadv_tt_local_purge_pending_clients(bat_priv); 3371a19d3d85SMarek Lindner 3372a19d3d85SMarek Lindner timeout /= 2; 3373a19d3d85SMarek Lindner reduced = true; 3374a19d3d85SMarek Lindner net_ratelimited_function(batadv_info, soft_iface, 3375a19d3d85SMarek Lindner "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n", 3376a19d3d85SMarek Lindner packet_size_max); 3377a19d3d85SMarek Lindner } 3378a19d3d85SMarek Lindner 3379a19d3d85SMarek Lindner /* commit these changes immediately, to avoid synchronization problem 3380a19d3d85SMarek Lindner * with the TTVN 3381a19d3d85SMarek Lindner */ 3382a19d3d85SMarek Lindner if (reduced) 3383a19d3d85SMarek Lindner batadv_tt_local_commit_changes_nolock(bat_priv); 3384a19d3d85SMarek Lindner 3385a19d3d85SMarek Lindner spin_unlock_bh(&bat_priv->tt.commit_lock); 3386a19d3d85SMarek Lindner } 3387a19d3d85SMarek Lindner 3388a19d3d85SMarek Lindner /** 3389e1bf0c14SMarek Lindner * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container 3390e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3391e1bf0c14SMarek Lindner * @orig: the orig_node of the ogm 3392e1bf0c14SMarek Lindner * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 3393e1bf0c14SMarek Lindner * @tvlv_value: tvlv buffer containing the gateway data 3394e1bf0c14SMarek Lindner * @tvlv_value_len: tvlv buffer length 3395e1bf0c14SMarek Lindner */ 3396e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 3397e1bf0c14SMarek Lindner struct batadv_orig_node *orig, 33987ea7b4a1SAntonio Quartulli uint8_t flags, void *tvlv_value, 3399e1bf0c14SMarek Lindner uint16_t tvlv_value_len) 3400e1bf0c14SMarek Lindner { 34017ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_vlan_data *tt_vlan; 34027ea7b4a1SAntonio Quartulli struct batadv_tvlv_tt_change *tt_change; 3403e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 34047ea7b4a1SAntonio Quartulli uint16_t num_entries, num_vlan; 3405e1bf0c14SMarek Lindner 3406e1bf0c14SMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 3407e1bf0c14SMarek Lindner return; 3408e1bf0c14SMarek Lindner 3409e1bf0c14SMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 3410e1bf0c14SMarek Lindner tvlv_value_len -= sizeof(*tt_data); 3411e1bf0c14SMarek Lindner 34127ea7b4a1SAntonio Quartulli num_vlan = ntohs(tt_data->num_vlan); 34137ea7b4a1SAntonio Quartulli 34147ea7b4a1SAntonio Quartulli if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) 34157ea7b4a1SAntonio Quartulli return; 34167ea7b4a1SAntonio Quartulli 34177ea7b4a1SAntonio Quartulli tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); 34187ea7b4a1SAntonio Quartulli tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); 34197ea7b4a1SAntonio Quartulli tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; 34207ea7b4a1SAntonio Quartulli 3421298e6e68SAntonio Quartulli num_entries = batadv_tt_entries(tvlv_value_len); 3422e1bf0c14SMarek Lindner 34237ea7b4a1SAntonio Quartulli batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, 34247ea7b4a1SAntonio Quartulli num_entries, tt_data->ttvn); 3425e1bf0c14SMarek Lindner } 3426e1bf0c14SMarek Lindner 3427e1bf0c14SMarek Lindner /** 3428335fbe0fSMarek Lindner * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv 3429335fbe0fSMarek Lindner * container 3430335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3431335fbe0fSMarek Lindner * @src: mac address of tt tvlv sender 3432335fbe0fSMarek Lindner * @dst: mac address of tt tvlv recipient 3433335fbe0fSMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 3434335fbe0fSMarek Lindner * @tvlv_value_len: tvlv buffer length 3435335fbe0fSMarek Lindner * 3436335fbe0fSMarek Lindner * Returns NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS 3437335fbe0fSMarek Lindner * otherwise. 3438335fbe0fSMarek Lindner */ 3439335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 3440335fbe0fSMarek Lindner uint8_t *src, uint8_t *dst, 3441335fbe0fSMarek Lindner void *tvlv_value, 3442335fbe0fSMarek Lindner uint16_t tvlv_value_len) 3443335fbe0fSMarek Lindner { 3444335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data; 34457ea7b4a1SAntonio Quartulli uint16_t tt_vlan_len, tt_num_entries; 3446335fbe0fSMarek Lindner char tt_flag; 3447335fbe0fSMarek Lindner bool ret; 3448335fbe0fSMarek Lindner 3449335fbe0fSMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 3450335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3451335fbe0fSMarek Lindner 3452335fbe0fSMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 3453335fbe0fSMarek Lindner tvlv_value_len -= sizeof(*tt_data); 3454335fbe0fSMarek Lindner 34557ea7b4a1SAntonio Quartulli tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); 34567ea7b4a1SAntonio Quartulli tt_vlan_len *= ntohs(tt_data->num_vlan); 34577ea7b4a1SAntonio Quartulli 34587ea7b4a1SAntonio Quartulli if (tvlv_value_len < tt_vlan_len) 34597ea7b4a1SAntonio Quartulli return NET_RX_SUCCESS; 34607ea7b4a1SAntonio Quartulli 34617ea7b4a1SAntonio Quartulli tvlv_value_len -= tt_vlan_len; 34627ea7b4a1SAntonio Quartulli tt_num_entries = batadv_tt_entries(tvlv_value_len); 3463335fbe0fSMarek Lindner 3464335fbe0fSMarek Lindner switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { 3465335fbe0fSMarek Lindner case BATADV_TT_REQUEST: 3466335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); 3467335fbe0fSMarek Lindner 3468335fbe0fSMarek Lindner /* If this node cannot provide a TT response the tt_request is 3469335fbe0fSMarek Lindner * forwarded 3470335fbe0fSMarek Lindner */ 3471335fbe0fSMarek Lindner ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); 3472335fbe0fSMarek Lindner if (!ret) { 3473335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 3474335fbe0fSMarek Lindner tt_flag = 'F'; 3475335fbe0fSMarek Lindner else 3476335fbe0fSMarek Lindner tt_flag = '.'; 3477335fbe0fSMarek Lindner 3478335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3479335fbe0fSMarek Lindner "Routing TT_REQUEST to %pM [%c]\n", 3480335fbe0fSMarek Lindner dst, tt_flag); 3481335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 3482335fbe0fSMarek Lindner return NET_RX_DROP; 3483335fbe0fSMarek Lindner } 3484335fbe0fSMarek Lindner break; 3485335fbe0fSMarek Lindner case BATADV_TT_RESPONSE: 3486335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); 3487335fbe0fSMarek Lindner 3488335fbe0fSMarek Lindner if (batadv_is_my_mac(bat_priv, dst)) { 3489335fbe0fSMarek Lindner batadv_handle_tt_response(bat_priv, tt_data, 34907ea7b4a1SAntonio Quartulli src, tt_num_entries); 3491335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3492335fbe0fSMarek Lindner } 3493335fbe0fSMarek Lindner 3494335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 3495335fbe0fSMarek Lindner tt_flag = 'F'; 3496335fbe0fSMarek Lindner else 3497335fbe0fSMarek Lindner tt_flag = '.'; 3498335fbe0fSMarek Lindner 3499335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3500335fbe0fSMarek Lindner "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag); 3501335fbe0fSMarek Lindner 3502335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 3503335fbe0fSMarek Lindner return NET_RX_DROP; 3504335fbe0fSMarek Lindner } 3505335fbe0fSMarek Lindner 3506335fbe0fSMarek Lindner return NET_RX_SUCCESS; 3507335fbe0fSMarek Lindner } 3508335fbe0fSMarek Lindner 3509335fbe0fSMarek Lindner /** 3510122edaa0SMarek Lindner * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container 3511122edaa0SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3512122edaa0SMarek Lindner * @src: mac address of tt tvlv sender 3513122edaa0SMarek Lindner * @dst: mac address of tt tvlv recipient 3514122edaa0SMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 3515122edaa0SMarek Lindner * @tvlv_value_len: tvlv buffer length 3516122edaa0SMarek Lindner * 3517122edaa0SMarek Lindner * Returns NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS 3518122edaa0SMarek Lindner * otherwise. 3519122edaa0SMarek Lindner */ 3520122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 3521122edaa0SMarek Lindner uint8_t *src, uint8_t *dst, 3522122edaa0SMarek Lindner void *tvlv_value, 3523122edaa0SMarek Lindner uint16_t tvlv_value_len) 3524122edaa0SMarek Lindner { 3525122edaa0SMarek Lindner struct batadv_tvlv_roam_adv *roaming_adv; 3526122edaa0SMarek Lindner struct batadv_orig_node *orig_node = NULL; 3527122edaa0SMarek Lindner 3528122edaa0SMarek Lindner /* If this node is not the intended recipient of the 3529122edaa0SMarek Lindner * roaming advertisement the packet is forwarded 3530122edaa0SMarek Lindner * (the tvlv API will re-route the packet). 3531122edaa0SMarek Lindner */ 3532122edaa0SMarek Lindner if (!batadv_is_my_mac(bat_priv, dst)) 3533122edaa0SMarek Lindner return NET_RX_DROP; 3534122edaa0SMarek Lindner 3535122edaa0SMarek Lindner if (tvlv_value_len < sizeof(*roaming_adv)) 3536122edaa0SMarek Lindner goto out; 3537122edaa0SMarek Lindner 3538122edaa0SMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, src); 3539122edaa0SMarek Lindner if (!orig_node) 3540122edaa0SMarek Lindner goto out; 3541122edaa0SMarek Lindner 3542122edaa0SMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); 3543122edaa0SMarek Lindner roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; 3544122edaa0SMarek Lindner 3545122edaa0SMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 3546122edaa0SMarek Lindner "Received ROAMING_ADV from %pM (client %pM)\n", 3547122edaa0SMarek Lindner src, roaming_adv->client); 3548122edaa0SMarek Lindner 3549122edaa0SMarek Lindner batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, 3550c018ad3dSAntonio Quartulli ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, 3551122edaa0SMarek Lindner atomic_read(&orig_node->last_ttvn) + 1); 3552122edaa0SMarek Lindner 3553122edaa0SMarek Lindner out: 3554122edaa0SMarek Lindner if (orig_node) 3555122edaa0SMarek Lindner batadv_orig_node_free_ref(orig_node); 3556122edaa0SMarek Lindner return NET_RX_SUCCESS; 3557122edaa0SMarek Lindner } 3558122edaa0SMarek Lindner 3559122edaa0SMarek Lindner /** 3560e1bf0c14SMarek Lindner * batadv_tt_init - initialise the translation table internals 3561e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 3562e1bf0c14SMarek Lindner * 3563e1bf0c14SMarek Lindner * Return 0 on success or negative error number in case of failure. 3564e1bf0c14SMarek Lindner */ 3565e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv) 3566e1bf0c14SMarek Lindner { 3567e1bf0c14SMarek Lindner int ret; 3568e1bf0c14SMarek Lindner 35690eb01568SAntonio Quartulli /* synchronized flags must be remote */ 35700eb01568SAntonio Quartulli BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK)); 35710eb01568SAntonio Quartulli 3572e1bf0c14SMarek Lindner ret = batadv_tt_local_init(bat_priv); 3573e1bf0c14SMarek Lindner if (ret < 0) 3574e1bf0c14SMarek Lindner return ret; 3575e1bf0c14SMarek Lindner 3576e1bf0c14SMarek Lindner ret = batadv_tt_global_init(bat_priv); 3577e1bf0c14SMarek Lindner if (ret < 0) 3578e1bf0c14SMarek Lindner return ret; 3579e1bf0c14SMarek Lindner 3580e1bf0c14SMarek Lindner batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, 3581335fbe0fSMarek Lindner batadv_tt_tvlv_unicast_handler_v1, 3582335fbe0fSMarek Lindner BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); 3583e1bf0c14SMarek Lindner 3584122edaa0SMarek Lindner batadv_tvlv_handler_register(bat_priv, NULL, 3585122edaa0SMarek Lindner batadv_roam_tvlv_unicast_handler_v1, 3586122edaa0SMarek Lindner BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); 3587122edaa0SMarek Lindner 3588e1bf0c14SMarek Lindner INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); 3589e1bf0c14SMarek Lindner queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 3590e1bf0c14SMarek Lindner msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 3591e1bf0c14SMarek Lindner 3592e1bf0c14SMarek Lindner return 1; 3593e1bf0c14SMarek Lindner } 359442cb0befSAntonio Quartulli 359542cb0befSAntonio Quartulli /** 359642cb0befSAntonio Quartulli * batadv_tt_global_is_isolated - check if a client is marked as isolated 359742cb0befSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 359842cb0befSAntonio Quartulli * @addr: the mac address of the client 359942cb0befSAntonio Quartulli * @vid: the identifier of the VLAN where this client is connected 360042cb0befSAntonio Quartulli * 360142cb0befSAntonio Quartulli * Returns true if the client is marked with the TT_CLIENT_ISOLA flag, false 360242cb0befSAntonio Quartulli * otherwise 360342cb0befSAntonio Quartulli */ 360442cb0befSAntonio Quartulli bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, 360542cb0befSAntonio Quartulli const uint8_t *addr, unsigned short vid) 360642cb0befSAntonio Quartulli { 360742cb0befSAntonio Quartulli struct batadv_tt_global_entry *tt; 360842cb0befSAntonio Quartulli bool ret; 360942cb0befSAntonio Quartulli 361042cb0befSAntonio Quartulli tt = batadv_tt_global_hash_find(bat_priv, addr, vid); 361142cb0befSAntonio Quartulli if (!tt) 361242cb0befSAntonio Quartulli return false; 361342cb0befSAntonio Quartulli 361442cb0befSAntonio Quartulli ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA; 361542cb0befSAntonio Quartulli 361642cb0befSAntonio Quartulli batadv_tt_global_entry_free_ref(tt); 361742cb0befSAntonio Quartulli 361842cb0befSAntonio Quartulli return ret; 361942cb0befSAntonio Quartulli } 3620