10b873931SAntonio Quartulli /* Copyright (C) 2007-2013 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 15c6c8fea2SSven Eckelmann * along with this program; if not, write to the Free Software 16c6c8fea2SSven Eckelmann * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17c6c8fea2SSven Eckelmann * 02110-1301, USA 18c6c8fea2SSven Eckelmann */ 19c6c8fea2SSven Eckelmann 20c6c8fea2SSven Eckelmann #include "main.h" 21c6c8fea2SSven Eckelmann #include "translation-table.h" 22c6c8fea2SSven Eckelmann #include "soft-interface.h" 2332ae9b22SMarek Lindner #include "hard-interface.h" 24a73105b8SAntonio Quartulli #include "send.h" 25c6c8fea2SSven Eckelmann #include "hash.h" 26c6c8fea2SSven Eckelmann #include "originator.h" 27a73105b8SAntonio Quartulli #include "routing.h" 2820ff9d59SSimon Wunderlich #include "bridge_loop_avoidance.h" 29c6c8fea2SSven Eckelmann 30a73105b8SAntonio Quartulli #include <linux/crc16.h> 31a73105b8SAntonio Quartulli 32dec05074SAntonio Quartulli /* hash class keys */ 33dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_local_hash_lock_class_key; 34dec05074SAntonio Quartulli static struct lock_class_key batadv_tt_global_hash_lock_class_key; 35dec05074SAntonio Quartulli 3656303d34SSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, 3756303d34SSven Eckelmann struct batadv_orig_node *orig_node); 38a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work); 39a513088dSSven Eckelmann static void 4056303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); 4130cfd02bSAntonio Quartulli static void batadv_tt_global_del(struct batadv_priv *bat_priv, 4230cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 4330cfd02bSAntonio Quartulli const unsigned char *addr, 4430cfd02bSAntonio Quartulli const char *message, 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 527aadf889SMarek Lindner return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); 537aadf889SMarek Lindner } 547aadf889SMarek Lindner 5556303d34SSven Eckelmann static struct batadv_tt_common_entry * 565bf74e9cSSven Eckelmann batadv_tt_hash_find(struct batadv_hashtable *hash, const void *data) 577aadf889SMarek Lindner { 587aadf889SMarek Lindner struct hlist_head *head; 5956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 6056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry_tmp = NULL; 61c90681b8SAntonio Quartulli uint32_t index; 627aadf889SMarek Lindner 637aadf889SMarek Lindner if (!hash) 647aadf889SMarek Lindner return NULL; 657aadf889SMarek Lindner 66da641193SSven Eckelmann index = batadv_choose_orig(data, hash->size); 677aadf889SMarek Lindner head = &hash->table[index]; 687aadf889SMarek Lindner 697aadf889SMarek Lindner rcu_read_lock(); 70b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, head, hash_entry) { 711eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_common_entry, data)) 727aadf889SMarek Lindner continue; 737aadf889SMarek Lindner 7448100bacSAntonio Quartulli if (!atomic_inc_not_zero(&tt_common_entry->refcount)) 757683fdc1SAntonio Quartulli continue; 767683fdc1SAntonio Quartulli 7748100bacSAntonio Quartulli tt_common_entry_tmp = tt_common_entry; 787aadf889SMarek Lindner break; 797aadf889SMarek Lindner } 807aadf889SMarek Lindner rcu_read_unlock(); 817aadf889SMarek Lindner 8248100bacSAntonio Quartulli return tt_common_entry_tmp; 8348100bacSAntonio Quartulli } 8448100bacSAntonio Quartulli 8556303d34SSven Eckelmann static struct batadv_tt_local_entry * 8656303d34SSven Eckelmann batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data) 8748100bacSAntonio Quartulli { 8856303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 8956303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 9048100bacSAntonio Quartulli 91807736f6SSven Eckelmann tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, data); 9248100bacSAntonio Quartulli if (tt_common_entry) 9348100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 9456303d34SSven Eckelmann struct batadv_tt_local_entry, 9556303d34SSven Eckelmann common); 9648100bacSAntonio Quartulli return tt_local_entry; 977aadf889SMarek Lindner } 987aadf889SMarek Lindner 9956303d34SSven Eckelmann static struct batadv_tt_global_entry * 10056303d34SSven Eckelmann batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const void *data) 1017aadf889SMarek Lindner { 10256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 10356303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 1047aadf889SMarek Lindner 105807736f6SSven Eckelmann tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, data); 10648100bacSAntonio Quartulli if (tt_common_entry) 10748100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 10856303d34SSven Eckelmann struct batadv_tt_global_entry, 10956303d34SSven Eckelmann common); 11048100bacSAntonio Quartulli return tt_global_entry; 1117aadf889SMarek Lindner } 1127aadf889SMarek Lindner 113a513088dSSven Eckelmann static void 11456303d34SSven Eckelmann batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry) 1157683fdc1SAntonio Quartulli { 11648100bacSAntonio Quartulli if (atomic_dec_and_test(&tt_local_entry->common.refcount)) 11748100bacSAntonio Quartulli kfree_rcu(tt_local_entry, common.rcu); 1187683fdc1SAntonio Quartulli } 1197683fdc1SAntonio Quartulli 120a513088dSSven Eckelmann static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu) 121531027fcSSimon Wunderlich { 12256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 12356303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 124531027fcSSimon Wunderlich 12556303d34SSven Eckelmann tt_common_entry = container_of(rcu, struct batadv_tt_common_entry, rcu); 12656303d34SSven Eckelmann tt_global_entry = container_of(tt_common_entry, 12756303d34SSven Eckelmann struct batadv_tt_global_entry, common); 128531027fcSSimon Wunderlich 129531027fcSSimon Wunderlich kfree(tt_global_entry); 130531027fcSSimon Wunderlich } 131531027fcSSimon Wunderlich 132a513088dSSven Eckelmann static void 13356303d34SSven Eckelmann batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) 1347683fdc1SAntonio Quartulli { 135db08e6e5SSimon Wunderlich if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { 136a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 13748100bacSAntonio Quartulli call_rcu(&tt_global_entry->common.rcu, 138a513088dSSven Eckelmann batadv_tt_global_entry_free_rcu); 1397683fdc1SAntonio Quartulli } 140db08e6e5SSimon Wunderlich } 141db08e6e5SSimon Wunderlich 142a513088dSSven Eckelmann static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) 143db08e6e5SSimon Wunderlich { 14456303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 145db08e6e5SSimon Wunderlich 14656303d34SSven Eckelmann orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu); 14772822225SLinus Lüssing 14872822225SLinus Lüssing /* We are in an rcu callback here, therefore we cannot use 14972822225SLinus Lüssing * batadv_orig_node_free_ref() and its call_rcu(): 15072822225SLinus Lüssing * An rcu_barrier() wouldn't wait for that to finish 15172822225SLinus Lüssing */ 15272822225SLinus Lüssing batadv_orig_node_free_ref_now(orig_entry->orig_node); 153db08e6e5SSimon Wunderlich kfree(orig_entry); 154db08e6e5SSimon Wunderlich } 155db08e6e5SSimon Wunderlich 156a513088dSSven Eckelmann static void 15756303d34SSven Eckelmann batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) 158db08e6e5SSimon Wunderlich { 159d657e621SAntonio Quartulli if (!atomic_dec_and_test(&orig_entry->refcount)) 160d657e621SAntonio Quartulli return; 16129cb99deSAntonio Quartulli /* to avoid race conditions, immediately decrease the tt counter */ 16229cb99deSAntonio Quartulli atomic_dec(&orig_entry->orig_node->tt_size); 163a513088dSSven Eckelmann call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); 164db08e6e5SSimon Wunderlich } 1657683fdc1SAntonio Quartulli 1663abe4adbSAntonio Quartulli /** 1673abe4adbSAntonio Quartulli * batadv_tt_local_event - store a local TT event (ADD/DEL) 1683abe4adbSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 1693abe4adbSAntonio Quartulli * @tt_local_entry: the TT entry involved in the event 1703abe4adbSAntonio Quartulli * @event_flags: flags to store in the event structure 1713abe4adbSAntonio Quartulli */ 17256303d34SSven Eckelmann static void batadv_tt_local_event(struct batadv_priv *bat_priv, 1733abe4adbSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry, 1743abe4adbSAntonio Quartulli uint8_t event_flags) 175a73105b8SAntonio Quartulli { 17656303d34SSven Eckelmann struct batadv_tt_change_node *tt_change_node, *entry, *safe; 1773abe4adbSAntonio Quartulli struct batadv_tt_common_entry *common = &tt_local_entry->common; 1783abe4adbSAntonio Quartulli uint8_t flags = common->flags | event_flags; 1793b643de5SAntonio Quartulli bool event_removed = false; 1803b643de5SAntonio Quartulli bool del_op_requested, del_op_entry; 181a73105b8SAntonio Quartulli 182a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 183a73105b8SAntonio Quartulli 184a73105b8SAntonio Quartulli if (!tt_change_node) 185a73105b8SAntonio Quartulli return; 186a73105b8SAntonio Quartulli 187ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 1883abe4adbSAntonio Quartulli memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN); 189a73105b8SAntonio Quartulli 190acd34afaSSven Eckelmann del_op_requested = flags & BATADV_TT_CLIENT_DEL; 1913b643de5SAntonio Quartulli 1923b643de5SAntonio Quartulli /* check for ADD+DEL or DEL+ADD events */ 193807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 194807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 1953b643de5SAntonio Quartulli list) { 1963abe4adbSAntonio Quartulli if (!batadv_compare_eth(entry->change.addr, common->addr)) 1973b643de5SAntonio Quartulli continue; 1983b643de5SAntonio Quartulli 1993b643de5SAntonio Quartulli /* DEL+ADD in the same orig interval have no effect and can be 2003b643de5SAntonio Quartulli * removed to avoid silly behaviour on the receiver side. The 2013b643de5SAntonio Quartulli * other way around (ADD+DEL) can happen in case of roaming of 2023b643de5SAntonio Quartulli * a client still in the NEW state. Roaming of NEW clients is 2033b643de5SAntonio Quartulli * now possible due to automatically recognition of "temporary" 2043b643de5SAntonio Quartulli * clients 2053b643de5SAntonio Quartulli */ 206acd34afaSSven Eckelmann del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; 2073b643de5SAntonio Quartulli if (!del_op_requested && del_op_entry) 2083b643de5SAntonio Quartulli goto del; 2093b643de5SAntonio Quartulli if (del_op_requested && !del_op_entry) 2103b643de5SAntonio Quartulli goto del; 2113b643de5SAntonio Quartulli continue; 2123b643de5SAntonio Quartulli del: 2133b643de5SAntonio Quartulli list_del(&entry->list); 2143b643de5SAntonio Quartulli kfree(entry); 215155e4e12SJesper Juhl kfree(tt_change_node); 2163b643de5SAntonio Quartulli event_removed = true; 2173b643de5SAntonio Quartulli goto unlock; 2183b643de5SAntonio Quartulli } 2193b643de5SAntonio Quartulli 220a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 221807736f6SSven Eckelmann list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list); 2223b643de5SAntonio Quartulli 2233b643de5SAntonio Quartulli unlock: 224807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 225a73105b8SAntonio Quartulli 2263b643de5SAntonio Quartulli if (event_removed) 227807736f6SSven Eckelmann atomic_dec(&bat_priv->tt.local_changes); 2283b643de5SAntonio Quartulli else 229807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.local_changes); 230a73105b8SAntonio Quartulli } 231a73105b8SAntonio Quartulli 23208c36d3eSSven Eckelmann int batadv_tt_len(int changes_num) 233a73105b8SAntonio Quartulli { 23496412690SSven Eckelmann return changes_num * sizeof(struct batadv_tt_change); 235a73105b8SAntonio Quartulli } 236a73105b8SAntonio Quartulli 23756303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv) 238c6c8fea2SSven Eckelmann { 239807736f6SSven Eckelmann if (bat_priv->tt.local_hash) 2405346c35eSSven Eckelmann return 0; 241c6c8fea2SSven Eckelmann 242807736f6SSven Eckelmann bat_priv->tt.local_hash = batadv_hash_new(1024); 243c6c8fea2SSven Eckelmann 244807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 2455346c35eSSven Eckelmann return -ENOMEM; 246c6c8fea2SSven Eckelmann 247dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.local_hash, 248dec05074SAntonio Quartulli &batadv_tt_local_hash_lock_class_key); 249dec05074SAntonio Quartulli 2505346c35eSSven Eckelmann return 0; 251c6c8fea2SSven Eckelmann } 252c6c8fea2SSven Eckelmann 253068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv, 254068ee6e2SAntonio Quartulli struct batadv_tt_global_entry *tt_global, 255068ee6e2SAntonio Quartulli const char *message) 256068ee6e2SAntonio Quartulli { 257068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 258068ee6e2SAntonio Quartulli "Deleting global tt entry %pM: %s\n", 259068ee6e2SAntonio Quartulli tt_global->common.addr, message); 260068ee6e2SAntonio Quartulli 261068ee6e2SAntonio Quartulli batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, 262068ee6e2SAntonio Quartulli batadv_choose_orig, tt_global->common.addr); 263068ee6e2SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 264068ee6e2SAntonio Quartulli } 265068ee6e2SAntonio Quartulli 26608c36d3eSSven Eckelmann void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 267bc279080SAntonio Quartulli int ifindex) 268c6c8fea2SSven Eckelmann { 26956303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(soft_iface); 270170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local; 271170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global; 272db08e6e5SSimon Wunderlich struct hlist_head *head; 27356303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 27480b3f58cSSimon Wunderlich int hash_added; 275068ee6e2SAntonio Quartulli bool roamed_back = false; 276c6c8fea2SSven Eckelmann 27747c94655SAntonio Quartulli tt_local = batadv_tt_local_hash_find(bat_priv, addr); 278068ee6e2SAntonio Quartulli tt_global = batadv_tt_global_hash_find(bat_priv, addr); 279c6c8fea2SSven Eckelmann 28047c94655SAntonio Quartulli if (tt_local) { 28147c94655SAntonio Quartulli tt_local->last_seen = jiffies; 282068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { 283068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 284068ee6e2SAntonio Quartulli "Re-adding pending client %pM\n", addr); 285068ee6e2SAntonio Quartulli /* whatever the reason why the PENDING flag was set, 286068ee6e2SAntonio Quartulli * this is a client which was enqueued to be removed in 287068ee6e2SAntonio Quartulli * this orig_interval. Since it popped up again, the 288068ee6e2SAntonio Quartulli * flag can be reset like it was never enqueued 289068ee6e2SAntonio Quartulli */ 29047c94655SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; 291068ee6e2SAntonio Quartulli goto add_event; 292068ee6e2SAntonio Quartulli } 293068ee6e2SAntonio Quartulli 294068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { 295068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 296068ee6e2SAntonio Quartulli "Roaming client %pM came back to its original location\n", 297068ee6e2SAntonio Quartulli addr); 298068ee6e2SAntonio Quartulli /* the ROAM flag is set because this client roamed away 299068ee6e2SAntonio Quartulli * and the node got a roaming_advertisement message. Now 300068ee6e2SAntonio Quartulli * that the client popped up again at its original 301068ee6e2SAntonio Quartulli * location such flag can be unset 302068ee6e2SAntonio Quartulli */ 303068ee6e2SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; 304068ee6e2SAntonio Quartulli roamed_back = true; 305068ee6e2SAntonio Quartulli } 306068ee6e2SAntonio Quartulli goto check_roaming; 307c6c8fea2SSven Eckelmann } 308c6c8fea2SSven Eckelmann 30947c94655SAntonio Quartulli tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); 31047c94655SAntonio Quartulli if (!tt_local) 3117683fdc1SAntonio Quartulli goto out; 312a73105b8SAntonio Quartulli 31339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 314a73105b8SAntonio Quartulli "Creating new local tt entry: %pM (ttvn: %d)\n", addr, 315807736f6SSven Eckelmann (uint8_t)atomic_read(&bat_priv->tt.vn)); 316c6c8fea2SSven Eckelmann 31747c94655SAntonio Quartulli memcpy(tt_local->common.addr, addr, ETH_ALEN); 3188425ec6aSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 3198425ec6aSAntonio Quartulli * a full table response going out before the next ttvn increment 3208425ec6aSAntonio Quartulli * (consistency check) 3218425ec6aSAntonio Quartulli */ 3228425ec6aSAntonio Quartulli tt_local->common.flags = BATADV_TT_CLIENT_NEW; 3239563877eSSven Eckelmann if (batadv_is_wifi_iface(ifindex)) 32447c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 32547c94655SAntonio Quartulli atomic_set(&tt_local->common.refcount, 2); 32647c94655SAntonio Quartulli tt_local->last_seen = jiffies; 32747c94655SAntonio Quartulli tt_local->common.added_at = tt_local->last_seen; 328c6c8fea2SSven Eckelmann 329c6c8fea2SSven Eckelmann /* the batman interface mac address should never be purged */ 3301eda58bfSSven Eckelmann if (batadv_compare_eth(addr, soft_iface->dev_addr)) 33147c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; 332c6c8fea2SSven Eckelmann 333807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, 33447c94655SAntonio Quartulli batadv_choose_orig, &tt_local->common, 33547c94655SAntonio Quartulli &tt_local->common.hash_entry); 33680b3f58cSSimon Wunderlich 33780b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 33880b3f58cSSimon Wunderlich /* remove the reference for the hash */ 33947c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 34080b3f58cSSimon Wunderlich goto out; 34180b3f58cSSimon Wunderlich } 34280b3f58cSSimon Wunderlich 343068ee6e2SAntonio Quartulli add_event: 3443abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 345ff66c975SAntonio Quartulli 346068ee6e2SAntonio Quartulli check_roaming: 347068ee6e2SAntonio Quartulli /* Check whether it is a roaming, but don't do anything if the roaming 348068ee6e2SAntonio Quartulli * process has already been handled 349068ee6e2SAntonio Quartulli */ 350068ee6e2SAntonio Quartulli if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { 351db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 35247c94655SAntonio Quartulli head = &tt_global->orig_list; 353db08e6e5SSimon Wunderlich rcu_read_lock(); 354b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 35547c94655SAntonio Quartulli batadv_send_roam_adv(bat_priv, tt_global->common.addr, 356db08e6e5SSimon Wunderlich orig_entry->orig_node); 357db08e6e5SSimon Wunderlich } 358db08e6e5SSimon Wunderlich rcu_read_unlock(); 359068ee6e2SAntonio Quartulli if (roamed_back) { 360068ee6e2SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global, 361068ee6e2SAntonio Quartulli "Roaming canceled"); 362068ee6e2SAntonio Quartulli tt_global = NULL; 363068ee6e2SAntonio Quartulli } else { 364db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 365db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 366db08e6e5SSimon Wunderlich */ 36747c94655SAntonio Quartulli tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; 36847c94655SAntonio Quartulli tt_global->roam_at = jiffies; 3697683fdc1SAntonio Quartulli } 370068ee6e2SAntonio Quartulli } 371068ee6e2SAntonio Quartulli 3727683fdc1SAntonio Quartulli out: 37347c94655SAntonio Quartulli if (tt_local) 37447c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 37547c94655SAntonio Quartulli if (tt_global) 37647c94655SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 377c6c8fea2SSven Eckelmann } 378c6c8fea2SSven Eckelmann 379a513088dSSven Eckelmann static void batadv_tt_realloc_packet_buff(unsigned char **packet_buff, 380a513088dSSven Eckelmann int *packet_buff_len, 381a513088dSSven Eckelmann int min_packet_len, 382be9aa4c1SMarek Lindner int new_packet_len) 383c6c8fea2SSven Eckelmann { 384be9aa4c1SMarek Lindner unsigned char *new_buff; 385c6c8fea2SSven Eckelmann 386be9aa4c1SMarek Lindner new_buff = kmalloc(new_packet_len, GFP_ATOMIC); 387be9aa4c1SMarek Lindner 388be9aa4c1SMarek Lindner /* keep old buffer if kmalloc should fail */ 389be9aa4c1SMarek Lindner if (new_buff) { 390be9aa4c1SMarek Lindner memcpy(new_buff, *packet_buff, min_packet_len); 391be9aa4c1SMarek Lindner kfree(*packet_buff); 392be9aa4c1SMarek Lindner *packet_buff = new_buff; 393be9aa4c1SMarek Lindner *packet_buff_len = new_packet_len; 394be9aa4c1SMarek Lindner } 395be9aa4c1SMarek Lindner } 396be9aa4c1SMarek Lindner 39756303d34SSven Eckelmann static void batadv_tt_prepare_packet_buff(struct batadv_priv *bat_priv, 398be9aa4c1SMarek Lindner unsigned char **packet_buff, 399a513088dSSven Eckelmann int *packet_buff_len, 400a513088dSSven Eckelmann int min_packet_len) 401be9aa4c1SMarek Lindner { 402be9aa4c1SMarek Lindner int req_len; 403be9aa4c1SMarek Lindner 404be9aa4c1SMarek Lindner req_len = min_packet_len; 405807736f6SSven Eckelmann req_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes)); 406be9aa4c1SMarek Lindner 407be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 408be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 409be9aa4c1SMarek Lindner */ 410736292c2SMarek Lindner if (req_len > bat_priv->soft_iface->mtu) 411be9aa4c1SMarek Lindner req_len = min_packet_len; 412be9aa4c1SMarek Lindner 413a513088dSSven Eckelmann batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, 414be9aa4c1SMarek Lindner min_packet_len, req_len); 415be9aa4c1SMarek Lindner } 416be9aa4c1SMarek Lindner 41756303d34SSven Eckelmann static int batadv_tt_changes_fill_buff(struct batadv_priv *bat_priv, 418be9aa4c1SMarek Lindner unsigned char **packet_buff, 419a513088dSSven Eckelmann int *packet_buff_len, 420a513088dSSven Eckelmann int min_packet_len) 421be9aa4c1SMarek Lindner { 42256303d34SSven Eckelmann struct batadv_tt_change_node *entry, *safe; 423be9aa4c1SMarek Lindner int count = 0, tot_changes = 0, new_len; 424be9aa4c1SMarek Lindner unsigned char *tt_buff; 425be9aa4c1SMarek Lindner 426a513088dSSven Eckelmann batadv_tt_prepare_packet_buff(bat_priv, packet_buff, 427be9aa4c1SMarek Lindner packet_buff_len, min_packet_len); 428be9aa4c1SMarek Lindner 429be9aa4c1SMarek Lindner new_len = *packet_buff_len - min_packet_len; 430be9aa4c1SMarek Lindner tt_buff = *packet_buff + min_packet_len; 431be9aa4c1SMarek Lindner 432be9aa4c1SMarek Lindner if (new_len > 0) 43308c36d3eSSven Eckelmann tot_changes = new_len / batadv_tt_len(1); 434c6c8fea2SSven Eckelmann 435807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 436807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 437c6c8fea2SSven Eckelmann 438807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 439a73105b8SAntonio Quartulli list) { 440a73105b8SAntonio Quartulli if (count < tot_changes) { 44108c36d3eSSven Eckelmann memcpy(tt_buff + batadv_tt_len(count), 44296412690SSven Eckelmann &entry->change, sizeof(struct batadv_tt_change)); 443c6c8fea2SSven Eckelmann count++; 444c6c8fea2SSven Eckelmann } 445a73105b8SAntonio Quartulli list_del(&entry->list); 446a73105b8SAntonio Quartulli kfree(entry); 447c6c8fea2SSven Eckelmann } 448807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 449c6c8fea2SSven Eckelmann 450a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 451807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 452807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 453807736f6SSven Eckelmann bat_priv->tt.last_changeset_len = 0; 454807736f6SSven Eckelmann bat_priv->tt.last_changeset = NULL; 455be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 456be9aa4c1SMarek Lindner if (new_len > 0) { 457be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 458a73105b8SAntonio Quartulli * instead of providing the diff 459a73105b8SAntonio Quartulli */ 460807736f6SSven Eckelmann bat_priv->tt.last_changeset = kmalloc(new_len, GFP_ATOMIC); 461807736f6SSven Eckelmann if (bat_priv->tt.last_changeset) { 462807736f6SSven Eckelmann memcpy(bat_priv->tt.last_changeset, tt_buff, new_len); 463807736f6SSven Eckelmann bat_priv->tt.last_changeset_len = new_len; 464a73105b8SAntonio Quartulli } 465a73105b8SAntonio Quartulli } 466807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 467c6c8fea2SSven Eckelmann 46808ad76ecSMarek Lindner return count; 469c6c8fea2SSven Eckelmann } 470c6c8fea2SSven Eckelmann 47108c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) 472c6c8fea2SSven Eckelmann { 473c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 47456303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 475807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 47656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 47785766a82SAntonio Quartulli struct batadv_tt_local_entry *tt_local; 47856303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 479c6c8fea2SSven Eckelmann struct hlist_head *head; 480c90681b8SAntonio Quartulli uint32_t i; 48185766a82SAntonio Quartulli int last_seen_secs; 48285766a82SAntonio Quartulli int last_seen_msecs; 48385766a82SAntonio Quartulli unsigned long last_seen_jiffies; 48485766a82SAntonio Quartulli bool no_purge; 48585766a82SAntonio Quartulli uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE; 486c6c8fea2SSven Eckelmann 48730da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 48830da63a6SMarek Lindner if (!primary_if) 48932ae9b22SMarek Lindner goto out; 490c6c8fea2SSven Eckelmann 49186ceb360SSven Eckelmann seq_printf(seq, 492f9d8a537SAntonio Quartulli "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.4x):\n", 493f9d8a537SAntonio Quartulli net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn), 494f9d8a537SAntonio Quartulli bat_priv->tt.local_crc); 49585766a82SAntonio Quartulli seq_printf(seq, " %-13s %-7s %-10s\n", "Client", "Flags", 49685766a82SAntonio Quartulli "Last seen"); 497c6c8fea2SSven Eckelmann 498c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 499c6c8fea2SSven Eckelmann head = &hash->table[i]; 500c6c8fea2SSven Eckelmann 5017aadf889SMarek Lindner rcu_read_lock(); 502b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 5037aadf889SMarek Lindner head, hash_entry) { 50485766a82SAntonio Quartulli tt_local = container_of(tt_common_entry, 50585766a82SAntonio Quartulli struct batadv_tt_local_entry, 50685766a82SAntonio Quartulli common); 50785766a82SAntonio Quartulli last_seen_jiffies = jiffies - tt_local->last_seen; 50885766a82SAntonio Quartulli last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 50985766a82SAntonio Quartulli last_seen_secs = last_seen_msecs / 1000; 51085766a82SAntonio Quartulli last_seen_msecs = last_seen_msecs % 1000; 51185766a82SAntonio Quartulli 51285766a82SAntonio Quartulli no_purge = tt_common_entry->flags & np_flag; 51385766a82SAntonio Quartulli 51485766a82SAntonio Quartulli seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n", 51548100bacSAntonio Quartulli tt_common_entry->addr, 51648100bacSAntonio Quartulli (tt_common_entry->flags & 517acd34afaSSven Eckelmann BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 51885766a82SAntonio Quartulli no_purge ? 'P' : '.', 51948100bacSAntonio Quartulli (tt_common_entry->flags & 520acd34afaSSven Eckelmann BATADV_TT_CLIENT_NEW ? 'N' : '.'), 52148100bacSAntonio Quartulli (tt_common_entry->flags & 522acd34afaSSven Eckelmann BATADV_TT_CLIENT_PENDING ? 'X' : '.'), 52348100bacSAntonio Quartulli (tt_common_entry->flags & 52485766a82SAntonio Quartulli BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 525a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_secs, 526a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_msecs); 527c6c8fea2SSven Eckelmann } 5287aadf889SMarek Lindner rcu_read_unlock(); 529c6c8fea2SSven Eckelmann } 53032ae9b22SMarek Lindner out: 53132ae9b22SMarek Lindner if (primary_if) 532e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 53330da63a6SMarek Lindner return 0; 534c6c8fea2SSven Eckelmann } 535c6c8fea2SSven Eckelmann 53656303d34SSven Eckelmann static void 53756303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv, 53856303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry, 539c566dbbeSAntonio Quartulli uint16_t flags, const char *message) 540c6c8fea2SSven Eckelmann { 5413abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, flags); 542c6c8fea2SSven Eckelmann 543015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 544015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 5459cfc7bd6SSven Eckelmann * response issued before the net ttvn increment (consistency check) 5469cfc7bd6SSven Eckelmann */ 547acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; 548c566dbbeSAntonio Quartulli 54939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 55086ceb360SSven Eckelmann "Local tt entry (%pM) pending to be removed: %s\n", 55186ceb360SSven Eckelmann tt_local_entry->common.addr, message); 552c6c8fea2SSven Eckelmann } 553c6c8fea2SSven Eckelmann 5547f91d06cSAntonio Quartulli /** 5557f91d06cSAntonio Quartulli * batadv_tt_local_remove - logically remove an entry from the local table 5567f91d06cSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 5577f91d06cSAntonio Quartulli * @addr: the MAC address of the client to remove 5587f91d06cSAntonio Quartulli * @message: message to append to the log on deletion 5597f91d06cSAntonio Quartulli * @roaming: true if the deletion is due to a roaming event 5607f91d06cSAntonio Quartulli * 5617f91d06cSAntonio Quartulli * Returns the flags assigned to the local entry before being deleted 5627f91d06cSAntonio Quartulli */ 5637f91d06cSAntonio Quartulli uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, 5647f91d06cSAntonio Quartulli const uint8_t *addr, const char *message, 5657f91d06cSAntonio Quartulli bool roaming) 566c6c8fea2SSven Eckelmann { 567170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 5687f91d06cSAntonio Quartulli uint16_t flags, curr_flags = BATADV_NO_FLAGS; 569c6c8fea2SSven Eckelmann 570a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 5717683fdc1SAntonio Quartulli if (!tt_local_entry) 5727683fdc1SAntonio Quartulli goto out; 5737683fdc1SAntonio Quartulli 5747f91d06cSAntonio Quartulli curr_flags = tt_local_entry->common.flags; 5757f91d06cSAntonio Quartulli 576acd34afaSSven Eckelmann flags = BATADV_TT_CLIENT_DEL; 577068ee6e2SAntonio Quartulli /* if this global entry addition is due to a roaming, the node has to 578068ee6e2SAntonio Quartulli * mark the local entry as "roamed" in order to correctly reroute 579068ee6e2SAntonio Quartulli * packets later 580068ee6e2SAntonio Quartulli */ 5817c1fd91dSAntonio Quartulli if (roaming) { 582acd34afaSSven Eckelmann flags |= BATADV_TT_CLIENT_ROAM; 5837c1fd91dSAntonio Quartulli /* mark the local client as ROAMed */ 5847c1fd91dSAntonio Quartulli tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 5857c1fd91dSAntonio Quartulli } 58642d0b044SSven Eckelmann 587068ee6e2SAntonio Quartulli if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { 588068ee6e2SAntonio Quartulli batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, 589068ee6e2SAntonio Quartulli message); 590068ee6e2SAntonio Quartulli goto out; 591068ee6e2SAntonio Quartulli } 592068ee6e2SAntonio Quartulli /* if this client has been added right now, it is possible to 593068ee6e2SAntonio Quartulli * immediately purge it 594068ee6e2SAntonio Quartulli */ 5953abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); 596068ee6e2SAntonio Quartulli hlist_del_rcu(&tt_local_entry->common.hash_entry); 597068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 5987f91d06cSAntonio Quartulli 5997683fdc1SAntonio Quartulli out: 6007683fdc1SAntonio Quartulli if (tt_local_entry) 601a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 6027f91d06cSAntonio Quartulli 6037f91d06cSAntonio Quartulli return curr_flags; 604c6c8fea2SSven Eckelmann } 605c6c8fea2SSven Eckelmann 60656303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 607acd34afaSSven Eckelmann struct hlist_head *head) 608c6c8fea2SSven Eckelmann { 60956303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 61056303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 611b67bfe0dSSasha Levin struct hlist_node *node_tmp; 612acd34afaSSven Eckelmann 613b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, 614acd34afaSSven Eckelmann hash_entry) { 615acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common_entry, 61656303d34SSven Eckelmann struct batadv_tt_local_entry, 61756303d34SSven Eckelmann common); 618acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) 619acd34afaSSven Eckelmann continue; 620acd34afaSSven Eckelmann 621acd34afaSSven Eckelmann /* entry already marked for deletion */ 622acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 623acd34afaSSven Eckelmann continue; 624acd34afaSSven Eckelmann 625acd34afaSSven Eckelmann if (!batadv_has_timed_out(tt_local_entry->last_seen, 626acd34afaSSven Eckelmann BATADV_TT_LOCAL_TIMEOUT)) 627acd34afaSSven Eckelmann continue; 628acd34afaSSven Eckelmann 629acd34afaSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 630acd34afaSSven Eckelmann BATADV_TT_CLIENT_DEL, "timed out"); 631acd34afaSSven Eckelmann } 632acd34afaSSven Eckelmann } 633acd34afaSSven Eckelmann 63456303d34SSven Eckelmann static void batadv_tt_local_purge(struct batadv_priv *bat_priv) 635acd34afaSSven Eckelmann { 636807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 637c6c8fea2SSven Eckelmann struct hlist_head *head; 6387683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 639c90681b8SAntonio Quartulli uint32_t i; 640c6c8fea2SSven Eckelmann 641c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 642c6c8fea2SSven Eckelmann head = &hash->table[i]; 6437683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 644c6c8fea2SSven Eckelmann 6457683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 646acd34afaSSven Eckelmann batadv_tt_local_purge_list(bat_priv, head); 6477683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 648c6c8fea2SSven Eckelmann } 649c6c8fea2SSven Eckelmann } 650c6c8fea2SSven Eckelmann 65156303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) 652c6c8fea2SSven Eckelmann { 6535bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 654a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 65556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 65656303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 657b67bfe0dSSasha Levin struct hlist_node *node_tmp; 6587683fdc1SAntonio Quartulli struct hlist_head *head; 659c90681b8SAntonio Quartulli uint32_t i; 660a73105b8SAntonio Quartulli 661807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 662c6c8fea2SSven Eckelmann return; 663c6c8fea2SSven Eckelmann 664807736f6SSven Eckelmann hash = bat_priv->tt.local_hash; 665a73105b8SAntonio Quartulli 666a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 667a73105b8SAntonio Quartulli head = &hash->table[i]; 668a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 669a73105b8SAntonio Quartulli 670a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 671b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 672a73105b8SAntonio Quartulli head, hash_entry) { 673b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 67456303d34SSven Eckelmann tt_local = container_of(tt_common_entry, 67556303d34SSven Eckelmann struct batadv_tt_local_entry, 67648100bacSAntonio Quartulli common); 67756303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 678a73105b8SAntonio Quartulli } 679a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 680a73105b8SAntonio Quartulli } 681a73105b8SAntonio Quartulli 6821a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 683a73105b8SAntonio Quartulli 684807736f6SSven Eckelmann bat_priv->tt.local_hash = NULL; 685c6c8fea2SSven Eckelmann } 686c6c8fea2SSven Eckelmann 68756303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv) 688c6c8fea2SSven Eckelmann { 689807736f6SSven Eckelmann if (bat_priv->tt.global_hash) 6905346c35eSSven Eckelmann return 0; 691c6c8fea2SSven Eckelmann 692807736f6SSven Eckelmann bat_priv->tt.global_hash = batadv_hash_new(1024); 693c6c8fea2SSven Eckelmann 694807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 6955346c35eSSven Eckelmann return -ENOMEM; 696c6c8fea2SSven Eckelmann 697dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.global_hash, 698dec05074SAntonio Quartulli &batadv_tt_global_hash_lock_class_key); 699dec05074SAntonio Quartulli 7005346c35eSSven Eckelmann return 0; 701c6c8fea2SSven Eckelmann } 702c6c8fea2SSven Eckelmann 70356303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) 704a73105b8SAntonio Quartulli { 70556303d34SSven Eckelmann struct batadv_tt_change_node *entry, *safe; 706a73105b8SAntonio Quartulli 707807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 708a73105b8SAntonio Quartulli 709807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 710a73105b8SAntonio Quartulli list) { 711a73105b8SAntonio Quartulli list_del(&entry->list); 712a73105b8SAntonio Quartulli kfree(entry); 713a73105b8SAntonio Quartulli } 714a73105b8SAntonio Quartulli 715807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 716807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 717a73105b8SAntonio Quartulli } 718a73105b8SAntonio Quartulli 719d657e621SAntonio Quartulli /* retrieves the orig_tt_list_entry belonging to orig_node from the 720d657e621SAntonio Quartulli * batadv_tt_global_entry list 721d657e621SAntonio Quartulli * 722d657e621SAntonio Quartulli * returns it with an increased refcounter, NULL if not found 723d657e621SAntonio Quartulli */ 724d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry * 725d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, 726d657e621SAntonio Quartulli const struct batadv_orig_node *orig_node) 727d657e621SAntonio Quartulli { 728d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; 729d657e621SAntonio Quartulli const struct hlist_head *head; 730d657e621SAntonio Quartulli 731d657e621SAntonio Quartulli rcu_read_lock(); 732d657e621SAntonio Quartulli head = &entry->orig_list; 733b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { 734d657e621SAntonio Quartulli if (tmp_orig_entry->orig_node != orig_node) 735d657e621SAntonio Quartulli continue; 736d657e621SAntonio Quartulli if (!atomic_inc_not_zero(&tmp_orig_entry->refcount)) 737d657e621SAntonio Quartulli continue; 738d657e621SAntonio Quartulli 739d657e621SAntonio Quartulli orig_entry = tmp_orig_entry; 740d657e621SAntonio Quartulli break; 741d657e621SAntonio Quartulli } 742d657e621SAntonio Quartulli rcu_read_unlock(); 743d657e621SAntonio Quartulli 744d657e621SAntonio Quartulli return orig_entry; 745d657e621SAntonio Quartulli } 746d657e621SAntonio Quartulli 747db08e6e5SSimon Wunderlich /* find out if an orig_node is already in the list of a tt_global_entry. 748d657e621SAntonio Quartulli * returns true if found, false otherwise 749db08e6e5SSimon Wunderlich */ 75056303d34SSven Eckelmann static bool 75156303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, 75256303d34SSven Eckelmann const struct batadv_orig_node *orig_node) 753db08e6e5SSimon Wunderlich { 754d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *orig_entry; 755db08e6e5SSimon Wunderlich bool found = false; 756db08e6e5SSimon Wunderlich 757d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); 758d657e621SAntonio Quartulli if (orig_entry) { 759db08e6e5SSimon Wunderlich found = true; 760d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 761db08e6e5SSimon Wunderlich } 762d657e621SAntonio Quartulli 763db08e6e5SSimon Wunderlich return found; 764db08e6e5SSimon Wunderlich } 765db08e6e5SSimon Wunderlich 766a513088dSSven Eckelmann static void 767d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, 76856303d34SSven Eckelmann struct batadv_orig_node *orig_node, int ttvn) 769db08e6e5SSimon Wunderlich { 77056303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 771db08e6e5SSimon Wunderlich 772d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); 77330cfd02bSAntonio Quartulli if (orig_entry) { 77430cfd02bSAntonio Quartulli /* refresh the ttvn: the current value could be a bogus one that 77530cfd02bSAntonio Quartulli * was added during a "temporary client detection" 77630cfd02bSAntonio Quartulli */ 77730cfd02bSAntonio Quartulli orig_entry->ttvn = ttvn; 778d657e621SAntonio Quartulli goto out; 77930cfd02bSAntonio Quartulli } 780d657e621SAntonio Quartulli 781db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 782db08e6e5SSimon Wunderlich if (!orig_entry) 783d657e621SAntonio Quartulli goto out; 784db08e6e5SSimon Wunderlich 785db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 786db08e6e5SSimon Wunderlich atomic_inc(&orig_node->refcount); 787db08e6e5SSimon Wunderlich atomic_inc(&orig_node->tt_size); 788db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 789db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 790d657e621SAntonio Quartulli atomic_set(&orig_entry->refcount, 2); 791db08e6e5SSimon Wunderlich 792d657e621SAntonio Quartulli spin_lock_bh(&tt_global->list_lock); 793db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 794d657e621SAntonio Quartulli &tt_global->orig_list); 795d657e621SAntonio Quartulli spin_unlock_bh(&tt_global->list_lock); 796d657e621SAntonio Quartulli out: 797d657e621SAntonio Quartulli if (orig_entry) 798d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 799db08e6e5SSimon Wunderlich } 800db08e6e5SSimon Wunderlich 801d4ff40f6SAntonio Quartulli /** 802d4ff40f6SAntonio Quartulli * batadv_tt_global_add - add a new TT global entry or update an existing one 803d4ff40f6SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 804d4ff40f6SAntonio Quartulli * @orig_node: the originator announcing the client 805d4ff40f6SAntonio Quartulli * @tt_addr: the mac address of the non-mesh client 806d4ff40f6SAntonio Quartulli * @flags: TT flags that have to be set for this non-mesh client 807d4ff40f6SAntonio Quartulli * @ttvn: the tt version number ever announcing this non-mesh client 808d4ff40f6SAntonio Quartulli * 809d4ff40f6SAntonio Quartulli * Add a new TT global entry for the given originator. If the entry already 810d4ff40f6SAntonio Quartulli * exists add a new reference to the given originator (a global entry can have 811d4ff40f6SAntonio Quartulli * references to multiple originators) and adjust the flags attribute to reflect 812d4ff40f6SAntonio Quartulli * the function argument. 813d4ff40f6SAntonio Quartulli * If a TT local entry exists for this non-mesh client remove it. 814d4ff40f6SAntonio Quartulli * 815d4ff40f6SAntonio Quartulli * The caller must hold orig_node refcount. 816d4ff40f6SAntonio Quartulli */ 81756303d34SSven Eckelmann int batadv_tt_global_add(struct batadv_priv *bat_priv, 81856303d34SSven Eckelmann struct batadv_orig_node *orig_node, 819d4ff40f6SAntonio Quartulli const unsigned char *tt_addr, uint16_t flags, 820d4f44692SAntonio Quartulli uint8_t ttvn) 821c6c8fea2SSven Eckelmann { 822170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 823170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 8247683fdc1SAntonio Quartulli int ret = 0; 82580b3f58cSSimon Wunderlich int hash_added; 82656303d34SSven Eckelmann struct batadv_tt_common_entry *common; 8277f91d06cSAntonio Quartulli uint16_t local_flags; 828c6c8fea2SSven Eckelmann 829a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); 830068ee6e2SAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr); 831068ee6e2SAntonio Quartulli 832068ee6e2SAntonio Quartulli /* if the node already has a local client for this entry, it has to wait 833068ee6e2SAntonio Quartulli * for a roaming advertisement instead of manually messing up the global 834068ee6e2SAntonio Quartulli * table 835068ee6e2SAntonio Quartulli */ 836068ee6e2SAntonio Quartulli if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && 837068ee6e2SAntonio Quartulli !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) 838068ee6e2SAntonio Quartulli goto out; 839c6c8fea2SSven Eckelmann 8402dafb49dSAntonio Quartulli if (!tt_global_entry) { 841d4f44692SAntonio Quartulli tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); 8422dafb49dSAntonio Quartulli if (!tt_global_entry) 8437683fdc1SAntonio Quartulli goto out; 8447683fdc1SAntonio Quartulli 845c0a55929SSven Eckelmann common = &tt_global_entry->common; 846c0a55929SSven Eckelmann memcpy(common->addr, tt_addr, ETH_ALEN); 847db08e6e5SSimon Wunderlich 848d4f44692SAntonio Quartulli common->flags = flags; 849cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 850fdf79320SAntonio Quartulli /* node must store current time in case of roaming. This is 851fdf79320SAntonio Quartulli * needed to purge this entry out on timeout (if nobody claims 852fdf79320SAntonio Quartulli * it) 853fdf79320SAntonio Quartulli */ 854fdf79320SAntonio Quartulli if (flags & BATADV_TT_CLIENT_ROAM) 855fdf79320SAntonio Quartulli tt_global_entry->roam_at = jiffies; 856c0a55929SSven Eckelmann atomic_set(&common->refcount, 2); 85730cfd02bSAntonio Quartulli common->added_at = jiffies; 858db08e6e5SSimon Wunderlich 859db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 860db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 8617683fdc1SAntonio Quartulli 862807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.global_hash, 863a513088dSSven Eckelmann batadv_compare_tt, 864a513088dSSven Eckelmann batadv_choose_orig, common, 865a513088dSSven Eckelmann &common->hash_entry); 86680b3f58cSSimon Wunderlich 86780b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 86880b3f58cSSimon Wunderlich /* remove the reference for the hash */ 869a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 87080b3f58cSSimon Wunderlich goto out_remove; 87180b3f58cSSimon Wunderlich } 872a73105b8SAntonio Quartulli } else { 873068ee6e2SAntonio Quartulli common = &tt_global_entry->common; 87430cfd02bSAntonio Quartulli /* If there is already a global entry, we can use this one for 87530cfd02bSAntonio Quartulli * our processing. 876068ee6e2SAntonio Quartulli * But if we are trying to add a temporary client then here are 877068ee6e2SAntonio Quartulli * two options at this point: 878068ee6e2SAntonio Quartulli * 1) the global client is not a temporary client: the global 879068ee6e2SAntonio Quartulli * client has to be left as it is, temporary information 880068ee6e2SAntonio Quartulli * should never override any already known client state 881068ee6e2SAntonio Quartulli * 2) the global client is a temporary client: purge the 882068ee6e2SAntonio Quartulli * originator list and add the new one orig_entry 88330cfd02bSAntonio Quartulli */ 884068ee6e2SAntonio Quartulli if (flags & BATADV_TT_CLIENT_TEMP) { 885068ee6e2SAntonio Quartulli if (!(common->flags & BATADV_TT_CLIENT_TEMP)) 88630cfd02bSAntonio Quartulli goto out; 887068ee6e2SAntonio Quartulli if (batadv_tt_global_entry_has_orig(tt_global_entry, 888068ee6e2SAntonio Quartulli orig_node)) 889068ee6e2SAntonio Quartulli goto out_remove; 890068ee6e2SAntonio Quartulli batadv_tt_global_del_orig_list(tt_global_entry); 891068ee6e2SAntonio Quartulli goto add_orig_entry; 892068ee6e2SAntonio Quartulli } 89330cfd02bSAntonio Quartulli 89430cfd02bSAntonio Quartulli /* if the client was temporary added before receiving the first 89530cfd02bSAntonio Quartulli * OGM announcing it, we have to clear the TEMP flag 89630cfd02bSAntonio Quartulli */ 897068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_TEMP; 898db08e6e5SSimon Wunderlich 899e9c00136SAntonio Quartulli /* the change can carry possible "attribute" flags like the 900e9c00136SAntonio Quartulli * TT_CLIENT_WIFI, therefore they have to be copied in the 901e9c00136SAntonio Quartulli * client entry 902e9c00136SAntonio Quartulli */ 903e9c00136SAntonio Quartulli tt_global_entry->common.flags |= flags; 904e9c00136SAntonio Quartulli 905acd34afaSSven Eckelmann /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 906acd34afaSSven Eckelmann * one originator left in the list and we previously received a 907db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 908db08e6e5SSimon Wunderlich * 909db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 910db08e6e5SSimon Wunderlich * new one. 911db08e6e5SSimon Wunderlich */ 912068ee6e2SAntonio Quartulli if (common->flags & BATADV_TT_CLIENT_ROAM) { 913a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 914068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_ROAM; 915cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 916c6c8fea2SSven Eckelmann } 917db08e6e5SSimon Wunderlich } 918068ee6e2SAntonio Quartulli add_orig_entry: 91930cfd02bSAntonio Quartulli /* add the new orig_entry (if needed) or update it */ 920d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); 921db08e6e5SSimon Wunderlich 92239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 923a73105b8SAntonio Quartulli "Creating new global tt entry: %pM (via %pM)\n", 924068ee6e2SAntonio Quartulli common->addr, orig_node->orig); 925c10dba05SAntonio Quartulli ret = 1; 926a73105b8SAntonio Quartulli 92780b3f58cSSimon Wunderlich out_remove: 9287f91d06cSAntonio Quartulli 929c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 9307f91d06cSAntonio Quartulli local_flags = batadv_tt_local_remove(bat_priv, tt_addr, 931acd34afaSSven Eckelmann "global tt received", 932c1d07431SAntonio Quartulli flags & BATADV_TT_CLIENT_ROAM); 9337f91d06cSAntonio Quartulli tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; 9347f91d06cSAntonio Quartulli 935068ee6e2SAntonio Quartulli if (!(flags & BATADV_TT_CLIENT_ROAM)) 936068ee6e2SAntonio Quartulli /* this is a normal global add. Therefore the client is not in a 937068ee6e2SAntonio Quartulli * roaming state anymore. 938068ee6e2SAntonio Quartulli */ 939068ee6e2SAntonio Quartulli tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 940068ee6e2SAntonio Quartulli 9417683fdc1SAntonio Quartulli out: 9427683fdc1SAntonio Quartulli if (tt_global_entry) 943a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 944068ee6e2SAntonio Quartulli if (tt_local_entry) 945068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 9467683fdc1SAntonio Quartulli return ret; 947c6c8fea2SSven Eckelmann } 948c6c8fea2SSven Eckelmann 949981d8900SSven Eckelmann /* batadv_transtable_best_orig - Get best originator list entry from tt entry 950981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be analyzed 951981d8900SSven Eckelmann * 952981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 953981d8900SSven Eckelmann * Returns best originator list entry or NULL on errors. 954981d8900SSven Eckelmann */ 955981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry * 956981d8900SSven Eckelmann batadv_transtable_best_orig(struct batadv_tt_global_entry *tt_global_entry) 957981d8900SSven Eckelmann { 958981d8900SSven Eckelmann struct batadv_neigh_node *router = NULL; 959981d8900SSven Eckelmann struct hlist_head *head; 960981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; 961981d8900SSven Eckelmann int best_tq = 0; 962981d8900SSven Eckelmann 963981d8900SSven Eckelmann head = &tt_global_entry->orig_list; 964b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 965981d8900SSven Eckelmann router = batadv_orig_node_get_router(orig_entry->orig_node); 966981d8900SSven Eckelmann if (!router) 967981d8900SSven Eckelmann continue; 968981d8900SSven Eckelmann 969981d8900SSven Eckelmann if (router->tq_avg > best_tq) { 970981d8900SSven Eckelmann best_entry = orig_entry; 971981d8900SSven Eckelmann best_tq = router->tq_avg; 972981d8900SSven Eckelmann } 973981d8900SSven Eckelmann 974981d8900SSven Eckelmann batadv_neigh_node_free_ref(router); 975981d8900SSven Eckelmann } 976981d8900SSven Eckelmann 977981d8900SSven Eckelmann return best_entry; 978981d8900SSven Eckelmann } 979981d8900SSven Eckelmann 980981d8900SSven Eckelmann /* batadv_tt_global_print_entry - print all orig nodes who announce the address 981981d8900SSven Eckelmann * for this global entry 982981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be printed 983981d8900SSven Eckelmann * @seq: debugfs table seq_file struct 984981d8900SSven Eckelmann * 985981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 986db08e6e5SSimon Wunderlich */ 987a513088dSSven Eckelmann static void 98856303d34SSven Eckelmann batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, 989db08e6e5SSimon Wunderlich struct seq_file *seq) 990db08e6e5SSimon Wunderlich { 991db08e6e5SSimon Wunderlich struct hlist_head *head; 992981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry; 99356303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 994db08e6e5SSimon Wunderlich uint16_t flags; 995db08e6e5SSimon Wunderlich uint8_t last_ttvn; 996db08e6e5SSimon Wunderlich 997db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 998981d8900SSven Eckelmann flags = tt_common_entry->flags; 999981d8900SSven Eckelmann 1000981d8900SSven Eckelmann best_entry = batadv_transtable_best_orig(tt_global_entry); 1001981d8900SSven Eckelmann if (best_entry) { 1002981d8900SSven Eckelmann last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); 1003f9d8a537SAntonio Quartulli seq_printf(seq, 1004f9d8a537SAntonio Quartulli " %c %pM (%3u) via %pM (%3u) (%#.4x) [%c%c%c]\n", 1005981d8900SSven Eckelmann '*', tt_global_entry->common.addr, 1006981d8900SSven Eckelmann best_entry->ttvn, best_entry->orig_node->orig, 1007f9d8a537SAntonio Quartulli last_ttvn, best_entry->orig_node->tt_crc, 1008981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 1009981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 1010981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); 1011981d8900SSven Eckelmann } 1012db08e6e5SSimon Wunderlich 1013db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1014db08e6e5SSimon Wunderlich 1015b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1016981d8900SSven Eckelmann if (best_entry == orig_entry) 1017981d8900SSven Eckelmann continue; 1018981d8900SSven Eckelmann 1019db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 1020981d8900SSven Eckelmann seq_printf(seq, " %c %pM (%3u) via %pM (%3u) [%c%c%c]\n", 1021981d8900SSven Eckelmann '+', tt_global_entry->common.addr, 1022981d8900SSven Eckelmann orig_entry->ttvn, orig_entry->orig_node->orig, 1023981d8900SSven Eckelmann last_ttvn, 1024acd34afaSSven Eckelmann (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 102530cfd02bSAntonio Quartulli (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 102630cfd02bSAntonio Quartulli (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); 1027db08e6e5SSimon Wunderlich } 1028db08e6e5SSimon Wunderlich } 1029db08e6e5SSimon Wunderlich 103008c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 1031c6c8fea2SSven Eckelmann { 1032c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 103356303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 1034807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 103556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 103656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 103756303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 1038c6c8fea2SSven Eckelmann struct hlist_head *head; 1039c90681b8SAntonio Quartulli uint32_t i; 1040c6c8fea2SSven Eckelmann 104130da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 104230da63a6SMarek Lindner if (!primary_if) 104332ae9b22SMarek Lindner goto out; 1044c6c8fea2SSven Eckelmann 10452dafb49dSAntonio Quartulli seq_printf(seq, 10462dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 1047c6c8fea2SSven Eckelmann net_dev->name); 1048f9d8a537SAntonio Quartulli seq_printf(seq, " %-13s %s %-15s %s (%-6s) %s\n", 1049f9d8a537SAntonio Quartulli "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC", 1050f9d8a537SAntonio Quartulli "Flags"); 1051c6c8fea2SSven Eckelmann 1052c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1053c6c8fea2SSven Eckelmann head = &hash->table[i]; 1054c6c8fea2SSven Eckelmann 10557aadf889SMarek Lindner rcu_read_lock(); 1056b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 10577aadf889SMarek Lindner head, hash_entry) { 105856303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 105956303d34SSven Eckelmann struct batadv_tt_global_entry, 106048100bacSAntonio Quartulli common); 106156303d34SSven Eckelmann batadv_tt_global_print_entry(tt_global, seq); 1062c6c8fea2SSven Eckelmann } 10637aadf889SMarek Lindner rcu_read_unlock(); 1064c6c8fea2SSven Eckelmann } 106532ae9b22SMarek Lindner out: 106632ae9b22SMarek Lindner if (primary_if) 1067e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 106830da63a6SMarek Lindner return 0; 1069c6c8fea2SSven Eckelmann } 1070c6c8fea2SSven Eckelmann 1071db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 1072a513088dSSven Eckelmann static void 107356303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) 1074db08e6e5SSimon Wunderlich { 1075db08e6e5SSimon Wunderlich struct hlist_head *head; 1076b67bfe0dSSasha Levin struct hlist_node *safe; 107756303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1078db08e6e5SSimon Wunderlich 1079db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1080db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1081b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1082b67bfe0dSSasha Levin hlist_del_rcu(&orig_entry->list); 1083a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 1084db08e6e5SSimon Wunderlich } 1085db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1086db08e6e5SSimon Wunderlich } 1087db08e6e5SSimon Wunderlich 1088a513088dSSven Eckelmann static void 108956303d34SSven Eckelmann batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, 109056303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 109156303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1092db08e6e5SSimon Wunderlich const char *message) 1093db08e6e5SSimon Wunderlich { 1094db08e6e5SSimon Wunderlich struct hlist_head *head; 1095b67bfe0dSSasha Levin struct hlist_node *safe; 109656303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1097db08e6e5SSimon Wunderlich 1098db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1099db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1100b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1101db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 110239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1103db08e6e5SSimon Wunderlich "Deleting %pM from global tt entry %pM: %s\n", 11041eda58bfSSven Eckelmann orig_node->orig, 11051eda58bfSSven Eckelmann tt_global_entry->common.addr, message); 1106b67bfe0dSSasha Levin hlist_del_rcu(&orig_entry->list); 1107a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 1108db08e6e5SSimon Wunderlich } 1109db08e6e5SSimon Wunderlich } 1110db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1111db08e6e5SSimon Wunderlich } 1112db08e6e5SSimon Wunderlich 1113db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 1114acd34afaSSven Eckelmann * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the 1115acd34afaSSven Eckelmann * timer, otherwise we simply remove the originator scheduled for deletion. 1116db08e6e5SSimon Wunderlich */ 1117a513088dSSven Eckelmann static void 111856303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, 111956303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 112056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 112156303d34SSven Eckelmann const char *message) 1122db08e6e5SSimon Wunderlich { 1123db08e6e5SSimon Wunderlich bool last_entry = true; 1124db08e6e5SSimon Wunderlich struct hlist_head *head; 112556303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1126db08e6e5SSimon Wunderlich 1127db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 1128db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 1129db08e6e5SSimon Wunderlich */ 1130db08e6e5SSimon Wunderlich 1131db08e6e5SSimon Wunderlich rcu_read_lock(); 1132db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1133b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1134db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 1135db08e6e5SSimon Wunderlich last_entry = false; 1136db08e6e5SSimon Wunderlich break; 1137db08e6e5SSimon Wunderlich } 1138db08e6e5SSimon Wunderlich } 1139db08e6e5SSimon Wunderlich rcu_read_unlock(); 1140db08e6e5SSimon Wunderlich 1141db08e6e5SSimon Wunderlich if (last_entry) { 1142db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 1143acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 1144db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 1145db08e6e5SSimon Wunderlich } else 1146db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 1147db08e6e5SSimon Wunderlich * one and can still use the other one. 1148db08e6e5SSimon Wunderlich */ 1149a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 1150db08e6e5SSimon Wunderlich orig_node, message); 1151db08e6e5SSimon Wunderlich } 1152db08e6e5SSimon Wunderlich 1153db08e6e5SSimon Wunderlich 1154db08e6e5SSimon Wunderlich 115556303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv, 115656303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1157de7aae65SSven Eckelmann const unsigned char *addr, 1158cc47f66eSAntonio Quartulli const char *message, bool roaming) 1159a73105b8SAntonio Quartulli { 1160170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 116156303d34SSven Eckelmann struct batadv_tt_local_entry *local_entry = NULL; 1162a73105b8SAntonio Quartulli 1163a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 1164db08e6e5SSimon Wunderlich if (!tt_global_entry) 11657683fdc1SAntonio Quartulli goto out; 1166a73105b8SAntonio Quartulli 1167db08e6e5SSimon Wunderlich if (!roaming) { 1168a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 1169a513088dSSven Eckelmann orig_node, message); 117092f90f56SSven Eckelmann 1171db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 1172be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, 1173db08e6e5SSimon Wunderlich message); 1174db08e6e5SSimon Wunderlich 1175cc47f66eSAntonio Quartulli goto out; 1176cc47f66eSAntonio Quartulli } 117792f90f56SSven Eckelmann 1178db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 1179db08e6e5SSimon Wunderlich * event, there are two possibilities: 1180db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 1181db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 1182acd34afaSSven Eckelmann * it with BATADV_TT_CLIENT_ROAM, we start a timer and we 1183db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 1184db08e6e5SSimon Wunderlich * the entry is purged. 1185db08e6e5SSimon Wunderlich * 1186db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 1187db08e6e5SSimon Wunderlich * the originator. 1188db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 11899cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 11909cfc7bd6SSven Eckelmann */ 1191a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 1192db08e6e5SSimon Wunderlich tt_global_entry->common.addr); 1193a513088dSSven Eckelmann if (local_entry) { 1194db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 1195a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1196be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, message); 1197db08e6e5SSimon Wunderlich } else 1198db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 1199a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 1200a513088dSSven Eckelmann orig_node, message); 1201db08e6e5SSimon Wunderlich 120292f90f56SSven Eckelmann 1203cc47f66eSAntonio Quartulli out: 12047683fdc1SAntonio Quartulli if (tt_global_entry) 1205a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1206a513088dSSven Eckelmann if (local_entry) 1207a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(local_entry); 1208a73105b8SAntonio Quartulli } 1209a73105b8SAntonio Quartulli 121056303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, 121156303d34SSven Eckelmann struct batadv_orig_node *orig_node, 121256303d34SSven Eckelmann const char *message) 1213c6c8fea2SSven Eckelmann { 121456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 121556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1216c90681b8SAntonio Quartulli uint32_t i; 1217807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 1218b67bfe0dSSasha Levin struct hlist_node *safe; 1219a73105b8SAntonio Quartulli struct hlist_head *head; 12207683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 1221c6c8fea2SSven Eckelmann 12226e801494SSimon Wunderlich if (!hash) 12236e801494SSimon Wunderlich return; 12246e801494SSimon Wunderlich 1225a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1226a73105b8SAntonio Quartulli head = &hash->table[i]; 12277683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1228c6c8fea2SSven Eckelmann 12297683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1230b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, safe, 1231a73105b8SAntonio Quartulli head, hash_entry) { 123256303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 123356303d34SSven Eckelmann struct batadv_tt_global_entry, 123448100bacSAntonio Quartulli common); 1235db08e6e5SSimon Wunderlich 123656303d34SSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global, 1237db08e6e5SSimon Wunderlich orig_node, message); 1238db08e6e5SSimon Wunderlich 123956303d34SSven Eckelmann if (hlist_empty(&tt_global->orig_list)) { 124039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1241db08e6e5SSimon Wunderlich "Deleting global tt entry %pM: %s\n", 124256303d34SSven Eckelmann tt_global->common.addr, message); 1243b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 124456303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 1245c6c8fea2SSven Eckelmann } 1246a73105b8SAntonio Quartulli } 12477683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 12487683fdc1SAntonio Quartulli } 124917071578SAntonio Quartulli orig_node->tt_initialised = false; 1250c6c8fea2SSven Eckelmann } 1251c6c8fea2SSven Eckelmann 125230cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, 125330cfd02bSAntonio Quartulli char **msg) 1254cc47f66eSAntonio Quartulli { 125530cfd02bSAntonio Quartulli bool purge = false; 125630cfd02bSAntonio Quartulli unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; 125730cfd02bSAntonio Quartulli unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; 1258cc47f66eSAntonio Quartulli 125930cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && 126030cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { 126130cfd02bSAntonio Quartulli purge = true; 126230cfd02bSAntonio Quartulli *msg = "Roaming timeout\n"; 126342d0b044SSven Eckelmann } 126442d0b044SSven Eckelmann 126530cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) && 126630cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) { 126730cfd02bSAntonio Quartulli purge = true; 126830cfd02bSAntonio Quartulli *msg = "Temporary client timeout\n"; 126930cfd02bSAntonio Quartulli } 127030cfd02bSAntonio Quartulli 127130cfd02bSAntonio Quartulli return purge; 127230cfd02bSAntonio Quartulli } 127330cfd02bSAntonio Quartulli 127430cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv) 127542d0b044SSven Eckelmann { 1276807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 127742d0b044SSven Eckelmann struct hlist_head *head; 1278b67bfe0dSSasha Levin struct hlist_node *node_tmp; 127942d0b044SSven Eckelmann spinlock_t *list_lock; /* protects write access to the hash lists */ 128042d0b044SSven Eckelmann uint32_t i; 128130cfd02bSAntonio Quartulli char *msg = NULL; 128230cfd02bSAntonio Quartulli struct batadv_tt_common_entry *tt_common; 128330cfd02bSAntonio Quartulli struct batadv_tt_global_entry *tt_global; 128442d0b044SSven Eckelmann 128542d0b044SSven Eckelmann for (i = 0; i < hash->size; i++) { 128642d0b044SSven Eckelmann head = &hash->table[i]; 128742d0b044SSven Eckelmann list_lock = &hash->list_locks[i]; 128842d0b044SSven Eckelmann 128942d0b044SSven Eckelmann spin_lock_bh(list_lock); 1290b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 129130cfd02bSAntonio Quartulli hash_entry) { 129230cfd02bSAntonio Quartulli tt_global = container_of(tt_common, 129330cfd02bSAntonio Quartulli struct batadv_tt_global_entry, 129430cfd02bSAntonio Quartulli common); 129530cfd02bSAntonio Quartulli 129630cfd02bSAntonio Quartulli if (!batadv_tt_global_to_purge(tt_global, &msg)) 129730cfd02bSAntonio Quartulli continue; 129830cfd02bSAntonio Quartulli 129930cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 130030cfd02bSAntonio Quartulli "Deleting global tt entry (%pM): %s\n", 130130cfd02bSAntonio Quartulli tt_global->common.addr, msg); 130230cfd02bSAntonio Quartulli 1303b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 130430cfd02bSAntonio Quartulli 130530cfd02bSAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 130630cfd02bSAntonio Quartulli } 13077683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1308cc47f66eSAntonio Quartulli } 1309cc47f66eSAntonio Quartulli } 1310cc47f66eSAntonio Quartulli 131156303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) 1312c6c8fea2SSven Eckelmann { 13135bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 13147683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 131556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 131656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 1317b67bfe0dSSasha Levin struct hlist_node *node_tmp; 13187683fdc1SAntonio Quartulli struct hlist_head *head; 1319c90681b8SAntonio Quartulli uint32_t i; 13207683fdc1SAntonio Quartulli 1321807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 1322c6c8fea2SSven Eckelmann return; 1323c6c8fea2SSven Eckelmann 1324807736f6SSven Eckelmann hash = bat_priv->tt.global_hash; 13257683fdc1SAntonio Quartulli 13267683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 13277683fdc1SAntonio Quartulli head = &hash->table[i]; 13287683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 13297683fdc1SAntonio Quartulli 13307683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1331b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 13327683fdc1SAntonio Quartulli head, hash_entry) { 1333b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 133456303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 133556303d34SSven Eckelmann struct batadv_tt_global_entry, 133648100bacSAntonio Quartulli common); 133756303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 13387683fdc1SAntonio Quartulli } 13397683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 13407683fdc1SAntonio Quartulli } 13417683fdc1SAntonio Quartulli 13421a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 13437683fdc1SAntonio Quartulli 1344807736f6SSven Eckelmann bat_priv->tt.global_hash = NULL; 1345c6c8fea2SSven Eckelmann } 1346c6c8fea2SSven Eckelmann 134756303d34SSven Eckelmann static bool 134856303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, 134956303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry) 135059b699cdSAntonio Quartulli { 135159b699cdSAntonio Quartulli bool ret = false; 135259b699cdSAntonio Quartulli 1353acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && 1354acd34afaSSven Eckelmann tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) 135559b699cdSAntonio Quartulli ret = true; 135659b699cdSAntonio Quartulli 135759b699cdSAntonio Quartulli return ret; 135859b699cdSAntonio Quartulli } 135959b699cdSAntonio Quartulli 136056303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, 136108c36d3eSSven Eckelmann const uint8_t *src, 136208c36d3eSSven Eckelmann const uint8_t *addr) 1363c6c8fea2SSven Eckelmann { 136456303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 136556303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 136656303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 1367981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *best_entry; 1368c6c8fea2SSven Eckelmann 13693d393e47SAntonio Quartulli if (src && atomic_read(&bat_priv->ap_isolation)) { 1370a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); 1371068ee6e2SAntonio Quartulli if (!tt_local_entry || 1372068ee6e2SAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) 13733d393e47SAntonio Quartulli goto out; 13743d393e47SAntonio Quartulli } 13757aadf889SMarek Lindner 1376a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 13772dafb49dSAntonio Quartulli if (!tt_global_entry) 13787b36e8eeSMarek Lindner goto out; 1379c6c8fea2SSven Eckelmann 13803d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 13819cfc7bd6SSven Eckelmann * isolation 13829cfc7bd6SSven Eckelmann */ 1383a513088dSSven Eckelmann if (tt_local_entry && 1384a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 13853d393e47SAntonio Quartulli goto out; 13863d393e47SAntonio Quartulli 1387db08e6e5SSimon Wunderlich rcu_read_lock(); 1388981d8900SSven Eckelmann best_entry = batadv_transtable_best_orig(tt_global_entry); 1389db08e6e5SSimon Wunderlich /* found anything? */ 1390981d8900SSven Eckelmann if (best_entry) 1391981d8900SSven Eckelmann orig_node = best_entry->orig_node; 1392db08e6e5SSimon Wunderlich if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) 1393db08e6e5SSimon Wunderlich orig_node = NULL; 1394db08e6e5SSimon Wunderlich rcu_read_unlock(); 1395981d8900SSven Eckelmann 13967b36e8eeSMarek Lindner out: 13973d393e47SAntonio Quartulli if (tt_global_entry) 1398a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 13993d393e47SAntonio Quartulli if (tt_local_entry) 1400a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 14013d393e47SAntonio Quartulli 14027b36e8eeSMarek Lindner return orig_node; 1403c6c8fea2SSven Eckelmann } 1404a73105b8SAntonio Quartulli 1405a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */ 140656303d34SSven Eckelmann static uint16_t batadv_tt_global_crc(struct batadv_priv *bat_priv, 140756303d34SSven Eckelmann struct batadv_orig_node *orig_node) 1408a73105b8SAntonio Quartulli { 1409a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1410807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 141156303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 141256303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 1413a73105b8SAntonio Quartulli struct hlist_head *head; 1414c90681b8SAntonio Quartulli uint32_t i; 1415c90681b8SAntonio Quartulli int j; 1416a73105b8SAntonio Quartulli 1417a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1418a73105b8SAntonio Quartulli head = &hash->table[i]; 1419a73105b8SAntonio Quartulli 1420a73105b8SAntonio Quartulli rcu_read_lock(); 1421b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 142256303d34SSven Eckelmann tt_global = container_of(tt_common, 142356303d34SSven Eckelmann struct batadv_tt_global_entry, 142448100bacSAntonio Quartulli common); 1425cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 1426cc47f66eSAntonio Quartulli * consistency only. They don't have to be 1427cc47f66eSAntonio Quartulli * taken into account while computing the 1428db08e6e5SSimon Wunderlich * global crc 1429db08e6e5SSimon Wunderlich */ 1430acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 1431cc47f66eSAntonio Quartulli continue; 143230cfd02bSAntonio Quartulli /* Temporary clients have not been announced yet, so 143330cfd02bSAntonio Quartulli * they have to be skipped while computing the global 143430cfd02bSAntonio Quartulli * crc 143530cfd02bSAntonio Quartulli */ 143630cfd02bSAntonio Quartulli if (tt_common->flags & BATADV_TT_CLIENT_TEMP) 143730cfd02bSAntonio Quartulli continue; 1438db08e6e5SSimon Wunderlich 1439db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 1440db08e6e5SSimon Wunderlich * originator 1441db08e6e5SSimon Wunderlich */ 144256303d34SSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global, 1443db08e6e5SSimon Wunderlich orig_node)) 1444db08e6e5SSimon Wunderlich continue; 1445db08e6e5SSimon Wunderlich 1446a73105b8SAntonio Quartulli total_one = 0; 1447a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1448a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 1449acd34afaSSven Eckelmann tt_common->addr[j]); 1450a73105b8SAntonio Quartulli total ^= total_one; 1451a73105b8SAntonio Quartulli } 1452a73105b8SAntonio Quartulli rcu_read_unlock(); 1453a73105b8SAntonio Quartulli } 1454a73105b8SAntonio Quartulli 1455a73105b8SAntonio Quartulli return total; 1456a73105b8SAntonio Quartulli } 1457a73105b8SAntonio Quartulli 1458a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */ 145956303d34SSven Eckelmann static uint16_t batadv_tt_local_crc(struct batadv_priv *bat_priv) 1460a73105b8SAntonio Quartulli { 1461a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1462807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 146356303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 1464a73105b8SAntonio Quartulli struct hlist_head *head; 1465c90681b8SAntonio Quartulli uint32_t i; 1466c90681b8SAntonio Quartulli int j; 1467a73105b8SAntonio Quartulli 1468a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1469a73105b8SAntonio Quartulli head = &hash->table[i]; 1470a73105b8SAntonio Quartulli 1471a73105b8SAntonio Quartulli rcu_read_lock(); 1472b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 1473058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 14749cfc7bd6SSven Eckelmann * account while computing the CRC 14759cfc7bd6SSven Eckelmann */ 1476acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_NEW) 1477058d0e26SAntonio Quartulli continue; 1478a73105b8SAntonio Quartulli total_one = 0; 1479a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1480a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 1481acd34afaSSven Eckelmann tt_common->addr[j]); 1482a73105b8SAntonio Quartulli total ^= total_one; 1483a73105b8SAntonio Quartulli } 1484a73105b8SAntonio Quartulli rcu_read_unlock(); 1485a73105b8SAntonio Quartulli } 1486a73105b8SAntonio Quartulli 1487a73105b8SAntonio Quartulli return total; 1488a73105b8SAntonio Quartulli } 1489a73105b8SAntonio Quartulli 149056303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) 1491a73105b8SAntonio Quartulli { 149256303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 1493a73105b8SAntonio Quartulli 1494807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 1495a73105b8SAntonio Quartulli 1496807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 1497a73105b8SAntonio Quartulli list_del(&node->list); 1498a73105b8SAntonio Quartulli kfree(node); 1499a73105b8SAntonio Quartulli } 1500a73105b8SAntonio Quartulli 1501807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 1502a73105b8SAntonio Quartulli } 1503a73105b8SAntonio Quartulli 150456303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, 150556303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1506de7aae65SSven Eckelmann const unsigned char *tt_buff, 1507de7aae65SSven Eckelmann uint8_t tt_num_changes) 1508a73105b8SAntonio Quartulli { 150908c36d3eSSven Eckelmann uint16_t tt_buff_len = batadv_tt_len(tt_num_changes); 1510a73105b8SAntonio Quartulli 1511a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 15129cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 15139cfc7bd6SSven Eckelmann */ 1514a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1515a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 1516a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1517a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1518a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 1519a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 1520a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 1521a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 1522a73105b8SAntonio Quartulli } 1523a73105b8SAntonio Quartulli } 1524a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1525a73105b8SAntonio Quartulli } 1526a73105b8SAntonio Quartulli 152756303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv) 1528a73105b8SAntonio Quartulli { 152956303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 1530a73105b8SAntonio Quartulli 1531807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 1532807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 153342d0b044SSven Eckelmann if (batadv_has_timed_out(node->issued_at, 153442d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) { 1535a73105b8SAntonio Quartulli list_del(&node->list); 1536a73105b8SAntonio Quartulli kfree(node); 1537a73105b8SAntonio Quartulli } 1538a73105b8SAntonio Quartulli } 1539807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 1540a73105b8SAntonio Quartulli } 1541a73105b8SAntonio Quartulli 1542a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 15439cfc7bd6SSven Eckelmann * has already been issued for this orig_node, NULL otherwise 15449cfc7bd6SSven Eckelmann */ 154556303d34SSven Eckelmann static struct batadv_tt_req_node * 154656303d34SSven Eckelmann batadv_new_tt_req_node(struct batadv_priv *bat_priv, 154756303d34SSven Eckelmann struct batadv_orig_node *orig_node) 1548a73105b8SAntonio Quartulli { 154956303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 1550a73105b8SAntonio Quartulli 1551807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 1552807736f6SSven Eckelmann list_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { 15531eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 15541eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 155542d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) 1556a73105b8SAntonio Quartulli goto unlock; 1557a73105b8SAntonio Quartulli } 1558a73105b8SAntonio Quartulli 1559a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 1560a73105b8SAntonio Quartulli if (!tt_req_node) 1561a73105b8SAntonio Quartulli goto unlock; 1562a73105b8SAntonio Quartulli 1563a73105b8SAntonio Quartulli memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); 1564a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 1565a73105b8SAntonio Quartulli 1566807736f6SSven Eckelmann list_add(&tt_req_node->list, &bat_priv->tt.req_list); 1567a73105b8SAntonio Quartulli unlock: 1568807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 1569a73105b8SAntonio Quartulli return tt_req_node; 1570a73105b8SAntonio Quartulli } 1571a73105b8SAntonio Quartulli 1572058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */ 1573a513088dSSven Eckelmann static int batadv_tt_local_valid_entry(const void *entry_ptr, 1574a513088dSSven Eckelmann const void *data_ptr) 1575058d0e26SAntonio Quartulli { 157656303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 1577058d0e26SAntonio Quartulli 1578acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) 1579058d0e26SAntonio Quartulli return 0; 1580058d0e26SAntonio Quartulli return 1; 1581058d0e26SAntonio Quartulli } 1582058d0e26SAntonio Quartulli 1583a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr, 1584a513088dSSven Eckelmann const void *data_ptr) 1585a73105b8SAntonio Quartulli { 158656303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 158756303d34SSven Eckelmann const struct batadv_tt_global_entry *tt_global_entry; 158856303d34SSven Eckelmann const struct batadv_orig_node *orig_node = data_ptr; 1589a73105b8SAntonio Quartulli 159030cfd02bSAntonio Quartulli if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || 159130cfd02bSAntonio Quartulli tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) 1592cc47f66eSAntonio Quartulli return 0; 1593cc47f66eSAntonio Quartulli 159456303d34SSven Eckelmann tt_global_entry = container_of(tt_common_entry, 159556303d34SSven Eckelmann struct batadv_tt_global_entry, 159648100bacSAntonio Quartulli common); 159748100bacSAntonio Quartulli 1598a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 1599a73105b8SAntonio Quartulli } 1600a73105b8SAntonio Quartulli 1601a513088dSSven Eckelmann static struct sk_buff * 1602a513088dSSven Eckelmann batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, 16035bf74e9cSSven Eckelmann struct batadv_hashtable *hash, 1604736292c2SMarek Lindner struct batadv_priv *bat_priv, 1605a513088dSSven Eckelmann int (*valid_cb)(const void *, const void *), 1606a73105b8SAntonio Quartulli void *cb_data) 1607a73105b8SAntonio Quartulli { 160856303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 160996412690SSven Eckelmann struct batadv_tt_query_packet *tt_response; 161096412690SSven Eckelmann struct batadv_tt_change *tt_change; 1611a73105b8SAntonio Quartulli struct hlist_head *head; 1612a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1613a73105b8SAntonio Quartulli uint16_t tt_tot, tt_count; 161496412690SSven Eckelmann ssize_t tt_query_size = sizeof(struct batadv_tt_query_packet); 1615c90681b8SAntonio Quartulli uint32_t i; 161696412690SSven Eckelmann size_t len; 1617a73105b8SAntonio Quartulli 1618736292c2SMarek Lindner if (tt_query_size + tt_len > bat_priv->soft_iface->mtu) { 1619736292c2SMarek Lindner tt_len = bat_priv->soft_iface->mtu - tt_query_size; 162096412690SSven Eckelmann tt_len -= tt_len % sizeof(struct batadv_tt_change); 1621a73105b8SAntonio Quartulli } 162296412690SSven Eckelmann tt_tot = tt_len / sizeof(struct batadv_tt_change); 1623a73105b8SAntonio Quartulli 162496412690SSven Eckelmann len = tt_query_size + tt_len; 162541ab6c48SAntonio Quartulli skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); 1626a73105b8SAntonio Quartulli if (!skb) 1627a73105b8SAntonio Quartulli goto out; 1628a73105b8SAntonio Quartulli 162941ab6c48SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 163096412690SSven Eckelmann tt_response = (struct batadv_tt_query_packet *)skb_put(skb, len); 1631a73105b8SAntonio Quartulli tt_response->ttvn = ttvn; 1632a73105b8SAntonio Quartulli 163396412690SSven Eckelmann tt_change = (struct batadv_tt_change *)(skb->data + tt_query_size); 1634a73105b8SAntonio Quartulli tt_count = 0; 1635a73105b8SAntonio Quartulli 1636a73105b8SAntonio Quartulli rcu_read_lock(); 1637a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1638a73105b8SAntonio Quartulli head = &hash->table[i]; 1639a73105b8SAntonio Quartulli 1640b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 1641a73105b8SAntonio Quartulli head, hash_entry) { 1642a73105b8SAntonio Quartulli if (tt_count == tt_tot) 1643a73105b8SAntonio Quartulli break; 1644a73105b8SAntonio Quartulli 164548100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 1646a73105b8SAntonio Quartulli continue; 1647a73105b8SAntonio Quartulli 164848100bacSAntonio Quartulli memcpy(tt_change->addr, tt_common_entry->addr, 164948100bacSAntonio Quartulli ETH_ALEN); 165027b37ebfSAntonio Quartulli tt_change->flags = tt_common_entry->flags; 1651a73105b8SAntonio Quartulli 1652a73105b8SAntonio Quartulli tt_count++; 1653a73105b8SAntonio Quartulli tt_change++; 1654a73105b8SAntonio Quartulli } 1655a73105b8SAntonio Quartulli } 1656a73105b8SAntonio Quartulli rcu_read_unlock(); 1657a73105b8SAntonio Quartulli 16589d852393SAntonio Quartulli /* store in the message the number of entries we have successfully 16599cfc7bd6SSven Eckelmann * copied 16609cfc7bd6SSven Eckelmann */ 16619d852393SAntonio Quartulli tt_response->tt_data = htons(tt_count); 16629d852393SAntonio Quartulli 1663a73105b8SAntonio Quartulli out: 1664a73105b8SAntonio Quartulli return skb; 1665a73105b8SAntonio Quartulli } 1666a73105b8SAntonio Quartulli 166756303d34SSven Eckelmann static int batadv_send_tt_request(struct batadv_priv *bat_priv, 166856303d34SSven Eckelmann struct batadv_orig_node *dst_orig_node, 1669a513088dSSven Eckelmann uint8_t ttvn, uint16_t tt_crc, 1670a513088dSSven Eckelmann bool full_table) 1671a73105b8SAntonio Quartulli { 1672a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 167396412690SSven Eckelmann struct batadv_tt_query_packet *tt_request; 167456303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 167556303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node = NULL; 1676a73105b8SAntonio Quartulli int ret = 1; 167796412690SSven Eckelmann size_t tt_req_len; 1678a73105b8SAntonio Quartulli 1679e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1680a73105b8SAntonio Quartulli if (!primary_if) 1681a73105b8SAntonio Quartulli goto out; 1682a73105b8SAntonio Quartulli 1683a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 16849cfc7bd6SSven Eckelmann * reply from the same orig_node yet 16859cfc7bd6SSven Eckelmann */ 1686a513088dSSven Eckelmann tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node); 1687a73105b8SAntonio Quartulli if (!tt_req_node) 1688a73105b8SAntonio Quartulli goto out; 1689a73105b8SAntonio Quartulli 169041ab6c48SAntonio Quartulli skb = netdev_alloc_skb_ip_align(NULL, sizeof(*tt_request) + ETH_HLEN); 1691a73105b8SAntonio Quartulli if (!skb) 1692a73105b8SAntonio Quartulli goto out; 1693a73105b8SAntonio Quartulli 169441ab6c48SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1695a73105b8SAntonio Quartulli 169696412690SSven Eckelmann tt_req_len = sizeof(*tt_request); 169796412690SSven Eckelmann tt_request = (struct batadv_tt_query_packet *)skb_put(skb, tt_req_len); 1698a73105b8SAntonio Quartulli 1699acd34afaSSven Eckelmann tt_request->header.packet_type = BATADV_TT_QUERY; 17007e071c79SSven Eckelmann tt_request->header.version = BATADV_COMPAT_VERSION; 1701a73105b8SAntonio Quartulli memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1702a73105b8SAntonio Quartulli memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); 170342d0b044SSven Eckelmann tt_request->header.ttl = BATADV_TTL; 1704a73105b8SAntonio Quartulli tt_request->ttvn = ttvn; 17056d2003fcSAntonio Quartulli tt_request->tt_data = htons(tt_crc); 1706acd34afaSSven Eckelmann tt_request->flags = BATADV_TT_REQUEST; 1707a73105b8SAntonio Quartulli 1708a73105b8SAntonio Quartulli if (full_table) 1709acd34afaSSven Eckelmann tt_request->flags |= BATADV_TT_FULL_TABLE; 1710a73105b8SAntonio Quartulli 1711bb351ba0SMartin Hundebøll batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", 1712bb351ba0SMartin Hundebøll dst_orig_node->orig, (full_table ? 'F' : '.')); 1713a73105b8SAntonio Quartulli 1714d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); 1715f8214865SMartin Hundebøll 1716e91ecfc6SMartin Hundebøll if (batadv_send_skb_to_orig(skb, dst_orig_node, NULL) != NET_XMIT_DROP) 1717a73105b8SAntonio Quartulli ret = 0; 1718a73105b8SAntonio Quartulli 1719a73105b8SAntonio Quartulli out: 1720a73105b8SAntonio Quartulli if (primary_if) 1721e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1722a73105b8SAntonio Quartulli if (ret) 1723a73105b8SAntonio Quartulli kfree_skb(skb); 1724a73105b8SAntonio Quartulli if (ret && tt_req_node) { 1725807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 1726a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 1727807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 1728a73105b8SAntonio Quartulli kfree(tt_req_node); 1729a73105b8SAntonio Quartulli } 1730a73105b8SAntonio Quartulli return ret; 1731a73105b8SAntonio Quartulli } 1732a73105b8SAntonio Quartulli 173396412690SSven Eckelmann static bool 173456303d34SSven Eckelmann batadv_send_other_tt_response(struct batadv_priv *bat_priv, 173596412690SSven Eckelmann struct batadv_tt_query_packet *tt_request) 1736a73105b8SAntonio Quartulli { 1737170173bfSSven Eckelmann struct batadv_orig_node *req_dst_orig_node; 173856303d34SSven Eckelmann struct batadv_orig_node *res_dst_orig_node = NULL; 1739a73105b8SAntonio Quartulli uint8_t orig_ttvn, req_ttvn, ttvn; 1740e91ecfc6SMartin Hundebøll int res, ret = false; 1741a73105b8SAntonio Quartulli unsigned char *tt_buff; 1742a73105b8SAntonio Quartulli bool full_table; 1743a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1744a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 174596412690SSven Eckelmann struct batadv_tt_query_packet *tt_response; 1746c67893d1SSven Eckelmann uint8_t *packet_pos; 174796412690SSven Eckelmann size_t len; 1748a73105b8SAntonio Quartulli 174939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 175086ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 175186ceb360SSven Eckelmann tt_request->src, tt_request->ttvn, tt_request->dst, 1752acd34afaSSven Eckelmann (tt_request->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1753a73105b8SAntonio Quartulli 1754a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 1755da641193SSven Eckelmann req_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->dst); 1756a73105b8SAntonio Quartulli if (!req_dst_orig_node) 1757a73105b8SAntonio Quartulli goto out; 1758a73105b8SAntonio Quartulli 1759da641193SSven Eckelmann res_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); 1760a73105b8SAntonio Quartulli if (!res_dst_orig_node) 1761a73105b8SAntonio Quartulli goto out; 1762a73105b8SAntonio Quartulli 1763a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1764a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1765a73105b8SAntonio Quartulli 1766015758d0SAntonio Quartulli /* I don't have the requested data */ 1767a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 1768f25bd58aSAl Viro tt_request->tt_data != htons(req_dst_orig_node->tt_crc)) 1769a73105b8SAntonio Quartulli goto out; 1770a73105b8SAntonio Quartulli 1771015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 1772acd34afaSSven Eckelmann if (tt_request->flags & BATADV_TT_FULL_TABLE || 1773a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 1774a73105b8SAntonio Quartulli full_table = true; 1775a73105b8SAntonio Quartulli else 1776a73105b8SAntonio Quartulli full_table = false; 1777a73105b8SAntonio Quartulli 1778a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 17799cfc7bd6SSven Eckelmann * I'll send only one packet with as much TT entries as I can 17809cfc7bd6SSven Eckelmann */ 1781a73105b8SAntonio Quartulli if (!full_table) { 1782a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 1783a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 178496412690SSven Eckelmann tt_tot = tt_len / sizeof(struct batadv_tt_change); 1785a73105b8SAntonio Quartulli 178696412690SSven Eckelmann len = sizeof(*tt_response) + tt_len; 178741ab6c48SAntonio Quartulli skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); 1788a73105b8SAntonio Quartulli if (!skb) 1789a73105b8SAntonio Quartulli goto unlock; 1790a73105b8SAntonio Quartulli 179141ab6c48SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1792c67893d1SSven Eckelmann packet_pos = skb_put(skb, len); 1793c67893d1SSven Eckelmann tt_response = (struct batadv_tt_query_packet *)packet_pos; 1794a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1795a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1796a73105b8SAntonio Quartulli 179796412690SSven Eckelmann tt_buff = skb->data + sizeof(*tt_response); 1798a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 1799a73105b8SAntonio Quartulli memcpy(tt_buff, req_dst_orig_node->tt_buff, 1800a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 1801a73105b8SAntonio Quartulli 1802a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1803a73105b8SAntonio Quartulli } else { 180496412690SSven Eckelmann tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size); 180596412690SSven Eckelmann tt_len *= sizeof(struct batadv_tt_change); 1806a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1807a73105b8SAntonio Quartulli 1808a513088dSSven Eckelmann skb = batadv_tt_response_fill_table(tt_len, ttvn, 1809807736f6SSven Eckelmann bat_priv->tt.global_hash, 1810736292c2SMarek Lindner bat_priv, 1811a513088dSSven Eckelmann batadv_tt_global_valid, 1812a73105b8SAntonio Quartulli req_dst_orig_node); 1813a73105b8SAntonio Quartulli if (!skb) 1814a73105b8SAntonio Quartulli goto out; 1815a73105b8SAntonio Quartulli 181696412690SSven Eckelmann tt_response = (struct batadv_tt_query_packet *)skb->data; 1817a73105b8SAntonio Quartulli } 1818a73105b8SAntonio Quartulli 1819acd34afaSSven Eckelmann tt_response->header.packet_type = BATADV_TT_QUERY; 18207e071c79SSven Eckelmann tt_response->header.version = BATADV_COMPAT_VERSION; 182142d0b044SSven Eckelmann tt_response->header.ttl = BATADV_TTL; 1822a73105b8SAntonio Quartulli memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); 1823a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1824acd34afaSSven Eckelmann tt_response->flags = BATADV_TT_RESPONSE; 1825a73105b8SAntonio Quartulli 1826a73105b8SAntonio Quartulli if (full_table) 1827acd34afaSSven Eckelmann tt_response->flags |= BATADV_TT_FULL_TABLE; 1828a73105b8SAntonio Quartulli 182939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1830bb351ba0SMartin Hundebøll "Sending TT_RESPONSE %pM for %pM (ttvn: %u)\n", 1831bb351ba0SMartin Hundebøll res_dst_orig_node->orig, req_dst_orig_node->orig, req_ttvn); 1832a73105b8SAntonio Quartulli 1833d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 1834f8214865SMartin Hundebøll 1835e91ecfc6SMartin Hundebøll res = batadv_send_skb_to_orig(skb, res_dst_orig_node, NULL); 1836e91ecfc6SMartin Hundebøll if (res != NET_XMIT_DROP) 1837a73105b8SAntonio Quartulli ret = true; 1838e91ecfc6SMartin Hundebøll 1839a73105b8SAntonio Quartulli goto out; 1840a73105b8SAntonio Quartulli 1841a73105b8SAntonio Quartulli unlock: 1842a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1843a73105b8SAntonio Quartulli 1844a73105b8SAntonio Quartulli out: 1845a73105b8SAntonio Quartulli if (res_dst_orig_node) 18467d211efcSSven Eckelmann batadv_orig_node_free_ref(res_dst_orig_node); 1847a73105b8SAntonio Quartulli if (req_dst_orig_node) 18487d211efcSSven Eckelmann batadv_orig_node_free_ref(req_dst_orig_node); 1849a73105b8SAntonio Quartulli if (!ret) 1850a73105b8SAntonio Quartulli kfree_skb(skb); 1851a73105b8SAntonio Quartulli return ret; 1852a73105b8SAntonio Quartulli } 185396412690SSven Eckelmann 185496412690SSven Eckelmann static bool 185556303d34SSven Eckelmann batadv_send_my_tt_response(struct batadv_priv *bat_priv, 185696412690SSven Eckelmann struct batadv_tt_query_packet *tt_request) 1857a73105b8SAntonio Quartulli { 1858170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 185956303d34SSven Eckelmann struct batadv_hard_iface *primary_if = NULL; 1860a73105b8SAntonio Quartulli uint8_t my_ttvn, req_ttvn, ttvn; 1861a73105b8SAntonio Quartulli int ret = false; 1862a73105b8SAntonio Quartulli unsigned char *tt_buff; 1863a73105b8SAntonio Quartulli bool full_table; 1864a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1865a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 186696412690SSven Eckelmann struct batadv_tt_query_packet *tt_response; 1867c67893d1SSven Eckelmann uint8_t *packet_pos; 186896412690SSven Eckelmann size_t len; 1869a73105b8SAntonio Quartulli 187039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 187186ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 187286ceb360SSven Eckelmann tt_request->src, tt_request->ttvn, 1873acd34afaSSven Eckelmann (tt_request->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1874a73105b8SAntonio Quartulli 1875a73105b8SAntonio Quartulli 1876807736f6SSven Eckelmann my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); 1877a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1878a73105b8SAntonio Quartulli 1879da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); 1880a73105b8SAntonio Quartulli if (!orig_node) 1881a73105b8SAntonio Quartulli goto out; 1882a73105b8SAntonio Quartulli 1883e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1884a73105b8SAntonio Quartulli if (!primary_if) 1885a73105b8SAntonio Quartulli goto out; 1886a73105b8SAntonio Quartulli 1887a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 18889cfc7bd6SSven Eckelmann * is too big send the whole local translation table 18899cfc7bd6SSven Eckelmann */ 1890acd34afaSSven Eckelmann if (tt_request->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || 1891807736f6SSven Eckelmann !bat_priv->tt.last_changeset) 1892a73105b8SAntonio Quartulli full_table = true; 1893a73105b8SAntonio Quartulli else 1894a73105b8SAntonio Quartulli full_table = false; 1895a73105b8SAntonio Quartulli 1896a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 18979cfc7bd6SSven Eckelmann * I'll send only one packet with as much TT entries as I can 18989cfc7bd6SSven Eckelmann */ 1899a73105b8SAntonio Quartulli if (!full_table) { 1900807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 1901807736f6SSven Eckelmann tt_len = bat_priv->tt.last_changeset_len; 190296412690SSven Eckelmann tt_tot = tt_len / sizeof(struct batadv_tt_change); 1903a73105b8SAntonio Quartulli 190496412690SSven Eckelmann len = sizeof(*tt_response) + tt_len; 190541ab6c48SAntonio Quartulli skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); 1906a73105b8SAntonio Quartulli if (!skb) 1907a73105b8SAntonio Quartulli goto unlock; 1908a73105b8SAntonio Quartulli 190941ab6c48SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1910c67893d1SSven Eckelmann packet_pos = skb_put(skb, len); 1911c67893d1SSven Eckelmann tt_response = (struct batadv_tt_query_packet *)packet_pos; 1912a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1913a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1914a73105b8SAntonio Quartulli 191596412690SSven Eckelmann tt_buff = skb->data + sizeof(*tt_response); 1916807736f6SSven Eckelmann memcpy(tt_buff, bat_priv->tt.last_changeset, 1917807736f6SSven Eckelmann bat_priv->tt.last_changeset_len); 1918807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 1919a73105b8SAntonio Quartulli } else { 1920807736f6SSven Eckelmann tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num); 192196412690SSven Eckelmann tt_len *= sizeof(struct batadv_tt_change); 1922807736f6SSven Eckelmann ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); 1923a73105b8SAntonio Quartulli 1924a513088dSSven Eckelmann skb = batadv_tt_response_fill_table(tt_len, ttvn, 1925807736f6SSven Eckelmann bat_priv->tt.local_hash, 1926736292c2SMarek Lindner bat_priv, 1927a513088dSSven Eckelmann batadv_tt_local_valid_entry, 1928058d0e26SAntonio Quartulli NULL); 1929a73105b8SAntonio Quartulli if (!skb) 1930a73105b8SAntonio Quartulli goto out; 1931a73105b8SAntonio Quartulli 193296412690SSven Eckelmann tt_response = (struct batadv_tt_query_packet *)skb->data; 1933a73105b8SAntonio Quartulli } 1934a73105b8SAntonio Quartulli 1935acd34afaSSven Eckelmann tt_response->header.packet_type = BATADV_TT_QUERY; 19367e071c79SSven Eckelmann tt_response->header.version = BATADV_COMPAT_VERSION; 193742d0b044SSven Eckelmann tt_response->header.ttl = BATADV_TTL; 1938a73105b8SAntonio Quartulli memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1939a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1940acd34afaSSven Eckelmann tt_response->flags = BATADV_TT_RESPONSE; 1941a73105b8SAntonio Quartulli 1942a73105b8SAntonio Quartulli if (full_table) 1943acd34afaSSven Eckelmann tt_response->flags |= BATADV_TT_FULL_TABLE; 1944a73105b8SAntonio Quartulli 194539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1946bb351ba0SMartin Hundebøll "Sending TT_RESPONSE to %pM [%c]\n", 1947bb351ba0SMartin Hundebøll orig_node->orig, 1948acd34afaSSven Eckelmann (tt_response->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1949a73105b8SAntonio Quartulli 1950d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 1951f8214865SMartin Hundebøll 1952e91ecfc6SMartin Hundebøll if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) 1953a73105b8SAntonio Quartulli ret = true; 1954a73105b8SAntonio Quartulli goto out; 1955a73105b8SAntonio Quartulli 1956a73105b8SAntonio Quartulli unlock: 1957807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 1958a73105b8SAntonio Quartulli out: 1959a73105b8SAntonio Quartulli if (orig_node) 19607d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1961a73105b8SAntonio Quartulli if (primary_if) 1962e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1963a73105b8SAntonio Quartulli if (!ret) 1964a73105b8SAntonio Quartulli kfree_skb(skb); 1965a73105b8SAntonio Quartulli /* This packet was for me, so it doesn't need to be re-routed */ 1966a73105b8SAntonio Quartulli return true; 1967a73105b8SAntonio Quartulli } 1968a73105b8SAntonio Quartulli 196956303d34SSven Eckelmann bool batadv_send_tt_response(struct batadv_priv *bat_priv, 197096412690SSven Eckelmann struct batadv_tt_query_packet *tt_request) 1971a73105b8SAntonio Quartulli { 1972fe8a93b9SAntonio Quartulli if (batadv_is_my_mac(bat_priv, tt_request->dst)) { 197320ff9d59SSimon Wunderlich /* don't answer backbone gws! */ 197408adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src)) 197520ff9d59SSimon Wunderlich return true; 197620ff9d59SSimon Wunderlich 1977a513088dSSven Eckelmann return batadv_send_my_tt_response(bat_priv, tt_request); 197820ff9d59SSimon Wunderlich } else { 1979a513088dSSven Eckelmann return batadv_send_other_tt_response(bat_priv, tt_request); 1980a73105b8SAntonio Quartulli } 198120ff9d59SSimon Wunderlich } 1982a73105b8SAntonio Quartulli 198356303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, 198456303d34SSven Eckelmann struct batadv_orig_node *orig_node, 198596412690SSven Eckelmann struct batadv_tt_change *tt_change, 1986a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 1987a73105b8SAntonio Quartulli { 1988a73105b8SAntonio Quartulli int i; 1989a513088dSSven Eckelmann int roams; 1990a73105b8SAntonio Quartulli 1991a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 1992acd34afaSSven Eckelmann if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { 1993acd34afaSSven Eckelmann roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; 1994a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 1995a73105b8SAntonio Quartulli (tt_change + i)->addr, 1996cc47f66eSAntonio Quartulli "tt removed by changes", 1997a513088dSSven Eckelmann roams); 199808c36d3eSSven Eckelmann } else { 199908c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 2000d4f44692SAntonio Quartulli (tt_change + i)->addr, 2001d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 2002a73105b8SAntonio Quartulli /* In case of problem while storing a 2003a73105b8SAntonio Quartulli * global_entry, we stop the updating 2004a73105b8SAntonio Quartulli * procedure without committing the 2005a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 2006a73105b8SAntonio Quartulli * corrupted data on tt_request 2007a73105b8SAntonio Quartulli */ 2008a73105b8SAntonio Quartulli return; 2009a73105b8SAntonio Quartulli } 201008c36d3eSSven Eckelmann } 201117071578SAntonio Quartulli orig_node->tt_initialised = true; 2012a73105b8SAntonio Quartulli } 2013a73105b8SAntonio Quartulli 201456303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, 201596412690SSven Eckelmann struct batadv_tt_query_packet *tt_response) 2016a73105b8SAntonio Quartulli { 2017170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 2018a73105b8SAntonio Quartulli 2019da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); 2020a73105b8SAntonio Quartulli if (!orig_node) 2021a73105b8SAntonio Quartulli goto out; 2022a73105b8SAntonio Quartulli 2023a73105b8SAntonio Quartulli /* Purge the old table first.. */ 202408c36d3eSSven Eckelmann batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table"); 2025a73105b8SAntonio Quartulli 2026a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, 202796412690SSven Eckelmann (struct batadv_tt_change *)(tt_response + 1), 2028a513088dSSven Eckelmann ntohs(tt_response->tt_data), 2029a513088dSSven Eckelmann tt_response->ttvn); 2030a73105b8SAntonio Quartulli 2031a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2032a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2033a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2034a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 2035a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2036a73105b8SAntonio Quartulli 2037a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, tt_response->ttvn); 2038a73105b8SAntonio Quartulli 2039a73105b8SAntonio Quartulli out: 2040a73105b8SAntonio Quartulli if (orig_node) 20417d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2042a73105b8SAntonio Quartulli } 2043a73105b8SAntonio Quartulli 204456303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv, 204556303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2046a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 204796412690SSven Eckelmann struct batadv_tt_change *tt_change) 2048a73105b8SAntonio Quartulli { 2049a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 2050a513088dSSven Eckelmann tt_num_changes, ttvn); 2051a73105b8SAntonio Quartulli 2052a513088dSSven Eckelmann batadv_tt_save_orig_buffer(bat_priv, orig_node, 2053a513088dSSven Eckelmann (unsigned char *)tt_change, tt_num_changes); 2054a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2055a73105b8SAntonio Quartulli } 2056a73105b8SAntonio Quartulli 205756303d34SSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr) 2058a73105b8SAntonio Quartulli { 2059170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 20607683fdc1SAntonio Quartulli bool ret = false; 2061a73105b8SAntonio Quartulli 2062a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 20637683fdc1SAntonio Quartulli if (!tt_local_entry) 20647683fdc1SAntonio Quartulli goto out; 2065058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 20669cfc7bd6SSven Eckelmann * consistency purpose) 20679cfc7bd6SSven Eckelmann */ 20687c1fd91dSAntonio Quartulli if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) || 20697c1fd91dSAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM)) 2070058d0e26SAntonio Quartulli goto out; 20717683fdc1SAntonio Quartulli ret = true; 20727683fdc1SAntonio Quartulli out: 2073a73105b8SAntonio Quartulli if (tt_local_entry) 2074a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 20757683fdc1SAntonio Quartulli return ret; 2076a73105b8SAntonio Quartulli } 2077a73105b8SAntonio Quartulli 207856303d34SSven Eckelmann void batadv_handle_tt_response(struct batadv_priv *bat_priv, 207996412690SSven Eckelmann struct batadv_tt_query_packet *tt_response) 2080a73105b8SAntonio Quartulli { 208156303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 208256303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 208396412690SSven Eckelmann struct batadv_tt_change *tt_change; 2084a73105b8SAntonio Quartulli 208539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 208686ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 2087f25bd58aSAl Viro tt_response->src, tt_response->ttvn, 2088f25bd58aSAl Viro ntohs(tt_response->tt_data), 2089acd34afaSSven Eckelmann (tt_response->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 2090a73105b8SAntonio Quartulli 209120ff9d59SSimon Wunderlich /* we should have never asked a backbone gw */ 209208adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src)) 209320ff9d59SSimon Wunderlich goto out; 209420ff9d59SSimon Wunderlich 2095da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); 2096a73105b8SAntonio Quartulli if (!orig_node) 2097a73105b8SAntonio Quartulli goto out; 2098a73105b8SAntonio Quartulli 209996412690SSven Eckelmann if (tt_response->flags & BATADV_TT_FULL_TABLE) { 2100a513088dSSven Eckelmann batadv_tt_fill_gtable(bat_priv, tt_response); 210196412690SSven Eckelmann } else { 210296412690SSven Eckelmann tt_change = (struct batadv_tt_change *)(tt_response + 1); 2103a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, 2104f25bd58aSAl Viro ntohs(tt_response->tt_data), 210596412690SSven Eckelmann tt_response->ttvn, tt_change); 210696412690SSven Eckelmann } 2107a73105b8SAntonio Quartulli 2108a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 2109807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2110807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 21111eda58bfSSven Eckelmann if (!batadv_compare_eth(node->addr, tt_response->src)) 2112a73105b8SAntonio Quartulli continue; 2113a73105b8SAntonio Quartulli list_del(&node->list); 2114a73105b8SAntonio Quartulli kfree(node); 2115a73105b8SAntonio Quartulli } 2116807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2117a73105b8SAntonio Quartulli 2118a73105b8SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 2119a513088dSSven Eckelmann orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 2120a73105b8SAntonio Quartulli out: 2121a73105b8SAntonio Quartulli if (orig_node) 21227d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2123a73105b8SAntonio Quartulli } 2124a73105b8SAntonio Quartulli 212556303d34SSven Eckelmann int batadv_tt_init(struct batadv_priv *bat_priv) 2126a73105b8SAntonio Quartulli { 21275346c35eSSven Eckelmann int ret; 2128a73105b8SAntonio Quartulli 2129a513088dSSven Eckelmann ret = batadv_tt_local_init(bat_priv); 21305346c35eSSven Eckelmann if (ret < 0) 21315346c35eSSven Eckelmann return ret; 21325346c35eSSven Eckelmann 2133a513088dSSven Eckelmann ret = batadv_tt_global_init(bat_priv); 21345346c35eSSven Eckelmann if (ret < 0) 21355346c35eSSven Eckelmann return ret; 2136a73105b8SAntonio Quartulli 213772414442SAntonio Quartulli INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); 213872414442SAntonio Quartulli queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 213972414442SAntonio Quartulli msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 2140a73105b8SAntonio Quartulli 2141a73105b8SAntonio Quartulli return 1; 2142a73105b8SAntonio Quartulli } 2143a73105b8SAntonio Quartulli 214456303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) 2145a73105b8SAntonio Quartulli { 214656303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 2147a73105b8SAntonio Quartulli 2148807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2149a73105b8SAntonio Quartulli 2150807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 2151cc47f66eSAntonio Quartulli list_del(&node->list); 2152cc47f66eSAntonio Quartulli kfree(node); 2153cc47f66eSAntonio Quartulli } 2154cc47f66eSAntonio Quartulli 2155807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2156cc47f66eSAntonio Quartulli } 2157cc47f66eSAntonio Quartulli 215856303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) 2159cc47f66eSAntonio Quartulli { 216056303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 2161cc47f66eSAntonio Quartulli 2162807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2163807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 216442d0b044SSven Eckelmann if (!batadv_has_timed_out(node->first_time, 216542d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 2166cc47f66eSAntonio Quartulli continue; 2167cc47f66eSAntonio Quartulli 2168cc47f66eSAntonio Quartulli list_del(&node->list); 2169cc47f66eSAntonio Quartulli kfree(node); 2170cc47f66eSAntonio Quartulli } 2171807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2172cc47f66eSAntonio Quartulli } 2173cc47f66eSAntonio Quartulli 2174cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 2175cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 2176cc47f66eSAntonio Quartulli * will not be sent. 2177cc47f66eSAntonio Quartulli * 21789cfc7bd6SSven Eckelmann * returns true if the ROAMING_ADV can be sent, false otherwise 21799cfc7bd6SSven Eckelmann */ 218056303d34SSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, 2181cc47f66eSAntonio Quartulli uint8_t *client) 2182cc47f66eSAntonio Quartulli { 218356303d34SSven Eckelmann struct batadv_tt_roam_node *tt_roam_node; 2184cc47f66eSAntonio Quartulli bool ret = false; 2185cc47f66eSAntonio Quartulli 2186807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2187cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 21889cfc7bd6SSven Eckelmann * reply from the same orig_node yet 21899cfc7bd6SSven Eckelmann */ 2190807736f6SSven Eckelmann list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) { 21911eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 2192cc47f66eSAntonio Quartulli continue; 2193cc47f66eSAntonio Quartulli 21941eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 219542d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 2196cc47f66eSAntonio Quartulli continue; 2197cc47f66eSAntonio Quartulli 21983e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 2199cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 2200cc47f66eSAntonio Quartulli goto unlock; 2201cc47f66eSAntonio Quartulli ret = true; 2202cc47f66eSAntonio Quartulli break; 2203cc47f66eSAntonio Quartulli } 2204cc47f66eSAntonio Quartulli 2205cc47f66eSAntonio Quartulli if (!ret) { 2206cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 2207cc47f66eSAntonio Quartulli if (!tt_roam_node) 2208cc47f66eSAntonio Quartulli goto unlock; 2209cc47f66eSAntonio Quartulli 2210cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 221142d0b044SSven Eckelmann atomic_set(&tt_roam_node->counter, 221242d0b044SSven Eckelmann BATADV_ROAMING_MAX_COUNT - 1); 2213cc47f66eSAntonio Quartulli memcpy(tt_roam_node->addr, client, ETH_ALEN); 2214cc47f66eSAntonio Quartulli 2215807736f6SSven Eckelmann list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); 2216cc47f66eSAntonio Quartulli ret = true; 2217cc47f66eSAntonio Quartulli } 2218cc47f66eSAntonio Quartulli 2219cc47f66eSAntonio Quartulli unlock: 2220807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2221cc47f66eSAntonio Quartulli return ret; 2222cc47f66eSAntonio Quartulli } 2223cc47f66eSAntonio Quartulli 222456303d34SSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, 222556303d34SSven Eckelmann struct batadv_orig_node *orig_node) 2226cc47f66eSAntonio Quartulli { 2227cc47f66eSAntonio Quartulli struct sk_buff *skb = NULL; 222896412690SSven Eckelmann struct batadv_roam_adv_packet *roam_adv_packet; 2229cc47f66eSAntonio Quartulli int ret = 1; 223056303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 223196412690SSven Eckelmann size_t len = sizeof(*roam_adv_packet); 2232cc47f66eSAntonio Quartulli 2233cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 22349cfc7bd6SSven Eckelmann * already roamed to us too many times 22359cfc7bd6SSven Eckelmann */ 2236a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 2237cc47f66eSAntonio Quartulli goto out; 2238cc47f66eSAntonio Quartulli 223941ab6c48SAntonio Quartulli skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); 2240cc47f66eSAntonio Quartulli if (!skb) 2241cc47f66eSAntonio Quartulli goto out; 2242cc47f66eSAntonio Quartulli 224341ab6c48SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 2244cc47f66eSAntonio Quartulli 224596412690SSven Eckelmann roam_adv_packet = (struct batadv_roam_adv_packet *)skb_put(skb, len); 2246cc47f66eSAntonio Quartulli 2247acd34afaSSven Eckelmann roam_adv_packet->header.packet_type = BATADV_ROAM_ADV; 22487e071c79SSven Eckelmann roam_adv_packet->header.version = BATADV_COMPAT_VERSION; 224942d0b044SSven Eckelmann roam_adv_packet->header.ttl = BATADV_TTL; 2250162d549cSSven Eckelmann roam_adv_packet->reserved = 0; 2251e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2252cc47f66eSAntonio Quartulli if (!primary_if) 2253cc47f66eSAntonio Quartulli goto out; 2254cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); 2255e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 2256cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); 2257cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->client, client, ETH_ALEN); 2258cc47f66eSAntonio Quartulli 225939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2260bb351ba0SMartin Hundebøll "Sending ROAMING_ADV to %pM (client %pM)\n", 2261bb351ba0SMartin Hundebøll orig_node->orig, client); 2262cc47f66eSAntonio Quartulli 2263d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); 2264f8214865SMartin Hundebøll 2265e91ecfc6SMartin Hundebøll if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) 2266cc47f66eSAntonio Quartulli ret = 0; 2267cc47f66eSAntonio Quartulli 2268cc47f66eSAntonio Quartulli out: 2269bb351ba0SMartin Hundebøll if (ret && skb) 2270cc47f66eSAntonio Quartulli kfree_skb(skb); 2271cc47f66eSAntonio Quartulli return; 2272a73105b8SAntonio Quartulli } 2273a73105b8SAntonio Quartulli 2274a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 2275a73105b8SAntonio Quartulli { 227656303d34SSven Eckelmann struct delayed_work *delayed_work; 2277807736f6SSven Eckelmann struct batadv_priv_tt *priv_tt; 227856303d34SSven Eckelmann struct batadv_priv *bat_priv; 227956303d34SSven Eckelmann 228056303d34SSven Eckelmann delayed_work = container_of(work, struct delayed_work, work); 2281807736f6SSven Eckelmann priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 2282807736f6SSven Eckelmann bat_priv = container_of(priv_tt, struct batadv_priv, tt); 2283a73105b8SAntonio Quartulli 2284a513088dSSven Eckelmann batadv_tt_local_purge(bat_priv); 228530cfd02bSAntonio Quartulli batadv_tt_global_purge(bat_priv); 2286a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 2287a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 2288a73105b8SAntonio Quartulli 228972414442SAntonio Quartulli queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 229072414442SAntonio Quartulli msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 2291a73105b8SAntonio Quartulli } 2292cc47f66eSAntonio Quartulli 229356303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv) 2294cc47f66eSAntonio Quartulli { 2295807736f6SSven Eckelmann cancel_delayed_work_sync(&bat_priv->tt.work); 2296cc47f66eSAntonio Quartulli 2297a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 2298a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 2299a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 2300a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 2301a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 2302cc47f66eSAntonio Quartulli 2303807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 2304cc47f66eSAntonio Quartulli } 2305058d0e26SAntonio Quartulli 2306697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries 23079cfc7bd6SSven Eckelmann * in the given hash table and returns the number of modified entries 23089cfc7bd6SSven Eckelmann */ 23095bf74e9cSSven Eckelmann static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash, 23105bf74e9cSSven Eckelmann uint16_t flags, bool enable) 2311058d0e26SAntonio Quartulli { 2312c90681b8SAntonio Quartulli uint32_t i; 2313697f2531SAntonio Quartulli uint16_t changed_num = 0; 2314058d0e26SAntonio Quartulli struct hlist_head *head; 231556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 2316058d0e26SAntonio Quartulli 2317058d0e26SAntonio Quartulli if (!hash) 2318697f2531SAntonio Quartulli goto out; 2319058d0e26SAntonio Quartulli 2320058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2321058d0e26SAntonio Quartulli head = &hash->table[i]; 2322058d0e26SAntonio Quartulli 2323058d0e26SAntonio Quartulli rcu_read_lock(); 2324b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 2325058d0e26SAntonio Quartulli head, hash_entry) { 2326697f2531SAntonio Quartulli if (enable) { 2327697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 2328697f2531SAntonio Quartulli continue; 2329697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 2330697f2531SAntonio Quartulli } else { 233148100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 233231901264SAntonio Quartulli continue; 233348100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 2334697f2531SAntonio Quartulli } 2335697f2531SAntonio Quartulli changed_num++; 2336058d0e26SAntonio Quartulli } 2337058d0e26SAntonio Quartulli rcu_read_unlock(); 2338058d0e26SAntonio Quartulli } 2339697f2531SAntonio Quartulli out: 2340697f2531SAntonio Quartulli return changed_num; 2341058d0e26SAntonio Quartulli } 2342058d0e26SAntonio Quartulli 2343acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ 234456303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) 2345058d0e26SAntonio Quartulli { 2346807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 234756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 234856303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 2349b67bfe0dSSasha Levin struct hlist_node *node_tmp; 2350058d0e26SAntonio Quartulli struct hlist_head *head; 2351058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 2352c90681b8SAntonio Quartulli uint32_t i; 2353058d0e26SAntonio Quartulli 2354058d0e26SAntonio Quartulli if (!hash) 2355058d0e26SAntonio Quartulli return; 2356058d0e26SAntonio Quartulli 2357058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2358058d0e26SAntonio Quartulli head = &hash->table[i]; 2359058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 2360058d0e26SAntonio Quartulli 2361058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 2362b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 2363acd34afaSSven Eckelmann hash_entry) { 2364acd34afaSSven Eckelmann if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) 2365058d0e26SAntonio Quartulli continue; 2366058d0e26SAntonio Quartulli 236739c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 236886ceb360SSven Eckelmann "Deleting local tt entry (%pM): pending\n", 2369acd34afaSSven Eckelmann tt_common->addr); 2370058d0e26SAntonio Quartulli 2371807736f6SSven Eckelmann atomic_dec(&bat_priv->tt.local_entry_num); 2372b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 237356303d34SSven Eckelmann tt_local = container_of(tt_common, 237456303d34SSven Eckelmann struct batadv_tt_local_entry, 237548100bacSAntonio Quartulli common); 237656303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 2377058d0e26SAntonio Quartulli } 2378058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 2379058d0e26SAntonio Quartulli } 2380058d0e26SAntonio Quartulli } 2381058d0e26SAntonio Quartulli 238256303d34SSven Eckelmann static int batadv_tt_commit_changes(struct batadv_priv *bat_priv, 2383a513088dSSven Eckelmann unsigned char **packet_buff, 2384a513088dSSven Eckelmann int *packet_buff_len, int packet_min_len) 2385058d0e26SAntonio Quartulli { 2386be9aa4c1SMarek Lindner uint16_t changed_num = 0; 2387be9aa4c1SMarek Lindner 2388807736f6SSven Eckelmann if (atomic_read(&bat_priv->tt.local_changes) < 1) 2389be9aa4c1SMarek Lindner return -ENOENT; 2390be9aa4c1SMarek Lindner 2391807736f6SSven Eckelmann changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash, 2392acd34afaSSven Eckelmann BATADV_TT_CLIENT_NEW, false); 2393be9aa4c1SMarek Lindner 2394be9aa4c1SMarek Lindner /* all reset entries have to be counted as local entries */ 2395807736f6SSven Eckelmann atomic_add(changed_num, &bat_priv->tt.local_entry_num); 2396a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 2397807736f6SSven Eckelmann bat_priv->tt.local_crc = batadv_tt_local_crc(bat_priv); 2398058d0e26SAntonio Quartulli 2399058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 2400807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.vn); 240139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 24021eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 2403807736f6SSven Eckelmann (uint8_t)atomic_read(&bat_priv->tt.vn)); 2404be9aa4c1SMarek Lindner 2405be9aa4c1SMarek Lindner /* reset the sending counter */ 2406807736f6SSven Eckelmann atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 2407be9aa4c1SMarek Lindner 2408a513088dSSven Eckelmann return batadv_tt_changes_fill_buff(bat_priv, packet_buff, 2409be9aa4c1SMarek Lindner packet_buff_len, packet_min_len); 2410be9aa4c1SMarek Lindner } 2411be9aa4c1SMarek Lindner 2412be9aa4c1SMarek Lindner /* when calling this function (hard_iface == primary_if) has to be true */ 241356303d34SSven Eckelmann int batadv_tt_append_diff(struct batadv_priv *bat_priv, 2414be9aa4c1SMarek Lindner unsigned char **packet_buff, int *packet_buff_len, 2415be9aa4c1SMarek Lindner int packet_min_len) 2416be9aa4c1SMarek Lindner { 2417be9aa4c1SMarek Lindner int tt_num_changes; 2418be9aa4c1SMarek Lindner 2419be9aa4c1SMarek Lindner /* if at least one change happened */ 2420a513088dSSven Eckelmann tt_num_changes = batadv_tt_commit_changes(bat_priv, packet_buff, 2421a513088dSSven Eckelmann packet_buff_len, 2422a513088dSSven Eckelmann packet_min_len); 2423be9aa4c1SMarek Lindner 2424be9aa4c1SMarek Lindner /* if the changes have been sent often enough */ 2425be9aa4c1SMarek Lindner if ((tt_num_changes < 0) && 2426807736f6SSven Eckelmann (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))) { 2427a513088dSSven Eckelmann batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, 2428be9aa4c1SMarek Lindner packet_min_len, packet_min_len); 2429be9aa4c1SMarek Lindner tt_num_changes = 0; 2430be9aa4c1SMarek Lindner } 2431be9aa4c1SMarek Lindner 2432be9aa4c1SMarek Lindner return tt_num_changes; 2433058d0e26SAntonio Quartulli } 243459b699cdSAntonio Quartulli 243556303d34SSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, 243608c36d3eSSven Eckelmann uint8_t *dst) 243759b699cdSAntonio Quartulli { 243856303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 243956303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 24405870adc6SMarek Lindner bool ret = false; 244159b699cdSAntonio Quartulli 244259b699cdSAntonio Quartulli if (!atomic_read(&bat_priv->ap_isolation)) 24435870adc6SMarek Lindner goto out; 244459b699cdSAntonio Quartulli 2445a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst); 244659b699cdSAntonio Quartulli if (!tt_local_entry) 244759b699cdSAntonio Quartulli goto out; 244859b699cdSAntonio Quartulli 2449a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, src); 245059b699cdSAntonio Quartulli if (!tt_global_entry) 245159b699cdSAntonio Quartulli goto out; 245259b699cdSAntonio Quartulli 24531f129fefSAntonio Quartulli if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 245459b699cdSAntonio Quartulli goto out; 245559b699cdSAntonio Quartulli 24565870adc6SMarek Lindner ret = true; 245759b699cdSAntonio Quartulli 245859b699cdSAntonio Quartulli out: 245959b699cdSAntonio Quartulli if (tt_global_entry) 2460a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 246159b699cdSAntonio Quartulli if (tt_local_entry) 2462a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 246359b699cdSAntonio Quartulli return ret; 246459b699cdSAntonio Quartulli } 2465a943cac1SMarek Lindner 246656303d34SSven Eckelmann void batadv_tt_update_orig(struct batadv_priv *bat_priv, 246756303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2468a943cac1SMarek Lindner const unsigned char *tt_buff, uint8_t tt_num_changes, 2469a943cac1SMarek Lindner uint8_t ttvn, uint16_t tt_crc) 2470a943cac1SMarek Lindner { 2471a943cac1SMarek Lindner uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); 2472a943cac1SMarek Lindner bool full_table = true; 247396412690SSven Eckelmann struct batadv_tt_change *tt_change; 2474a943cac1SMarek Lindner 247520ff9d59SSimon Wunderlich /* don't care about a backbone gateways updates. */ 247608adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) 247720ff9d59SSimon Wunderlich return; 247820ff9d59SSimon Wunderlich 247917071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 24809cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 24819cfc7bd6SSven Eckelmann */ 248217071578SAntonio Quartulli if ((!orig_node->tt_initialised && ttvn == 1) || 248317071578SAntonio Quartulli ttvn - orig_ttvn == 1) { 2484a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 248542d0b044SSven Eckelmann * because they have already been sent BATADV_TT_OGM_APPEND_MAX 248642d0b044SSven Eckelmann * times. 24879cfc7bd6SSven Eckelmann * In this case send a tt request 24889cfc7bd6SSven Eckelmann */ 2489a943cac1SMarek Lindner if (!tt_num_changes) { 2490a943cac1SMarek Lindner full_table = false; 2491a943cac1SMarek Lindner goto request_table; 2492a943cac1SMarek Lindner } 2493a943cac1SMarek Lindner 249496412690SSven Eckelmann tt_change = (struct batadv_tt_change *)tt_buff; 2495a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 249696412690SSven Eckelmann ttvn, tt_change); 2497a943cac1SMarek Lindner 2498a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 2499a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 25009cfc7bd6SSven Eckelmann * in the global table 25019cfc7bd6SSven Eckelmann */ 2502a513088dSSven Eckelmann orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 2503a943cac1SMarek Lindner 2504a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 2505a943cac1SMarek Lindner * because a single value could represent different states 2506a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 2507a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 2508a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 2509a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 2510a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 25119cfc7bd6SSven Eckelmann * inconsistency 25129cfc7bd6SSven Eckelmann */ 2513a943cac1SMarek Lindner if (orig_node->tt_crc != tt_crc) 2514a943cac1SMarek Lindner goto request_table; 2515a943cac1SMarek Lindner } else { 2516a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 25179cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 25189cfc7bd6SSven Eckelmann */ 251917071578SAntonio Quartulli if (!orig_node->tt_initialised || ttvn != orig_ttvn || 252017071578SAntonio Quartulli orig_node->tt_crc != tt_crc) { 2521a943cac1SMarek Lindner request_table: 252239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 252339a32991SAntonio Quartulli "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %#.4x last_crc: %#.4x num_changes: %u)\n", 252486ceb360SSven Eckelmann orig_node->orig, ttvn, orig_ttvn, tt_crc, 252586ceb360SSven Eckelmann orig_node->tt_crc, tt_num_changes); 2526a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 2527a513088dSSven Eckelmann tt_crc, full_table); 2528a943cac1SMarek Lindner return; 2529a943cac1SMarek Lindner } 2530a943cac1SMarek Lindner } 2531a943cac1SMarek Lindner } 25323275e7ccSAntonio Quartulli 25333275e7ccSAntonio Quartulli /* returns true whether we know that the client has moved from its old 25343275e7ccSAntonio Quartulli * originator to another one. This entry is kept is still kept for consistency 25353275e7ccSAntonio Quartulli * purposes 25363275e7ccSAntonio Quartulli */ 253756303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, 253808c36d3eSSven Eckelmann uint8_t *addr) 25393275e7ccSAntonio Quartulli { 254056303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 25413275e7ccSAntonio Quartulli bool ret = false; 25423275e7ccSAntonio Quartulli 2543a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 25443275e7ccSAntonio Quartulli if (!tt_global_entry) 25453275e7ccSAntonio Quartulli goto out; 25463275e7ccSAntonio Quartulli 2547c1d07431SAntonio Quartulli ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; 2548a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 25493275e7ccSAntonio Quartulli out: 25503275e7ccSAntonio Quartulli return ret; 25513275e7ccSAntonio Quartulli } 255230cfd02bSAntonio Quartulli 25537c1fd91dSAntonio Quartulli /** 25547c1fd91dSAntonio Quartulli * batadv_tt_local_client_is_roaming - tells whether the client is roaming 25557c1fd91dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 25567c1fd91dSAntonio Quartulli * @addr: the MAC address of the local client to query 25577c1fd91dSAntonio Quartulli * 25587c1fd91dSAntonio Quartulli * Returns true if the local client is known to be roaming (it is not served by 25597c1fd91dSAntonio Quartulli * this node anymore) or not. If yes, the client is still present in the table 25607c1fd91dSAntonio Quartulli * to keep the latter consistent with the node TTVN 25617c1fd91dSAntonio Quartulli */ 25627c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, 25637c1fd91dSAntonio Quartulli uint8_t *addr) 25647c1fd91dSAntonio Quartulli { 25657c1fd91dSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry; 25667c1fd91dSAntonio Quartulli bool ret = false; 25677c1fd91dSAntonio Quartulli 25687c1fd91dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 25697c1fd91dSAntonio Quartulli if (!tt_local_entry) 25707c1fd91dSAntonio Quartulli goto out; 25717c1fd91dSAntonio Quartulli 25727c1fd91dSAntonio Quartulli ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; 25737c1fd91dSAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 25747c1fd91dSAntonio Quartulli out: 25757c1fd91dSAntonio Quartulli return ret; 25767c1fd91dSAntonio Quartulli } 25777c1fd91dSAntonio Quartulli 257830cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, 257930cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 258030cfd02bSAntonio Quartulli const unsigned char *addr) 258130cfd02bSAntonio Quartulli { 258230cfd02bSAntonio Quartulli bool ret = false; 258330cfd02bSAntonio Quartulli 25841f36aebcSAntonio Quartulli /* if the originator is a backbone node (meaning it belongs to the same 25851f36aebcSAntonio Quartulli * LAN of this node) the temporary client must not be added because to 25861f36aebcSAntonio Quartulli * reach such destination the node must use the LAN instead of the mesh 25871f36aebcSAntonio Quartulli */ 25881f36aebcSAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) 25891f36aebcSAntonio Quartulli goto out; 25901f36aebcSAntonio Quartulli 259130cfd02bSAntonio Quartulli if (!batadv_tt_global_add(bat_priv, orig_node, addr, 259230cfd02bSAntonio Quartulli BATADV_TT_CLIENT_TEMP, 259330cfd02bSAntonio Quartulli atomic_read(&orig_node->last_ttvn))) 259430cfd02bSAntonio Quartulli goto out; 259530cfd02bSAntonio Quartulli 259630cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 259730cfd02bSAntonio Quartulli "Added temporary global client (addr: %pM orig: %pM)\n", 259830cfd02bSAntonio Quartulli addr, orig_node->orig); 259930cfd02bSAntonio Quartulli ret = true; 260030cfd02bSAntonio Quartulli out: 260130cfd02bSAntonio Quartulli return ret; 260230cfd02bSAntonio Quartulli } 2603