1c6c8fea2SSven Eckelmann /* 264afe353SSven Eckelmann * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: 3c6c8fea2SSven Eckelmann * 4c6c8fea2SSven Eckelmann * Marek Lindner, Simon Wunderlich 5c6c8fea2SSven Eckelmann * 6c6c8fea2SSven Eckelmann * This program is free software; you can redistribute it and/or 7c6c8fea2SSven Eckelmann * modify it under the terms of version 2 of the GNU General Public 8c6c8fea2SSven Eckelmann * License as published by the Free Software Foundation. 9c6c8fea2SSven Eckelmann * 10c6c8fea2SSven Eckelmann * This program is distributed in the hope that it will be useful, but 11c6c8fea2SSven Eckelmann * WITHOUT ANY WARRANTY; without even the implied warranty of 12c6c8fea2SSven Eckelmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13c6c8fea2SSven Eckelmann * General Public License for more details. 14c6c8fea2SSven Eckelmann * 15c6c8fea2SSven Eckelmann * You should have received a copy of the GNU General Public License 16c6c8fea2SSven Eckelmann * along with this program; if not, write to the Free Software 17c6c8fea2SSven Eckelmann * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18c6c8fea2SSven Eckelmann * 02110-1301, USA 19c6c8fea2SSven Eckelmann * 20c6c8fea2SSven Eckelmann */ 21c6c8fea2SSven Eckelmann 22c6c8fea2SSven Eckelmann #include "main.h" 23c6c8fea2SSven Eckelmann #include "translation-table.h" 24c6c8fea2SSven Eckelmann #include "soft-interface.h" 2532ae9b22SMarek Lindner #include "hard-interface.h" 26a73105b8SAntonio Quartulli #include "send.h" 27c6c8fea2SSven Eckelmann #include "hash.h" 28c6c8fea2SSven Eckelmann #include "originator.h" 29a73105b8SAntonio Quartulli #include "routing.h" 30c6c8fea2SSven Eckelmann 31a73105b8SAntonio Quartulli #include <linux/crc16.h> 32a73105b8SAntonio Quartulli 33a73105b8SAntonio Quartulli static void _tt_global_del(struct bat_priv *bat_priv, 342dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry, 35747e4221SSven Eckelmann const char *message); 36a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work); 37c6c8fea2SSven Eckelmann 387aadf889SMarek Lindner /* returns 1 if they are the same mac addr */ 3948100bacSAntonio Quartulli static int compare_tt(const struct hlist_node *node, const void *data2) 407aadf889SMarek Lindner { 4148100bacSAntonio Quartulli const void *data1 = container_of(node, struct tt_common_entry, 42747e4221SSven Eckelmann hash_entry); 437aadf889SMarek Lindner 447aadf889SMarek Lindner return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); 457aadf889SMarek Lindner } 467aadf889SMarek Lindner 47a73105b8SAntonio Quartulli static void tt_start_timer(struct bat_priv *bat_priv) 48c6c8fea2SSven Eckelmann { 49a73105b8SAntonio Quartulli INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge); 50a73105b8SAntonio Quartulli queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 51a73105b8SAntonio Quartulli msecs_to_jiffies(5000)); 52c6c8fea2SSven Eckelmann } 53c6c8fea2SSven Eckelmann 5448100bacSAntonio Quartulli static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash, 55747e4221SSven Eckelmann const void *data) 567aadf889SMarek Lindner { 577aadf889SMarek Lindner struct hlist_head *head; 587aadf889SMarek Lindner struct hlist_node *node; 5948100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL; 60c90681b8SAntonio Quartulli uint32_t index; 617aadf889SMarek Lindner 627aadf889SMarek Lindner if (!hash) 637aadf889SMarek Lindner return NULL; 647aadf889SMarek Lindner 657aadf889SMarek Lindner index = choose_orig(data, hash->size); 667aadf889SMarek Lindner head = &hash->table[index]; 677aadf889SMarek Lindner 687aadf889SMarek Lindner rcu_read_lock(); 6948100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) { 7048100bacSAntonio Quartulli if (!compare_eth(tt_common_entry, data)) 717aadf889SMarek Lindner continue; 727aadf889SMarek Lindner 7348100bacSAntonio Quartulli if (!atomic_inc_not_zero(&tt_common_entry->refcount)) 747683fdc1SAntonio Quartulli continue; 757683fdc1SAntonio Quartulli 7648100bacSAntonio Quartulli tt_common_entry_tmp = tt_common_entry; 777aadf889SMarek Lindner break; 787aadf889SMarek Lindner } 797aadf889SMarek Lindner rcu_read_unlock(); 807aadf889SMarek Lindner 8148100bacSAntonio Quartulli return tt_common_entry_tmp; 8248100bacSAntonio Quartulli } 8348100bacSAntonio Quartulli 8448100bacSAntonio Quartulli static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv, 8548100bacSAntonio Quartulli const void *data) 8648100bacSAntonio Quartulli { 8748100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 8848100bacSAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 8948100bacSAntonio Quartulli 9048100bacSAntonio Quartulli tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data); 9148100bacSAntonio Quartulli if (tt_common_entry) 9248100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 9348100bacSAntonio Quartulli struct tt_local_entry, common); 9448100bacSAntonio Quartulli return tt_local_entry; 957aadf889SMarek Lindner } 967aadf889SMarek Lindner 972dafb49dSAntonio Quartulli static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv, 98747e4221SSven Eckelmann const void *data) 997aadf889SMarek Lindner { 10048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 10148100bacSAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 1027aadf889SMarek Lindner 10348100bacSAntonio Quartulli tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data); 10448100bacSAntonio Quartulli if (tt_common_entry) 10548100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 10648100bacSAntonio Quartulli struct tt_global_entry, common); 10748100bacSAntonio Quartulli return tt_global_entry; 1087aadf889SMarek Lindner 1097aadf889SMarek Lindner } 1107aadf889SMarek Lindner 111a73105b8SAntonio Quartulli static bool is_out_of_time(unsigned long starting_time, unsigned long timeout) 112a73105b8SAntonio Quartulli { 113a73105b8SAntonio Quartulli unsigned long deadline; 114a73105b8SAntonio Quartulli deadline = starting_time + msecs_to_jiffies(timeout); 115a73105b8SAntonio Quartulli 116a73105b8SAntonio Quartulli return time_after(jiffies, deadline); 117a73105b8SAntonio Quartulli } 118a73105b8SAntonio Quartulli 1197683fdc1SAntonio Quartulli static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry) 1207683fdc1SAntonio Quartulli { 12148100bacSAntonio Quartulli if (atomic_dec_and_test(&tt_local_entry->common.refcount)) 12248100bacSAntonio Quartulli kfree_rcu(tt_local_entry, common.rcu); 1237683fdc1SAntonio Quartulli } 1247683fdc1SAntonio Quartulli 125531027fcSSimon Wunderlich static void tt_global_entry_free_rcu(struct rcu_head *rcu) 126531027fcSSimon Wunderlich { 12748100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 128531027fcSSimon Wunderlich struct tt_global_entry *tt_global_entry; 129531027fcSSimon Wunderlich 13048100bacSAntonio Quartulli tt_common_entry = container_of(rcu, struct tt_common_entry, rcu); 13148100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, 13248100bacSAntonio Quartulli common); 133531027fcSSimon Wunderlich 134531027fcSSimon Wunderlich if (tt_global_entry->orig_node) 135531027fcSSimon Wunderlich orig_node_free_ref(tt_global_entry->orig_node); 136531027fcSSimon Wunderlich 137531027fcSSimon Wunderlich kfree(tt_global_entry); 138531027fcSSimon Wunderlich } 139531027fcSSimon Wunderlich 1407683fdc1SAntonio Quartulli static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry) 1417683fdc1SAntonio Quartulli { 14248100bacSAntonio Quartulli if (atomic_dec_and_test(&tt_global_entry->common.refcount)) 14348100bacSAntonio Quartulli call_rcu(&tt_global_entry->common.rcu, 14448100bacSAntonio Quartulli tt_global_entry_free_rcu); 1457683fdc1SAntonio Quartulli } 1467683fdc1SAntonio Quartulli 147ff66c975SAntonio Quartulli static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr, 148ff66c975SAntonio Quartulli uint8_t flags) 149a73105b8SAntonio Quartulli { 150a73105b8SAntonio Quartulli struct tt_change_node *tt_change_node; 151a73105b8SAntonio Quartulli 152a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 153a73105b8SAntonio Quartulli 154a73105b8SAntonio Quartulli if (!tt_change_node) 155a73105b8SAntonio Quartulli return; 156a73105b8SAntonio Quartulli 157ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 158a73105b8SAntonio Quartulli memcpy(tt_change_node->change.addr, addr, ETH_ALEN); 159a73105b8SAntonio Quartulli 160a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 161a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 162a73105b8SAntonio Quartulli list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list); 163a73105b8SAntonio Quartulli atomic_inc(&bat_priv->tt_local_changes); 164a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 165a73105b8SAntonio Quartulli 166a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_ogm_append_cnt, 0); 167a73105b8SAntonio Quartulli } 168a73105b8SAntonio Quartulli 169a73105b8SAntonio Quartulli int tt_len(int changes_num) 170a73105b8SAntonio Quartulli { 171a73105b8SAntonio Quartulli return changes_num * sizeof(struct tt_change); 172a73105b8SAntonio Quartulli } 173a73105b8SAntonio Quartulli 174a73105b8SAntonio Quartulli static int tt_local_init(struct bat_priv *bat_priv) 175c6c8fea2SSven Eckelmann { 1762dafb49dSAntonio Quartulli if (bat_priv->tt_local_hash) 177c6c8fea2SSven Eckelmann return 1; 178c6c8fea2SSven Eckelmann 1792dafb49dSAntonio Quartulli bat_priv->tt_local_hash = hash_new(1024); 180c6c8fea2SSven Eckelmann 1812dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 182c6c8fea2SSven Eckelmann return 0; 183c6c8fea2SSven Eckelmann 184c6c8fea2SSven Eckelmann return 1; 185c6c8fea2SSven Eckelmann } 186c6c8fea2SSven Eckelmann 187bc279080SAntonio Quartulli void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 188bc279080SAntonio Quartulli int ifindex) 189c6c8fea2SSven Eckelmann { 190c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(soft_iface); 1917683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 1927683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 19380b3f58cSSimon Wunderlich int hash_added; 194c6c8fea2SSven Eckelmann 1952dafb49dSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 196c6c8fea2SSven Eckelmann 1972dafb49dSAntonio Quartulli if (tt_local_entry) { 1982dafb49dSAntonio Quartulli tt_local_entry->last_seen = jiffies; 1997683fdc1SAntonio Quartulli goto out; 200c6c8fea2SSven Eckelmann } 201c6c8fea2SSven Eckelmann 202704509b8SSven Eckelmann tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC); 2032dafb49dSAntonio Quartulli if (!tt_local_entry) 2047683fdc1SAntonio Quartulli goto out; 205a73105b8SAntonio Quartulli 206a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 207a73105b8SAntonio Quartulli "Creating new local tt entry: %pM (ttvn: %d)\n", addr, 208a73105b8SAntonio Quartulli (uint8_t)atomic_read(&bat_priv->ttvn)); 209c6c8fea2SSven Eckelmann 21048100bacSAntonio Quartulli memcpy(tt_local_entry->common.addr, addr, ETH_ALEN); 21148100bacSAntonio Quartulli tt_local_entry->common.flags = NO_FLAGS; 212bc279080SAntonio Quartulli if (is_wifi_iface(ifindex)) 21348100bacSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_WIFI; 21448100bacSAntonio Quartulli atomic_set(&tt_local_entry->common.refcount, 2); 21548100bacSAntonio Quartulli tt_local_entry->last_seen = jiffies; 216c6c8fea2SSven Eckelmann 217c6c8fea2SSven Eckelmann /* the batman interface mac address should never be purged */ 21839901e71SMarek Lindner if (compare_eth(addr, soft_iface->dev_addr)) 21948100bacSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_NOPURGE; 220c6c8fea2SSven Eckelmann 22180b3f58cSSimon Wunderlich hash_added = hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig, 22280b3f58cSSimon Wunderlich &tt_local_entry->common, 22380b3f58cSSimon Wunderlich &tt_local_entry->common.hash_entry); 22480b3f58cSSimon Wunderlich 22580b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 22680b3f58cSSimon Wunderlich /* remove the reference for the hash */ 22780b3f58cSSimon Wunderlich tt_local_entry_free_ref(tt_local_entry); 22880b3f58cSSimon Wunderlich goto out; 22980b3f58cSSimon Wunderlich } 23080b3f58cSSimon Wunderlich 23148100bacSAntonio Quartulli tt_local_event(bat_priv, addr, tt_local_entry->common.flags); 232ff66c975SAntonio Quartulli 233058d0e26SAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 234058d0e26SAntonio Quartulli * a full table response going out before the next ttvn increment 235058d0e26SAntonio Quartulli * (consistency check) */ 23648100bacSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_NEW; 237058d0e26SAntonio Quartulli 238c6c8fea2SSven Eckelmann /* remove address from global hash if present */ 2392dafb49dSAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 240c6c8fea2SSven Eckelmann 241cc47f66eSAntonio Quartulli /* Check whether it is a roaming! */ 242cc47f66eSAntonio Quartulli if (tt_global_entry) { 243cc47f66eSAntonio Quartulli /* This node is probably going to update its tt table */ 244cc47f66eSAntonio Quartulli tt_global_entry->orig_node->tt_poss_change = true; 24503fc3070SAntonio Quartulli /* The global entry has to be marked as ROAMING and has to be 246980d55b2SAntonio Quartulli * kept for consistency purpose */ 24748100bacSAntonio Quartulli tt_global_entry->common.flags |= TT_CLIENT_PENDING; 24803fc3070SAntonio Quartulli tt_global_entry->roam_at = jiffies; 24948100bacSAntonio Quartulli send_roam_adv(bat_priv, tt_global_entry->common.addr, 250cc47f66eSAntonio Quartulli tt_global_entry->orig_node); 2517683fdc1SAntonio Quartulli } 2527683fdc1SAntonio Quartulli out: 2537683fdc1SAntonio Quartulli if (tt_local_entry) 2547683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 2557683fdc1SAntonio Quartulli if (tt_global_entry) 2567683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 257c6c8fea2SSven Eckelmann } 258c6c8fea2SSven Eckelmann 259a73105b8SAntonio Quartulli int tt_changes_fill_buffer(struct bat_priv *bat_priv, 260c6c8fea2SSven Eckelmann unsigned char *buff, int buff_len) 261c6c8fea2SSven Eckelmann { 262a73105b8SAntonio Quartulli int count = 0, tot_changes = 0; 263a73105b8SAntonio Quartulli struct tt_change_node *entry, *safe; 264c6c8fea2SSven Eckelmann 265a73105b8SAntonio Quartulli if (buff_len > 0) 266a73105b8SAntonio Quartulli tot_changes = buff_len / tt_len(1); 267c6c8fea2SSven Eckelmann 268a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 269a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 270c6c8fea2SSven Eckelmann 271a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 272a73105b8SAntonio Quartulli list) { 273a73105b8SAntonio Quartulli if (count < tot_changes) { 274a73105b8SAntonio Quartulli memcpy(buff + tt_len(count), 275a73105b8SAntonio Quartulli &entry->change, sizeof(struct tt_change)); 276c6c8fea2SSven Eckelmann count++; 277c6c8fea2SSven Eckelmann } 278a73105b8SAntonio Quartulli list_del(&entry->list); 279a73105b8SAntonio Quartulli kfree(entry); 280c6c8fea2SSven Eckelmann } 281a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 282c6c8fea2SSven Eckelmann 283a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 284a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 285a73105b8SAntonio Quartulli kfree(bat_priv->tt_buff); 286a73105b8SAntonio Quartulli bat_priv->tt_buff_len = 0; 287a73105b8SAntonio Quartulli bat_priv->tt_buff = NULL; 288a73105b8SAntonio Quartulli /* We check whether this new OGM has no changes due to size 289a73105b8SAntonio Quartulli * problems */ 290a73105b8SAntonio Quartulli if (buff_len > 0) { 291a73105b8SAntonio Quartulli /** 292a73105b8SAntonio Quartulli * if kmalloc() fails we will reply with the full table 293a73105b8SAntonio Quartulli * instead of providing the diff 294a73105b8SAntonio Quartulli */ 295a73105b8SAntonio Quartulli bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC); 296a73105b8SAntonio Quartulli if (bat_priv->tt_buff) { 297a73105b8SAntonio Quartulli memcpy(bat_priv->tt_buff, buff, buff_len); 298a73105b8SAntonio Quartulli bat_priv->tt_buff_len = buff_len; 299a73105b8SAntonio Quartulli } 300a73105b8SAntonio Quartulli } 301a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 302c6c8fea2SSven Eckelmann 303a73105b8SAntonio Quartulli return tot_changes; 304c6c8fea2SSven Eckelmann } 305c6c8fea2SSven Eckelmann 3062dafb49dSAntonio Quartulli int tt_local_seq_print_text(struct seq_file *seq, void *offset) 307c6c8fea2SSven Eckelmann { 308c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 309c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 3102dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 31148100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 31232ae9b22SMarek Lindner struct hard_iface *primary_if; 3137aadf889SMarek Lindner struct hlist_node *node; 314c6c8fea2SSven Eckelmann struct hlist_head *head; 315c90681b8SAntonio Quartulli uint32_t i; 316c90681b8SAntonio Quartulli int ret = 0; 317c6c8fea2SSven Eckelmann 31832ae9b22SMarek Lindner primary_if = primary_if_get_selected(bat_priv); 31932ae9b22SMarek Lindner if (!primary_if) { 32032ae9b22SMarek Lindner ret = seq_printf(seq, "BATMAN mesh %s disabled - " 321c6c8fea2SSven Eckelmann "please specify interfaces to enable it\n", 322c6c8fea2SSven Eckelmann net_dev->name); 32332ae9b22SMarek Lindner goto out; 32432ae9b22SMarek Lindner } 32532ae9b22SMarek Lindner 32632ae9b22SMarek Lindner if (primary_if->if_status != IF_ACTIVE) { 32732ae9b22SMarek Lindner ret = seq_printf(seq, "BATMAN mesh %s disabled - " 32832ae9b22SMarek Lindner "primary interface not active\n", 32932ae9b22SMarek Lindner net_dev->name); 33032ae9b22SMarek Lindner goto out; 331c6c8fea2SSven Eckelmann } 332c6c8fea2SSven Eckelmann 333c6c8fea2SSven Eckelmann seq_printf(seq, "Locally retrieved addresses (from %s) " 334a73105b8SAntonio Quartulli "announced via TT (TTVN: %u):\n", 335a73105b8SAntonio Quartulli net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn)); 336c6c8fea2SSven Eckelmann 337c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 338c6c8fea2SSven Eckelmann head = &hash->table[i]; 339c6c8fea2SSven Eckelmann 3407aadf889SMarek Lindner rcu_read_lock(); 34148100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 3427aadf889SMarek Lindner head, hash_entry) { 343d099c2c5SSimon Wunderlich seq_printf(seq, " * %pM [%c%c%c%c%c]\n", 34448100bacSAntonio Quartulli tt_common_entry->addr, 34548100bacSAntonio Quartulli (tt_common_entry->flags & 346df6edb9eSAntonio Quartulli TT_CLIENT_ROAM ? 'R' : '.'), 34748100bacSAntonio Quartulli (tt_common_entry->flags & 348df6edb9eSAntonio Quartulli TT_CLIENT_NOPURGE ? 'P' : '.'), 34948100bacSAntonio Quartulli (tt_common_entry->flags & 350df6edb9eSAntonio Quartulli TT_CLIENT_NEW ? 'N' : '.'), 35148100bacSAntonio Quartulli (tt_common_entry->flags & 352df6edb9eSAntonio Quartulli TT_CLIENT_PENDING ? 'X' : '.'), 35348100bacSAntonio Quartulli (tt_common_entry->flags & 354df6edb9eSAntonio Quartulli TT_CLIENT_WIFI ? 'W' : '.')); 355c6c8fea2SSven Eckelmann } 3567aadf889SMarek Lindner rcu_read_unlock(); 357c6c8fea2SSven Eckelmann } 35832ae9b22SMarek Lindner out: 35932ae9b22SMarek Lindner if (primary_if) 36032ae9b22SMarek Lindner hardif_free_ref(primary_if); 36132ae9b22SMarek Lindner return ret; 362c6c8fea2SSven Eckelmann } 363c6c8fea2SSven Eckelmann 364058d0e26SAntonio Quartulli static void tt_local_set_pending(struct bat_priv *bat_priv, 3652dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry, 366058d0e26SAntonio Quartulli uint16_t flags) 367c6c8fea2SSven Eckelmann { 36848100bacSAntonio Quartulli tt_local_event(bat_priv, tt_local_entry->common.addr, 36948100bacSAntonio Quartulli tt_local_entry->common.flags | flags); 370c6c8fea2SSven Eckelmann 371015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 372015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 373058d0e26SAntonio Quartulli * response issued before the net ttvn increment (consistency check) */ 37448100bacSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_PENDING; 375c6c8fea2SSven Eckelmann } 376c6c8fea2SSven Eckelmann 377a73105b8SAntonio Quartulli void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, 378cc47f66eSAntonio Quartulli const char *message, bool roaming) 379c6c8fea2SSven Eckelmann { 3807683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 381c6c8fea2SSven Eckelmann 3822dafb49dSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 3837683fdc1SAntonio Quartulli if (!tt_local_entry) 3847683fdc1SAntonio Quartulli goto out; 3857683fdc1SAntonio Quartulli 386058d0e26SAntonio Quartulli tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | 387ff66c975SAntonio Quartulli (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); 388058d0e26SAntonio Quartulli 389058d0e26SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " 39048100bacSAntonio Quartulli "%s\n", tt_local_entry->common.addr, message); 3917683fdc1SAntonio Quartulli out: 3927683fdc1SAntonio Quartulli if (tt_local_entry) 3937683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 394c6c8fea2SSven Eckelmann } 395c6c8fea2SSven Eckelmann 396a73105b8SAntonio Quartulli static void tt_local_purge(struct bat_priv *bat_priv) 397c6c8fea2SSven Eckelmann { 3982dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 3992dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry; 40048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 4017aadf889SMarek Lindner struct hlist_node *node, *node_tmp; 402c6c8fea2SSven Eckelmann struct hlist_head *head; 4037683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 404c90681b8SAntonio Quartulli uint32_t i; 405c6c8fea2SSven Eckelmann 406c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 407c6c8fea2SSven Eckelmann head = &hash->table[i]; 4087683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 409c6c8fea2SSven Eckelmann 4107683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 41148100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 4127aadf889SMarek Lindner head, hash_entry) { 41348100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 41448100bacSAntonio Quartulli struct tt_local_entry, 41548100bacSAntonio Quartulli common); 41648100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE) 4177aadf889SMarek Lindner continue; 418c6c8fea2SSven Eckelmann 419058d0e26SAntonio Quartulli /* entry already marked for deletion */ 42048100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_PENDING) 421058d0e26SAntonio Quartulli continue; 422058d0e26SAntonio Quartulli 423a73105b8SAntonio Quartulli if (!is_out_of_time(tt_local_entry->last_seen, 424a73105b8SAntonio Quartulli TT_LOCAL_TIMEOUT * 1000)) 4257aadf889SMarek Lindner continue; 4267aadf889SMarek Lindner 427058d0e26SAntonio Quartulli tt_local_set_pending(bat_priv, tt_local_entry, 428058d0e26SAntonio Quartulli TT_CLIENT_DEL); 429058d0e26SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) " 430058d0e26SAntonio Quartulli "pending to be removed: timed out\n", 43148100bacSAntonio Quartulli tt_local_entry->common.addr); 432c6c8fea2SSven Eckelmann } 4337683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 434c6c8fea2SSven Eckelmann } 435c6c8fea2SSven Eckelmann 436c6c8fea2SSven Eckelmann } 437c6c8fea2SSven Eckelmann 438a73105b8SAntonio Quartulli static void tt_local_table_free(struct bat_priv *bat_priv) 439c6c8fea2SSven Eckelmann { 440a73105b8SAntonio Quartulli struct hashtable_t *hash; 441a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 44248100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 443a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 4447683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 4457683fdc1SAntonio Quartulli struct hlist_head *head; 446c90681b8SAntonio Quartulli uint32_t i; 447a73105b8SAntonio Quartulli 4482dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 449c6c8fea2SSven Eckelmann return; 450c6c8fea2SSven Eckelmann 451a73105b8SAntonio Quartulli hash = bat_priv->tt_local_hash; 452a73105b8SAntonio Quartulli 453a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 454a73105b8SAntonio Quartulli head = &hash->table[i]; 455a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 456a73105b8SAntonio Quartulli 457a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 45848100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 459a73105b8SAntonio Quartulli head, hash_entry) { 460a73105b8SAntonio Quartulli hlist_del_rcu(node); 46148100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 46248100bacSAntonio Quartulli struct tt_local_entry, 46348100bacSAntonio Quartulli common); 4647683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 465a73105b8SAntonio Quartulli } 466a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 467a73105b8SAntonio Quartulli } 468a73105b8SAntonio Quartulli 469a73105b8SAntonio Quartulli hash_destroy(hash); 470a73105b8SAntonio Quartulli 4712dafb49dSAntonio Quartulli bat_priv->tt_local_hash = NULL; 472c6c8fea2SSven Eckelmann } 473c6c8fea2SSven Eckelmann 474a73105b8SAntonio Quartulli static int tt_global_init(struct bat_priv *bat_priv) 475c6c8fea2SSven Eckelmann { 4762dafb49dSAntonio Quartulli if (bat_priv->tt_global_hash) 477c6c8fea2SSven Eckelmann return 1; 478c6c8fea2SSven Eckelmann 4792dafb49dSAntonio Quartulli bat_priv->tt_global_hash = hash_new(1024); 480c6c8fea2SSven Eckelmann 4812dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 482c6c8fea2SSven Eckelmann return 0; 483c6c8fea2SSven Eckelmann 484c6c8fea2SSven Eckelmann return 1; 485c6c8fea2SSven Eckelmann } 486c6c8fea2SSven Eckelmann 487a73105b8SAntonio Quartulli static void tt_changes_list_free(struct bat_priv *bat_priv) 488a73105b8SAntonio Quartulli { 489a73105b8SAntonio Quartulli struct tt_change_node *entry, *safe; 490a73105b8SAntonio Quartulli 491a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 492a73105b8SAntonio Quartulli 493a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 494a73105b8SAntonio Quartulli list) { 495a73105b8SAntonio Quartulli list_del(&entry->list); 496a73105b8SAntonio Quartulli kfree(entry); 497a73105b8SAntonio Quartulli } 498a73105b8SAntonio Quartulli 499a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 500a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 501a73105b8SAntonio Quartulli } 502a73105b8SAntonio Quartulli 503a73105b8SAntonio Quartulli /* caller must hold orig_node refcount */ 504a73105b8SAntonio Quartulli int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, 505bc279080SAntonio Quartulli const unsigned char *tt_addr, uint8_t ttvn, bool roaming, 506bc279080SAntonio Quartulli bool wifi) 507c6c8fea2SSven Eckelmann { 5082dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 509a73105b8SAntonio Quartulli struct orig_node *orig_node_tmp; 5107683fdc1SAntonio Quartulli int ret = 0; 51180b3f58cSSimon Wunderlich int hash_added; 512c6c8fea2SSven Eckelmann 513a73105b8SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, tt_addr); 514c6c8fea2SSven Eckelmann 5152dafb49dSAntonio Quartulli if (!tt_global_entry) { 516a73105b8SAntonio Quartulli tt_global_entry = 517a73105b8SAntonio Quartulli kmalloc(sizeof(*tt_global_entry), 518c6c8fea2SSven Eckelmann GFP_ATOMIC); 5192dafb49dSAntonio Quartulli if (!tt_global_entry) 5207683fdc1SAntonio Quartulli goto out; 5217683fdc1SAntonio Quartulli 52248100bacSAntonio Quartulli memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN); 52348100bacSAntonio Quartulli tt_global_entry->common.flags = NO_FLAGS; 52448100bacSAntonio Quartulli atomic_set(&tt_global_entry->common.refcount, 2); 525a73105b8SAntonio Quartulli /* Assign the new orig_node */ 526a73105b8SAntonio Quartulli atomic_inc(&orig_node->refcount); 527a73105b8SAntonio Quartulli tt_global_entry->orig_node = orig_node; 528a73105b8SAntonio Quartulli tt_global_entry->ttvn = ttvn; 529cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 5307683fdc1SAntonio Quartulli 53180b3f58cSSimon Wunderlich hash_added = hash_add(bat_priv->tt_global_hash, compare_tt, 53248100bacSAntonio Quartulli choose_orig, &tt_global_entry->common, 53348100bacSAntonio Quartulli &tt_global_entry->common.hash_entry); 53480b3f58cSSimon Wunderlich 53580b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 53680b3f58cSSimon Wunderlich /* remove the reference for the hash */ 53780b3f58cSSimon Wunderlich tt_global_entry_free_ref(tt_global_entry); 53880b3f58cSSimon Wunderlich goto out_remove; 53980b3f58cSSimon Wunderlich } 5407683fdc1SAntonio Quartulli atomic_inc(&orig_node->tt_size); 541a73105b8SAntonio Quartulli } else { 542a73105b8SAntonio Quartulli if (tt_global_entry->orig_node != orig_node) { 543a73105b8SAntonio Quartulli atomic_dec(&tt_global_entry->orig_node->tt_size); 544a73105b8SAntonio Quartulli orig_node_tmp = tt_global_entry->orig_node; 545a73105b8SAntonio Quartulli atomic_inc(&orig_node->refcount); 546a73105b8SAntonio Quartulli tt_global_entry->orig_node = orig_node; 547a73105b8SAntonio Quartulli orig_node_free_ref(orig_node_tmp); 548a73105b8SAntonio Quartulli atomic_inc(&orig_node->tt_size); 549a73105b8SAntonio Quartulli } 55048100bacSAntonio Quartulli tt_global_entry->common.flags = NO_FLAGS; 551cc47f66eSAntonio Quartulli tt_global_entry->ttvn = ttvn; 552cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 553c6c8fea2SSven Eckelmann } 554c6c8fea2SSven Eckelmann 555bc279080SAntonio Quartulli if (wifi) 55648100bacSAntonio Quartulli tt_global_entry->common.flags |= TT_CLIENT_WIFI; 557bc279080SAntonio Quartulli 558a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 559a73105b8SAntonio Quartulli "Creating new global tt entry: %pM (via %pM)\n", 56048100bacSAntonio Quartulli tt_global_entry->common.addr, orig_node->orig); 561a73105b8SAntonio Quartulli 56280b3f58cSSimon Wunderlich out_remove: 563c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 56448100bacSAntonio Quartulli tt_local_remove(bat_priv, tt_global_entry->common.addr, 565cc47f66eSAntonio Quartulli "global tt received", roaming); 5667683fdc1SAntonio Quartulli ret = 1; 5677683fdc1SAntonio Quartulli out: 5687683fdc1SAntonio Quartulli if (tt_global_entry) 5697683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 5707683fdc1SAntonio Quartulli return ret; 571c6c8fea2SSven Eckelmann } 572c6c8fea2SSven Eckelmann 5732dafb49dSAntonio Quartulli int tt_global_seq_print_text(struct seq_file *seq, void *offset) 574c6c8fea2SSven Eckelmann { 575c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 576c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 5772dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 57848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 5792dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 58032ae9b22SMarek Lindner struct hard_iface *primary_if; 5817aadf889SMarek Lindner struct hlist_node *node; 582c6c8fea2SSven Eckelmann struct hlist_head *head; 583c90681b8SAntonio Quartulli uint32_t i; 584c90681b8SAntonio Quartulli int ret = 0; 585c6c8fea2SSven Eckelmann 58632ae9b22SMarek Lindner primary_if = primary_if_get_selected(bat_priv); 58732ae9b22SMarek Lindner if (!primary_if) { 58832ae9b22SMarek Lindner ret = seq_printf(seq, "BATMAN mesh %s disabled - please " 58932ae9b22SMarek Lindner "specify interfaces to enable it\n", 590c6c8fea2SSven Eckelmann net_dev->name); 59132ae9b22SMarek Lindner goto out; 59232ae9b22SMarek Lindner } 59332ae9b22SMarek Lindner 59432ae9b22SMarek Lindner if (primary_if->if_status != IF_ACTIVE) { 59532ae9b22SMarek Lindner ret = seq_printf(seq, "BATMAN mesh %s disabled - " 59632ae9b22SMarek Lindner "primary interface not active\n", 59732ae9b22SMarek Lindner net_dev->name); 59832ae9b22SMarek Lindner goto out; 599c6c8fea2SSven Eckelmann } 600c6c8fea2SSven Eckelmann 6012dafb49dSAntonio Quartulli seq_printf(seq, 6022dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 603c6c8fea2SSven Eckelmann net_dev->name); 604df6edb9eSAntonio Quartulli seq_printf(seq, " %-13s %s %-15s %s %s\n", 605df6edb9eSAntonio Quartulli "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags"); 606c6c8fea2SSven Eckelmann 607c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 608c6c8fea2SSven Eckelmann head = &hash->table[i]; 609c6c8fea2SSven Eckelmann 6107aadf889SMarek Lindner rcu_read_lock(); 61148100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 6127aadf889SMarek Lindner head, hash_entry) { 61348100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 61448100bacSAntonio Quartulli struct tt_global_entry, 61548100bacSAntonio Quartulli common); 616d099c2c5SSimon Wunderlich seq_printf(seq, " * %pM (%3u) via %pM (%3u) " 61748100bacSAntonio Quartulli "[%c%c%c]\n", 61848100bacSAntonio Quartulli tt_global_entry->common.addr, 619a73105b8SAntonio Quartulli tt_global_entry->ttvn, 620a73105b8SAntonio Quartulli tt_global_entry->orig_node->orig, 621a73105b8SAntonio Quartulli (uint8_t) atomic_read( 622a73105b8SAntonio Quartulli &tt_global_entry->orig_node-> 623df6edb9eSAntonio Quartulli last_ttvn), 62448100bacSAntonio Quartulli (tt_global_entry->common.flags & 625df6edb9eSAntonio Quartulli TT_CLIENT_ROAM ? 'R' : '.'), 62648100bacSAntonio Quartulli (tt_global_entry->common.flags & 627df6edb9eSAntonio Quartulli TT_CLIENT_PENDING ? 'X' : '.'), 62848100bacSAntonio Quartulli (tt_global_entry->common.flags & 629df6edb9eSAntonio Quartulli TT_CLIENT_WIFI ? 'W' : '.')); 630c6c8fea2SSven Eckelmann } 6317aadf889SMarek Lindner rcu_read_unlock(); 632c6c8fea2SSven Eckelmann } 63332ae9b22SMarek Lindner out: 63432ae9b22SMarek Lindner if (primary_if) 63532ae9b22SMarek Lindner hardif_free_ref(primary_if); 63632ae9b22SMarek Lindner return ret; 637c6c8fea2SSven Eckelmann } 638c6c8fea2SSven Eckelmann 639a73105b8SAntonio Quartulli static void _tt_global_del(struct bat_priv *bat_priv, 6402dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry, 641747e4221SSven Eckelmann const char *message) 642c6c8fea2SSven Eckelmann { 643a73105b8SAntonio Quartulli if (!tt_global_entry) 6447683fdc1SAntonio Quartulli goto out; 645a73105b8SAntonio Quartulli 646a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 6472dafb49dSAntonio Quartulli "Deleting global tt entry %pM (via %pM): %s\n", 64848100bacSAntonio Quartulli tt_global_entry->common.addr, tt_global_entry->orig_node->orig, 649c6c8fea2SSven Eckelmann message); 650c6c8fea2SSven Eckelmann 651a73105b8SAntonio Quartulli atomic_dec(&tt_global_entry->orig_node->tt_size); 6527683fdc1SAntonio Quartulli 65348100bacSAntonio Quartulli hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig, 65448100bacSAntonio Quartulli tt_global_entry->common.addr); 6557683fdc1SAntonio Quartulli out: 6567683fdc1SAntonio Quartulli if (tt_global_entry) 6577683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 658c6c8fea2SSven Eckelmann } 659c6c8fea2SSven Eckelmann 660a73105b8SAntonio Quartulli void tt_global_del(struct bat_priv *bat_priv, 661a73105b8SAntonio Quartulli struct orig_node *orig_node, const unsigned char *addr, 662cc47f66eSAntonio Quartulli const char *message, bool roaming) 663a73105b8SAntonio Quartulli { 6647683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 665797399b4SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 666a73105b8SAntonio Quartulli 667a73105b8SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 6687683fdc1SAntonio Quartulli if (!tt_global_entry) 6697683fdc1SAntonio Quartulli goto out; 670a73105b8SAntonio Quartulli 6717683fdc1SAntonio Quartulli if (tt_global_entry->orig_node == orig_node) { 672cc47f66eSAntonio Quartulli if (roaming) { 673797399b4SAntonio Quartulli /* if we are deleting a global entry due to a roam 674797399b4SAntonio Quartulli * event, there are two possibilities: 675797399b4SAntonio Quartulli * 1) the client roamed from node A to node B => we mark 676797399b4SAntonio Quartulli * it with TT_CLIENT_ROAM, we start a timer and we 677797399b4SAntonio Quartulli * wait for node B to claim it. In case of timeout 678797399b4SAntonio Quartulli * the entry is purged. 679797399b4SAntonio Quartulli * 2) the client roamed to us => we can directly delete 680797399b4SAntonio Quartulli * the global entry, since it is useless now. */ 681797399b4SAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, 682b26e478fSDavid S. Miller tt_global_entry->common.addr); 683797399b4SAntonio Quartulli if (!tt_local_entry) { 68448100bacSAntonio Quartulli tt_global_entry->common.flags |= TT_CLIENT_ROAM; 685cc47f66eSAntonio Quartulli tt_global_entry->roam_at = jiffies; 686cc47f66eSAntonio Quartulli goto out; 687cc47f66eSAntonio Quartulli } 688797399b4SAntonio Quartulli } 689a73105b8SAntonio Quartulli _tt_global_del(bat_priv, tt_global_entry, message); 690a73105b8SAntonio Quartulli } 691cc47f66eSAntonio Quartulli out: 6927683fdc1SAntonio Quartulli if (tt_global_entry) 6937683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 694797399b4SAntonio Quartulli if (tt_local_entry) 695797399b4SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 696a73105b8SAntonio Quartulli } 697a73105b8SAntonio Quartulli 6982dafb49dSAntonio Quartulli void tt_global_del_orig(struct bat_priv *bat_priv, 699747e4221SSven Eckelmann struct orig_node *orig_node, const char *message) 700c6c8fea2SSven Eckelmann { 7012dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 70248100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 703c90681b8SAntonio Quartulli uint32_t i; 704a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 705a73105b8SAntonio Quartulli struct hlist_node *node, *safe; 706a73105b8SAntonio Quartulli struct hlist_head *head; 7077683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 708c6c8fea2SSven Eckelmann 7096e801494SSimon Wunderlich if (!hash) 7106e801494SSimon Wunderlich return; 7116e801494SSimon Wunderlich 712a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 713a73105b8SAntonio Quartulli head = &hash->table[i]; 7147683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 715c6c8fea2SSven Eckelmann 7167683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 71748100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, safe, 718a73105b8SAntonio Quartulli head, hash_entry) { 71948100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 72048100bacSAntonio Quartulli struct tt_global_entry, 72148100bacSAntonio Quartulli common); 7227683fdc1SAntonio Quartulli if (tt_global_entry->orig_node == orig_node) { 7237683fdc1SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 7247683fdc1SAntonio Quartulli "Deleting global tt entry %pM " 72587944973SAntonio Quartulli "(via %pM): %s\n", 72648100bacSAntonio Quartulli tt_global_entry->common.addr, 72787944973SAntonio Quartulli tt_global_entry->orig_node->orig, 72887944973SAntonio Quartulli message); 7297683fdc1SAntonio Quartulli hlist_del_rcu(node); 7307683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 731c6c8fea2SSven Eckelmann } 732a73105b8SAntonio Quartulli } 7337683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 7347683fdc1SAntonio Quartulli } 735a73105b8SAntonio Quartulli atomic_set(&orig_node->tt_size, 0); 736c6c8fea2SSven Eckelmann } 737c6c8fea2SSven Eckelmann 738cc47f66eSAntonio Quartulli static void tt_global_roam_purge(struct bat_priv *bat_priv) 739cc47f66eSAntonio Quartulli { 740cc47f66eSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 74148100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 742cc47f66eSAntonio Quartulli struct tt_global_entry *tt_global_entry; 743cc47f66eSAntonio Quartulli struct hlist_node *node, *node_tmp; 744cc47f66eSAntonio Quartulli struct hlist_head *head; 7457683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 746c90681b8SAntonio Quartulli uint32_t i; 747cc47f66eSAntonio Quartulli 748cc47f66eSAntonio Quartulli for (i = 0; i < hash->size; i++) { 749cc47f66eSAntonio Quartulli head = &hash->table[i]; 7507683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 751cc47f66eSAntonio Quartulli 7527683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 75348100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 754cc47f66eSAntonio Quartulli head, hash_entry) { 75548100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 75648100bacSAntonio Quartulli struct tt_global_entry, 75748100bacSAntonio Quartulli common); 75848100bacSAntonio Quartulli if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM)) 759cc47f66eSAntonio Quartulli continue; 760cc47f66eSAntonio Quartulli if (!is_out_of_time(tt_global_entry->roam_at, 761cc47f66eSAntonio Quartulli TT_CLIENT_ROAM_TIMEOUT * 1000)) 762cc47f66eSAntonio Quartulli continue; 763cc47f66eSAntonio Quartulli 7647683fdc1SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Deleting global " 7657683fdc1SAntonio Quartulli "tt entry (%pM): Roaming timeout\n", 76648100bacSAntonio Quartulli tt_global_entry->common.addr); 7677683fdc1SAntonio Quartulli atomic_dec(&tt_global_entry->orig_node->tt_size); 7687683fdc1SAntonio Quartulli hlist_del_rcu(node); 7697683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 770cc47f66eSAntonio Quartulli } 7717683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 772cc47f66eSAntonio Quartulli } 773cc47f66eSAntonio Quartulli 774cc47f66eSAntonio Quartulli } 775cc47f66eSAntonio Quartulli 776a73105b8SAntonio Quartulli static void tt_global_table_free(struct bat_priv *bat_priv) 777c6c8fea2SSven Eckelmann { 7787683fdc1SAntonio Quartulli struct hashtable_t *hash; 7797683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 78048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 7817683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry; 7827683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 7837683fdc1SAntonio Quartulli struct hlist_head *head; 784c90681b8SAntonio Quartulli uint32_t i; 7857683fdc1SAntonio Quartulli 7862dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 787c6c8fea2SSven Eckelmann return; 788c6c8fea2SSven Eckelmann 7897683fdc1SAntonio Quartulli hash = bat_priv->tt_global_hash; 7907683fdc1SAntonio Quartulli 7917683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 7927683fdc1SAntonio Quartulli head = &hash->table[i]; 7937683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 7947683fdc1SAntonio Quartulli 7957683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 79648100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 7977683fdc1SAntonio Quartulli head, hash_entry) { 7987683fdc1SAntonio Quartulli hlist_del_rcu(node); 79948100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 80048100bacSAntonio Quartulli struct tt_global_entry, 80148100bacSAntonio Quartulli common); 8027683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 8037683fdc1SAntonio Quartulli } 8047683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 8057683fdc1SAntonio Quartulli } 8067683fdc1SAntonio Quartulli 8077683fdc1SAntonio Quartulli hash_destroy(hash); 8087683fdc1SAntonio Quartulli 8092dafb49dSAntonio Quartulli bat_priv->tt_global_hash = NULL; 810c6c8fea2SSven Eckelmann } 811c6c8fea2SSven Eckelmann 81259b699cdSAntonio Quartulli static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry, 81359b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry) 81459b699cdSAntonio Quartulli { 81559b699cdSAntonio Quartulli bool ret = false; 81659b699cdSAntonio Quartulli 81748100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_WIFI && 81848100bacSAntonio Quartulli tt_global_entry->common.flags & TT_CLIENT_WIFI) 81959b699cdSAntonio Quartulli ret = true; 82059b699cdSAntonio Quartulli 82159b699cdSAntonio Quartulli return ret; 82259b699cdSAntonio Quartulli } 82359b699cdSAntonio Quartulli 824747e4221SSven Eckelmann struct orig_node *transtable_search(struct bat_priv *bat_priv, 8253d393e47SAntonio Quartulli const uint8_t *src, const uint8_t *addr) 826c6c8fea2SSven Eckelmann { 8273d393e47SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 8283d393e47SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 8297b36e8eeSMarek Lindner struct orig_node *orig_node = NULL; 830c6c8fea2SSven Eckelmann 8313d393e47SAntonio Quartulli if (src && atomic_read(&bat_priv->ap_isolation)) { 8323d393e47SAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, src); 8333d393e47SAntonio Quartulli if (!tt_local_entry) 8343d393e47SAntonio Quartulli goto out; 8353d393e47SAntonio Quartulli } 8367aadf889SMarek Lindner 8373d393e47SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 8382dafb49dSAntonio Quartulli if (!tt_global_entry) 8397b36e8eeSMarek Lindner goto out; 840c6c8fea2SSven Eckelmann 8413d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 8423d393e47SAntonio Quartulli * isolation */ 8433d393e47SAntonio Quartulli if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry)) 8443d393e47SAntonio Quartulli goto out; 8453d393e47SAntonio Quartulli 8462dafb49dSAntonio Quartulli if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) 8473d393e47SAntonio Quartulli goto out; 8487b36e8eeSMarek Lindner 849980d55b2SAntonio Quartulli /* A global client marked as PENDING has already moved from that 850980d55b2SAntonio Quartulli * originator */ 85148100bacSAntonio Quartulli if (tt_global_entry->common.flags & TT_CLIENT_PENDING) 8523d393e47SAntonio Quartulli goto out; 853980d55b2SAntonio Quartulli 8542dafb49dSAntonio Quartulli orig_node = tt_global_entry->orig_node; 8557b36e8eeSMarek Lindner 8567b36e8eeSMarek Lindner out: 8573d393e47SAntonio Quartulli if (tt_global_entry) 8583d393e47SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 8593d393e47SAntonio Quartulli if (tt_local_entry) 8603d393e47SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 8613d393e47SAntonio Quartulli 8627b36e8eeSMarek Lindner return orig_node; 863c6c8fea2SSven Eckelmann } 864a73105b8SAntonio Quartulli 865a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */ 866a73105b8SAntonio Quartulli uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node) 867a73105b8SAntonio Quartulli { 868a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 869a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 87048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 871a73105b8SAntonio Quartulli struct tt_global_entry *tt_global_entry; 872a73105b8SAntonio Quartulli struct hlist_node *node; 873a73105b8SAntonio Quartulli struct hlist_head *head; 874c90681b8SAntonio Quartulli uint32_t i; 875c90681b8SAntonio Quartulli int j; 876a73105b8SAntonio Quartulli 877a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 878a73105b8SAntonio Quartulli head = &hash->table[i]; 879a73105b8SAntonio Quartulli 880a73105b8SAntonio Quartulli rcu_read_lock(); 88148100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 882a73105b8SAntonio Quartulli head, hash_entry) { 88348100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 88448100bacSAntonio Quartulli struct tt_global_entry, 88548100bacSAntonio Quartulli common); 886a73105b8SAntonio Quartulli if (compare_eth(tt_global_entry->orig_node, 887a73105b8SAntonio Quartulli orig_node)) { 888cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 889cc47f66eSAntonio Quartulli * consistency only. They don't have to be 890cc47f66eSAntonio Quartulli * taken into account while computing the 891cc47f66eSAntonio Quartulli * global crc */ 89248100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_ROAM) 893cc47f66eSAntonio Quartulli continue; 894a73105b8SAntonio Quartulli total_one = 0; 895a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 896a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 89748100bacSAntonio Quartulli tt_common_entry->addr[j]); 898a73105b8SAntonio Quartulli total ^= total_one; 899a73105b8SAntonio Quartulli } 900a73105b8SAntonio Quartulli } 901a73105b8SAntonio Quartulli rcu_read_unlock(); 902a73105b8SAntonio Quartulli } 903a73105b8SAntonio Quartulli 904a73105b8SAntonio Quartulli return total; 905a73105b8SAntonio Quartulli } 906a73105b8SAntonio Quartulli 907a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */ 908a73105b8SAntonio Quartulli uint16_t tt_local_crc(struct bat_priv *bat_priv) 909a73105b8SAntonio Quartulli { 910a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 911a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 91248100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 913a73105b8SAntonio Quartulli struct hlist_node *node; 914a73105b8SAntonio Quartulli struct hlist_head *head; 915c90681b8SAntonio Quartulli uint32_t i; 916c90681b8SAntonio Quartulli int j; 917a73105b8SAntonio Quartulli 918a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 919a73105b8SAntonio Quartulli head = &hash->table[i]; 920a73105b8SAntonio Quartulli 921a73105b8SAntonio Quartulli rcu_read_lock(); 92248100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 923a73105b8SAntonio Quartulli head, hash_entry) { 924058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 925058d0e26SAntonio Quartulli * account while computing the CRC */ 92648100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_NEW) 927058d0e26SAntonio Quartulli continue; 928a73105b8SAntonio Quartulli total_one = 0; 929a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 930a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 93148100bacSAntonio Quartulli tt_common_entry->addr[j]); 932a73105b8SAntonio Quartulli total ^= total_one; 933a73105b8SAntonio Quartulli } 934a73105b8SAntonio Quartulli rcu_read_unlock(); 935a73105b8SAntonio Quartulli } 936a73105b8SAntonio Quartulli 937a73105b8SAntonio Quartulli return total; 938a73105b8SAntonio Quartulli } 939a73105b8SAntonio Quartulli 940a73105b8SAntonio Quartulli static void tt_req_list_free(struct bat_priv *bat_priv) 941a73105b8SAntonio Quartulli { 942a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 943a73105b8SAntonio Quartulli 944a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 945a73105b8SAntonio Quartulli 946a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 947a73105b8SAntonio Quartulli list_del(&node->list); 948a73105b8SAntonio Quartulli kfree(node); 949a73105b8SAntonio Quartulli } 950a73105b8SAntonio Quartulli 951a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 952a73105b8SAntonio Quartulli } 953a73105b8SAntonio Quartulli 954a73105b8SAntonio Quartulli void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node, 955a73105b8SAntonio Quartulli const unsigned char *tt_buff, uint8_t tt_num_changes) 956a73105b8SAntonio Quartulli { 957a73105b8SAntonio Quartulli uint16_t tt_buff_len = tt_len(tt_num_changes); 958a73105b8SAntonio Quartulli 959a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 960a73105b8SAntonio Quartulli * last OGM (the OGM could carry no changes) */ 961a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 962a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 963a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 964a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 965a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 966a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 967a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 968a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 969a73105b8SAntonio Quartulli } 970a73105b8SAntonio Quartulli } 971a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 972a73105b8SAntonio Quartulli } 973a73105b8SAntonio Quartulli 974a73105b8SAntonio Quartulli static void tt_req_purge(struct bat_priv *bat_priv) 975a73105b8SAntonio Quartulli { 976a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 977a73105b8SAntonio Quartulli 978a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 979a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 980a73105b8SAntonio Quartulli if (is_out_of_time(node->issued_at, 981a73105b8SAntonio Quartulli TT_REQUEST_TIMEOUT * 1000)) { 982a73105b8SAntonio Quartulli list_del(&node->list); 983a73105b8SAntonio Quartulli kfree(node); 984a73105b8SAntonio Quartulli } 985a73105b8SAntonio Quartulli } 986a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 987a73105b8SAntonio Quartulli } 988a73105b8SAntonio Quartulli 989a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 990a73105b8SAntonio Quartulli * has already been issued for this orig_node, NULL otherwise */ 991a73105b8SAntonio Quartulli static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv, 992a73105b8SAntonio Quartulli struct orig_node *orig_node) 993a73105b8SAntonio Quartulli { 994a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 995a73105b8SAntonio Quartulli 996a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 997a73105b8SAntonio Quartulli list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { 998a73105b8SAntonio Quartulli if (compare_eth(tt_req_node_tmp, orig_node) && 999a73105b8SAntonio Quartulli !is_out_of_time(tt_req_node_tmp->issued_at, 1000a73105b8SAntonio Quartulli TT_REQUEST_TIMEOUT * 1000)) 1001a73105b8SAntonio Quartulli goto unlock; 1002a73105b8SAntonio Quartulli } 1003a73105b8SAntonio Quartulli 1004a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 1005a73105b8SAntonio Quartulli if (!tt_req_node) 1006a73105b8SAntonio Quartulli goto unlock; 1007a73105b8SAntonio Quartulli 1008a73105b8SAntonio Quartulli memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); 1009a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 1010a73105b8SAntonio Quartulli 1011a73105b8SAntonio Quartulli list_add(&tt_req_node->list, &bat_priv->tt_req_list); 1012a73105b8SAntonio Quartulli unlock: 1013a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1014a73105b8SAntonio Quartulli return tt_req_node; 1015a73105b8SAntonio Quartulli } 1016a73105b8SAntonio Quartulli 1017058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */ 1018058d0e26SAntonio Quartulli static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr) 1019058d0e26SAntonio Quartulli { 102048100bacSAntonio Quartulli const struct tt_common_entry *tt_common_entry = entry_ptr; 1021058d0e26SAntonio Quartulli 102248100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_NEW) 1023058d0e26SAntonio Quartulli return 0; 1024058d0e26SAntonio Quartulli return 1; 1025058d0e26SAntonio Quartulli } 1026058d0e26SAntonio Quartulli 1027a73105b8SAntonio Quartulli static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) 1028a73105b8SAntonio Quartulli { 102948100bacSAntonio Quartulli const struct tt_common_entry *tt_common_entry = entry_ptr; 103048100bacSAntonio Quartulli const struct tt_global_entry *tt_global_entry; 1031a73105b8SAntonio Quartulli const struct orig_node *orig_node = data_ptr; 1032a73105b8SAntonio Quartulli 103348100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_ROAM) 1034cc47f66eSAntonio Quartulli return 0; 1035cc47f66eSAntonio Quartulli 103648100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, 103748100bacSAntonio Quartulli common); 103848100bacSAntonio Quartulli 1039a73105b8SAntonio Quartulli return (tt_global_entry->orig_node == orig_node); 1040a73105b8SAntonio Quartulli } 1041a73105b8SAntonio Quartulli 1042a73105b8SAntonio Quartulli static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, 1043a73105b8SAntonio Quartulli struct hashtable_t *hash, 1044a73105b8SAntonio Quartulli struct hard_iface *primary_if, 1045a73105b8SAntonio Quartulli int (*valid_cb)(const void *, 1046a73105b8SAntonio Quartulli const void *), 1047a73105b8SAntonio Quartulli void *cb_data) 1048a73105b8SAntonio Quartulli { 104948100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1050a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1051a73105b8SAntonio Quartulli struct tt_change *tt_change; 1052a73105b8SAntonio Quartulli struct hlist_node *node; 1053a73105b8SAntonio Quartulli struct hlist_head *head; 1054a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1055a73105b8SAntonio Quartulli uint16_t tt_tot, tt_count; 1056a73105b8SAntonio Quartulli ssize_t tt_query_size = sizeof(struct tt_query_packet); 1057c90681b8SAntonio Quartulli uint32_t i; 1058a73105b8SAntonio Quartulli 1059a73105b8SAntonio Quartulli if (tt_query_size + tt_len > primary_if->soft_iface->mtu) { 1060a73105b8SAntonio Quartulli tt_len = primary_if->soft_iface->mtu - tt_query_size; 1061a73105b8SAntonio Quartulli tt_len -= tt_len % sizeof(struct tt_change); 1062a73105b8SAntonio Quartulli } 1063a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1064a73105b8SAntonio Quartulli 1065a73105b8SAntonio Quartulli skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN); 1066a73105b8SAntonio Quartulli if (!skb) 1067a73105b8SAntonio Quartulli goto out; 1068a73105b8SAntonio Quartulli 1069a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1070a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1071a73105b8SAntonio Quartulli tt_query_size + tt_len); 1072a73105b8SAntonio Quartulli tt_response->ttvn = ttvn; 1073a73105b8SAntonio Quartulli 1074a73105b8SAntonio Quartulli tt_change = (struct tt_change *)(skb->data + tt_query_size); 1075a73105b8SAntonio Quartulli tt_count = 0; 1076a73105b8SAntonio Quartulli 1077a73105b8SAntonio Quartulli rcu_read_lock(); 1078a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1079a73105b8SAntonio Quartulli head = &hash->table[i]; 1080a73105b8SAntonio Quartulli 108148100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1082a73105b8SAntonio Quartulli head, hash_entry) { 1083a73105b8SAntonio Quartulli if (tt_count == tt_tot) 1084a73105b8SAntonio Quartulli break; 1085a73105b8SAntonio Quartulli 108648100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 1087a73105b8SAntonio Quartulli continue; 1088a73105b8SAntonio Quartulli 108948100bacSAntonio Quartulli memcpy(tt_change->addr, tt_common_entry->addr, 109048100bacSAntonio Quartulli ETH_ALEN); 1091a73105b8SAntonio Quartulli tt_change->flags = NO_FLAGS; 1092a73105b8SAntonio Quartulli 1093a73105b8SAntonio Quartulli tt_count++; 1094a73105b8SAntonio Quartulli tt_change++; 1095a73105b8SAntonio Quartulli } 1096a73105b8SAntonio Quartulli } 1097a73105b8SAntonio Quartulli rcu_read_unlock(); 1098a73105b8SAntonio Quartulli 10999d852393SAntonio Quartulli /* store in the message the number of entries we have successfully 11009d852393SAntonio Quartulli * copied */ 11019d852393SAntonio Quartulli tt_response->tt_data = htons(tt_count); 11029d852393SAntonio Quartulli 1103a73105b8SAntonio Quartulli out: 1104a73105b8SAntonio Quartulli return skb; 1105a73105b8SAntonio Quartulli } 1106a73105b8SAntonio Quartulli 1107a943cac1SMarek Lindner static int send_tt_request(struct bat_priv *bat_priv, 1108a943cac1SMarek Lindner struct orig_node *dst_orig_node, 1109a73105b8SAntonio Quartulli uint8_t ttvn, uint16_t tt_crc, bool full_table) 1110a73105b8SAntonio Quartulli { 1111a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1112a73105b8SAntonio Quartulli struct tt_query_packet *tt_request; 1113a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1114a73105b8SAntonio Quartulli struct hard_iface *primary_if; 1115a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node = NULL; 1116a73105b8SAntonio Quartulli int ret = 1; 1117a73105b8SAntonio Quartulli 1118a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1119a73105b8SAntonio Quartulli if (!primary_if) 1120a73105b8SAntonio Quartulli goto out; 1121a73105b8SAntonio Quartulli 1122a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 1123a73105b8SAntonio Quartulli * reply from the same orig_node yet */ 1124a73105b8SAntonio Quartulli tt_req_node = new_tt_req_node(bat_priv, dst_orig_node); 1125a73105b8SAntonio Quartulli if (!tt_req_node) 1126a73105b8SAntonio Quartulli goto out; 1127a73105b8SAntonio Quartulli 1128a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN); 1129a73105b8SAntonio Quartulli if (!skb) 1130a73105b8SAntonio Quartulli goto out; 1131a73105b8SAntonio Quartulli 1132a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1133a73105b8SAntonio Quartulli 1134a73105b8SAntonio Quartulli tt_request = (struct tt_query_packet *)skb_put(skb, 1135a73105b8SAntonio Quartulli sizeof(struct tt_query_packet)); 1136a73105b8SAntonio Quartulli 1137a73105b8SAntonio Quartulli tt_request->packet_type = BAT_TT_QUERY; 1138a73105b8SAntonio Quartulli tt_request->version = COMPAT_VERSION; 1139a73105b8SAntonio Quartulli memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1140a73105b8SAntonio Quartulli memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); 1141a73105b8SAntonio Quartulli tt_request->ttl = TTL; 1142a73105b8SAntonio Quartulli tt_request->ttvn = ttvn; 1143a73105b8SAntonio Quartulli tt_request->tt_data = tt_crc; 1144a73105b8SAntonio Quartulli tt_request->flags = TT_REQUEST; 1145a73105b8SAntonio Quartulli 1146a73105b8SAntonio Quartulli if (full_table) 1147a73105b8SAntonio Quartulli tt_request->flags |= TT_FULL_TABLE; 1148a73105b8SAntonio Quartulli 1149a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(dst_orig_node); 1150a73105b8SAntonio Quartulli if (!neigh_node) 1151a73105b8SAntonio Quartulli goto out; 1152a73105b8SAntonio Quartulli 1153a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM " 1154a73105b8SAntonio Quartulli "[%c]\n", dst_orig_node->orig, neigh_node->addr, 1155a73105b8SAntonio Quartulli (full_table ? 'F' : '.')); 1156a73105b8SAntonio Quartulli 1157a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1158a73105b8SAntonio Quartulli ret = 0; 1159a73105b8SAntonio Quartulli 1160a73105b8SAntonio Quartulli out: 1161a73105b8SAntonio Quartulli if (neigh_node) 1162a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1163a73105b8SAntonio Quartulli if (primary_if) 1164a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1165a73105b8SAntonio Quartulli if (ret) 1166a73105b8SAntonio Quartulli kfree_skb(skb); 1167a73105b8SAntonio Quartulli if (ret && tt_req_node) { 1168a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1169a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 1170a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1171a73105b8SAntonio Quartulli kfree(tt_req_node); 1172a73105b8SAntonio Quartulli } 1173a73105b8SAntonio Quartulli return ret; 1174a73105b8SAntonio Quartulli } 1175a73105b8SAntonio Quartulli 1176a73105b8SAntonio Quartulli static bool send_other_tt_response(struct bat_priv *bat_priv, 1177a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1178a73105b8SAntonio Quartulli { 1179a73105b8SAntonio Quartulli struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL; 1180a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1181a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1182a73105b8SAntonio Quartulli uint8_t orig_ttvn, req_ttvn, ttvn; 1183a73105b8SAntonio Quartulli int ret = false; 1184a73105b8SAntonio Quartulli unsigned char *tt_buff; 1185a73105b8SAntonio Quartulli bool full_table; 1186a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1187a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1188a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1189a73105b8SAntonio Quartulli 1190a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1191a73105b8SAntonio Quartulli "Received TT_REQUEST from %pM for " 1192a73105b8SAntonio Quartulli "ttvn: %u (%pM) [%c]\n", tt_request->src, 1193a73105b8SAntonio Quartulli tt_request->ttvn, tt_request->dst, 1194a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1195a73105b8SAntonio Quartulli 1196a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 1197eb7e2a1eSAntonio Quartulli req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst); 1198a73105b8SAntonio Quartulli if (!req_dst_orig_node) 1199a73105b8SAntonio Quartulli goto out; 1200a73105b8SAntonio Quartulli 1201eb7e2a1eSAntonio Quartulli res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src); 1202a73105b8SAntonio Quartulli if (!res_dst_orig_node) 1203a73105b8SAntonio Quartulli goto out; 1204a73105b8SAntonio Quartulli 1205a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(res_dst_orig_node); 1206a73105b8SAntonio Quartulli if (!neigh_node) 1207a73105b8SAntonio Quartulli goto out; 1208a73105b8SAntonio Quartulli 1209a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1210a73105b8SAntonio Quartulli if (!primary_if) 1211a73105b8SAntonio Quartulli goto out; 1212a73105b8SAntonio Quartulli 1213a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1214a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1215a73105b8SAntonio Quartulli 1216015758d0SAntonio Quartulli /* I don't have the requested data */ 1217a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 1218a73105b8SAntonio Quartulli tt_request->tt_data != req_dst_orig_node->tt_crc) 1219a73105b8SAntonio Quartulli goto out; 1220a73105b8SAntonio Quartulli 1221015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 1222a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || 1223a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 1224a73105b8SAntonio Quartulli full_table = true; 1225a73105b8SAntonio Quartulli else 1226a73105b8SAntonio Quartulli full_table = false; 1227a73105b8SAntonio Quartulli 1228a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 1229a73105b8SAntonio Quartulli * I'll send only one packet with as much TT entries as I can */ 1230a73105b8SAntonio Quartulli if (!full_table) { 1231a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 1232a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 1233a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1234a73105b8SAntonio Quartulli 1235a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1236a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1237a73105b8SAntonio Quartulli if (!skb) 1238a73105b8SAntonio Quartulli goto unlock; 1239a73105b8SAntonio Quartulli 1240a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1241a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1242a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1243a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1244a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1245a73105b8SAntonio Quartulli 1246a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1247a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 1248a73105b8SAntonio Quartulli memcpy(tt_buff, req_dst_orig_node->tt_buff, 1249a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 1250a73105b8SAntonio Quartulli 1251a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1252a73105b8SAntonio Quartulli } else { 1253a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) * 1254a73105b8SAntonio Quartulli sizeof(struct tt_change); 1255a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1256a73105b8SAntonio Quartulli 1257a73105b8SAntonio Quartulli skb = tt_response_fill_table(tt_len, ttvn, 1258a73105b8SAntonio Quartulli bat_priv->tt_global_hash, 1259a73105b8SAntonio Quartulli primary_if, tt_global_valid_entry, 1260a73105b8SAntonio Quartulli req_dst_orig_node); 1261a73105b8SAntonio Quartulli if (!skb) 1262a73105b8SAntonio Quartulli goto out; 1263a73105b8SAntonio Quartulli 1264a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1265a73105b8SAntonio Quartulli } 1266a73105b8SAntonio Quartulli 1267a73105b8SAntonio Quartulli tt_response->packet_type = BAT_TT_QUERY; 1268a73105b8SAntonio Quartulli tt_response->version = COMPAT_VERSION; 1269a73105b8SAntonio Quartulli tt_response->ttl = TTL; 1270a73105b8SAntonio Quartulli memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); 1271a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1272a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1273a73105b8SAntonio Quartulli 1274a73105b8SAntonio Quartulli if (full_table) 1275a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1276a73105b8SAntonio Quartulli 1277a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1278a73105b8SAntonio Quartulli "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n", 1279a73105b8SAntonio Quartulli res_dst_orig_node->orig, neigh_node->addr, 1280a73105b8SAntonio Quartulli req_dst_orig_node->orig, req_ttvn); 1281a73105b8SAntonio Quartulli 1282a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1283a73105b8SAntonio Quartulli ret = true; 1284a73105b8SAntonio Quartulli goto out; 1285a73105b8SAntonio Quartulli 1286a73105b8SAntonio Quartulli unlock: 1287a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1288a73105b8SAntonio Quartulli 1289a73105b8SAntonio Quartulli out: 1290a73105b8SAntonio Quartulli if (res_dst_orig_node) 1291a73105b8SAntonio Quartulli orig_node_free_ref(res_dst_orig_node); 1292a73105b8SAntonio Quartulli if (req_dst_orig_node) 1293a73105b8SAntonio Quartulli orig_node_free_ref(req_dst_orig_node); 1294a73105b8SAntonio Quartulli if (neigh_node) 1295a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1296a73105b8SAntonio Quartulli if (primary_if) 1297a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1298a73105b8SAntonio Quartulli if (!ret) 1299a73105b8SAntonio Quartulli kfree_skb(skb); 1300a73105b8SAntonio Quartulli return ret; 1301a73105b8SAntonio Quartulli 1302a73105b8SAntonio Quartulli } 1303a73105b8SAntonio Quartulli static bool send_my_tt_response(struct bat_priv *bat_priv, 1304a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1305a73105b8SAntonio Quartulli { 1306a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1307a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1308a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1309a73105b8SAntonio Quartulli uint8_t my_ttvn, req_ttvn, ttvn; 1310a73105b8SAntonio Quartulli int ret = false; 1311a73105b8SAntonio Quartulli unsigned char *tt_buff; 1312a73105b8SAntonio Quartulli bool full_table; 1313a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1314a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1315a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1316a73105b8SAntonio Quartulli 1317a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1318a73105b8SAntonio Quartulli "Received TT_REQUEST from %pM for " 1319a73105b8SAntonio Quartulli "ttvn: %u (me) [%c]\n", tt_request->src, 1320a73105b8SAntonio Quartulli tt_request->ttvn, 1321a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1322a73105b8SAntonio Quartulli 1323a73105b8SAntonio Quartulli 1324a73105b8SAntonio Quartulli my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1325a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1326a73105b8SAntonio Quartulli 1327eb7e2a1eSAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_request->src); 1328a73105b8SAntonio Quartulli if (!orig_node) 1329a73105b8SAntonio Quartulli goto out; 1330a73105b8SAntonio Quartulli 1331a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(orig_node); 1332a73105b8SAntonio Quartulli if (!neigh_node) 1333a73105b8SAntonio Quartulli goto out; 1334a73105b8SAntonio Quartulli 1335a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1336a73105b8SAntonio Quartulli if (!primary_if) 1337a73105b8SAntonio Quartulli goto out; 1338a73105b8SAntonio Quartulli 1339a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 1340a73105b8SAntonio Quartulli * is too big send the whole local translation table */ 1341a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn || 1342a73105b8SAntonio Quartulli !bat_priv->tt_buff) 1343a73105b8SAntonio Quartulli full_table = true; 1344a73105b8SAntonio Quartulli else 1345a73105b8SAntonio Quartulli full_table = false; 1346a73105b8SAntonio Quartulli 1347a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 1348a73105b8SAntonio Quartulli * I'll send only one packet with as much TT entries as I can */ 1349a73105b8SAntonio Quartulli if (!full_table) { 1350a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 1351a73105b8SAntonio Quartulli tt_len = bat_priv->tt_buff_len; 1352a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1353a73105b8SAntonio Quartulli 1354a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1355a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1356a73105b8SAntonio Quartulli if (!skb) 1357a73105b8SAntonio Quartulli goto unlock; 1358a73105b8SAntonio Quartulli 1359a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1360a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1361a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1362a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1363a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1364a73105b8SAntonio Quartulli 1365a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1366a73105b8SAntonio Quartulli memcpy(tt_buff, bat_priv->tt_buff, 1367a73105b8SAntonio Quartulli bat_priv->tt_buff_len); 1368a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1369a73105b8SAntonio Quartulli } else { 1370a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) * 1371a73105b8SAntonio Quartulli sizeof(struct tt_change); 1372a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1373a73105b8SAntonio Quartulli 1374a73105b8SAntonio Quartulli skb = tt_response_fill_table(tt_len, ttvn, 1375a73105b8SAntonio Quartulli bat_priv->tt_local_hash, 1376058d0e26SAntonio Quartulli primary_if, tt_local_valid_entry, 1377058d0e26SAntonio Quartulli NULL); 1378a73105b8SAntonio Quartulli if (!skb) 1379a73105b8SAntonio Quartulli goto out; 1380a73105b8SAntonio Quartulli 1381a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1382a73105b8SAntonio Quartulli } 1383a73105b8SAntonio Quartulli 1384a73105b8SAntonio Quartulli tt_response->packet_type = BAT_TT_QUERY; 1385a73105b8SAntonio Quartulli tt_response->version = COMPAT_VERSION; 1386a73105b8SAntonio Quartulli tt_response->ttl = TTL; 1387a73105b8SAntonio Quartulli memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1388a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1389a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1390a73105b8SAntonio Quartulli 1391a73105b8SAntonio Quartulli if (full_table) 1392a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1393a73105b8SAntonio Quartulli 1394a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1395a73105b8SAntonio Quartulli "Sending TT_RESPONSE to %pM via %pM [%c]\n", 1396a73105b8SAntonio Quartulli orig_node->orig, neigh_node->addr, 1397a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1398a73105b8SAntonio Quartulli 1399a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1400a73105b8SAntonio Quartulli ret = true; 1401a73105b8SAntonio Quartulli goto out; 1402a73105b8SAntonio Quartulli 1403a73105b8SAntonio Quartulli unlock: 1404a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1405a73105b8SAntonio Quartulli out: 1406a73105b8SAntonio Quartulli if (orig_node) 1407a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1408a73105b8SAntonio Quartulli if (neigh_node) 1409a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1410a73105b8SAntonio Quartulli if (primary_if) 1411a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1412a73105b8SAntonio Quartulli if (!ret) 1413a73105b8SAntonio Quartulli kfree_skb(skb); 1414a73105b8SAntonio Quartulli /* This packet was for me, so it doesn't need to be re-routed */ 1415a73105b8SAntonio Quartulli return true; 1416a73105b8SAntonio Quartulli } 1417a73105b8SAntonio Quartulli 1418a73105b8SAntonio Quartulli bool send_tt_response(struct bat_priv *bat_priv, 1419a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1420a73105b8SAntonio Quartulli { 1421a73105b8SAntonio Quartulli if (is_my_mac(tt_request->dst)) 1422a73105b8SAntonio Quartulli return send_my_tt_response(bat_priv, tt_request); 1423a73105b8SAntonio Quartulli else 1424a73105b8SAntonio Quartulli return send_other_tt_response(bat_priv, tt_request); 1425a73105b8SAntonio Quartulli } 1426a73105b8SAntonio Quartulli 1427a73105b8SAntonio Quartulli static void _tt_update_changes(struct bat_priv *bat_priv, 1428a73105b8SAntonio Quartulli struct orig_node *orig_node, 1429a73105b8SAntonio Quartulli struct tt_change *tt_change, 1430a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 1431a73105b8SAntonio Quartulli { 1432a73105b8SAntonio Quartulli int i; 1433a73105b8SAntonio Quartulli 1434a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 14355fbc1598SAntonio Quartulli if ((tt_change + i)->flags & TT_CLIENT_DEL) 1436a73105b8SAntonio Quartulli tt_global_del(bat_priv, orig_node, 1437a73105b8SAntonio Quartulli (tt_change + i)->addr, 1438cc47f66eSAntonio Quartulli "tt removed by changes", 1439cc47f66eSAntonio Quartulli (tt_change + i)->flags & TT_CLIENT_ROAM); 1440a73105b8SAntonio Quartulli else 1441a73105b8SAntonio Quartulli if (!tt_global_add(bat_priv, orig_node, 1442bc279080SAntonio Quartulli (tt_change + i)->addr, ttvn, false, 1443bc279080SAntonio Quartulli (tt_change + i)->flags & 1444bc279080SAntonio Quartulli TT_CLIENT_WIFI)) 1445a73105b8SAntonio Quartulli /* In case of problem while storing a 1446a73105b8SAntonio Quartulli * global_entry, we stop the updating 1447a73105b8SAntonio Quartulli * procedure without committing the 1448a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 1449a73105b8SAntonio Quartulli * corrupted data on tt_request 1450a73105b8SAntonio Quartulli */ 1451a73105b8SAntonio Quartulli return; 1452a73105b8SAntonio Quartulli } 1453a73105b8SAntonio Quartulli } 1454a73105b8SAntonio Quartulli 1455a73105b8SAntonio Quartulli static void tt_fill_gtable(struct bat_priv *bat_priv, 1456a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1457a73105b8SAntonio Quartulli { 1458a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1459a73105b8SAntonio Quartulli 1460a73105b8SAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_response->src); 1461a73105b8SAntonio Quartulli if (!orig_node) 1462a73105b8SAntonio Quartulli goto out; 1463a73105b8SAntonio Quartulli 1464a73105b8SAntonio Quartulli /* Purge the old table first.. */ 1465a73105b8SAntonio Quartulli tt_global_del_orig(bat_priv, orig_node, "Received full table"); 1466a73105b8SAntonio Quartulli 1467a73105b8SAntonio Quartulli _tt_update_changes(bat_priv, orig_node, 1468a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1), 1469a73105b8SAntonio Quartulli tt_response->tt_data, tt_response->ttvn); 1470a73105b8SAntonio Quartulli 1471a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1472a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1473a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1474a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 1475a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1476a73105b8SAntonio Quartulli 1477a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, tt_response->ttvn); 1478a73105b8SAntonio Quartulli 1479a73105b8SAntonio Quartulli out: 1480a73105b8SAntonio Quartulli if (orig_node) 1481a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1482a73105b8SAntonio Quartulli } 1483a73105b8SAntonio Quartulli 1484a943cac1SMarek Lindner static void tt_update_changes(struct bat_priv *bat_priv, 1485a943cac1SMarek Lindner struct orig_node *orig_node, 1486a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 1487a73105b8SAntonio Quartulli struct tt_change *tt_change) 1488a73105b8SAntonio Quartulli { 1489a73105b8SAntonio Quartulli _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes, 1490a73105b8SAntonio Quartulli ttvn); 1491a73105b8SAntonio Quartulli 1492a73105b8SAntonio Quartulli tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change, 1493a73105b8SAntonio Quartulli tt_num_changes); 1494a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 1495a73105b8SAntonio Quartulli } 1496a73105b8SAntonio Quartulli 1497a73105b8SAntonio Quartulli bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) 1498a73105b8SAntonio Quartulli { 14997683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 15007683fdc1SAntonio Quartulli bool ret = false; 1501a73105b8SAntonio Quartulli 1502a73105b8SAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 15037683fdc1SAntonio Quartulli if (!tt_local_entry) 15047683fdc1SAntonio Quartulli goto out; 1505058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 1506058d0e26SAntonio Quartulli * consistency purpose) */ 150748100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_PENDING) 1508058d0e26SAntonio Quartulli goto out; 15097683fdc1SAntonio Quartulli ret = true; 15107683fdc1SAntonio Quartulli out: 1511a73105b8SAntonio Quartulli if (tt_local_entry) 15127683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 15137683fdc1SAntonio Quartulli return ret; 1514a73105b8SAntonio Quartulli } 1515a73105b8SAntonio Quartulli 1516a73105b8SAntonio Quartulli void handle_tt_response(struct bat_priv *bat_priv, 1517a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1518a73105b8SAntonio Quartulli { 1519a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1520a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1521a73105b8SAntonio Quartulli 1522a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for " 1523a73105b8SAntonio Quartulli "ttvn %d t_size: %d [%c]\n", 1524a73105b8SAntonio Quartulli tt_response->src, tt_response->ttvn, 1525a73105b8SAntonio Quartulli tt_response->tt_data, 1526a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1527a73105b8SAntonio Quartulli 1528a73105b8SAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_response->src); 1529a73105b8SAntonio Quartulli if (!orig_node) 1530a73105b8SAntonio Quartulli goto out; 1531a73105b8SAntonio Quartulli 1532a73105b8SAntonio Quartulli if (tt_response->flags & TT_FULL_TABLE) 1533a73105b8SAntonio Quartulli tt_fill_gtable(bat_priv, tt_response); 1534a73105b8SAntonio Quartulli else 1535a73105b8SAntonio Quartulli tt_update_changes(bat_priv, orig_node, tt_response->tt_data, 1536a73105b8SAntonio Quartulli tt_response->ttvn, 1537a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1)); 1538a73105b8SAntonio Quartulli 1539a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 1540a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1541a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 1542a73105b8SAntonio Quartulli if (!compare_eth(node->addr, tt_response->src)) 1543a73105b8SAntonio Quartulli continue; 1544a73105b8SAntonio Quartulli list_del(&node->list); 1545a73105b8SAntonio Quartulli kfree(node); 1546a73105b8SAntonio Quartulli } 1547a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1548a73105b8SAntonio Quartulli 1549a73105b8SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 1550a73105b8SAntonio Quartulli orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); 1551cc47f66eSAntonio Quartulli /* Roaming phase is over: tables are in sync again. I can 1552cc47f66eSAntonio Quartulli * unset the flag */ 1553cc47f66eSAntonio Quartulli orig_node->tt_poss_change = false; 1554a73105b8SAntonio Quartulli out: 1555a73105b8SAntonio Quartulli if (orig_node) 1556a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1557a73105b8SAntonio Quartulli } 1558a73105b8SAntonio Quartulli 1559a73105b8SAntonio Quartulli int tt_init(struct bat_priv *bat_priv) 1560a73105b8SAntonio Quartulli { 1561a73105b8SAntonio Quartulli if (!tt_local_init(bat_priv)) 1562a73105b8SAntonio Quartulli return 0; 1563a73105b8SAntonio Quartulli 1564a73105b8SAntonio Quartulli if (!tt_global_init(bat_priv)) 1565a73105b8SAntonio Quartulli return 0; 1566a73105b8SAntonio Quartulli 1567a73105b8SAntonio Quartulli tt_start_timer(bat_priv); 1568a73105b8SAntonio Quartulli 1569a73105b8SAntonio Quartulli return 1; 1570a73105b8SAntonio Quartulli } 1571a73105b8SAntonio Quartulli 1572cc47f66eSAntonio Quartulli static void tt_roam_list_free(struct bat_priv *bat_priv) 1573a73105b8SAntonio Quartulli { 1574cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1575a73105b8SAntonio Quartulli 1576cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1577a73105b8SAntonio Quartulli 1578cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1579cc47f66eSAntonio Quartulli list_del(&node->list); 1580cc47f66eSAntonio Quartulli kfree(node); 1581cc47f66eSAntonio Quartulli } 1582cc47f66eSAntonio Quartulli 1583cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1584cc47f66eSAntonio Quartulli } 1585cc47f66eSAntonio Quartulli 1586cc47f66eSAntonio Quartulli static void tt_roam_purge(struct bat_priv *bat_priv) 1587cc47f66eSAntonio Quartulli { 1588cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1589cc47f66eSAntonio Quartulli 1590cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1591cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1592cc47f66eSAntonio Quartulli if (!is_out_of_time(node->first_time, 1593cc47f66eSAntonio Quartulli ROAMING_MAX_TIME * 1000)) 1594cc47f66eSAntonio Quartulli continue; 1595cc47f66eSAntonio Quartulli 1596cc47f66eSAntonio Quartulli list_del(&node->list); 1597cc47f66eSAntonio Quartulli kfree(node); 1598cc47f66eSAntonio Quartulli } 1599cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1600cc47f66eSAntonio Quartulli } 1601cc47f66eSAntonio Quartulli 1602cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 1603cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 1604cc47f66eSAntonio Quartulli * will not be sent. 1605cc47f66eSAntonio Quartulli * 1606cc47f66eSAntonio Quartulli * returns true if the ROAMING_ADV can be sent, false otherwise */ 1607cc47f66eSAntonio Quartulli static bool tt_check_roam_count(struct bat_priv *bat_priv, 1608cc47f66eSAntonio Quartulli uint8_t *client) 1609cc47f66eSAntonio Quartulli { 1610cc47f66eSAntonio Quartulli struct tt_roam_node *tt_roam_node; 1611cc47f66eSAntonio Quartulli bool ret = false; 1612cc47f66eSAntonio Quartulli 1613cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1614cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 1615cc47f66eSAntonio Quartulli * reply from the same orig_node yet */ 1616cc47f66eSAntonio Quartulli list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) { 1617cc47f66eSAntonio Quartulli if (!compare_eth(tt_roam_node->addr, client)) 1618cc47f66eSAntonio Quartulli continue; 1619cc47f66eSAntonio Quartulli 1620cc47f66eSAntonio Quartulli if (is_out_of_time(tt_roam_node->first_time, 1621cc47f66eSAntonio Quartulli ROAMING_MAX_TIME * 1000)) 1622cc47f66eSAntonio Quartulli continue; 1623cc47f66eSAntonio Quartulli 1624cc47f66eSAntonio Quartulli if (!atomic_dec_not_zero(&tt_roam_node->counter)) 1625cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 1626cc47f66eSAntonio Quartulli goto unlock; 1627cc47f66eSAntonio Quartulli ret = true; 1628cc47f66eSAntonio Quartulli break; 1629cc47f66eSAntonio Quartulli } 1630cc47f66eSAntonio Quartulli 1631cc47f66eSAntonio Quartulli if (!ret) { 1632cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 1633cc47f66eSAntonio Quartulli if (!tt_roam_node) 1634cc47f66eSAntonio Quartulli goto unlock; 1635cc47f66eSAntonio Quartulli 1636cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 1637cc47f66eSAntonio Quartulli atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1); 1638cc47f66eSAntonio Quartulli memcpy(tt_roam_node->addr, client, ETH_ALEN); 1639cc47f66eSAntonio Quartulli 1640cc47f66eSAntonio Quartulli list_add(&tt_roam_node->list, &bat_priv->tt_roam_list); 1641cc47f66eSAntonio Quartulli ret = true; 1642cc47f66eSAntonio Quartulli } 1643cc47f66eSAntonio Quartulli 1644cc47f66eSAntonio Quartulli unlock: 1645cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1646cc47f66eSAntonio Quartulli return ret; 1647cc47f66eSAntonio Quartulli } 1648cc47f66eSAntonio Quartulli 1649cc47f66eSAntonio Quartulli void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 1650cc47f66eSAntonio Quartulli struct orig_node *orig_node) 1651cc47f66eSAntonio Quartulli { 1652cc47f66eSAntonio Quartulli struct neigh_node *neigh_node = NULL; 1653cc47f66eSAntonio Quartulli struct sk_buff *skb = NULL; 1654cc47f66eSAntonio Quartulli struct roam_adv_packet *roam_adv_packet; 1655cc47f66eSAntonio Quartulli int ret = 1; 1656cc47f66eSAntonio Quartulli struct hard_iface *primary_if; 1657cc47f66eSAntonio Quartulli 1658cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 1659cc47f66eSAntonio Quartulli * already roamed to us too many times */ 1660cc47f66eSAntonio Quartulli if (!tt_check_roam_count(bat_priv, client)) 1661cc47f66eSAntonio Quartulli goto out; 1662cc47f66eSAntonio Quartulli 1663cc47f66eSAntonio Quartulli skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN); 1664cc47f66eSAntonio Quartulli if (!skb) 1665cc47f66eSAntonio Quartulli goto out; 1666cc47f66eSAntonio Quartulli 1667cc47f66eSAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1668cc47f66eSAntonio Quartulli 1669cc47f66eSAntonio Quartulli roam_adv_packet = (struct roam_adv_packet *)skb_put(skb, 1670cc47f66eSAntonio Quartulli sizeof(struct roam_adv_packet)); 1671cc47f66eSAntonio Quartulli 1672cc47f66eSAntonio Quartulli roam_adv_packet->packet_type = BAT_ROAM_ADV; 1673cc47f66eSAntonio Quartulli roam_adv_packet->version = COMPAT_VERSION; 1674cc47f66eSAntonio Quartulli roam_adv_packet->ttl = TTL; 1675cc47f66eSAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1676cc47f66eSAntonio Quartulli if (!primary_if) 1677cc47f66eSAntonio Quartulli goto out; 1678cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1679cc47f66eSAntonio Quartulli hardif_free_ref(primary_if); 1680cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); 1681cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->client, client, ETH_ALEN); 1682cc47f66eSAntonio Quartulli 1683cc47f66eSAntonio Quartulli neigh_node = orig_node_get_router(orig_node); 1684cc47f66eSAntonio Quartulli if (!neigh_node) 1685cc47f66eSAntonio Quartulli goto out; 1686cc47f66eSAntonio Quartulli 1687cc47f66eSAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1688cc47f66eSAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM) via %pM\n", 1689cc47f66eSAntonio Quartulli orig_node->orig, client, neigh_node->addr); 1690cc47f66eSAntonio Quartulli 1691cc47f66eSAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1692cc47f66eSAntonio Quartulli ret = 0; 1693cc47f66eSAntonio Quartulli 1694cc47f66eSAntonio Quartulli out: 1695cc47f66eSAntonio Quartulli if (neigh_node) 1696cc47f66eSAntonio Quartulli neigh_node_free_ref(neigh_node); 1697cc47f66eSAntonio Quartulli if (ret) 1698cc47f66eSAntonio Quartulli kfree_skb(skb); 1699cc47f66eSAntonio Quartulli return; 1700a73105b8SAntonio Quartulli } 1701a73105b8SAntonio Quartulli 1702a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work) 1703a73105b8SAntonio Quartulli { 1704a73105b8SAntonio Quartulli struct delayed_work *delayed_work = 1705a73105b8SAntonio Quartulli container_of(work, struct delayed_work, work); 1706a73105b8SAntonio Quartulli struct bat_priv *bat_priv = 1707a73105b8SAntonio Quartulli container_of(delayed_work, struct bat_priv, tt_work); 1708a73105b8SAntonio Quartulli 1709a73105b8SAntonio Quartulli tt_local_purge(bat_priv); 1710cc47f66eSAntonio Quartulli tt_global_roam_purge(bat_priv); 1711a73105b8SAntonio Quartulli tt_req_purge(bat_priv); 1712cc47f66eSAntonio Quartulli tt_roam_purge(bat_priv); 1713a73105b8SAntonio Quartulli 1714a73105b8SAntonio Quartulli tt_start_timer(bat_priv); 1715a73105b8SAntonio Quartulli } 1716cc47f66eSAntonio Quartulli 1717cc47f66eSAntonio Quartulli void tt_free(struct bat_priv *bat_priv) 1718cc47f66eSAntonio Quartulli { 1719cc47f66eSAntonio Quartulli cancel_delayed_work_sync(&bat_priv->tt_work); 1720cc47f66eSAntonio Quartulli 1721cc47f66eSAntonio Quartulli tt_local_table_free(bat_priv); 1722cc47f66eSAntonio Quartulli tt_global_table_free(bat_priv); 1723cc47f66eSAntonio Quartulli tt_req_list_free(bat_priv); 1724cc47f66eSAntonio Quartulli tt_changes_list_free(bat_priv); 1725cc47f66eSAntonio Quartulli tt_roam_list_free(bat_priv); 1726cc47f66eSAntonio Quartulli 1727cc47f66eSAntonio Quartulli kfree(bat_priv->tt_buff); 1728cc47f66eSAntonio Quartulli } 1729058d0e26SAntonio Quartulli 1730697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries 1731697f2531SAntonio Quartulli * in the given hash table and returns the number of modified entries */ 1732697f2531SAntonio Quartulli static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags, 1733697f2531SAntonio Quartulli bool enable) 1734058d0e26SAntonio Quartulli { 1735c90681b8SAntonio Quartulli uint32_t i; 1736697f2531SAntonio Quartulli uint16_t changed_num = 0; 1737058d0e26SAntonio Quartulli struct hlist_head *head; 1738058d0e26SAntonio Quartulli struct hlist_node *node; 173948100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1740058d0e26SAntonio Quartulli 1741058d0e26SAntonio Quartulli if (!hash) 1742697f2531SAntonio Quartulli goto out; 1743058d0e26SAntonio Quartulli 1744058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1745058d0e26SAntonio Quartulli head = &hash->table[i]; 1746058d0e26SAntonio Quartulli 1747058d0e26SAntonio Quartulli rcu_read_lock(); 174848100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1749058d0e26SAntonio Quartulli head, hash_entry) { 1750697f2531SAntonio Quartulli if (enable) { 1751697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 1752697f2531SAntonio Quartulli continue; 1753697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 1754697f2531SAntonio Quartulli } else { 175548100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 175631901264SAntonio Quartulli continue; 175748100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 1758697f2531SAntonio Quartulli } 1759697f2531SAntonio Quartulli changed_num++; 1760058d0e26SAntonio Quartulli } 1761058d0e26SAntonio Quartulli rcu_read_unlock(); 1762058d0e26SAntonio Quartulli } 1763697f2531SAntonio Quartulli out: 1764697f2531SAntonio Quartulli return changed_num; 1765058d0e26SAntonio Quartulli } 1766058d0e26SAntonio Quartulli 1767058d0e26SAntonio Quartulli /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ 1768058d0e26SAntonio Quartulli static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) 1769058d0e26SAntonio Quartulli { 1770058d0e26SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 177148100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1772058d0e26SAntonio Quartulli struct tt_local_entry *tt_local_entry; 1773058d0e26SAntonio Quartulli struct hlist_node *node, *node_tmp; 1774058d0e26SAntonio Quartulli struct hlist_head *head; 1775058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 1776c90681b8SAntonio Quartulli uint32_t i; 1777058d0e26SAntonio Quartulli 1778058d0e26SAntonio Quartulli if (!hash) 1779058d0e26SAntonio Quartulli return; 1780058d0e26SAntonio Quartulli 1781058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1782058d0e26SAntonio Quartulli head = &hash->table[i]; 1783058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 1784058d0e26SAntonio Quartulli 1785058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 178648100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 1787058d0e26SAntonio Quartulli head, hash_entry) { 178848100bacSAntonio Quartulli if (!(tt_common_entry->flags & TT_CLIENT_PENDING)) 1789058d0e26SAntonio Quartulli continue; 1790058d0e26SAntonio Quartulli 1791058d0e26SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " 179248100bacSAntonio Quartulli "(%pM): pending\n", tt_common_entry->addr); 1793058d0e26SAntonio Quartulli 1794058d0e26SAntonio Quartulli atomic_dec(&bat_priv->num_local_tt); 1795058d0e26SAntonio Quartulli hlist_del_rcu(node); 179648100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 179748100bacSAntonio Quartulli struct tt_local_entry, 179848100bacSAntonio Quartulli common); 1799058d0e26SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 1800058d0e26SAntonio Quartulli } 1801058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 1802058d0e26SAntonio Quartulli } 1803058d0e26SAntonio Quartulli 1804058d0e26SAntonio Quartulli } 1805058d0e26SAntonio Quartulli 1806058d0e26SAntonio Quartulli void tt_commit_changes(struct bat_priv *bat_priv) 1807058d0e26SAntonio Quartulli { 1808697f2531SAntonio Quartulli uint16_t changed_num = tt_set_flags(bat_priv->tt_local_hash, 1809697f2531SAntonio Quartulli TT_CLIENT_NEW, false); 1810697f2531SAntonio Quartulli /* all the reset entries have now to be effectively counted as local 1811697f2531SAntonio Quartulli * entries */ 1812697f2531SAntonio Quartulli atomic_add(changed_num, &bat_priv->num_local_tt); 1813058d0e26SAntonio Quartulli tt_local_purge_pending_clients(bat_priv); 1814058d0e26SAntonio Quartulli 1815058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 1816058d0e26SAntonio Quartulli atomic_inc(&bat_priv->ttvn); 1817058d0e26SAntonio Quartulli bat_priv->tt_poss_change = false; 1818058d0e26SAntonio Quartulli } 181959b699cdSAntonio Quartulli 182059b699cdSAntonio Quartulli bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst) 182159b699cdSAntonio Quartulli { 182259b699cdSAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 182359b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 182459b699cdSAntonio Quartulli bool ret = true; 182559b699cdSAntonio Quartulli 182659b699cdSAntonio Quartulli if (!atomic_read(&bat_priv->ap_isolation)) 182759b699cdSAntonio Quartulli return false; 182859b699cdSAntonio Quartulli 182959b699cdSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, dst); 183059b699cdSAntonio Quartulli if (!tt_local_entry) 183159b699cdSAntonio Quartulli goto out; 183259b699cdSAntonio Quartulli 183359b699cdSAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, src); 183459b699cdSAntonio Quartulli if (!tt_global_entry) 183559b699cdSAntonio Quartulli goto out; 183659b699cdSAntonio Quartulli 183759b699cdSAntonio Quartulli if (_is_ap_isolated(tt_local_entry, tt_global_entry)) 183859b699cdSAntonio Quartulli goto out; 183959b699cdSAntonio Quartulli 184059b699cdSAntonio Quartulli ret = false; 184159b699cdSAntonio Quartulli 184259b699cdSAntonio Quartulli out: 184359b699cdSAntonio Quartulli if (tt_global_entry) 184459b699cdSAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 184559b699cdSAntonio Quartulli if (tt_local_entry) 184659b699cdSAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 184759b699cdSAntonio Quartulli return ret; 184859b699cdSAntonio Quartulli } 1849a943cac1SMarek Lindner 1850a943cac1SMarek Lindner void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, 1851a943cac1SMarek Lindner const unsigned char *tt_buff, uint8_t tt_num_changes, 1852a943cac1SMarek Lindner uint8_t ttvn, uint16_t tt_crc) 1853a943cac1SMarek Lindner { 1854a943cac1SMarek Lindner uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); 1855a943cac1SMarek Lindner bool full_table = true; 1856a943cac1SMarek Lindner 1857a943cac1SMarek Lindner /* the ttvn increased by one -> we can apply the attached changes */ 1858a943cac1SMarek Lindner if (ttvn - orig_ttvn == 1) { 1859a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 1860a943cac1SMarek Lindner * because they have already been sent TT_OGM_APPEND_MAX times. 1861a943cac1SMarek Lindner * In this case send a tt request */ 1862a943cac1SMarek Lindner if (!tt_num_changes) { 1863a943cac1SMarek Lindner full_table = false; 1864a943cac1SMarek Lindner goto request_table; 1865a943cac1SMarek Lindner } 1866a943cac1SMarek Lindner 1867a943cac1SMarek Lindner tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn, 1868a943cac1SMarek Lindner (struct tt_change *)tt_buff); 1869a943cac1SMarek Lindner 1870a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 1871a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 1872a943cac1SMarek Lindner * in the global table */ 1873a943cac1SMarek Lindner orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); 1874a943cac1SMarek Lindner 1875a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 1876a943cac1SMarek Lindner * because a single value could represent different states 1877a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 1878a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 1879a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 1880a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 1881a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 1882a943cac1SMarek Lindner * inconsistency */ 1883a943cac1SMarek Lindner if (orig_node->tt_crc != tt_crc) 1884a943cac1SMarek Lindner goto request_table; 1885a943cac1SMarek Lindner 1886a943cac1SMarek Lindner /* Roaming phase is over: tables are in sync again. I can 1887a943cac1SMarek Lindner * unset the flag */ 1888a943cac1SMarek Lindner orig_node->tt_poss_change = false; 1889a943cac1SMarek Lindner } else { 1890a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 1891a943cac1SMarek Lindner * in sync anymore -> request fresh tt data */ 1892a943cac1SMarek Lindner if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) { 1893a943cac1SMarek Lindner request_table: 1894a943cac1SMarek Lindner bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. " 1895a943cac1SMarek Lindner "Need to retrieve the correct information " 1896a943cac1SMarek Lindner "(ttvn: %u last_ttvn: %u crc: %u last_crc: " 1897a943cac1SMarek Lindner "%u num_changes: %u)\n", orig_node->orig, ttvn, 1898a943cac1SMarek Lindner orig_ttvn, tt_crc, orig_node->tt_crc, 1899a943cac1SMarek Lindner tt_num_changes); 1900a943cac1SMarek Lindner send_tt_request(bat_priv, orig_node, ttvn, tt_crc, 1901a943cac1SMarek Lindner full_table); 1902a943cac1SMarek Lindner return; 1903a943cac1SMarek Lindner } 1904a943cac1SMarek Lindner } 1905a943cac1SMarek Lindner } 1906