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 if (!tt_change_node) 184a73105b8SAntonio Quartulli return; 185a73105b8SAntonio Quartulli 186ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 187e1bf0c14SMarek Lindner tt_change_node->change.reserved = 0; 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 232335fbe0fSMarek Lindner /** 233335fbe0fSMarek Lindner * batadv_tt_len - compute length in bytes of given number of tt changes 234335fbe0fSMarek Lindner * @changes_num: number of tt changes 235335fbe0fSMarek Lindner * 236335fbe0fSMarek Lindner * Returns computed length in bytes. 237335fbe0fSMarek Lindner */ 238335fbe0fSMarek Lindner static int batadv_tt_len(int changes_num) 239a73105b8SAntonio Quartulli { 240335fbe0fSMarek Lindner return changes_num * sizeof(struct batadv_tvlv_tt_change); 241a73105b8SAntonio Quartulli } 242a73105b8SAntonio Quartulli 24356303d34SSven Eckelmann static int batadv_tt_local_init(struct batadv_priv *bat_priv) 244c6c8fea2SSven Eckelmann { 245807736f6SSven Eckelmann if (bat_priv->tt.local_hash) 2465346c35eSSven Eckelmann return 0; 247c6c8fea2SSven Eckelmann 248807736f6SSven Eckelmann bat_priv->tt.local_hash = batadv_hash_new(1024); 249c6c8fea2SSven Eckelmann 250807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 2515346c35eSSven Eckelmann return -ENOMEM; 252c6c8fea2SSven Eckelmann 253dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.local_hash, 254dec05074SAntonio Quartulli &batadv_tt_local_hash_lock_class_key); 255dec05074SAntonio Quartulli 2565346c35eSSven Eckelmann return 0; 257c6c8fea2SSven Eckelmann } 258c6c8fea2SSven Eckelmann 259068ee6e2SAntonio Quartulli static void batadv_tt_global_free(struct batadv_priv *bat_priv, 260068ee6e2SAntonio Quartulli struct batadv_tt_global_entry *tt_global, 261068ee6e2SAntonio Quartulli const char *message) 262068ee6e2SAntonio Quartulli { 263068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 264068ee6e2SAntonio Quartulli "Deleting global tt entry %pM: %s\n", 265068ee6e2SAntonio Quartulli tt_global->common.addr, message); 266068ee6e2SAntonio Quartulli 267068ee6e2SAntonio Quartulli batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, 268068ee6e2SAntonio Quartulli batadv_choose_orig, tt_global->common.addr); 269068ee6e2SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 270068ee6e2SAntonio Quartulli } 271068ee6e2SAntonio Quartulli 27208c36d3eSSven Eckelmann void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 273bc279080SAntonio Quartulli int ifindex) 274c6c8fea2SSven Eckelmann { 27556303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(soft_iface); 276170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local; 277170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global; 278db08e6e5SSimon Wunderlich struct hlist_head *head; 27956303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 28080b3f58cSSimon Wunderlich int hash_added; 281068ee6e2SAntonio Quartulli bool roamed_back = false; 282c6c8fea2SSven Eckelmann 28347c94655SAntonio Quartulli tt_local = batadv_tt_local_hash_find(bat_priv, addr); 284068ee6e2SAntonio Quartulli tt_global = batadv_tt_global_hash_find(bat_priv, addr); 285c6c8fea2SSven Eckelmann 28647c94655SAntonio Quartulli if (tt_local) { 28747c94655SAntonio Quartulli tt_local->last_seen = jiffies; 288068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { 289068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 290068ee6e2SAntonio Quartulli "Re-adding pending client %pM\n", addr); 291068ee6e2SAntonio Quartulli /* whatever the reason why the PENDING flag was set, 292068ee6e2SAntonio Quartulli * this is a client which was enqueued to be removed in 293068ee6e2SAntonio Quartulli * this orig_interval. Since it popped up again, the 294068ee6e2SAntonio Quartulli * flag can be reset like it was never enqueued 295068ee6e2SAntonio Quartulli */ 29647c94655SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; 297068ee6e2SAntonio Quartulli goto add_event; 298068ee6e2SAntonio Quartulli } 299068ee6e2SAntonio Quartulli 300068ee6e2SAntonio Quartulli if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { 301068ee6e2SAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 302068ee6e2SAntonio Quartulli "Roaming client %pM came back to its original location\n", 303068ee6e2SAntonio Quartulli addr); 304068ee6e2SAntonio Quartulli /* the ROAM flag is set because this client roamed away 305068ee6e2SAntonio Quartulli * and the node got a roaming_advertisement message. Now 306068ee6e2SAntonio Quartulli * that the client popped up again at its original 307068ee6e2SAntonio Quartulli * location such flag can be unset 308068ee6e2SAntonio Quartulli */ 309068ee6e2SAntonio Quartulli tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; 310068ee6e2SAntonio Quartulli roamed_back = true; 311068ee6e2SAntonio Quartulli } 312068ee6e2SAntonio Quartulli goto check_roaming; 313c6c8fea2SSven Eckelmann } 314c6c8fea2SSven Eckelmann 31547c94655SAntonio Quartulli tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); 31647c94655SAntonio Quartulli if (!tt_local) 3177683fdc1SAntonio Quartulli goto out; 318a73105b8SAntonio Quartulli 31939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 320a73105b8SAntonio Quartulli "Creating new local tt entry: %pM (ttvn: %d)\n", addr, 321807736f6SSven Eckelmann (uint8_t)atomic_read(&bat_priv->tt.vn)); 322c6c8fea2SSven Eckelmann 32347c94655SAntonio Quartulli memcpy(tt_local->common.addr, addr, ETH_ALEN); 3248425ec6aSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 3258425ec6aSAntonio Quartulli * a full table response going out before the next ttvn increment 3268425ec6aSAntonio Quartulli * (consistency check) 3278425ec6aSAntonio Quartulli */ 3288425ec6aSAntonio Quartulli tt_local->common.flags = BATADV_TT_CLIENT_NEW; 3299563877eSSven Eckelmann if (batadv_is_wifi_iface(ifindex)) 33047c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; 33147c94655SAntonio Quartulli atomic_set(&tt_local->common.refcount, 2); 33247c94655SAntonio Quartulli tt_local->last_seen = jiffies; 33347c94655SAntonio Quartulli tt_local->common.added_at = tt_local->last_seen; 334c6c8fea2SSven Eckelmann 335c6c8fea2SSven Eckelmann /* the batman interface mac address should never be purged */ 3361eda58bfSSven Eckelmann if (batadv_compare_eth(addr, soft_iface->dev_addr)) 33747c94655SAntonio Quartulli tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; 338c6c8fea2SSven Eckelmann 339807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, 34047c94655SAntonio Quartulli batadv_choose_orig, &tt_local->common, 34147c94655SAntonio Quartulli &tt_local->common.hash_entry); 34280b3f58cSSimon Wunderlich 34380b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 34480b3f58cSSimon Wunderlich /* remove the reference for the hash */ 34547c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 34680b3f58cSSimon Wunderlich goto out; 34780b3f58cSSimon Wunderlich } 34880b3f58cSSimon Wunderlich 349068ee6e2SAntonio Quartulli add_event: 3503abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); 351ff66c975SAntonio Quartulli 352068ee6e2SAntonio Quartulli check_roaming: 353068ee6e2SAntonio Quartulli /* Check whether it is a roaming, but don't do anything if the roaming 354068ee6e2SAntonio Quartulli * process has already been handled 355068ee6e2SAntonio Quartulli */ 356068ee6e2SAntonio Quartulli if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { 357db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 35847c94655SAntonio Quartulli head = &tt_global->orig_list; 359db08e6e5SSimon Wunderlich rcu_read_lock(); 360b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 36147c94655SAntonio Quartulli batadv_send_roam_adv(bat_priv, tt_global->common.addr, 362db08e6e5SSimon Wunderlich orig_entry->orig_node); 363db08e6e5SSimon Wunderlich } 364db08e6e5SSimon Wunderlich rcu_read_unlock(); 365068ee6e2SAntonio Quartulli if (roamed_back) { 366068ee6e2SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global, 367068ee6e2SAntonio Quartulli "Roaming canceled"); 368068ee6e2SAntonio Quartulli tt_global = NULL; 369068ee6e2SAntonio Quartulli } else { 370db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 371db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 372db08e6e5SSimon Wunderlich */ 37347c94655SAntonio Quartulli tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; 37447c94655SAntonio Quartulli tt_global->roam_at = jiffies; 3757683fdc1SAntonio Quartulli } 376068ee6e2SAntonio Quartulli } 377068ee6e2SAntonio Quartulli 3787683fdc1SAntonio Quartulli out: 37947c94655SAntonio Quartulli if (tt_local) 38047c94655SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local); 38147c94655SAntonio Quartulli if (tt_global) 38247c94655SAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 383c6c8fea2SSven Eckelmann } 384c6c8fea2SSven Eckelmann 385e1bf0c14SMarek Lindner /** 386e1bf0c14SMarek Lindner * batadv_tt_tvlv_container_update - update the translation table tvlv container 387e1bf0c14SMarek Lindner * after local tt changes have been committed 388e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 389e1bf0c14SMarek Lindner */ 390e1bf0c14SMarek Lindner static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) 391c6c8fea2SSven Eckelmann { 392e1bf0c14SMarek Lindner struct batadv_tt_change_node *entry, *safe; 393e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 394e1bf0c14SMarek Lindner struct batadv_tvlv_tt_change *tt_change; 395e1bf0c14SMarek Lindner int tt_diff_len = 0, tt_change_len = 0; 396e1bf0c14SMarek Lindner int tt_diff_entries_num = 0, tt_diff_entries_count = 0; 397c6c8fea2SSven Eckelmann 398e1bf0c14SMarek Lindner tt_diff_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes)); 399be9aa4c1SMarek Lindner 400be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 401be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 402be9aa4c1SMarek Lindner */ 403e1bf0c14SMarek Lindner if (tt_diff_len > bat_priv->soft_iface->mtu) 404e1bf0c14SMarek Lindner tt_diff_len = 0; 405be9aa4c1SMarek Lindner 406e1bf0c14SMarek Lindner tt_data = kzalloc(sizeof(*tt_data) + tt_diff_len, GFP_ATOMIC); 407e1bf0c14SMarek Lindner if (!tt_data) 408e1bf0c14SMarek Lindner return; 409be9aa4c1SMarek Lindner 410e1bf0c14SMarek Lindner tt_data->flags = BATADV_TT_OGM_DIFF; 411e1bf0c14SMarek Lindner tt_data->ttvn = atomic_read(&bat_priv->tt.vn); 412e1bf0c14SMarek Lindner tt_data->crc = htons(bat_priv->tt.local_crc); 413be9aa4c1SMarek Lindner 414e1bf0c14SMarek Lindner if (tt_diff_len == 0) 415e1bf0c14SMarek Lindner goto container_register; 416be9aa4c1SMarek Lindner 417e1bf0c14SMarek Lindner tt_diff_entries_num = tt_diff_len / batadv_tt_len(1); 418c6c8fea2SSven Eckelmann 419807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 420807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 421c6c8fea2SSven Eckelmann 422e1bf0c14SMarek Lindner tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1); 423e1bf0c14SMarek Lindner 424807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 425a73105b8SAntonio Quartulli list) { 426e1bf0c14SMarek Lindner if (tt_diff_entries_count < tt_diff_entries_num) { 427e1bf0c14SMarek Lindner memcpy(tt_change + tt_diff_entries_count, 428e1bf0c14SMarek Lindner &entry->change, 429e1bf0c14SMarek Lindner sizeof(struct batadv_tvlv_tt_change)); 430e1bf0c14SMarek Lindner tt_diff_entries_count++; 431c6c8fea2SSven Eckelmann } 432a73105b8SAntonio Quartulli list_del(&entry->list); 433a73105b8SAntonio Quartulli kfree(entry); 434c6c8fea2SSven Eckelmann } 435807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 436c6c8fea2SSven Eckelmann 437a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 438807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 439807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 440807736f6SSven Eckelmann bat_priv->tt.last_changeset_len = 0; 441807736f6SSven Eckelmann bat_priv->tt.last_changeset = NULL; 442e1bf0c14SMarek Lindner tt_change_len = batadv_tt_len(tt_diff_entries_count); 443be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 444e1bf0c14SMarek Lindner if (tt_diff_entries_count > 0) { 445be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 446a73105b8SAntonio Quartulli * instead of providing the diff 447a73105b8SAntonio Quartulli */ 448e1bf0c14SMarek Lindner bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); 449807736f6SSven Eckelmann if (bat_priv->tt.last_changeset) { 450e1bf0c14SMarek Lindner memcpy(bat_priv->tt.last_changeset, 451e1bf0c14SMarek Lindner tt_change, tt_change_len); 452e1bf0c14SMarek Lindner bat_priv->tt.last_changeset_len = tt_diff_len; 453a73105b8SAntonio Quartulli } 454a73105b8SAntonio Quartulli } 455807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 456c6c8fea2SSven Eckelmann 457e1bf0c14SMarek Lindner container_register: 458e1bf0c14SMarek Lindner batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, 459e1bf0c14SMarek Lindner sizeof(*tt_data) + tt_change_len); 460e1bf0c14SMarek Lindner kfree(tt_data); 461c6c8fea2SSven Eckelmann } 462c6c8fea2SSven Eckelmann 46308c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) 464c6c8fea2SSven Eckelmann { 465c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 46656303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 467807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 46856303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 46985766a82SAntonio Quartulli struct batadv_tt_local_entry *tt_local; 47056303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 471c6c8fea2SSven Eckelmann struct hlist_head *head; 472c90681b8SAntonio Quartulli uint32_t i; 47385766a82SAntonio Quartulli int last_seen_secs; 47485766a82SAntonio Quartulli int last_seen_msecs; 47585766a82SAntonio Quartulli unsigned long last_seen_jiffies; 47685766a82SAntonio Quartulli bool no_purge; 47785766a82SAntonio Quartulli uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE; 478c6c8fea2SSven Eckelmann 47930da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 48030da63a6SMarek Lindner if (!primary_if) 48132ae9b22SMarek Lindner goto out; 482c6c8fea2SSven Eckelmann 48386ceb360SSven Eckelmann seq_printf(seq, 484f9d8a537SAntonio Quartulli "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.4x):\n", 485f9d8a537SAntonio Quartulli net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn), 486f9d8a537SAntonio Quartulli bat_priv->tt.local_crc); 48785766a82SAntonio Quartulli seq_printf(seq, " %-13s %-7s %-10s\n", "Client", "Flags", 48885766a82SAntonio Quartulli "Last seen"); 489c6c8fea2SSven Eckelmann 490c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 491c6c8fea2SSven Eckelmann head = &hash->table[i]; 492c6c8fea2SSven Eckelmann 4937aadf889SMarek Lindner rcu_read_lock(); 494b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 4957aadf889SMarek Lindner head, hash_entry) { 49685766a82SAntonio Quartulli tt_local = container_of(tt_common_entry, 49785766a82SAntonio Quartulli struct batadv_tt_local_entry, 49885766a82SAntonio Quartulli common); 49985766a82SAntonio Quartulli last_seen_jiffies = jiffies - tt_local->last_seen; 50085766a82SAntonio Quartulli last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 50185766a82SAntonio Quartulli last_seen_secs = last_seen_msecs / 1000; 50285766a82SAntonio Quartulli last_seen_msecs = last_seen_msecs % 1000; 50385766a82SAntonio Quartulli 50485766a82SAntonio Quartulli no_purge = tt_common_entry->flags & np_flag; 50585766a82SAntonio Quartulli 50685766a82SAntonio Quartulli seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n", 50748100bacSAntonio Quartulli tt_common_entry->addr, 50848100bacSAntonio Quartulli (tt_common_entry->flags & 509acd34afaSSven Eckelmann BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 51085766a82SAntonio Quartulli no_purge ? 'P' : '.', 51148100bacSAntonio Quartulli (tt_common_entry->flags & 512acd34afaSSven Eckelmann BATADV_TT_CLIENT_NEW ? 'N' : '.'), 51348100bacSAntonio Quartulli (tt_common_entry->flags & 514acd34afaSSven Eckelmann BATADV_TT_CLIENT_PENDING ? 'X' : '.'), 51548100bacSAntonio Quartulli (tt_common_entry->flags & 51685766a82SAntonio Quartulli BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 517a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_secs, 518a7966d90SAntonio Quartulli no_purge ? 0 : last_seen_msecs); 519c6c8fea2SSven Eckelmann } 5207aadf889SMarek Lindner rcu_read_unlock(); 521c6c8fea2SSven Eckelmann } 52232ae9b22SMarek Lindner out: 52332ae9b22SMarek Lindner if (primary_if) 524e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 52530da63a6SMarek Lindner return 0; 526c6c8fea2SSven Eckelmann } 527c6c8fea2SSven Eckelmann 52856303d34SSven Eckelmann static void 52956303d34SSven Eckelmann batadv_tt_local_set_pending(struct batadv_priv *bat_priv, 53056303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry, 531c566dbbeSAntonio Quartulli uint16_t flags, const char *message) 532c6c8fea2SSven Eckelmann { 5333abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, flags); 534c6c8fea2SSven Eckelmann 535015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 536015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 5379cfc7bd6SSven Eckelmann * response issued before the net ttvn increment (consistency check) 5389cfc7bd6SSven Eckelmann */ 539acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; 540c566dbbeSAntonio Quartulli 54139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 54286ceb360SSven Eckelmann "Local tt entry (%pM) pending to be removed: %s\n", 54386ceb360SSven Eckelmann tt_local_entry->common.addr, message); 544c6c8fea2SSven Eckelmann } 545c6c8fea2SSven Eckelmann 5467f91d06cSAntonio Quartulli /** 5477f91d06cSAntonio Quartulli * batadv_tt_local_remove - logically remove an entry from the local table 5487f91d06cSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 5497f91d06cSAntonio Quartulli * @addr: the MAC address of the client to remove 5507f91d06cSAntonio Quartulli * @message: message to append to the log on deletion 5517f91d06cSAntonio Quartulli * @roaming: true if the deletion is due to a roaming event 5527f91d06cSAntonio Quartulli * 5537f91d06cSAntonio Quartulli * Returns the flags assigned to the local entry before being deleted 5547f91d06cSAntonio Quartulli */ 5557f91d06cSAntonio Quartulli uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, 5567f91d06cSAntonio Quartulli const uint8_t *addr, const char *message, 5577f91d06cSAntonio Quartulli bool roaming) 558c6c8fea2SSven Eckelmann { 559170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 5607f91d06cSAntonio Quartulli uint16_t flags, curr_flags = BATADV_NO_FLAGS; 561c6c8fea2SSven Eckelmann 562a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 5637683fdc1SAntonio Quartulli if (!tt_local_entry) 5647683fdc1SAntonio Quartulli goto out; 5657683fdc1SAntonio Quartulli 5667f91d06cSAntonio Quartulli curr_flags = tt_local_entry->common.flags; 5677f91d06cSAntonio Quartulli 568acd34afaSSven Eckelmann flags = BATADV_TT_CLIENT_DEL; 569068ee6e2SAntonio Quartulli /* if this global entry addition is due to a roaming, the node has to 570068ee6e2SAntonio Quartulli * mark the local entry as "roamed" in order to correctly reroute 571068ee6e2SAntonio Quartulli * packets later 572068ee6e2SAntonio Quartulli */ 5737c1fd91dSAntonio Quartulli if (roaming) { 574acd34afaSSven Eckelmann flags |= BATADV_TT_CLIENT_ROAM; 5757c1fd91dSAntonio Quartulli /* mark the local client as ROAMed */ 5767c1fd91dSAntonio Quartulli tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 5777c1fd91dSAntonio Quartulli } 57842d0b044SSven Eckelmann 579068ee6e2SAntonio Quartulli if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { 580068ee6e2SAntonio Quartulli batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, 581068ee6e2SAntonio Quartulli message); 582068ee6e2SAntonio Quartulli goto out; 583068ee6e2SAntonio Quartulli } 584068ee6e2SAntonio Quartulli /* if this client has been added right now, it is possible to 585068ee6e2SAntonio Quartulli * immediately purge it 586068ee6e2SAntonio Quartulli */ 5873abe4adbSAntonio Quartulli batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); 588068ee6e2SAntonio Quartulli hlist_del_rcu(&tt_local_entry->common.hash_entry); 589068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 5907f91d06cSAntonio Quartulli 5917683fdc1SAntonio Quartulli out: 5927683fdc1SAntonio Quartulli if (tt_local_entry) 593a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 5947f91d06cSAntonio Quartulli 5957f91d06cSAntonio Quartulli return curr_flags; 596c6c8fea2SSven Eckelmann } 597c6c8fea2SSven Eckelmann 59856303d34SSven Eckelmann static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 599acd34afaSSven Eckelmann struct hlist_head *head) 600c6c8fea2SSven Eckelmann { 60156303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 60256303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 603b67bfe0dSSasha Levin struct hlist_node *node_tmp; 604acd34afaSSven Eckelmann 605b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, 606acd34afaSSven Eckelmann hash_entry) { 607acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common_entry, 60856303d34SSven Eckelmann struct batadv_tt_local_entry, 60956303d34SSven Eckelmann common); 610acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) 611acd34afaSSven Eckelmann continue; 612acd34afaSSven Eckelmann 613acd34afaSSven Eckelmann /* entry already marked for deletion */ 614acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 615acd34afaSSven Eckelmann continue; 616acd34afaSSven Eckelmann 617acd34afaSSven Eckelmann if (!batadv_has_timed_out(tt_local_entry->last_seen, 618acd34afaSSven Eckelmann BATADV_TT_LOCAL_TIMEOUT)) 619acd34afaSSven Eckelmann continue; 620acd34afaSSven Eckelmann 621acd34afaSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 622acd34afaSSven Eckelmann BATADV_TT_CLIENT_DEL, "timed out"); 623acd34afaSSven Eckelmann } 624acd34afaSSven Eckelmann } 625acd34afaSSven Eckelmann 62656303d34SSven Eckelmann static void batadv_tt_local_purge(struct batadv_priv *bat_priv) 627acd34afaSSven Eckelmann { 628807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 629c6c8fea2SSven Eckelmann struct hlist_head *head; 6307683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 631c90681b8SAntonio Quartulli uint32_t i; 632c6c8fea2SSven Eckelmann 633c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 634c6c8fea2SSven Eckelmann head = &hash->table[i]; 6357683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 636c6c8fea2SSven Eckelmann 6377683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 638acd34afaSSven Eckelmann batadv_tt_local_purge_list(bat_priv, head); 6397683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 640c6c8fea2SSven Eckelmann } 641c6c8fea2SSven Eckelmann } 642c6c8fea2SSven Eckelmann 64356303d34SSven Eckelmann static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) 644c6c8fea2SSven Eckelmann { 6455bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 646a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 64756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 64856303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 649b67bfe0dSSasha Levin struct hlist_node *node_tmp; 6507683fdc1SAntonio Quartulli struct hlist_head *head; 651c90681b8SAntonio Quartulli uint32_t i; 652a73105b8SAntonio Quartulli 653807736f6SSven Eckelmann if (!bat_priv->tt.local_hash) 654c6c8fea2SSven Eckelmann return; 655c6c8fea2SSven Eckelmann 656807736f6SSven Eckelmann hash = bat_priv->tt.local_hash; 657a73105b8SAntonio Quartulli 658a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 659a73105b8SAntonio Quartulli head = &hash->table[i]; 660a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 661a73105b8SAntonio Quartulli 662a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 663b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 664a73105b8SAntonio Quartulli head, hash_entry) { 665b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 66656303d34SSven Eckelmann tt_local = container_of(tt_common_entry, 66756303d34SSven Eckelmann struct batadv_tt_local_entry, 66848100bacSAntonio Quartulli common); 66956303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 670a73105b8SAntonio Quartulli } 671a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 672a73105b8SAntonio Quartulli } 673a73105b8SAntonio Quartulli 6741a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 675a73105b8SAntonio Quartulli 676807736f6SSven Eckelmann bat_priv->tt.local_hash = NULL; 677c6c8fea2SSven Eckelmann } 678c6c8fea2SSven Eckelmann 67956303d34SSven Eckelmann static int batadv_tt_global_init(struct batadv_priv *bat_priv) 680c6c8fea2SSven Eckelmann { 681807736f6SSven Eckelmann if (bat_priv->tt.global_hash) 6825346c35eSSven Eckelmann return 0; 683c6c8fea2SSven Eckelmann 684807736f6SSven Eckelmann bat_priv->tt.global_hash = batadv_hash_new(1024); 685c6c8fea2SSven Eckelmann 686807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 6875346c35eSSven Eckelmann return -ENOMEM; 688c6c8fea2SSven Eckelmann 689dec05074SAntonio Quartulli batadv_hash_set_lock_class(bat_priv->tt.global_hash, 690dec05074SAntonio Quartulli &batadv_tt_global_hash_lock_class_key); 691dec05074SAntonio Quartulli 6925346c35eSSven Eckelmann return 0; 693c6c8fea2SSven Eckelmann } 694c6c8fea2SSven Eckelmann 69556303d34SSven Eckelmann static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) 696a73105b8SAntonio Quartulli { 69756303d34SSven Eckelmann struct batadv_tt_change_node *entry, *safe; 698a73105b8SAntonio Quartulli 699807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.changes_list_lock); 700a73105b8SAntonio Quartulli 701807736f6SSven Eckelmann list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, 702a73105b8SAntonio Quartulli list) { 703a73105b8SAntonio Quartulli list_del(&entry->list); 704a73105b8SAntonio Quartulli kfree(entry); 705a73105b8SAntonio Quartulli } 706a73105b8SAntonio Quartulli 707807736f6SSven Eckelmann atomic_set(&bat_priv->tt.local_changes, 0); 708807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.changes_list_lock); 709a73105b8SAntonio Quartulli } 710a73105b8SAntonio Quartulli 711d657e621SAntonio Quartulli /* retrieves the orig_tt_list_entry belonging to orig_node from the 712d657e621SAntonio Quartulli * batadv_tt_global_entry list 713d657e621SAntonio Quartulli * 714d657e621SAntonio Quartulli * returns it with an increased refcounter, NULL if not found 715d657e621SAntonio Quartulli */ 716d657e621SAntonio Quartulli static struct batadv_tt_orig_list_entry * 717d657e621SAntonio Quartulli batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, 718d657e621SAntonio Quartulli const struct batadv_orig_node *orig_node) 719d657e621SAntonio Quartulli { 720d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; 721d657e621SAntonio Quartulli const struct hlist_head *head; 722d657e621SAntonio Quartulli 723d657e621SAntonio Quartulli rcu_read_lock(); 724d657e621SAntonio Quartulli head = &entry->orig_list; 725b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { 726d657e621SAntonio Quartulli if (tmp_orig_entry->orig_node != orig_node) 727d657e621SAntonio Quartulli continue; 728d657e621SAntonio Quartulli if (!atomic_inc_not_zero(&tmp_orig_entry->refcount)) 729d657e621SAntonio Quartulli continue; 730d657e621SAntonio Quartulli 731d657e621SAntonio Quartulli orig_entry = tmp_orig_entry; 732d657e621SAntonio Quartulli break; 733d657e621SAntonio Quartulli } 734d657e621SAntonio Quartulli rcu_read_unlock(); 735d657e621SAntonio Quartulli 736d657e621SAntonio Quartulli return orig_entry; 737d657e621SAntonio Quartulli } 738d657e621SAntonio Quartulli 739db08e6e5SSimon Wunderlich /* find out if an orig_node is already in the list of a tt_global_entry. 740d657e621SAntonio Quartulli * returns true if found, false otherwise 741db08e6e5SSimon Wunderlich */ 74256303d34SSven Eckelmann static bool 74356303d34SSven Eckelmann batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, 74456303d34SSven Eckelmann const struct batadv_orig_node *orig_node) 745db08e6e5SSimon Wunderlich { 746d657e621SAntonio Quartulli struct batadv_tt_orig_list_entry *orig_entry; 747db08e6e5SSimon Wunderlich bool found = false; 748db08e6e5SSimon Wunderlich 749d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); 750d657e621SAntonio Quartulli if (orig_entry) { 751db08e6e5SSimon Wunderlich found = true; 752d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 753db08e6e5SSimon Wunderlich } 754d657e621SAntonio Quartulli 755db08e6e5SSimon Wunderlich return found; 756db08e6e5SSimon Wunderlich } 757db08e6e5SSimon Wunderlich 758a513088dSSven Eckelmann static void 759d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, 76056303d34SSven Eckelmann struct batadv_orig_node *orig_node, int ttvn) 761db08e6e5SSimon Wunderlich { 76256303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 763db08e6e5SSimon Wunderlich 764d657e621SAntonio Quartulli orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); 76530cfd02bSAntonio Quartulli if (orig_entry) { 76630cfd02bSAntonio Quartulli /* refresh the ttvn: the current value could be a bogus one that 76730cfd02bSAntonio Quartulli * was added during a "temporary client detection" 76830cfd02bSAntonio Quartulli */ 76930cfd02bSAntonio Quartulli orig_entry->ttvn = ttvn; 770d657e621SAntonio Quartulli goto out; 77130cfd02bSAntonio Quartulli } 772d657e621SAntonio Quartulli 773db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 774db08e6e5SSimon Wunderlich if (!orig_entry) 775d657e621SAntonio Quartulli goto out; 776db08e6e5SSimon Wunderlich 777db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 778db08e6e5SSimon Wunderlich atomic_inc(&orig_node->refcount); 779db08e6e5SSimon Wunderlich atomic_inc(&orig_node->tt_size); 780db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 781db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 782d657e621SAntonio Quartulli atomic_set(&orig_entry->refcount, 2); 783db08e6e5SSimon Wunderlich 784d657e621SAntonio Quartulli spin_lock_bh(&tt_global->list_lock); 785db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 786d657e621SAntonio Quartulli &tt_global->orig_list); 787d657e621SAntonio Quartulli spin_unlock_bh(&tt_global->list_lock); 788d657e621SAntonio Quartulli out: 789d657e621SAntonio Quartulli if (orig_entry) 790d657e621SAntonio Quartulli batadv_tt_orig_list_entry_free_ref(orig_entry); 791db08e6e5SSimon Wunderlich } 792db08e6e5SSimon Wunderlich 793d4ff40f6SAntonio Quartulli /** 794d4ff40f6SAntonio Quartulli * batadv_tt_global_add - add a new TT global entry or update an existing one 795d4ff40f6SAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 796d4ff40f6SAntonio Quartulli * @orig_node: the originator announcing the client 797d4ff40f6SAntonio Quartulli * @tt_addr: the mac address of the non-mesh client 798d4ff40f6SAntonio Quartulli * @flags: TT flags that have to be set for this non-mesh client 799d4ff40f6SAntonio Quartulli * @ttvn: the tt version number ever announcing this non-mesh client 800d4ff40f6SAntonio Quartulli * 801d4ff40f6SAntonio Quartulli * Add a new TT global entry for the given originator. If the entry already 802d4ff40f6SAntonio Quartulli * exists add a new reference to the given originator (a global entry can have 803d4ff40f6SAntonio Quartulli * references to multiple originators) and adjust the flags attribute to reflect 804d4ff40f6SAntonio Quartulli * the function argument. 805d4ff40f6SAntonio Quartulli * If a TT local entry exists for this non-mesh client remove it. 806d4ff40f6SAntonio Quartulli * 807d4ff40f6SAntonio Quartulli * The caller must hold orig_node refcount. 808d4ff40f6SAntonio Quartulli */ 80956303d34SSven Eckelmann int batadv_tt_global_add(struct batadv_priv *bat_priv, 81056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 811d4ff40f6SAntonio Quartulli const unsigned char *tt_addr, uint16_t flags, 812d4f44692SAntonio Quartulli uint8_t ttvn) 813c6c8fea2SSven Eckelmann { 814170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 815170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 8167683fdc1SAntonio Quartulli int ret = 0; 81780b3f58cSSimon Wunderlich int hash_added; 81856303d34SSven Eckelmann struct batadv_tt_common_entry *common; 8197f91d06cSAntonio Quartulli uint16_t local_flags; 820c6c8fea2SSven Eckelmann 821a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); 822068ee6e2SAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr); 823068ee6e2SAntonio Quartulli 824068ee6e2SAntonio Quartulli /* if the node already has a local client for this entry, it has to wait 825068ee6e2SAntonio Quartulli * for a roaming advertisement instead of manually messing up the global 826068ee6e2SAntonio Quartulli * table 827068ee6e2SAntonio Quartulli */ 828068ee6e2SAntonio Quartulli if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && 829068ee6e2SAntonio Quartulli !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) 830068ee6e2SAntonio Quartulli goto out; 831c6c8fea2SSven Eckelmann 8322dafb49dSAntonio Quartulli if (!tt_global_entry) { 833d4f44692SAntonio Quartulli tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); 8342dafb49dSAntonio Quartulli if (!tt_global_entry) 8357683fdc1SAntonio Quartulli goto out; 8367683fdc1SAntonio Quartulli 837c0a55929SSven Eckelmann common = &tt_global_entry->common; 838c0a55929SSven Eckelmann memcpy(common->addr, tt_addr, ETH_ALEN); 839db08e6e5SSimon Wunderlich 840d4f44692SAntonio Quartulli common->flags = flags; 841cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 842fdf79320SAntonio Quartulli /* node must store current time in case of roaming. This is 843fdf79320SAntonio Quartulli * needed to purge this entry out on timeout (if nobody claims 844fdf79320SAntonio Quartulli * it) 845fdf79320SAntonio Quartulli */ 846fdf79320SAntonio Quartulli if (flags & BATADV_TT_CLIENT_ROAM) 847fdf79320SAntonio Quartulli tt_global_entry->roam_at = jiffies; 848c0a55929SSven Eckelmann atomic_set(&common->refcount, 2); 84930cfd02bSAntonio Quartulli common->added_at = jiffies; 850db08e6e5SSimon Wunderlich 851db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 852db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 8537683fdc1SAntonio Quartulli 854807736f6SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt.global_hash, 855a513088dSSven Eckelmann batadv_compare_tt, 856a513088dSSven Eckelmann batadv_choose_orig, common, 857a513088dSSven Eckelmann &common->hash_entry); 85880b3f58cSSimon Wunderlich 85980b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 86080b3f58cSSimon Wunderlich /* remove the reference for the hash */ 861a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 86280b3f58cSSimon Wunderlich goto out_remove; 86380b3f58cSSimon Wunderlich } 864a73105b8SAntonio Quartulli } else { 865068ee6e2SAntonio Quartulli common = &tt_global_entry->common; 86630cfd02bSAntonio Quartulli /* If there is already a global entry, we can use this one for 86730cfd02bSAntonio Quartulli * our processing. 868068ee6e2SAntonio Quartulli * But if we are trying to add a temporary client then here are 869068ee6e2SAntonio Quartulli * two options at this point: 870068ee6e2SAntonio Quartulli * 1) the global client is not a temporary client: the global 871068ee6e2SAntonio Quartulli * client has to be left as it is, temporary information 872068ee6e2SAntonio Quartulli * should never override any already known client state 873068ee6e2SAntonio Quartulli * 2) the global client is a temporary client: purge the 874068ee6e2SAntonio Quartulli * originator list and add the new one orig_entry 87530cfd02bSAntonio Quartulli */ 876068ee6e2SAntonio Quartulli if (flags & BATADV_TT_CLIENT_TEMP) { 877068ee6e2SAntonio Quartulli if (!(common->flags & BATADV_TT_CLIENT_TEMP)) 87830cfd02bSAntonio Quartulli goto out; 879068ee6e2SAntonio Quartulli if (batadv_tt_global_entry_has_orig(tt_global_entry, 880068ee6e2SAntonio Quartulli orig_node)) 881068ee6e2SAntonio Quartulli goto out_remove; 882068ee6e2SAntonio Quartulli batadv_tt_global_del_orig_list(tt_global_entry); 883068ee6e2SAntonio Quartulli goto add_orig_entry; 884068ee6e2SAntonio Quartulli } 88530cfd02bSAntonio Quartulli 88630cfd02bSAntonio Quartulli /* if the client was temporary added before receiving the first 88730cfd02bSAntonio Quartulli * OGM announcing it, we have to clear the TEMP flag 88830cfd02bSAntonio Quartulli */ 889068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_TEMP; 890db08e6e5SSimon Wunderlich 891e9c00136SAntonio Quartulli /* the change can carry possible "attribute" flags like the 892e9c00136SAntonio Quartulli * TT_CLIENT_WIFI, therefore they have to be copied in the 893e9c00136SAntonio Quartulli * client entry 894e9c00136SAntonio Quartulli */ 895e9c00136SAntonio Quartulli tt_global_entry->common.flags |= flags; 896e9c00136SAntonio Quartulli 897acd34afaSSven Eckelmann /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 898acd34afaSSven Eckelmann * one originator left in the list and we previously received a 899db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 900db08e6e5SSimon Wunderlich * 901db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 902db08e6e5SSimon Wunderlich * new one. 903db08e6e5SSimon Wunderlich */ 904068ee6e2SAntonio Quartulli if (common->flags & BATADV_TT_CLIENT_ROAM) { 905a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 906068ee6e2SAntonio Quartulli common->flags &= ~BATADV_TT_CLIENT_ROAM; 907cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 908c6c8fea2SSven Eckelmann } 909db08e6e5SSimon Wunderlich } 910068ee6e2SAntonio Quartulli add_orig_entry: 91130cfd02bSAntonio Quartulli /* add the new orig_entry (if needed) or update it */ 912d657e621SAntonio Quartulli batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); 913db08e6e5SSimon Wunderlich 91439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 915a73105b8SAntonio Quartulli "Creating new global tt entry: %pM (via %pM)\n", 916068ee6e2SAntonio Quartulli common->addr, orig_node->orig); 917c10dba05SAntonio Quartulli ret = 1; 918a73105b8SAntonio Quartulli 91980b3f58cSSimon Wunderlich out_remove: 9207f91d06cSAntonio Quartulli 921c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 9227f91d06cSAntonio Quartulli local_flags = batadv_tt_local_remove(bat_priv, tt_addr, 923acd34afaSSven Eckelmann "global tt received", 924c1d07431SAntonio Quartulli flags & BATADV_TT_CLIENT_ROAM); 9257f91d06cSAntonio Quartulli tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; 9267f91d06cSAntonio Quartulli 927068ee6e2SAntonio Quartulli if (!(flags & BATADV_TT_CLIENT_ROAM)) 928068ee6e2SAntonio Quartulli /* this is a normal global add. Therefore the client is not in a 929068ee6e2SAntonio Quartulli * roaming state anymore. 930068ee6e2SAntonio Quartulli */ 931068ee6e2SAntonio Quartulli tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 932068ee6e2SAntonio Quartulli 9337683fdc1SAntonio Quartulli out: 9347683fdc1SAntonio Quartulli if (tt_global_entry) 935a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 936068ee6e2SAntonio Quartulli if (tt_local_entry) 937068ee6e2SAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 9387683fdc1SAntonio Quartulli return ret; 939c6c8fea2SSven Eckelmann } 940c6c8fea2SSven Eckelmann 941981d8900SSven Eckelmann /* batadv_transtable_best_orig - Get best originator list entry from tt entry 942981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be analyzed 943981d8900SSven Eckelmann * 944981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 945981d8900SSven Eckelmann * Returns best originator list entry or NULL on errors. 946981d8900SSven Eckelmann */ 947981d8900SSven Eckelmann static struct batadv_tt_orig_list_entry * 948981d8900SSven Eckelmann batadv_transtable_best_orig(struct batadv_tt_global_entry *tt_global_entry) 949981d8900SSven Eckelmann { 950981d8900SSven Eckelmann struct batadv_neigh_node *router = NULL; 951981d8900SSven Eckelmann struct hlist_head *head; 952981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; 953981d8900SSven Eckelmann int best_tq = 0; 954981d8900SSven Eckelmann 955981d8900SSven Eckelmann head = &tt_global_entry->orig_list; 956b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 957981d8900SSven Eckelmann router = batadv_orig_node_get_router(orig_entry->orig_node); 958981d8900SSven Eckelmann if (!router) 959981d8900SSven Eckelmann continue; 960981d8900SSven Eckelmann 961981d8900SSven Eckelmann if (router->tq_avg > best_tq) { 962981d8900SSven Eckelmann best_entry = orig_entry; 963981d8900SSven Eckelmann best_tq = router->tq_avg; 964981d8900SSven Eckelmann } 965981d8900SSven Eckelmann 966981d8900SSven Eckelmann batadv_neigh_node_free_ref(router); 967981d8900SSven Eckelmann } 968981d8900SSven Eckelmann 969981d8900SSven Eckelmann return best_entry; 970981d8900SSven Eckelmann } 971981d8900SSven Eckelmann 972981d8900SSven Eckelmann /* batadv_tt_global_print_entry - print all orig nodes who announce the address 973981d8900SSven Eckelmann * for this global entry 974981d8900SSven Eckelmann * @tt_global_entry: global translation table entry to be printed 975981d8900SSven Eckelmann * @seq: debugfs table seq_file struct 976981d8900SSven Eckelmann * 977981d8900SSven Eckelmann * This functon assumes the caller holds rcu_read_lock(). 978db08e6e5SSimon Wunderlich */ 979a513088dSSven Eckelmann static void 98056303d34SSven Eckelmann batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, 981db08e6e5SSimon Wunderlich struct seq_file *seq) 982db08e6e5SSimon Wunderlich { 983db08e6e5SSimon Wunderlich struct hlist_head *head; 984981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry, *best_entry; 98556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 986db08e6e5SSimon Wunderlich uint16_t flags; 987db08e6e5SSimon Wunderlich uint8_t last_ttvn; 988db08e6e5SSimon Wunderlich 989db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 990981d8900SSven Eckelmann flags = tt_common_entry->flags; 991981d8900SSven Eckelmann 992981d8900SSven Eckelmann best_entry = batadv_transtable_best_orig(tt_global_entry); 993981d8900SSven Eckelmann if (best_entry) { 994981d8900SSven Eckelmann last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); 995f9d8a537SAntonio Quartulli seq_printf(seq, 996f9d8a537SAntonio Quartulli " %c %pM (%3u) via %pM (%3u) (%#.4x) [%c%c%c]\n", 997981d8900SSven Eckelmann '*', tt_global_entry->common.addr, 998981d8900SSven Eckelmann best_entry->ttvn, best_entry->orig_node->orig, 999f9d8a537SAntonio Quartulli last_ttvn, best_entry->orig_node->tt_crc, 1000981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 1001981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 1002981d8900SSven Eckelmann (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); 1003981d8900SSven Eckelmann } 1004db08e6e5SSimon Wunderlich 1005db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1006db08e6e5SSimon Wunderlich 1007b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1008981d8900SSven Eckelmann if (best_entry == orig_entry) 1009981d8900SSven Eckelmann continue; 1010981d8900SSven Eckelmann 1011db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 1012981d8900SSven Eckelmann seq_printf(seq, " %c %pM (%3u) via %pM (%3u) [%c%c%c]\n", 1013981d8900SSven Eckelmann '+', tt_global_entry->common.addr, 1014981d8900SSven Eckelmann orig_entry->ttvn, orig_entry->orig_node->orig, 1015981d8900SSven Eckelmann last_ttvn, 1016acd34afaSSven Eckelmann (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 101730cfd02bSAntonio Quartulli (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), 101830cfd02bSAntonio Quartulli (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); 1019db08e6e5SSimon Wunderlich } 1020db08e6e5SSimon Wunderlich } 1021db08e6e5SSimon Wunderlich 102208c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 1023c6c8fea2SSven Eckelmann { 1024c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 102556303d34SSven Eckelmann struct batadv_priv *bat_priv = netdev_priv(net_dev); 1026807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 102756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 102856303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 102956303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 1030c6c8fea2SSven Eckelmann struct hlist_head *head; 1031c90681b8SAntonio Quartulli uint32_t i; 1032c6c8fea2SSven Eckelmann 103330da63a6SMarek Lindner primary_if = batadv_seq_print_text_primary_if_get(seq); 103430da63a6SMarek Lindner if (!primary_if) 103532ae9b22SMarek Lindner goto out; 1036c6c8fea2SSven Eckelmann 10372dafb49dSAntonio Quartulli seq_printf(seq, 10382dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 1039c6c8fea2SSven Eckelmann net_dev->name); 1040f9d8a537SAntonio Quartulli seq_printf(seq, " %-13s %s %-15s %s (%-6s) %s\n", 1041f9d8a537SAntonio Quartulli "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC", 1042f9d8a537SAntonio Quartulli "Flags"); 1043c6c8fea2SSven Eckelmann 1044c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 1045c6c8fea2SSven Eckelmann head = &hash->table[i]; 1046c6c8fea2SSven Eckelmann 10477aadf889SMarek Lindner rcu_read_lock(); 1048b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 10497aadf889SMarek Lindner head, hash_entry) { 105056303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 105156303d34SSven Eckelmann struct batadv_tt_global_entry, 105248100bacSAntonio Quartulli common); 105356303d34SSven Eckelmann batadv_tt_global_print_entry(tt_global, seq); 1054c6c8fea2SSven Eckelmann } 10557aadf889SMarek Lindner rcu_read_unlock(); 1056c6c8fea2SSven Eckelmann } 105732ae9b22SMarek Lindner out: 105832ae9b22SMarek Lindner if (primary_if) 1059e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 106030da63a6SMarek Lindner return 0; 1061c6c8fea2SSven Eckelmann } 1062c6c8fea2SSven Eckelmann 1063db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 1064a513088dSSven Eckelmann static void 106556303d34SSven Eckelmann batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) 1066db08e6e5SSimon Wunderlich { 1067db08e6e5SSimon Wunderlich struct hlist_head *head; 1068b67bfe0dSSasha Levin struct hlist_node *safe; 106956303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1070db08e6e5SSimon Wunderlich 1071db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1072db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1073b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1074b67bfe0dSSasha Levin hlist_del_rcu(&orig_entry->list); 1075a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 1076db08e6e5SSimon Wunderlich } 1077db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1078db08e6e5SSimon Wunderlich } 1079db08e6e5SSimon Wunderlich 1080a513088dSSven Eckelmann static void 108156303d34SSven Eckelmann batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, 108256303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 108356303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1084db08e6e5SSimon Wunderlich const char *message) 1085db08e6e5SSimon Wunderlich { 1086db08e6e5SSimon Wunderlich struct hlist_head *head; 1087b67bfe0dSSasha Levin struct hlist_node *safe; 108856303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1089db08e6e5SSimon Wunderlich 1090db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 1091db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1092b67bfe0dSSasha Levin hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1093db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 109439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1095db08e6e5SSimon Wunderlich "Deleting %pM from global tt entry %pM: %s\n", 10961eda58bfSSven Eckelmann orig_node->orig, 10971eda58bfSSven Eckelmann tt_global_entry->common.addr, message); 1098b67bfe0dSSasha Levin hlist_del_rcu(&orig_entry->list); 1099a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 1100db08e6e5SSimon Wunderlich } 1101db08e6e5SSimon Wunderlich } 1102db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 1103db08e6e5SSimon Wunderlich } 1104db08e6e5SSimon Wunderlich 1105db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 1106acd34afaSSven Eckelmann * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the 1107acd34afaSSven Eckelmann * timer, otherwise we simply remove the originator scheduled for deletion. 1108db08e6e5SSimon Wunderlich */ 1109a513088dSSven Eckelmann static void 111056303d34SSven Eckelmann batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, 111156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry, 111256303d34SSven Eckelmann struct batadv_orig_node *orig_node, 111356303d34SSven Eckelmann const char *message) 1114db08e6e5SSimon Wunderlich { 1115db08e6e5SSimon Wunderlich bool last_entry = true; 1116db08e6e5SSimon Wunderlich struct hlist_head *head; 111756303d34SSven Eckelmann struct batadv_tt_orig_list_entry *orig_entry; 1118db08e6e5SSimon Wunderlich 1119db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 1120db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 1121db08e6e5SSimon Wunderlich */ 1122db08e6e5SSimon Wunderlich 1123db08e6e5SSimon Wunderlich rcu_read_lock(); 1124db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1125b67bfe0dSSasha Levin hlist_for_each_entry_rcu(orig_entry, head, list) { 1126db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 1127db08e6e5SSimon Wunderlich last_entry = false; 1128db08e6e5SSimon Wunderlich break; 1129db08e6e5SSimon Wunderlich } 1130db08e6e5SSimon Wunderlich } 1131db08e6e5SSimon Wunderlich rcu_read_unlock(); 1132db08e6e5SSimon Wunderlich 1133db08e6e5SSimon Wunderlich if (last_entry) { 1134db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 1135acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 1136db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 1137db08e6e5SSimon Wunderlich } else 1138db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 1139db08e6e5SSimon Wunderlich * one and can still use the other one. 1140db08e6e5SSimon Wunderlich */ 1141a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 1142db08e6e5SSimon Wunderlich orig_node, message); 1143db08e6e5SSimon Wunderlich } 1144db08e6e5SSimon Wunderlich 1145db08e6e5SSimon Wunderlich 1146db08e6e5SSimon Wunderlich 114756303d34SSven Eckelmann static void batadv_tt_global_del(struct batadv_priv *bat_priv, 114856303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1149de7aae65SSven Eckelmann const unsigned char *addr, 1150cc47f66eSAntonio Quartulli const char *message, bool roaming) 1151a73105b8SAntonio Quartulli { 1152170173bfSSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 115356303d34SSven Eckelmann struct batadv_tt_local_entry *local_entry = NULL; 1154a73105b8SAntonio Quartulli 1155a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 1156db08e6e5SSimon Wunderlich if (!tt_global_entry) 11577683fdc1SAntonio Quartulli goto out; 1158a73105b8SAntonio Quartulli 1159db08e6e5SSimon Wunderlich if (!roaming) { 1160a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 1161a513088dSSven Eckelmann orig_node, message); 116292f90f56SSven Eckelmann 1163db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 1164be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, 1165db08e6e5SSimon Wunderlich message); 1166db08e6e5SSimon Wunderlich 1167cc47f66eSAntonio Quartulli goto out; 1168cc47f66eSAntonio Quartulli } 116992f90f56SSven Eckelmann 1170db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 1171db08e6e5SSimon Wunderlich * event, there are two possibilities: 1172db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 1173db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 1174acd34afaSSven Eckelmann * it with BATADV_TT_CLIENT_ROAM, we start a timer and we 1175db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 1176db08e6e5SSimon Wunderlich * the entry is purged. 1177db08e6e5SSimon Wunderlich * 1178db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 1179db08e6e5SSimon Wunderlich * the originator. 1180db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 11819cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 11829cfc7bd6SSven Eckelmann */ 1183a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 1184db08e6e5SSimon Wunderlich tt_global_entry->common.addr); 1185a513088dSSven Eckelmann if (local_entry) { 1186db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 1187a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 1188be73b488SAntonio Quartulli batadv_tt_global_free(bat_priv, tt_global_entry, message); 1189db08e6e5SSimon Wunderlich } else 1190db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 1191a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 1192a513088dSSven Eckelmann orig_node, message); 1193db08e6e5SSimon Wunderlich 119492f90f56SSven Eckelmann 1195cc47f66eSAntonio Quartulli out: 11967683fdc1SAntonio Quartulli if (tt_global_entry) 1197a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1198a513088dSSven Eckelmann if (local_entry) 1199a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(local_entry); 1200a73105b8SAntonio Quartulli } 1201a73105b8SAntonio Quartulli 120256303d34SSven Eckelmann void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, 120356303d34SSven Eckelmann struct batadv_orig_node *orig_node, 120456303d34SSven Eckelmann const char *message) 1205c6c8fea2SSven Eckelmann { 120656303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 120756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1208c90681b8SAntonio Quartulli uint32_t i; 1209807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 1210b67bfe0dSSasha Levin struct hlist_node *safe; 1211a73105b8SAntonio Quartulli struct hlist_head *head; 12127683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 1213c6c8fea2SSven Eckelmann 12146e801494SSimon Wunderlich if (!hash) 12156e801494SSimon Wunderlich return; 12166e801494SSimon Wunderlich 1217a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1218a73105b8SAntonio Quartulli head = &hash->table[i]; 12197683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1220c6c8fea2SSven Eckelmann 12217683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1222b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, safe, 1223a73105b8SAntonio Quartulli head, hash_entry) { 122456303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 122556303d34SSven Eckelmann struct batadv_tt_global_entry, 122648100bacSAntonio Quartulli common); 1227db08e6e5SSimon Wunderlich 122856303d34SSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global, 1229db08e6e5SSimon Wunderlich orig_node, message); 1230db08e6e5SSimon Wunderlich 123156303d34SSven Eckelmann if (hlist_empty(&tt_global->orig_list)) { 123239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1233db08e6e5SSimon Wunderlich "Deleting global tt entry %pM: %s\n", 123456303d34SSven Eckelmann tt_global->common.addr, message); 1235b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 123656303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 1237c6c8fea2SSven Eckelmann } 1238a73105b8SAntonio Quartulli } 12397683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 12407683fdc1SAntonio Quartulli } 124117071578SAntonio Quartulli orig_node->tt_initialised = false; 1242c6c8fea2SSven Eckelmann } 1243c6c8fea2SSven Eckelmann 124430cfd02bSAntonio Quartulli static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, 124530cfd02bSAntonio Quartulli char **msg) 1246cc47f66eSAntonio Quartulli { 124730cfd02bSAntonio Quartulli bool purge = false; 124830cfd02bSAntonio Quartulli unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; 124930cfd02bSAntonio Quartulli unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; 1250cc47f66eSAntonio Quartulli 125130cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && 125230cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { 125330cfd02bSAntonio Quartulli purge = true; 125430cfd02bSAntonio Quartulli *msg = "Roaming timeout\n"; 125542d0b044SSven Eckelmann } 125642d0b044SSven Eckelmann 125730cfd02bSAntonio Quartulli if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) && 125830cfd02bSAntonio Quartulli batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) { 125930cfd02bSAntonio Quartulli purge = true; 126030cfd02bSAntonio Quartulli *msg = "Temporary client timeout\n"; 126130cfd02bSAntonio Quartulli } 126230cfd02bSAntonio Quartulli 126330cfd02bSAntonio Quartulli return purge; 126430cfd02bSAntonio Quartulli } 126530cfd02bSAntonio Quartulli 126630cfd02bSAntonio Quartulli static void batadv_tt_global_purge(struct batadv_priv *bat_priv) 126742d0b044SSven Eckelmann { 1268807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 126942d0b044SSven Eckelmann struct hlist_head *head; 1270b67bfe0dSSasha Levin struct hlist_node *node_tmp; 127142d0b044SSven Eckelmann spinlock_t *list_lock; /* protects write access to the hash lists */ 127242d0b044SSven Eckelmann uint32_t i; 127330cfd02bSAntonio Quartulli char *msg = NULL; 127430cfd02bSAntonio Quartulli struct batadv_tt_common_entry *tt_common; 127530cfd02bSAntonio Quartulli struct batadv_tt_global_entry *tt_global; 127642d0b044SSven Eckelmann 127742d0b044SSven Eckelmann for (i = 0; i < hash->size; i++) { 127842d0b044SSven Eckelmann head = &hash->table[i]; 127942d0b044SSven Eckelmann list_lock = &hash->list_locks[i]; 128042d0b044SSven Eckelmann 128142d0b044SSven Eckelmann spin_lock_bh(list_lock); 1282b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 128330cfd02bSAntonio Quartulli hash_entry) { 128430cfd02bSAntonio Quartulli tt_global = container_of(tt_common, 128530cfd02bSAntonio Quartulli struct batadv_tt_global_entry, 128630cfd02bSAntonio Quartulli common); 128730cfd02bSAntonio Quartulli 128830cfd02bSAntonio Quartulli if (!batadv_tt_global_to_purge(tt_global, &msg)) 128930cfd02bSAntonio Quartulli continue; 129030cfd02bSAntonio Quartulli 129130cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 129230cfd02bSAntonio Quartulli "Deleting global tt entry (%pM): %s\n", 129330cfd02bSAntonio Quartulli tt_global->common.addr, msg); 129430cfd02bSAntonio Quartulli 1295b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 129630cfd02bSAntonio Quartulli 129730cfd02bSAntonio Quartulli batadv_tt_global_entry_free_ref(tt_global); 129830cfd02bSAntonio Quartulli } 12997683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1300cc47f66eSAntonio Quartulli } 1301cc47f66eSAntonio Quartulli } 1302cc47f66eSAntonio Quartulli 130356303d34SSven Eckelmann static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) 1304c6c8fea2SSven Eckelmann { 13055bf74e9cSSven Eckelmann struct batadv_hashtable *hash; 13067683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 130756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 130856303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 1309b67bfe0dSSasha Levin struct hlist_node *node_tmp; 13107683fdc1SAntonio Quartulli struct hlist_head *head; 1311c90681b8SAntonio Quartulli uint32_t i; 13127683fdc1SAntonio Quartulli 1313807736f6SSven Eckelmann if (!bat_priv->tt.global_hash) 1314c6c8fea2SSven Eckelmann return; 1315c6c8fea2SSven Eckelmann 1316807736f6SSven Eckelmann hash = bat_priv->tt.global_hash; 13177683fdc1SAntonio Quartulli 13187683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 13197683fdc1SAntonio Quartulli head = &hash->table[i]; 13207683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 13217683fdc1SAntonio Quartulli 13227683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 1323b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common_entry, node_tmp, 13247683fdc1SAntonio Quartulli head, hash_entry) { 1325b67bfe0dSSasha Levin hlist_del_rcu(&tt_common_entry->hash_entry); 132656303d34SSven Eckelmann tt_global = container_of(tt_common_entry, 132756303d34SSven Eckelmann struct batadv_tt_global_entry, 132848100bacSAntonio Quartulli common); 132956303d34SSven Eckelmann batadv_tt_global_entry_free_ref(tt_global); 13307683fdc1SAntonio Quartulli } 13317683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 13327683fdc1SAntonio Quartulli } 13337683fdc1SAntonio Quartulli 13341a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 13357683fdc1SAntonio Quartulli 1336807736f6SSven Eckelmann bat_priv->tt.global_hash = NULL; 1337c6c8fea2SSven Eckelmann } 1338c6c8fea2SSven Eckelmann 133956303d34SSven Eckelmann static bool 134056303d34SSven Eckelmann _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, 134156303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry) 134259b699cdSAntonio Quartulli { 134359b699cdSAntonio Quartulli bool ret = false; 134459b699cdSAntonio Quartulli 1345acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && 1346acd34afaSSven Eckelmann tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) 134759b699cdSAntonio Quartulli ret = true; 134859b699cdSAntonio Quartulli 134959b699cdSAntonio Quartulli return ret; 135059b699cdSAntonio Quartulli } 135159b699cdSAntonio Quartulli 135256303d34SSven Eckelmann struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, 135308c36d3eSSven Eckelmann const uint8_t *src, 135408c36d3eSSven Eckelmann const uint8_t *addr) 1355c6c8fea2SSven Eckelmann { 135656303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 135756303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 135856303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 1359981d8900SSven Eckelmann struct batadv_tt_orig_list_entry *best_entry; 1360c6c8fea2SSven Eckelmann 13613d393e47SAntonio Quartulli if (src && atomic_read(&bat_priv->ap_isolation)) { 1362a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); 1363068ee6e2SAntonio Quartulli if (!tt_local_entry || 1364068ee6e2SAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) 13653d393e47SAntonio Quartulli goto out; 13663d393e47SAntonio Quartulli } 13677aadf889SMarek Lindner 1368a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 13692dafb49dSAntonio Quartulli if (!tt_global_entry) 13707b36e8eeSMarek Lindner goto out; 1371c6c8fea2SSven Eckelmann 13723d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 13739cfc7bd6SSven Eckelmann * isolation 13749cfc7bd6SSven Eckelmann */ 1375a513088dSSven Eckelmann if (tt_local_entry && 1376a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 13773d393e47SAntonio Quartulli goto out; 13783d393e47SAntonio Quartulli 1379db08e6e5SSimon Wunderlich rcu_read_lock(); 1380981d8900SSven Eckelmann best_entry = batadv_transtable_best_orig(tt_global_entry); 1381db08e6e5SSimon Wunderlich /* found anything? */ 1382981d8900SSven Eckelmann if (best_entry) 1383981d8900SSven Eckelmann orig_node = best_entry->orig_node; 1384db08e6e5SSimon Wunderlich if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) 1385db08e6e5SSimon Wunderlich orig_node = NULL; 1386db08e6e5SSimon Wunderlich rcu_read_unlock(); 1387981d8900SSven Eckelmann 13887b36e8eeSMarek Lindner out: 13893d393e47SAntonio Quartulli if (tt_global_entry) 1390a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 13913d393e47SAntonio Quartulli if (tt_local_entry) 1392a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 13933d393e47SAntonio Quartulli 13947b36e8eeSMarek Lindner return orig_node; 1395c6c8fea2SSven Eckelmann } 1396a73105b8SAntonio Quartulli 1397a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */ 139856303d34SSven Eckelmann static uint16_t batadv_tt_global_crc(struct batadv_priv *bat_priv, 139956303d34SSven Eckelmann struct batadv_orig_node *orig_node) 1400a73105b8SAntonio Quartulli { 1401a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1402807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.global_hash; 140356303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 140456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global; 1405a73105b8SAntonio Quartulli struct hlist_head *head; 1406c90681b8SAntonio Quartulli uint32_t i; 1407c90681b8SAntonio Quartulli int j; 1408a73105b8SAntonio Quartulli 1409a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1410a73105b8SAntonio Quartulli head = &hash->table[i]; 1411a73105b8SAntonio Quartulli 1412a73105b8SAntonio Quartulli rcu_read_lock(); 1413b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 141456303d34SSven Eckelmann tt_global = container_of(tt_common, 141556303d34SSven Eckelmann struct batadv_tt_global_entry, 141648100bacSAntonio Quartulli common); 1417cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 1418cc47f66eSAntonio Quartulli * consistency only. They don't have to be 1419cc47f66eSAntonio Quartulli * taken into account while computing the 1420db08e6e5SSimon Wunderlich * global crc 1421db08e6e5SSimon Wunderlich */ 1422acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 1423cc47f66eSAntonio Quartulli continue; 142430cfd02bSAntonio Quartulli /* Temporary clients have not been announced yet, so 142530cfd02bSAntonio Quartulli * they have to be skipped while computing the global 142630cfd02bSAntonio Quartulli * crc 142730cfd02bSAntonio Quartulli */ 142830cfd02bSAntonio Quartulli if (tt_common->flags & BATADV_TT_CLIENT_TEMP) 142930cfd02bSAntonio Quartulli continue; 1430db08e6e5SSimon Wunderlich 1431db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 1432db08e6e5SSimon Wunderlich * originator 1433db08e6e5SSimon Wunderlich */ 143456303d34SSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global, 1435db08e6e5SSimon Wunderlich orig_node)) 1436db08e6e5SSimon Wunderlich continue; 1437db08e6e5SSimon Wunderlich 1438a73105b8SAntonio Quartulli total_one = 0; 1439a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1440a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 1441acd34afaSSven Eckelmann tt_common->addr[j]); 1442a73105b8SAntonio Quartulli total ^= total_one; 1443a73105b8SAntonio Quartulli } 1444a73105b8SAntonio Quartulli rcu_read_unlock(); 1445a73105b8SAntonio Quartulli } 1446a73105b8SAntonio Quartulli 1447a73105b8SAntonio Quartulli return total; 1448a73105b8SAntonio Quartulli } 1449a73105b8SAntonio Quartulli 1450a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */ 145156303d34SSven Eckelmann static uint16_t batadv_tt_local_crc(struct batadv_priv *bat_priv) 1452a73105b8SAntonio Quartulli { 1453a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1454807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 145556303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 1456a73105b8SAntonio Quartulli struct hlist_head *head; 1457c90681b8SAntonio Quartulli uint32_t i; 1458c90681b8SAntonio Quartulli int j; 1459a73105b8SAntonio Quartulli 1460a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1461a73105b8SAntonio Quartulli head = &hash->table[i]; 1462a73105b8SAntonio Quartulli 1463a73105b8SAntonio Quartulli rcu_read_lock(); 1464b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common, head, hash_entry) { 1465058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 14669cfc7bd6SSven Eckelmann * account while computing the CRC 14679cfc7bd6SSven Eckelmann */ 1468acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_NEW) 1469058d0e26SAntonio Quartulli continue; 1470a73105b8SAntonio Quartulli total_one = 0; 1471a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1472a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 1473acd34afaSSven Eckelmann tt_common->addr[j]); 1474a73105b8SAntonio Quartulli total ^= total_one; 1475a73105b8SAntonio Quartulli } 1476a73105b8SAntonio Quartulli rcu_read_unlock(); 1477a73105b8SAntonio Quartulli } 1478a73105b8SAntonio Quartulli 1479a73105b8SAntonio Quartulli return total; 1480a73105b8SAntonio Quartulli } 1481a73105b8SAntonio Quartulli 148256303d34SSven Eckelmann static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) 1483a73105b8SAntonio Quartulli { 148456303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 1485a73105b8SAntonio Quartulli 1486807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 1487a73105b8SAntonio Quartulli 1488807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 1489a73105b8SAntonio Quartulli list_del(&node->list); 1490a73105b8SAntonio Quartulli kfree(node); 1491a73105b8SAntonio Quartulli } 1492a73105b8SAntonio Quartulli 1493807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 1494a73105b8SAntonio Quartulli } 1495a73105b8SAntonio Quartulli 149656303d34SSven Eckelmann static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, 149756303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1498de7aae65SSven Eckelmann const unsigned char *tt_buff, 1499e1bf0c14SMarek Lindner uint16_t tt_num_changes) 1500a73105b8SAntonio Quartulli { 150108c36d3eSSven Eckelmann uint16_t tt_buff_len = batadv_tt_len(tt_num_changes); 1502a73105b8SAntonio Quartulli 1503a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 15049cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 15059cfc7bd6SSven Eckelmann */ 1506a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1507a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 1508a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1509a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1510a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 1511a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 1512a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 1513a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 1514a73105b8SAntonio Quartulli } 1515a73105b8SAntonio Quartulli } 1516a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1517a73105b8SAntonio Quartulli } 1518a73105b8SAntonio Quartulli 151956303d34SSven Eckelmann static void batadv_tt_req_purge(struct batadv_priv *bat_priv) 1520a73105b8SAntonio Quartulli { 152156303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 1522a73105b8SAntonio Quartulli 1523807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 1524807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 152542d0b044SSven Eckelmann if (batadv_has_timed_out(node->issued_at, 152642d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) { 1527a73105b8SAntonio Quartulli list_del(&node->list); 1528a73105b8SAntonio Quartulli kfree(node); 1529a73105b8SAntonio Quartulli } 1530a73105b8SAntonio Quartulli } 1531807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 1532a73105b8SAntonio Quartulli } 1533a73105b8SAntonio Quartulli 1534a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 15359cfc7bd6SSven Eckelmann * has already been issued for this orig_node, NULL otherwise 15369cfc7bd6SSven Eckelmann */ 153756303d34SSven Eckelmann static struct batadv_tt_req_node * 153856303d34SSven Eckelmann batadv_new_tt_req_node(struct batadv_priv *bat_priv, 153956303d34SSven Eckelmann struct batadv_orig_node *orig_node) 1540a73105b8SAntonio Quartulli { 154156303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 1542a73105b8SAntonio Quartulli 1543807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 1544807736f6SSven Eckelmann list_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { 15451eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 15461eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 154742d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) 1548a73105b8SAntonio Quartulli goto unlock; 1549a73105b8SAntonio Quartulli } 1550a73105b8SAntonio Quartulli 1551a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 1552a73105b8SAntonio Quartulli if (!tt_req_node) 1553a73105b8SAntonio Quartulli goto unlock; 1554a73105b8SAntonio Quartulli 1555a73105b8SAntonio Quartulli memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); 1556a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 1557a73105b8SAntonio Quartulli 1558807736f6SSven Eckelmann list_add(&tt_req_node->list, &bat_priv->tt.req_list); 1559a73105b8SAntonio Quartulli unlock: 1560807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 1561a73105b8SAntonio Quartulli return tt_req_node; 1562a73105b8SAntonio Quartulli } 1563a73105b8SAntonio Quartulli 1564335fbe0fSMarek Lindner /** 1565335fbe0fSMarek Lindner * batadv_tt_local_valid - verify that given tt entry is a valid one 1566335fbe0fSMarek Lindner * @entry_ptr: to be checked local tt entry 1567335fbe0fSMarek Lindner * @data_ptr: not used but definition required to satisfy the callback prototype 1568335fbe0fSMarek Lindner * 1569335fbe0fSMarek Lindner * Returns 1 if the entry is a valid, 0 otherwise. 1570335fbe0fSMarek Lindner */ 1571335fbe0fSMarek Lindner static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) 1572058d0e26SAntonio Quartulli { 157356303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 1574058d0e26SAntonio Quartulli 1575acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) 1576058d0e26SAntonio Quartulli return 0; 1577058d0e26SAntonio Quartulli return 1; 1578058d0e26SAntonio Quartulli } 1579058d0e26SAntonio Quartulli 1580a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr, 1581a513088dSSven Eckelmann const void *data_ptr) 1582a73105b8SAntonio Quartulli { 158356303d34SSven Eckelmann const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; 158456303d34SSven Eckelmann const struct batadv_tt_global_entry *tt_global_entry; 158556303d34SSven Eckelmann const struct batadv_orig_node *orig_node = data_ptr; 1586a73105b8SAntonio Quartulli 158730cfd02bSAntonio Quartulli if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || 158830cfd02bSAntonio Quartulli tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) 1589cc47f66eSAntonio Quartulli return 0; 1590cc47f66eSAntonio Quartulli 159156303d34SSven Eckelmann tt_global_entry = container_of(tt_common_entry, 159256303d34SSven Eckelmann struct batadv_tt_global_entry, 159348100bacSAntonio Quartulli common); 159448100bacSAntonio Quartulli 1595a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 1596a73105b8SAntonio Quartulli } 1597a73105b8SAntonio Quartulli 1598335fbe0fSMarek Lindner /** 1599335fbe0fSMarek Lindner * batadv_tt_tvlv_generate - creates tvlv tt data buffer to fill it with the 1600335fbe0fSMarek Lindner * tt entries from the specified tt hash 1601335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1602335fbe0fSMarek Lindner * @hash: hash table containing the tt entries 1603335fbe0fSMarek Lindner * @tt_len: expected tvlv tt data buffer length in number of bytes 1604335fbe0fSMarek Lindner * @valid_cb: function to filter tt change entries 1605335fbe0fSMarek Lindner * @cb_data: data passed to the filter function as argument 1606335fbe0fSMarek Lindner * 1607335fbe0fSMarek Lindner * Returns pointer to allocated tvlv tt data buffer if operation was 1608335fbe0fSMarek Lindner * successful or NULL otherwise. 1609335fbe0fSMarek Lindner */ 1610335fbe0fSMarek Lindner static struct batadv_tvlv_tt_data * 1611335fbe0fSMarek Lindner batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, 1612335fbe0fSMarek Lindner struct batadv_hashtable *hash, uint16_t tt_len, 1613a513088dSSven Eckelmann int (*valid_cb)(const void *, const void *), 1614a73105b8SAntonio Quartulli void *cb_data) 1615a73105b8SAntonio Quartulli { 161656303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 1617335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 1618335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 1619a73105b8SAntonio Quartulli struct hlist_head *head; 1620335fbe0fSMarek Lindner uint16_t tt_tot, tt_num_entries = 0; 1621335fbe0fSMarek Lindner ssize_t tvlv_tt_size = sizeof(struct batadv_tvlv_tt_data); 1622c90681b8SAntonio Quartulli uint32_t i; 1623a73105b8SAntonio Quartulli 1624335fbe0fSMarek Lindner if (tvlv_tt_size + tt_len > bat_priv->soft_iface->mtu) { 1625335fbe0fSMarek Lindner tt_len = bat_priv->soft_iface->mtu - tvlv_tt_size; 1626335fbe0fSMarek Lindner tt_len -= tt_len % sizeof(struct batadv_tvlv_tt_change); 1627a73105b8SAntonio Quartulli } 1628a73105b8SAntonio Quartulli 1629335fbe0fSMarek Lindner tt_tot = tt_len / sizeof(struct batadv_tvlv_tt_change); 1630335fbe0fSMarek Lindner 1631335fbe0fSMarek Lindner tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, 1632335fbe0fSMarek Lindner GFP_ATOMIC); 1633335fbe0fSMarek Lindner if (!tvlv_tt_data) 1634a73105b8SAntonio Quartulli goto out; 1635a73105b8SAntonio Quartulli 1636335fbe0fSMarek Lindner tt_change = (struct batadv_tvlv_tt_change *)(tvlv_tt_data + 1); 1637a73105b8SAntonio Quartulli 1638a73105b8SAntonio Quartulli rcu_read_lock(); 1639a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1640a73105b8SAntonio Quartulli head = &hash->table[i]; 1641a73105b8SAntonio Quartulli 1642b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 1643a73105b8SAntonio Quartulli head, hash_entry) { 1644335fbe0fSMarek Lindner if (tt_tot == tt_num_entries) 1645a73105b8SAntonio Quartulli break; 1646a73105b8SAntonio Quartulli 164748100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 1648a73105b8SAntonio Quartulli continue; 1649a73105b8SAntonio Quartulli 165048100bacSAntonio Quartulli memcpy(tt_change->addr, tt_common_entry->addr, 165148100bacSAntonio Quartulli ETH_ALEN); 165227b37ebfSAntonio Quartulli tt_change->flags = tt_common_entry->flags; 1653335fbe0fSMarek Lindner tt_change->reserved = 0; 1654a73105b8SAntonio Quartulli 1655335fbe0fSMarek Lindner tt_num_entries++; 1656a73105b8SAntonio Quartulli tt_change++; 1657a73105b8SAntonio Quartulli } 1658a73105b8SAntonio Quartulli } 1659a73105b8SAntonio Quartulli rcu_read_unlock(); 1660a73105b8SAntonio Quartulli 1661a73105b8SAntonio Quartulli out: 1662335fbe0fSMarek Lindner return tvlv_tt_data; 1663a73105b8SAntonio Quartulli } 1664a73105b8SAntonio Quartulli 166556303d34SSven Eckelmann static int batadv_send_tt_request(struct batadv_priv *bat_priv, 166656303d34SSven Eckelmann struct batadv_orig_node *dst_orig_node, 1667a513088dSSven Eckelmann uint8_t ttvn, uint16_t tt_crc, 1668a513088dSSven Eckelmann bool full_table) 1669a73105b8SAntonio Quartulli { 1670335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 167156303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 167256303d34SSven Eckelmann struct batadv_tt_req_node *tt_req_node = NULL; 1673335fbe0fSMarek Lindner bool ret = false; 1674a73105b8SAntonio Quartulli 1675e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1676a73105b8SAntonio Quartulli if (!primary_if) 1677a73105b8SAntonio Quartulli goto out; 1678a73105b8SAntonio Quartulli 1679a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 16809cfc7bd6SSven Eckelmann * reply from the same orig_node yet 16819cfc7bd6SSven Eckelmann */ 1682a513088dSSven Eckelmann tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node); 1683a73105b8SAntonio Quartulli if (!tt_req_node) 1684a73105b8SAntonio Quartulli goto out; 1685a73105b8SAntonio Quartulli 1686335fbe0fSMarek Lindner tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data), GFP_ATOMIC); 1687335fbe0fSMarek Lindner if (!tvlv_tt_data) 1688a73105b8SAntonio Quartulli goto out; 1689a73105b8SAntonio Quartulli 1690335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_REQUEST; 1691335fbe0fSMarek Lindner tvlv_tt_data->ttvn = ttvn; 1692335fbe0fSMarek Lindner tvlv_tt_data->crc = htons(tt_crc); 1693a73105b8SAntonio Quartulli 1694a73105b8SAntonio Quartulli if (full_table) 1695335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 1696a73105b8SAntonio Quartulli 1697bb351ba0SMartin Hundebøll batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", 1698335fbe0fSMarek Lindner dst_orig_node->orig, full_table ? 'F' : '.'); 1699a73105b8SAntonio Quartulli 1700d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); 1701335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 1702335fbe0fSMarek Lindner dst_orig_node->orig, BATADV_TVLV_TT, 1, 1703335fbe0fSMarek Lindner tvlv_tt_data, sizeof(*tvlv_tt_data)); 1704335fbe0fSMarek Lindner ret = true; 1705a73105b8SAntonio Quartulli 1706a73105b8SAntonio Quartulli out: 1707a73105b8SAntonio Quartulli if (primary_if) 1708e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1709a73105b8SAntonio Quartulli if (ret && tt_req_node) { 1710807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 1711a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 1712807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 1713a73105b8SAntonio Quartulli kfree(tt_req_node); 1714a73105b8SAntonio Quartulli } 1715335fbe0fSMarek Lindner kfree(tvlv_tt_data); 1716a73105b8SAntonio Quartulli return ret; 1717a73105b8SAntonio Quartulli } 1718a73105b8SAntonio Quartulli 1719335fbe0fSMarek Lindner /** 1720335fbe0fSMarek Lindner * batadv_send_other_tt_response - send reply to tt request concerning another 1721335fbe0fSMarek Lindner * node's translation table 1722335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1723335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 1724335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 1725335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 1726335fbe0fSMarek Lindner * 1727335fbe0fSMarek Lindner * Returns true if tt request reply was sent, false otherwise. 1728335fbe0fSMarek Lindner */ 1729335fbe0fSMarek Lindner static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, 1730335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 1731335fbe0fSMarek Lindner uint8_t *req_src, uint8_t *req_dst) 1732a73105b8SAntonio Quartulli { 1733170173bfSSven Eckelmann struct batadv_orig_node *req_dst_orig_node; 173456303d34SSven Eckelmann struct batadv_orig_node *res_dst_orig_node = NULL; 1735335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 1736335fbe0fSMarek Lindner uint8_t orig_ttvn, req_ttvn; 1737335fbe0fSMarek Lindner uint16_t tt_len; 1738335fbe0fSMarek Lindner bool ret = false, full_table; 1739a73105b8SAntonio Quartulli 174039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 174186ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 1742335fbe0fSMarek Lindner req_src, tt_data->ttvn, req_dst, 1743335fbe0fSMarek Lindner (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1744a73105b8SAntonio Quartulli 1745a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 1746335fbe0fSMarek Lindner req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); 1747a73105b8SAntonio Quartulli if (!req_dst_orig_node) 1748a73105b8SAntonio Quartulli goto out; 1749a73105b8SAntonio Quartulli 1750335fbe0fSMarek Lindner res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); 1751a73105b8SAntonio Quartulli if (!res_dst_orig_node) 1752a73105b8SAntonio Quartulli goto out; 1753a73105b8SAntonio Quartulli 1754a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1755335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 1756a73105b8SAntonio Quartulli 1757335fbe0fSMarek Lindner /* this node doesn't have the requested data */ 1758a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 1759335fbe0fSMarek Lindner tt_data->crc != htons(req_dst_orig_node->tt_crc)) 1760a73105b8SAntonio Quartulli goto out; 1761a73105b8SAntonio Quartulli 1762015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 1763335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || 1764a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 1765a73105b8SAntonio Quartulli full_table = true; 1766a73105b8SAntonio Quartulli else 1767a73105b8SAntonio Quartulli full_table = false; 1768a73105b8SAntonio Quartulli 1769335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 1770335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 17719cfc7bd6SSven Eckelmann */ 1772a73105b8SAntonio Quartulli if (!full_table) { 1773a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 1774a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 1775a73105b8SAntonio Quartulli 1776335fbe0fSMarek Lindner tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, 1777335fbe0fSMarek Lindner GFP_ATOMIC); 1778335fbe0fSMarek Lindner if (!tvlv_tt_data) 1779a73105b8SAntonio Quartulli goto unlock; 1780a73105b8SAntonio Quartulli 1781a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 1782335fbe0fSMarek Lindner memcpy(tvlv_tt_data + 1, req_dst_orig_node->tt_buff, 1783a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 1784a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1785a73105b8SAntonio Quartulli } else { 178696412690SSven Eckelmann tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size); 1787335fbe0fSMarek Lindner tt_len = batadv_tt_len(tt_len); 1788a73105b8SAntonio Quartulli 1789335fbe0fSMarek Lindner tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv, 1790807736f6SSven Eckelmann bat_priv->tt.global_hash, 1791335fbe0fSMarek Lindner tt_len, 1792a513088dSSven Eckelmann batadv_tt_global_valid, 1793a73105b8SAntonio Quartulli req_dst_orig_node); 1794335fbe0fSMarek Lindner if (!tvlv_tt_data) 1795a73105b8SAntonio Quartulli goto out; 1796a73105b8SAntonio Quartulli } 1797a73105b8SAntonio Quartulli 1798335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 1799335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 1800a73105b8SAntonio Quartulli 1801a73105b8SAntonio Quartulli if (full_table) 1802335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 1803a73105b8SAntonio Quartulli 180439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1805335fbe0fSMarek Lindner "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n", 1806335fbe0fSMarek Lindner res_dst_orig_node->orig, req_dst_orig_node->orig, 1807335fbe0fSMarek Lindner full_table ? 'F' : '.', req_ttvn); 1808a73105b8SAntonio Quartulli 1809d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 1810f8214865SMartin Hundebøll 1811335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, 1812335fbe0fSMarek Lindner req_src, BATADV_TVLV_TT, 1, 1813335fbe0fSMarek Lindner tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len); 1814e91ecfc6SMartin Hundebøll 1815335fbe0fSMarek Lindner ret = true; 1816a73105b8SAntonio Quartulli goto out; 1817a73105b8SAntonio Quartulli 1818a73105b8SAntonio Quartulli unlock: 1819a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1820a73105b8SAntonio Quartulli 1821a73105b8SAntonio Quartulli out: 1822a73105b8SAntonio Quartulli if (res_dst_orig_node) 18237d211efcSSven Eckelmann batadv_orig_node_free_ref(res_dst_orig_node); 1824a73105b8SAntonio Quartulli if (req_dst_orig_node) 18257d211efcSSven Eckelmann batadv_orig_node_free_ref(req_dst_orig_node); 1826335fbe0fSMarek Lindner kfree(tvlv_tt_data); 1827a73105b8SAntonio Quartulli return ret; 1828a73105b8SAntonio Quartulli } 182996412690SSven Eckelmann 1830335fbe0fSMarek Lindner /** 1831335fbe0fSMarek Lindner * batadv_send_my_tt_response - send reply to tt request concerning this node's 1832335fbe0fSMarek Lindner * translation table 1833335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1834335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 1835335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 1836335fbe0fSMarek Lindner * 1837335fbe0fSMarek Lindner * Returns true if tt request reply was sent, false otherwise. 1838335fbe0fSMarek Lindner */ 1839335fbe0fSMarek Lindner static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, 1840335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 1841335fbe0fSMarek Lindner uint8_t *req_src) 1842a73105b8SAntonio Quartulli { 1843335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; 1844170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 184556303d34SSven Eckelmann struct batadv_hard_iface *primary_if = NULL; 1846335fbe0fSMarek Lindner uint8_t my_ttvn, req_ttvn; 1847a73105b8SAntonio Quartulli bool full_table; 1848335fbe0fSMarek Lindner uint16_t tt_len; 1849a73105b8SAntonio Quartulli 185039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 185186ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 1852335fbe0fSMarek Lindner req_src, tt_data->ttvn, 1853335fbe0fSMarek Lindner (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1854a73105b8SAntonio Quartulli 1855a73105b8SAntonio Quartulli 1856807736f6SSven Eckelmann my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); 1857335fbe0fSMarek Lindner req_ttvn = tt_data->ttvn; 1858a73105b8SAntonio Quartulli 1859335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, req_src); 1860a73105b8SAntonio Quartulli if (!orig_node) 1861a73105b8SAntonio Quartulli goto out; 1862a73105b8SAntonio Quartulli 1863e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1864a73105b8SAntonio Quartulli if (!primary_if) 1865a73105b8SAntonio Quartulli goto out; 1866a73105b8SAntonio Quartulli 1867a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 18689cfc7bd6SSven Eckelmann * is too big send the whole local translation table 18699cfc7bd6SSven Eckelmann */ 1870335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || 1871807736f6SSven Eckelmann !bat_priv->tt.last_changeset) 1872a73105b8SAntonio Quartulli full_table = true; 1873a73105b8SAntonio Quartulli else 1874a73105b8SAntonio Quartulli full_table = false; 1875a73105b8SAntonio Quartulli 1876335fbe0fSMarek Lindner /* TT fragmentation hasn't been implemented yet, so send as many 1877335fbe0fSMarek Lindner * TT entries fit a single packet as possible only 18789cfc7bd6SSven Eckelmann */ 1879a73105b8SAntonio Quartulli if (!full_table) { 1880807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.last_changeset_lock); 1881807736f6SSven Eckelmann tt_len = bat_priv->tt.last_changeset_len; 1882a73105b8SAntonio Quartulli 1883335fbe0fSMarek Lindner tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, 1884335fbe0fSMarek Lindner GFP_ATOMIC); 1885335fbe0fSMarek Lindner if (!tvlv_tt_data) 1886a73105b8SAntonio Quartulli goto unlock; 1887a73105b8SAntonio Quartulli 1888335fbe0fSMarek Lindner /* Copy the last orig_node's OGM buffer */ 1889335fbe0fSMarek Lindner memcpy(tvlv_tt_data + 1, bat_priv->tt.last_changeset, 1890807736f6SSven Eckelmann bat_priv->tt.last_changeset_len); 1891807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 1892a73105b8SAntonio Quartulli } else { 1893807736f6SSven Eckelmann tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num); 1894335fbe0fSMarek Lindner tt_len = batadv_tt_len(tt_len); 1895335fbe0fSMarek Lindner req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); 1896a73105b8SAntonio Quartulli 1897335fbe0fSMarek Lindner tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv, 1898807736f6SSven Eckelmann bat_priv->tt.local_hash, 1899335fbe0fSMarek Lindner tt_len, 1900335fbe0fSMarek Lindner batadv_tt_local_valid, 1901058d0e26SAntonio Quartulli NULL); 1902335fbe0fSMarek Lindner if (!tvlv_tt_data) 1903a73105b8SAntonio Quartulli goto out; 1904a73105b8SAntonio Quartulli } 1905a73105b8SAntonio Quartulli 1906335fbe0fSMarek Lindner tvlv_tt_data->flags = BATADV_TT_RESPONSE; 1907335fbe0fSMarek Lindner tvlv_tt_data->ttvn = req_ttvn; 1908a73105b8SAntonio Quartulli 1909a73105b8SAntonio Quartulli if (full_table) 1910335fbe0fSMarek Lindner tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; 1911a73105b8SAntonio Quartulli 191239c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1913335fbe0fSMarek Lindner "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n", 1914335fbe0fSMarek Lindner orig_node->orig, full_table ? 'F' : '.', req_ttvn); 1915a73105b8SAntonio Quartulli 1916d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 1917f8214865SMartin Hundebøll 1918335fbe0fSMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 1919335fbe0fSMarek Lindner req_src, BATADV_TVLV_TT, 1, 1920335fbe0fSMarek Lindner tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len); 1921335fbe0fSMarek Lindner 1922a73105b8SAntonio Quartulli goto out; 1923a73105b8SAntonio Quartulli 1924a73105b8SAntonio Quartulli unlock: 1925807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 1926a73105b8SAntonio Quartulli out: 1927a73105b8SAntonio Quartulli if (orig_node) 19287d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1929a73105b8SAntonio Quartulli if (primary_if) 1930e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1931335fbe0fSMarek Lindner kfree(tvlv_tt_data); 1932335fbe0fSMarek Lindner /* The packet was for this host, so it doesn't need to be re-routed */ 1933a73105b8SAntonio Quartulli return true; 1934a73105b8SAntonio Quartulli } 1935a73105b8SAntonio Quartulli 1936335fbe0fSMarek Lindner /** 1937335fbe0fSMarek Lindner * batadv_send_tt_response - send reply to tt request 1938335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 1939335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 1940335fbe0fSMarek Lindner * @req_src: mac address of tt request sender 1941335fbe0fSMarek Lindner * @req_dst: mac address of tt request recipient 1942335fbe0fSMarek Lindner * 1943335fbe0fSMarek Lindner * Returns true if tt request reply was sent, false otherwise. 1944335fbe0fSMarek Lindner */ 1945335fbe0fSMarek Lindner static bool batadv_send_tt_response(struct batadv_priv *bat_priv, 1946335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 1947335fbe0fSMarek Lindner uint8_t *req_src, uint8_t *req_dst) 1948a73105b8SAntonio Quartulli { 1949335fbe0fSMarek Lindner if (batadv_is_my_mac(bat_priv, req_dst)) { 195020ff9d59SSimon Wunderlich /* don't answer backbone gws! */ 1951335fbe0fSMarek Lindner if (batadv_bla_is_backbone_gw_orig(bat_priv, req_src)) 195220ff9d59SSimon Wunderlich return true; 195320ff9d59SSimon Wunderlich 1954335fbe0fSMarek Lindner return batadv_send_my_tt_response(bat_priv, tt_data, req_src); 195520ff9d59SSimon Wunderlich } else { 1956335fbe0fSMarek Lindner return batadv_send_other_tt_response(bat_priv, tt_data, 1957335fbe0fSMarek Lindner req_src, req_dst); 1958a73105b8SAntonio Quartulli } 195920ff9d59SSimon Wunderlich } 1960a73105b8SAntonio Quartulli 196156303d34SSven Eckelmann static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, 196256303d34SSven Eckelmann struct batadv_orig_node *orig_node, 1963335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change, 1964a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 1965a73105b8SAntonio Quartulli { 1966a73105b8SAntonio Quartulli int i; 1967a513088dSSven Eckelmann int roams; 1968a73105b8SAntonio Quartulli 1969a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 1970acd34afaSSven Eckelmann if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { 1971acd34afaSSven Eckelmann roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; 1972a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 1973a73105b8SAntonio Quartulli (tt_change + i)->addr, 1974cc47f66eSAntonio Quartulli "tt removed by changes", 1975a513088dSSven Eckelmann roams); 197608c36d3eSSven Eckelmann } else { 197708c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 1978d4f44692SAntonio Quartulli (tt_change + i)->addr, 1979d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 1980a73105b8SAntonio Quartulli /* In case of problem while storing a 1981a73105b8SAntonio Quartulli * global_entry, we stop the updating 1982a73105b8SAntonio Quartulli * procedure without committing the 1983a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 1984a73105b8SAntonio Quartulli * corrupted data on tt_request 1985a73105b8SAntonio Quartulli */ 1986a73105b8SAntonio Quartulli return; 1987a73105b8SAntonio Quartulli } 198808c36d3eSSven Eckelmann } 198917071578SAntonio Quartulli orig_node->tt_initialised = true; 1990a73105b8SAntonio Quartulli } 1991a73105b8SAntonio Quartulli 199256303d34SSven Eckelmann static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, 1993335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 1994335fbe0fSMarek Lindner uint8_t *resp_src, uint16_t num_entries) 1995a73105b8SAntonio Quartulli { 1996170173bfSSven Eckelmann struct batadv_orig_node *orig_node; 1997a73105b8SAntonio Quartulli 1998335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 1999a73105b8SAntonio Quartulli if (!orig_node) 2000a73105b8SAntonio Quartulli goto out; 2001a73105b8SAntonio Quartulli 2002a73105b8SAntonio Quartulli /* Purge the old table first.. */ 200308c36d3eSSven Eckelmann batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table"); 2004a73105b8SAntonio Quartulli 2005a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, 2006335fbe0fSMarek Lindner (struct batadv_tvlv_tt_change *)(tt_data + 1), 2007335fbe0fSMarek Lindner num_entries, tt_data->ttvn); 2008a73105b8SAntonio Quartulli 2009a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 2010a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 2011a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 2012a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 2013a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 2014a73105b8SAntonio Quartulli 2015335fbe0fSMarek Lindner atomic_set(&orig_node->last_ttvn, tt_data->ttvn); 2016a73105b8SAntonio Quartulli 2017a73105b8SAntonio Quartulli out: 2018a73105b8SAntonio Quartulli if (orig_node) 20197d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2020a73105b8SAntonio Quartulli } 2021a73105b8SAntonio Quartulli 202256303d34SSven Eckelmann static void batadv_tt_update_changes(struct batadv_priv *bat_priv, 202356303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2024a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 2025335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change) 2026a73105b8SAntonio Quartulli { 2027a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 2028a513088dSSven Eckelmann tt_num_changes, ttvn); 2029a73105b8SAntonio Quartulli 2030a513088dSSven Eckelmann batadv_tt_save_orig_buffer(bat_priv, orig_node, 2031a513088dSSven Eckelmann (unsigned char *)tt_change, tt_num_changes); 2032a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 2033a73105b8SAntonio Quartulli } 2034a73105b8SAntonio Quartulli 203556303d34SSven Eckelmann bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr) 2036a73105b8SAntonio Quartulli { 2037170173bfSSven Eckelmann struct batadv_tt_local_entry *tt_local_entry; 20387683fdc1SAntonio Quartulli bool ret = false; 2039a73105b8SAntonio Quartulli 2040a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 20417683fdc1SAntonio Quartulli if (!tt_local_entry) 20427683fdc1SAntonio Quartulli goto out; 2043058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 20449cfc7bd6SSven Eckelmann * consistency purpose) 20459cfc7bd6SSven Eckelmann */ 20467c1fd91dSAntonio Quartulli if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) || 20477c1fd91dSAntonio Quartulli (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM)) 2048058d0e26SAntonio Quartulli goto out; 20497683fdc1SAntonio Quartulli ret = true; 20507683fdc1SAntonio Quartulli out: 2051a73105b8SAntonio Quartulli if (tt_local_entry) 2052a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 20537683fdc1SAntonio Quartulli return ret; 2054a73105b8SAntonio Quartulli } 2055a73105b8SAntonio Quartulli 2056335fbe0fSMarek Lindner /** 2057335fbe0fSMarek Lindner * batadv_handle_tt_response - process incoming tt reply 2058335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2059335fbe0fSMarek Lindner * @tt_data: tt data containing the tt request information 2060335fbe0fSMarek Lindner * @resp_src: mac address of tt reply sender 2061335fbe0fSMarek Lindner * @num_entries: number of tt change entries appended to the tt data 2062335fbe0fSMarek Lindner */ 2063335fbe0fSMarek Lindner static void batadv_handle_tt_response(struct batadv_priv *bat_priv, 2064335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data, 2065335fbe0fSMarek Lindner uint8_t *resp_src, uint16_t num_entries) 2066a73105b8SAntonio Quartulli { 206756303d34SSven Eckelmann struct batadv_tt_req_node *node, *safe; 206856303d34SSven Eckelmann struct batadv_orig_node *orig_node = NULL; 2069335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 2070a73105b8SAntonio Quartulli 207139c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 207286ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 2073335fbe0fSMarek Lindner resp_src, tt_data->ttvn, num_entries, 2074335fbe0fSMarek Lindner (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 2075a73105b8SAntonio Quartulli 207620ff9d59SSimon Wunderlich /* we should have never asked a backbone gw */ 2077335fbe0fSMarek Lindner if (batadv_bla_is_backbone_gw_orig(bat_priv, resp_src)) 207820ff9d59SSimon Wunderlich goto out; 207920ff9d59SSimon Wunderlich 2080335fbe0fSMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, resp_src); 2081a73105b8SAntonio Quartulli if (!orig_node) 2082a73105b8SAntonio Quartulli goto out; 2083a73105b8SAntonio Quartulli 2084335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) { 2085335fbe0fSMarek Lindner batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries); 208696412690SSven Eckelmann } else { 2087335fbe0fSMarek Lindner tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1); 2088335fbe0fSMarek Lindner batadv_tt_update_changes(bat_priv, orig_node, num_entries, 2089335fbe0fSMarek Lindner tt_data->ttvn, tt_change); 209096412690SSven Eckelmann } 2091a73105b8SAntonio Quartulli 2092a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 2093807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.req_list_lock); 2094807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 2095335fbe0fSMarek Lindner if (!batadv_compare_eth(node->addr, resp_src)) 2096a73105b8SAntonio Quartulli continue; 2097a73105b8SAntonio Quartulli list_del(&node->list); 2098a73105b8SAntonio Quartulli kfree(node); 2099a73105b8SAntonio Quartulli } 2100807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.req_list_lock); 2101a73105b8SAntonio Quartulli 2102a73105b8SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 2103a513088dSSven Eckelmann orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 2104a73105b8SAntonio Quartulli out: 2105a73105b8SAntonio Quartulli if (orig_node) 21067d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 2107a73105b8SAntonio Quartulli } 2108a73105b8SAntonio Quartulli 210956303d34SSven Eckelmann static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) 2110a73105b8SAntonio Quartulli { 211156303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 2112a73105b8SAntonio Quartulli 2113807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2114a73105b8SAntonio Quartulli 2115807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 2116cc47f66eSAntonio Quartulli list_del(&node->list); 2117cc47f66eSAntonio Quartulli kfree(node); 2118cc47f66eSAntonio Quartulli } 2119cc47f66eSAntonio Quartulli 2120807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2121cc47f66eSAntonio Quartulli } 2122cc47f66eSAntonio Quartulli 212356303d34SSven Eckelmann static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) 2124cc47f66eSAntonio Quartulli { 212556303d34SSven Eckelmann struct batadv_tt_roam_node *node, *safe; 2126cc47f66eSAntonio Quartulli 2127807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2128807736f6SSven Eckelmann list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { 212942d0b044SSven Eckelmann if (!batadv_has_timed_out(node->first_time, 213042d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 2131cc47f66eSAntonio Quartulli continue; 2132cc47f66eSAntonio Quartulli 2133cc47f66eSAntonio Quartulli list_del(&node->list); 2134cc47f66eSAntonio Quartulli kfree(node); 2135cc47f66eSAntonio Quartulli } 2136807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2137cc47f66eSAntonio Quartulli } 2138cc47f66eSAntonio Quartulli 2139cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 2140cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 2141cc47f66eSAntonio Quartulli * will not be sent. 2142cc47f66eSAntonio Quartulli * 21439cfc7bd6SSven Eckelmann * returns true if the ROAMING_ADV can be sent, false otherwise 21449cfc7bd6SSven Eckelmann */ 214556303d34SSven Eckelmann static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, 2146cc47f66eSAntonio Quartulli uint8_t *client) 2147cc47f66eSAntonio Quartulli { 214856303d34SSven Eckelmann struct batadv_tt_roam_node *tt_roam_node; 2149cc47f66eSAntonio Quartulli bool ret = false; 2150cc47f66eSAntonio Quartulli 2151807736f6SSven Eckelmann spin_lock_bh(&bat_priv->tt.roam_list_lock); 2152cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 21539cfc7bd6SSven Eckelmann * reply from the same orig_node yet 21549cfc7bd6SSven Eckelmann */ 2155807736f6SSven Eckelmann list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) { 21561eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 2157cc47f66eSAntonio Quartulli continue; 2158cc47f66eSAntonio Quartulli 21591eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 216042d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 2161cc47f66eSAntonio Quartulli continue; 2162cc47f66eSAntonio Quartulli 21633e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 2164cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 2165cc47f66eSAntonio Quartulli goto unlock; 2166cc47f66eSAntonio Quartulli ret = true; 2167cc47f66eSAntonio Quartulli break; 2168cc47f66eSAntonio Quartulli } 2169cc47f66eSAntonio Quartulli 2170cc47f66eSAntonio Quartulli if (!ret) { 2171cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 2172cc47f66eSAntonio Quartulli if (!tt_roam_node) 2173cc47f66eSAntonio Quartulli goto unlock; 2174cc47f66eSAntonio Quartulli 2175cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 217642d0b044SSven Eckelmann atomic_set(&tt_roam_node->counter, 217742d0b044SSven Eckelmann BATADV_ROAMING_MAX_COUNT - 1); 2178cc47f66eSAntonio Quartulli memcpy(tt_roam_node->addr, client, ETH_ALEN); 2179cc47f66eSAntonio Quartulli 2180807736f6SSven Eckelmann list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); 2181cc47f66eSAntonio Quartulli ret = true; 2182cc47f66eSAntonio Quartulli } 2183cc47f66eSAntonio Quartulli 2184cc47f66eSAntonio Quartulli unlock: 2185807736f6SSven Eckelmann spin_unlock_bh(&bat_priv->tt.roam_list_lock); 2186cc47f66eSAntonio Quartulli return ret; 2187cc47f66eSAntonio Quartulli } 2188cc47f66eSAntonio Quartulli 218956303d34SSven Eckelmann static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, 219056303d34SSven Eckelmann struct batadv_orig_node *orig_node) 2191cc47f66eSAntonio Quartulli { 219256303d34SSven Eckelmann struct batadv_hard_iface *primary_if; 2193122edaa0SMarek Lindner struct batadv_tvlv_roam_adv tvlv_roam; 2194122edaa0SMarek Lindner 2195122edaa0SMarek Lindner primary_if = batadv_primary_if_get_selected(bat_priv); 2196122edaa0SMarek Lindner if (!primary_if) 2197122edaa0SMarek Lindner goto out; 2198cc47f66eSAntonio Quartulli 2199cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 22009cfc7bd6SSven Eckelmann * already roamed to us too many times 22019cfc7bd6SSven Eckelmann */ 2202a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 2203cc47f66eSAntonio Quartulli goto out; 2204cc47f66eSAntonio Quartulli 220539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2206bb351ba0SMartin Hundebøll "Sending ROAMING_ADV to %pM (client %pM)\n", 2207bb351ba0SMartin Hundebøll orig_node->orig, client); 2208cc47f66eSAntonio Quartulli 2209d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); 2210f8214865SMartin Hundebøll 2211122edaa0SMarek Lindner memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); 2212122edaa0SMarek Lindner tvlv_roam.reserved = 0; 2213122edaa0SMarek Lindner 2214122edaa0SMarek Lindner batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, 2215122edaa0SMarek Lindner orig_node->orig, BATADV_TVLV_ROAM, 1, 2216122edaa0SMarek Lindner &tvlv_roam, sizeof(tvlv_roam)); 2217cc47f66eSAntonio Quartulli 2218cc47f66eSAntonio Quartulli out: 2219122edaa0SMarek Lindner if (primary_if) 2220122edaa0SMarek Lindner batadv_hardif_free_ref(primary_if); 2221a73105b8SAntonio Quartulli } 2222a73105b8SAntonio Quartulli 2223a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 2224a73105b8SAntonio Quartulli { 222556303d34SSven Eckelmann struct delayed_work *delayed_work; 2226807736f6SSven Eckelmann struct batadv_priv_tt *priv_tt; 222756303d34SSven Eckelmann struct batadv_priv *bat_priv; 222856303d34SSven Eckelmann 222956303d34SSven Eckelmann delayed_work = container_of(work, struct delayed_work, work); 2230807736f6SSven Eckelmann priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 2231807736f6SSven Eckelmann bat_priv = container_of(priv_tt, struct batadv_priv, tt); 2232a73105b8SAntonio Quartulli 2233a513088dSSven Eckelmann batadv_tt_local_purge(bat_priv); 223430cfd02bSAntonio Quartulli batadv_tt_global_purge(bat_priv); 2235a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 2236a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 2237a73105b8SAntonio Quartulli 223872414442SAntonio Quartulli queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 223972414442SAntonio Quartulli msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 2240a73105b8SAntonio Quartulli } 2241cc47f66eSAntonio Quartulli 224256303d34SSven Eckelmann void batadv_tt_free(struct batadv_priv *bat_priv) 2243cc47f66eSAntonio Quartulli { 2244e1bf0c14SMarek Lindner batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); 2245e1bf0c14SMarek Lindner batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); 2246e1bf0c14SMarek Lindner 2247807736f6SSven Eckelmann cancel_delayed_work_sync(&bat_priv->tt.work); 2248cc47f66eSAntonio Quartulli 2249a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 2250a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 2251a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 2252a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 2253a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 2254cc47f66eSAntonio Quartulli 2255807736f6SSven Eckelmann kfree(bat_priv->tt.last_changeset); 2256cc47f66eSAntonio Quartulli } 2257058d0e26SAntonio Quartulli 2258697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries 22599cfc7bd6SSven Eckelmann * in the given hash table and returns the number of modified entries 22609cfc7bd6SSven Eckelmann */ 22615bf74e9cSSven Eckelmann static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash, 22625bf74e9cSSven Eckelmann uint16_t flags, bool enable) 2263058d0e26SAntonio Quartulli { 2264c90681b8SAntonio Quartulli uint32_t i; 2265697f2531SAntonio Quartulli uint16_t changed_num = 0; 2266058d0e26SAntonio Quartulli struct hlist_head *head; 226756303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common_entry; 2268058d0e26SAntonio Quartulli 2269058d0e26SAntonio Quartulli if (!hash) 2270697f2531SAntonio Quartulli goto out; 2271058d0e26SAntonio Quartulli 2272058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2273058d0e26SAntonio Quartulli head = &hash->table[i]; 2274058d0e26SAntonio Quartulli 2275058d0e26SAntonio Quartulli rcu_read_lock(); 2276b67bfe0dSSasha Levin hlist_for_each_entry_rcu(tt_common_entry, 2277058d0e26SAntonio Quartulli head, hash_entry) { 2278697f2531SAntonio Quartulli if (enable) { 2279697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 2280697f2531SAntonio Quartulli continue; 2281697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 2282697f2531SAntonio Quartulli } else { 228348100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 228431901264SAntonio Quartulli continue; 228548100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 2286697f2531SAntonio Quartulli } 2287697f2531SAntonio Quartulli changed_num++; 2288058d0e26SAntonio Quartulli } 2289058d0e26SAntonio Quartulli rcu_read_unlock(); 2290058d0e26SAntonio Quartulli } 2291697f2531SAntonio Quartulli out: 2292697f2531SAntonio Quartulli return changed_num; 2293058d0e26SAntonio Quartulli } 2294058d0e26SAntonio Quartulli 2295acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ 229656303d34SSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) 2297058d0e26SAntonio Quartulli { 2298807736f6SSven Eckelmann struct batadv_hashtable *hash = bat_priv->tt.local_hash; 229956303d34SSven Eckelmann struct batadv_tt_common_entry *tt_common; 230056303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local; 2301b67bfe0dSSasha Levin struct hlist_node *node_tmp; 2302058d0e26SAntonio Quartulli struct hlist_head *head; 2303058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 2304c90681b8SAntonio Quartulli uint32_t i; 2305058d0e26SAntonio Quartulli 2306058d0e26SAntonio Quartulli if (!hash) 2307058d0e26SAntonio Quartulli return; 2308058d0e26SAntonio Quartulli 2309058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2310058d0e26SAntonio Quartulli head = &hash->table[i]; 2311058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 2312058d0e26SAntonio Quartulli 2313058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 2314b67bfe0dSSasha Levin hlist_for_each_entry_safe(tt_common, node_tmp, head, 2315acd34afaSSven Eckelmann hash_entry) { 2316acd34afaSSven Eckelmann if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) 2317058d0e26SAntonio Quartulli continue; 2318058d0e26SAntonio Quartulli 231939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 232086ceb360SSven Eckelmann "Deleting local tt entry (%pM): pending\n", 2321acd34afaSSven Eckelmann tt_common->addr); 2322058d0e26SAntonio Quartulli 2323807736f6SSven Eckelmann atomic_dec(&bat_priv->tt.local_entry_num); 2324b67bfe0dSSasha Levin hlist_del_rcu(&tt_common->hash_entry); 232556303d34SSven Eckelmann tt_local = container_of(tt_common, 232656303d34SSven Eckelmann struct batadv_tt_local_entry, 232748100bacSAntonio Quartulli common); 232856303d34SSven Eckelmann batadv_tt_local_entry_free_ref(tt_local); 2329058d0e26SAntonio Quartulli } 2330058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 2331058d0e26SAntonio Quartulli } 2332058d0e26SAntonio Quartulli } 2333058d0e26SAntonio Quartulli 2334e1bf0c14SMarek Lindner /** 2335e1bf0c14SMarek Lindner * batadv_tt_local_commit_changes - commit all pending local tt changes which 2336e1bf0c14SMarek Lindner * have been queued in the time since the last commit 2337e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2338e1bf0c14SMarek Lindner */ 2339e1bf0c14SMarek Lindner void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) 2340058d0e26SAntonio Quartulli { 2341be9aa4c1SMarek Lindner uint16_t changed_num = 0; 2342be9aa4c1SMarek Lindner 2343e1bf0c14SMarek Lindner if (atomic_read(&bat_priv->tt.local_changes) < 1) { 2344e1bf0c14SMarek Lindner if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 2345e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 2346e1bf0c14SMarek Lindner return; 2347e1bf0c14SMarek Lindner } 2348be9aa4c1SMarek Lindner 2349807736f6SSven Eckelmann changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash, 2350acd34afaSSven Eckelmann BATADV_TT_CLIENT_NEW, false); 2351be9aa4c1SMarek Lindner 2352be9aa4c1SMarek Lindner /* all reset entries have to be counted as local entries */ 2353807736f6SSven Eckelmann atomic_add(changed_num, &bat_priv->tt.local_entry_num); 2354a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 2355807736f6SSven Eckelmann bat_priv->tt.local_crc = batadv_tt_local_crc(bat_priv); 2356058d0e26SAntonio Quartulli 2357058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 2358807736f6SSven Eckelmann atomic_inc(&bat_priv->tt.vn); 235939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 23601eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 2361807736f6SSven Eckelmann (uint8_t)atomic_read(&bat_priv->tt.vn)); 2362be9aa4c1SMarek Lindner 2363be9aa4c1SMarek Lindner /* reset the sending counter */ 2364807736f6SSven Eckelmann atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 2365e1bf0c14SMarek Lindner batadv_tt_tvlv_container_update(bat_priv); 2366058d0e26SAntonio Quartulli } 236759b699cdSAntonio Quartulli 236856303d34SSven Eckelmann bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, 236908c36d3eSSven Eckelmann uint8_t *dst) 237059b699cdSAntonio Quartulli { 237156303d34SSven Eckelmann struct batadv_tt_local_entry *tt_local_entry = NULL; 237256303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry = NULL; 23735870adc6SMarek Lindner bool ret = false; 237459b699cdSAntonio Quartulli 237559b699cdSAntonio Quartulli if (!atomic_read(&bat_priv->ap_isolation)) 23765870adc6SMarek Lindner goto out; 237759b699cdSAntonio Quartulli 2378a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst); 237959b699cdSAntonio Quartulli if (!tt_local_entry) 238059b699cdSAntonio Quartulli goto out; 238159b699cdSAntonio Quartulli 2382a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, src); 238359b699cdSAntonio Quartulli if (!tt_global_entry) 238459b699cdSAntonio Quartulli goto out; 238559b699cdSAntonio Quartulli 23861f129fefSAntonio Quartulli if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 238759b699cdSAntonio Quartulli goto out; 238859b699cdSAntonio Quartulli 23895870adc6SMarek Lindner ret = true; 239059b699cdSAntonio Quartulli 239159b699cdSAntonio Quartulli out: 239259b699cdSAntonio Quartulli if (tt_global_entry) 2393a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 239459b699cdSAntonio Quartulli if (tt_local_entry) 2395a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 239659b699cdSAntonio Quartulli return ret; 239759b699cdSAntonio Quartulli } 2398a943cac1SMarek Lindner 2399e1bf0c14SMarek Lindner /** 2400e1bf0c14SMarek Lindner * batadv_tt_update_orig - update global translation table with new tt 2401e1bf0c14SMarek Lindner * information received via ogms 2402e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2403e1bf0c14SMarek Lindner * @orig: the orig_node of the ogm 2404e1bf0c14SMarek Lindner * @tt_buff: buffer holding the tt information 2405e1bf0c14SMarek Lindner * @tt_num_changes: number of tt changes inside the tt buffer 2406e1bf0c14SMarek Lindner * @ttvn: translation table version number of this changeset 2407e1bf0c14SMarek Lindner * @tt_crc: crc16 checksum of orig node's translation table 2408e1bf0c14SMarek Lindner */ 2409e1bf0c14SMarek Lindner static void batadv_tt_update_orig(struct batadv_priv *bat_priv, 241056303d34SSven Eckelmann struct batadv_orig_node *orig_node, 2411e1bf0c14SMarek Lindner const unsigned char *tt_buff, 2412e1bf0c14SMarek Lindner uint16_t tt_num_changes, uint8_t ttvn, 2413e1bf0c14SMarek Lindner uint16_t tt_crc) 2414a943cac1SMarek Lindner { 2415a943cac1SMarek Lindner uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); 2416a943cac1SMarek Lindner bool full_table = true; 2417335fbe0fSMarek Lindner struct batadv_tvlv_tt_change *tt_change; 2418a943cac1SMarek Lindner 241920ff9d59SSimon Wunderlich /* don't care about a backbone gateways updates. */ 242008adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) 242120ff9d59SSimon Wunderlich return; 242220ff9d59SSimon Wunderlich 242317071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 24249cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 24259cfc7bd6SSven Eckelmann */ 242617071578SAntonio Quartulli if ((!orig_node->tt_initialised && ttvn == 1) || 242717071578SAntonio Quartulli ttvn - orig_ttvn == 1) { 2428a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 242942d0b044SSven Eckelmann * because they have already been sent BATADV_TT_OGM_APPEND_MAX 243042d0b044SSven Eckelmann * times. 24319cfc7bd6SSven Eckelmann * In this case send a tt request 24329cfc7bd6SSven Eckelmann */ 2433a943cac1SMarek Lindner if (!tt_num_changes) { 2434a943cac1SMarek Lindner full_table = false; 2435a943cac1SMarek Lindner goto request_table; 2436a943cac1SMarek Lindner } 2437a943cac1SMarek Lindner 2438335fbe0fSMarek Lindner tt_change = (struct batadv_tvlv_tt_change *)tt_buff; 2439a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 244096412690SSven Eckelmann ttvn, tt_change); 2441a943cac1SMarek Lindner 2442a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 2443a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 24449cfc7bd6SSven Eckelmann * in the global table 24459cfc7bd6SSven Eckelmann */ 2446a513088dSSven Eckelmann orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 2447a943cac1SMarek Lindner 2448a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 2449a943cac1SMarek Lindner * because a single value could represent different states 2450a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 2451a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 2452a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 2453a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 2454a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 24559cfc7bd6SSven Eckelmann * inconsistency 24569cfc7bd6SSven Eckelmann */ 2457a943cac1SMarek Lindner if (orig_node->tt_crc != tt_crc) 2458a943cac1SMarek Lindner goto request_table; 2459a943cac1SMarek Lindner } else { 2460a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 24619cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 24629cfc7bd6SSven Eckelmann */ 246317071578SAntonio Quartulli if (!orig_node->tt_initialised || ttvn != orig_ttvn || 246417071578SAntonio Quartulli orig_node->tt_crc != tt_crc) { 2465a943cac1SMarek Lindner request_table: 246639c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 246739a32991SAntonio 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", 246886ceb360SSven Eckelmann orig_node->orig, ttvn, orig_ttvn, tt_crc, 246986ceb360SSven Eckelmann orig_node->tt_crc, tt_num_changes); 2470a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 2471a513088dSSven Eckelmann tt_crc, full_table); 2472a943cac1SMarek Lindner return; 2473a943cac1SMarek Lindner } 2474a943cac1SMarek Lindner } 2475a943cac1SMarek Lindner } 24763275e7ccSAntonio Quartulli 24773275e7ccSAntonio Quartulli /* returns true whether we know that the client has moved from its old 24783275e7ccSAntonio Quartulli * originator to another one. This entry is kept is still kept for consistency 24793275e7ccSAntonio Quartulli * purposes 24803275e7ccSAntonio Quartulli */ 248156303d34SSven Eckelmann bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, 248208c36d3eSSven Eckelmann uint8_t *addr) 24833275e7ccSAntonio Quartulli { 248456303d34SSven Eckelmann struct batadv_tt_global_entry *tt_global_entry; 24853275e7ccSAntonio Quartulli bool ret = false; 24863275e7ccSAntonio Quartulli 2487a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 24883275e7ccSAntonio Quartulli if (!tt_global_entry) 24893275e7ccSAntonio Quartulli goto out; 24903275e7ccSAntonio Quartulli 2491c1d07431SAntonio Quartulli ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; 2492a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 24933275e7ccSAntonio Quartulli out: 24943275e7ccSAntonio Quartulli return ret; 24953275e7ccSAntonio Quartulli } 249630cfd02bSAntonio Quartulli 24977c1fd91dSAntonio Quartulli /** 24987c1fd91dSAntonio Quartulli * batadv_tt_local_client_is_roaming - tells whether the client is roaming 24997c1fd91dSAntonio Quartulli * @bat_priv: the bat priv with all the soft interface information 25007c1fd91dSAntonio Quartulli * @addr: the MAC address of the local client to query 25017c1fd91dSAntonio Quartulli * 25027c1fd91dSAntonio Quartulli * Returns true if the local client is known to be roaming (it is not served by 25037c1fd91dSAntonio Quartulli * this node anymore) or not. If yes, the client is still present in the table 25047c1fd91dSAntonio Quartulli * to keep the latter consistent with the node TTVN 25057c1fd91dSAntonio Quartulli */ 25067c1fd91dSAntonio Quartulli bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, 25077c1fd91dSAntonio Quartulli uint8_t *addr) 25087c1fd91dSAntonio Quartulli { 25097c1fd91dSAntonio Quartulli struct batadv_tt_local_entry *tt_local_entry; 25107c1fd91dSAntonio Quartulli bool ret = false; 25117c1fd91dSAntonio Quartulli 25127c1fd91dSAntonio Quartulli tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 25137c1fd91dSAntonio Quartulli if (!tt_local_entry) 25147c1fd91dSAntonio Quartulli goto out; 25157c1fd91dSAntonio Quartulli 25167c1fd91dSAntonio Quartulli ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; 25177c1fd91dSAntonio Quartulli batadv_tt_local_entry_free_ref(tt_local_entry); 25187c1fd91dSAntonio Quartulli out: 25197c1fd91dSAntonio Quartulli return ret; 25207c1fd91dSAntonio Quartulli } 25217c1fd91dSAntonio Quartulli 252230cfd02bSAntonio Quartulli bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, 252330cfd02bSAntonio Quartulli struct batadv_orig_node *orig_node, 252430cfd02bSAntonio Quartulli const unsigned char *addr) 252530cfd02bSAntonio Quartulli { 252630cfd02bSAntonio Quartulli bool ret = false; 252730cfd02bSAntonio Quartulli 25281f36aebcSAntonio Quartulli /* if the originator is a backbone node (meaning it belongs to the same 25291f36aebcSAntonio Quartulli * LAN of this node) the temporary client must not be added because to 25301f36aebcSAntonio Quartulli * reach such destination the node must use the LAN instead of the mesh 25311f36aebcSAntonio Quartulli */ 25321f36aebcSAntonio Quartulli if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) 25331f36aebcSAntonio Quartulli goto out; 25341f36aebcSAntonio Quartulli 253530cfd02bSAntonio Quartulli if (!batadv_tt_global_add(bat_priv, orig_node, addr, 253630cfd02bSAntonio Quartulli BATADV_TT_CLIENT_TEMP, 253730cfd02bSAntonio Quartulli atomic_read(&orig_node->last_ttvn))) 253830cfd02bSAntonio Quartulli goto out; 253930cfd02bSAntonio Quartulli 254030cfd02bSAntonio Quartulli batadv_dbg(BATADV_DBG_TT, bat_priv, 254130cfd02bSAntonio Quartulli "Added temporary global client (addr: %pM orig: %pM)\n", 254230cfd02bSAntonio Quartulli addr, orig_node->orig); 254330cfd02bSAntonio Quartulli ret = true; 254430cfd02bSAntonio Quartulli out: 254530cfd02bSAntonio Quartulli return ret; 254630cfd02bSAntonio Quartulli } 2547e1bf0c14SMarek Lindner 2548e1bf0c14SMarek Lindner /** 2549e1bf0c14SMarek Lindner * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container 2550e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2551e1bf0c14SMarek Lindner * @orig: the orig_node of the ogm 2552e1bf0c14SMarek Lindner * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 2553e1bf0c14SMarek Lindner * @tvlv_value: tvlv buffer containing the gateway data 2554e1bf0c14SMarek Lindner * @tvlv_value_len: tvlv buffer length 2555e1bf0c14SMarek Lindner */ 2556e1bf0c14SMarek Lindner static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 2557e1bf0c14SMarek Lindner struct batadv_orig_node *orig, 2558e1bf0c14SMarek Lindner uint8_t flags, 2559e1bf0c14SMarek Lindner void *tvlv_value, 2560e1bf0c14SMarek Lindner uint16_t tvlv_value_len) 2561e1bf0c14SMarek Lindner { 2562e1bf0c14SMarek Lindner struct batadv_tvlv_tt_data *tt_data; 2563e1bf0c14SMarek Lindner uint16_t num_entries; 2564e1bf0c14SMarek Lindner 2565e1bf0c14SMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 2566e1bf0c14SMarek Lindner return; 2567e1bf0c14SMarek Lindner 2568e1bf0c14SMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 2569e1bf0c14SMarek Lindner tvlv_value_len -= sizeof(*tt_data); 2570e1bf0c14SMarek Lindner 2571e1bf0c14SMarek Lindner num_entries = tvlv_value_len / batadv_tt_len(1); 2572e1bf0c14SMarek Lindner 2573e1bf0c14SMarek Lindner batadv_tt_update_orig(bat_priv, orig, 2574e1bf0c14SMarek Lindner (unsigned char *)(tt_data + 1), 2575e1bf0c14SMarek Lindner num_entries, tt_data->ttvn, ntohs(tt_data->crc)); 2576e1bf0c14SMarek Lindner } 2577e1bf0c14SMarek Lindner 2578e1bf0c14SMarek Lindner /** 2579335fbe0fSMarek Lindner * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv 2580335fbe0fSMarek Lindner * container 2581335fbe0fSMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2582335fbe0fSMarek Lindner * @src: mac address of tt tvlv sender 2583335fbe0fSMarek Lindner * @dst: mac address of tt tvlv recipient 2584335fbe0fSMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 2585335fbe0fSMarek Lindner * @tvlv_value_len: tvlv buffer length 2586335fbe0fSMarek Lindner * 2587335fbe0fSMarek Lindner * Returns NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS 2588335fbe0fSMarek Lindner * otherwise. 2589335fbe0fSMarek Lindner */ 2590335fbe0fSMarek Lindner static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 2591335fbe0fSMarek Lindner uint8_t *src, uint8_t *dst, 2592335fbe0fSMarek Lindner void *tvlv_value, 2593335fbe0fSMarek Lindner uint16_t tvlv_value_len) 2594335fbe0fSMarek Lindner { 2595335fbe0fSMarek Lindner struct batadv_tvlv_tt_data *tt_data; 2596335fbe0fSMarek Lindner uint16_t num_entries; 2597335fbe0fSMarek Lindner char tt_flag; 2598335fbe0fSMarek Lindner bool ret; 2599335fbe0fSMarek Lindner 2600335fbe0fSMarek Lindner if (tvlv_value_len < sizeof(*tt_data)) 2601335fbe0fSMarek Lindner return NET_RX_SUCCESS; 2602335fbe0fSMarek Lindner 2603335fbe0fSMarek Lindner tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; 2604335fbe0fSMarek Lindner tvlv_value_len -= sizeof(*tt_data); 2605335fbe0fSMarek Lindner 2606335fbe0fSMarek Lindner num_entries = tvlv_value_len / batadv_tt_len(1); 2607335fbe0fSMarek Lindner 2608335fbe0fSMarek Lindner switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { 2609335fbe0fSMarek Lindner case BATADV_TT_REQUEST: 2610335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); 2611335fbe0fSMarek Lindner 2612335fbe0fSMarek Lindner /* If this node cannot provide a TT response the tt_request is 2613335fbe0fSMarek Lindner * forwarded 2614335fbe0fSMarek Lindner */ 2615335fbe0fSMarek Lindner ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); 2616335fbe0fSMarek Lindner if (!ret) { 2617335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 2618335fbe0fSMarek Lindner tt_flag = 'F'; 2619335fbe0fSMarek Lindner else 2620335fbe0fSMarek Lindner tt_flag = '.'; 2621335fbe0fSMarek Lindner 2622335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 2623335fbe0fSMarek Lindner "Routing TT_REQUEST to %pM [%c]\n", 2624335fbe0fSMarek Lindner dst, tt_flag); 2625335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 2626335fbe0fSMarek Lindner return NET_RX_DROP; 2627335fbe0fSMarek Lindner } 2628335fbe0fSMarek Lindner break; 2629335fbe0fSMarek Lindner case BATADV_TT_RESPONSE: 2630335fbe0fSMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); 2631335fbe0fSMarek Lindner 2632335fbe0fSMarek Lindner if (batadv_is_my_mac(bat_priv, dst)) { 2633335fbe0fSMarek Lindner batadv_handle_tt_response(bat_priv, tt_data, 2634335fbe0fSMarek Lindner src, num_entries); 2635335fbe0fSMarek Lindner return NET_RX_SUCCESS; 2636335fbe0fSMarek Lindner } 2637335fbe0fSMarek Lindner 2638335fbe0fSMarek Lindner if (tt_data->flags & BATADV_TT_FULL_TABLE) 2639335fbe0fSMarek Lindner tt_flag = 'F'; 2640335fbe0fSMarek Lindner else 2641335fbe0fSMarek Lindner tt_flag = '.'; 2642335fbe0fSMarek Lindner 2643335fbe0fSMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 2644335fbe0fSMarek Lindner "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag); 2645335fbe0fSMarek Lindner 2646335fbe0fSMarek Lindner /* tvlv API will re-route the packet */ 2647335fbe0fSMarek Lindner return NET_RX_DROP; 2648335fbe0fSMarek Lindner } 2649335fbe0fSMarek Lindner 2650335fbe0fSMarek Lindner return NET_RX_SUCCESS; 2651335fbe0fSMarek Lindner } 2652335fbe0fSMarek Lindner 2653335fbe0fSMarek Lindner /** 2654122edaa0SMarek Lindner * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container 2655122edaa0SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2656122edaa0SMarek Lindner * @src: mac address of tt tvlv sender 2657122edaa0SMarek Lindner * @dst: mac address of tt tvlv recipient 2658122edaa0SMarek Lindner * @tvlv_value: tvlv buffer containing the tt data 2659122edaa0SMarek Lindner * @tvlv_value_len: tvlv buffer length 2660122edaa0SMarek Lindner * 2661122edaa0SMarek Lindner * Returns NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS 2662122edaa0SMarek Lindner * otherwise. 2663122edaa0SMarek Lindner */ 2664122edaa0SMarek Lindner static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, 2665122edaa0SMarek Lindner uint8_t *src, uint8_t *dst, 2666122edaa0SMarek Lindner void *tvlv_value, 2667122edaa0SMarek Lindner uint16_t tvlv_value_len) 2668122edaa0SMarek Lindner { 2669122edaa0SMarek Lindner struct batadv_tvlv_roam_adv *roaming_adv; 2670122edaa0SMarek Lindner struct batadv_orig_node *orig_node = NULL; 2671122edaa0SMarek Lindner 2672122edaa0SMarek Lindner /* If this node is not the intended recipient of the 2673122edaa0SMarek Lindner * roaming advertisement the packet is forwarded 2674122edaa0SMarek Lindner * (the tvlv API will re-route the packet). 2675122edaa0SMarek Lindner */ 2676122edaa0SMarek Lindner if (!batadv_is_my_mac(bat_priv, dst)) 2677122edaa0SMarek Lindner return NET_RX_DROP; 2678122edaa0SMarek Lindner 2679122edaa0SMarek Lindner /* check if it is a backbone gateway. we don't accept 2680122edaa0SMarek Lindner * roaming advertisement from it, as it has the same 2681122edaa0SMarek Lindner * entries as we have. 2682122edaa0SMarek Lindner */ 2683122edaa0SMarek Lindner if (batadv_bla_is_backbone_gw_orig(bat_priv, src)) 2684122edaa0SMarek Lindner goto out; 2685122edaa0SMarek Lindner 2686122edaa0SMarek Lindner if (tvlv_value_len < sizeof(*roaming_adv)) 2687122edaa0SMarek Lindner goto out; 2688122edaa0SMarek Lindner 2689122edaa0SMarek Lindner orig_node = batadv_orig_hash_find(bat_priv, src); 2690122edaa0SMarek Lindner if (!orig_node) 2691122edaa0SMarek Lindner goto out; 2692122edaa0SMarek Lindner 2693122edaa0SMarek Lindner batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); 2694122edaa0SMarek Lindner roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; 2695122edaa0SMarek Lindner 2696122edaa0SMarek Lindner batadv_dbg(BATADV_DBG_TT, bat_priv, 2697122edaa0SMarek Lindner "Received ROAMING_ADV from %pM (client %pM)\n", 2698122edaa0SMarek Lindner src, roaming_adv->client); 2699122edaa0SMarek Lindner 2700122edaa0SMarek Lindner batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, 2701122edaa0SMarek Lindner BATADV_TT_CLIENT_ROAM, 2702122edaa0SMarek Lindner atomic_read(&orig_node->last_ttvn) + 1); 2703122edaa0SMarek Lindner 2704122edaa0SMarek Lindner out: 2705122edaa0SMarek Lindner if (orig_node) 2706122edaa0SMarek Lindner batadv_orig_node_free_ref(orig_node); 2707122edaa0SMarek Lindner return NET_RX_SUCCESS; 2708122edaa0SMarek Lindner } 2709122edaa0SMarek Lindner 2710122edaa0SMarek Lindner /** 2711e1bf0c14SMarek Lindner * batadv_tt_init - initialise the translation table internals 2712e1bf0c14SMarek Lindner * @bat_priv: the bat priv with all the soft interface information 2713e1bf0c14SMarek Lindner * 2714e1bf0c14SMarek Lindner * Return 0 on success or negative error number in case of failure. 2715e1bf0c14SMarek Lindner */ 2716e1bf0c14SMarek Lindner int batadv_tt_init(struct batadv_priv *bat_priv) 2717e1bf0c14SMarek Lindner { 2718e1bf0c14SMarek Lindner int ret; 2719e1bf0c14SMarek Lindner 2720e1bf0c14SMarek Lindner ret = batadv_tt_local_init(bat_priv); 2721e1bf0c14SMarek Lindner if (ret < 0) 2722e1bf0c14SMarek Lindner return ret; 2723e1bf0c14SMarek Lindner 2724e1bf0c14SMarek Lindner ret = batadv_tt_global_init(bat_priv); 2725e1bf0c14SMarek Lindner if (ret < 0) 2726e1bf0c14SMarek Lindner return ret; 2727e1bf0c14SMarek Lindner 2728e1bf0c14SMarek Lindner batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, 2729335fbe0fSMarek Lindner batadv_tt_tvlv_unicast_handler_v1, 2730335fbe0fSMarek Lindner BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); 2731e1bf0c14SMarek Lindner 2732122edaa0SMarek Lindner batadv_tvlv_handler_register(bat_priv, NULL, 2733122edaa0SMarek Lindner batadv_roam_tvlv_unicast_handler_v1, 2734122edaa0SMarek Lindner BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); 2735122edaa0SMarek Lindner 2736e1bf0c14SMarek Lindner INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); 2737e1bf0c14SMarek Lindner queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, 2738e1bf0c14SMarek Lindner msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); 2739e1bf0c14SMarek Lindner 2740e1bf0c14SMarek Lindner return 1; 2741e1bf0c14SMarek Lindner } 2742