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 */ 39747e4221SSven Eckelmann static int compare_ltt(const struct hlist_node *node, const void *data2) 407aadf889SMarek Lindner { 41747e4221SSven Eckelmann const void *data1 = container_of(node, struct tt_local_entry, 42747e4221SSven Eckelmann hash_entry); 437aadf889SMarek Lindner 447aadf889SMarek Lindner return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); 457aadf889SMarek Lindner } 467aadf889SMarek Lindner 477aadf889SMarek Lindner /* returns 1 if they are the same mac addr */ 48747e4221SSven Eckelmann static int compare_gtt(const struct hlist_node *node, const void *data2) 497aadf889SMarek Lindner { 50747e4221SSven Eckelmann const void *data1 = container_of(node, struct tt_global_entry, 51747e4221SSven Eckelmann hash_entry); 527aadf889SMarek Lindner 537aadf889SMarek Lindner return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); 547aadf889SMarek Lindner } 557aadf889SMarek Lindner 56a73105b8SAntonio Quartulli static void tt_start_timer(struct bat_priv *bat_priv) 57c6c8fea2SSven Eckelmann { 58a73105b8SAntonio Quartulli INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge); 59a73105b8SAntonio Quartulli queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 60a73105b8SAntonio Quartulli msecs_to_jiffies(5000)); 61c6c8fea2SSven Eckelmann } 62c6c8fea2SSven Eckelmann 632dafb49dSAntonio Quartulli static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv, 64747e4221SSven Eckelmann const void *data) 657aadf889SMarek Lindner { 662dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 677aadf889SMarek Lindner struct hlist_head *head; 687aadf889SMarek Lindner struct hlist_node *node; 692dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry, *tt_local_entry_tmp = NULL; 707aadf889SMarek Lindner int index; 717aadf889SMarek Lindner 727aadf889SMarek Lindner if (!hash) 737aadf889SMarek Lindner return NULL; 747aadf889SMarek Lindner 757aadf889SMarek Lindner index = choose_orig(data, hash->size); 767aadf889SMarek Lindner head = &hash->table[index]; 777aadf889SMarek Lindner 787aadf889SMarek Lindner rcu_read_lock(); 792dafb49dSAntonio Quartulli hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { 802dafb49dSAntonio Quartulli if (!compare_eth(tt_local_entry, data)) 817aadf889SMarek Lindner continue; 827aadf889SMarek Lindner 837683fdc1SAntonio Quartulli if (!atomic_inc_not_zero(&tt_local_entry->refcount)) 847683fdc1SAntonio Quartulli continue; 857683fdc1SAntonio Quartulli 862dafb49dSAntonio Quartulli tt_local_entry_tmp = tt_local_entry; 877aadf889SMarek Lindner break; 887aadf889SMarek Lindner } 897aadf889SMarek Lindner rcu_read_unlock(); 907aadf889SMarek Lindner 912dafb49dSAntonio Quartulli return tt_local_entry_tmp; 927aadf889SMarek Lindner } 937aadf889SMarek Lindner 942dafb49dSAntonio Quartulli static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv, 95747e4221SSven Eckelmann const void *data) 967aadf889SMarek Lindner { 972dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 987aadf889SMarek Lindner struct hlist_head *head; 997aadf889SMarek Lindner struct hlist_node *node; 1002dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 1012dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry_tmp = NULL; 1027aadf889SMarek Lindner int index; 1037aadf889SMarek Lindner 1047aadf889SMarek Lindner if (!hash) 1057aadf889SMarek Lindner return NULL; 1067aadf889SMarek Lindner 1077aadf889SMarek Lindner index = choose_orig(data, hash->size); 1087aadf889SMarek Lindner head = &hash->table[index]; 1097aadf889SMarek Lindner 1107aadf889SMarek Lindner rcu_read_lock(); 1112dafb49dSAntonio Quartulli hlist_for_each_entry_rcu(tt_global_entry, node, head, hash_entry) { 1122dafb49dSAntonio Quartulli if (!compare_eth(tt_global_entry, data)) 1137aadf889SMarek Lindner continue; 1147aadf889SMarek Lindner 1157683fdc1SAntonio Quartulli if (!atomic_inc_not_zero(&tt_global_entry->refcount)) 1167683fdc1SAntonio Quartulli continue; 1177683fdc1SAntonio Quartulli 1182dafb49dSAntonio Quartulli tt_global_entry_tmp = tt_global_entry; 1197aadf889SMarek Lindner break; 1207aadf889SMarek Lindner } 1217aadf889SMarek Lindner rcu_read_unlock(); 1227aadf889SMarek Lindner 1232dafb49dSAntonio Quartulli return tt_global_entry_tmp; 1247aadf889SMarek Lindner } 1257aadf889SMarek Lindner 126a73105b8SAntonio Quartulli static bool is_out_of_time(unsigned long starting_time, unsigned long timeout) 127a73105b8SAntonio Quartulli { 128a73105b8SAntonio Quartulli unsigned long deadline; 129a73105b8SAntonio Quartulli deadline = starting_time + msecs_to_jiffies(timeout); 130a73105b8SAntonio Quartulli 131a73105b8SAntonio Quartulli return time_after(jiffies, deadline); 132a73105b8SAntonio Quartulli } 133a73105b8SAntonio Quartulli 1347683fdc1SAntonio Quartulli static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry) 1357683fdc1SAntonio Quartulli { 1367683fdc1SAntonio Quartulli if (atomic_dec_and_test(&tt_local_entry->refcount)) 1377683fdc1SAntonio Quartulli kfree_rcu(tt_local_entry, rcu); 1387683fdc1SAntonio Quartulli } 1397683fdc1SAntonio Quartulli 1407683fdc1SAntonio Quartulli static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry) 1417683fdc1SAntonio Quartulli { 1427683fdc1SAntonio Quartulli if (atomic_dec_and_test(&tt_global_entry->refcount)) 1437683fdc1SAntonio Quartulli kfree_rcu(tt_global_entry, rcu); 1447683fdc1SAntonio Quartulli } 1457683fdc1SAntonio Quartulli 146ff66c975SAntonio Quartulli static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr, 147ff66c975SAntonio Quartulli uint8_t flags) 148a73105b8SAntonio Quartulli { 149a73105b8SAntonio Quartulli struct tt_change_node *tt_change_node; 150a73105b8SAntonio Quartulli 151a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 152a73105b8SAntonio Quartulli 153a73105b8SAntonio Quartulli if (!tt_change_node) 154a73105b8SAntonio Quartulli return; 155a73105b8SAntonio Quartulli 156ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 157a73105b8SAntonio Quartulli memcpy(tt_change_node->change.addr, addr, ETH_ALEN); 158a73105b8SAntonio Quartulli 159a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 160a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 161a73105b8SAntonio Quartulli list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list); 162a73105b8SAntonio Quartulli atomic_inc(&bat_priv->tt_local_changes); 163a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 164a73105b8SAntonio Quartulli 165a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_ogm_append_cnt, 0); 166a73105b8SAntonio Quartulli } 167a73105b8SAntonio Quartulli 168a73105b8SAntonio Quartulli int tt_len(int changes_num) 169a73105b8SAntonio Quartulli { 170a73105b8SAntonio Quartulli return changes_num * sizeof(struct tt_change); 171a73105b8SAntonio Quartulli } 172a73105b8SAntonio Quartulli 173a73105b8SAntonio Quartulli static int tt_local_init(struct bat_priv *bat_priv) 174c6c8fea2SSven Eckelmann { 1752dafb49dSAntonio Quartulli if (bat_priv->tt_local_hash) 176c6c8fea2SSven Eckelmann return 1; 177c6c8fea2SSven Eckelmann 1782dafb49dSAntonio Quartulli bat_priv->tt_local_hash = hash_new(1024); 179c6c8fea2SSven Eckelmann 1802dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 181c6c8fea2SSven Eckelmann return 0; 182c6c8fea2SSven Eckelmann 183c6c8fea2SSven Eckelmann return 1; 184c6c8fea2SSven Eckelmann } 185c6c8fea2SSven Eckelmann 186bc279080SAntonio Quartulli void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 187bc279080SAntonio Quartulli int ifindex) 188c6c8fea2SSven Eckelmann { 189c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(soft_iface); 1907683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 1917683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 192c6c8fea2SSven Eckelmann 1932dafb49dSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 194c6c8fea2SSven Eckelmann 1952dafb49dSAntonio Quartulli if (tt_local_entry) { 1962dafb49dSAntonio Quartulli tt_local_entry->last_seen = jiffies; 1977683fdc1SAntonio Quartulli goto out; 198c6c8fea2SSven Eckelmann } 199c6c8fea2SSven Eckelmann 200704509b8SSven Eckelmann tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC); 2012dafb49dSAntonio Quartulli if (!tt_local_entry) 2027683fdc1SAntonio Quartulli goto out; 203a73105b8SAntonio Quartulli 204a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 205a73105b8SAntonio Quartulli "Creating new local tt entry: %pM (ttvn: %d)\n", addr, 206a73105b8SAntonio Quartulli (uint8_t)atomic_read(&bat_priv->ttvn)); 207c6c8fea2SSven Eckelmann 2082dafb49dSAntonio Quartulli memcpy(tt_local_entry->addr, addr, ETH_ALEN); 2092dafb49dSAntonio Quartulli tt_local_entry->last_seen = jiffies; 2105fbc1598SAntonio Quartulli tt_local_entry->flags = NO_FLAGS; 211bc279080SAntonio Quartulli if (is_wifi_iface(ifindex)) 212bc279080SAntonio Quartulli tt_local_entry->flags |= TT_CLIENT_WIFI; 2137683fdc1SAntonio Quartulli atomic_set(&tt_local_entry->refcount, 2); 214c6c8fea2SSven Eckelmann 215c6c8fea2SSven Eckelmann /* the batman interface mac address should never be purged */ 21639901e71SMarek Lindner if (compare_eth(addr, soft_iface->dev_addr)) 2175fbc1598SAntonio Quartulli tt_local_entry->flags |= TT_CLIENT_NOPURGE; 218c6c8fea2SSven Eckelmann 219ff66c975SAntonio Quartulli tt_local_event(bat_priv, addr, tt_local_entry->flags); 220ff66c975SAntonio Quartulli 221058d0e26SAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 222058d0e26SAntonio Quartulli * a full table response going out before the next ttvn increment 223058d0e26SAntonio Quartulli * (consistency check) */ 224058d0e26SAntonio Quartulli tt_local_entry->flags |= TT_CLIENT_NEW; 225058d0e26SAntonio Quartulli 2262dafb49dSAntonio Quartulli hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, 2272dafb49dSAntonio Quartulli tt_local_entry, &tt_local_entry->hash_entry); 2287683fdc1SAntonio Quartulli 229c6c8fea2SSven Eckelmann /* remove address from global hash if present */ 2302dafb49dSAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 231c6c8fea2SSven Eckelmann 232cc47f66eSAntonio Quartulli /* Check whether it is a roaming! */ 233cc47f66eSAntonio Quartulli if (tt_global_entry) { 234cc47f66eSAntonio Quartulli /* This node is probably going to update its tt table */ 235cc47f66eSAntonio Quartulli tt_global_entry->orig_node->tt_poss_change = true; 236980d55b2SAntonio Quartulli /* The global entry has to be marked as PENDING and has to be 237980d55b2SAntonio Quartulli * kept for consistency purpose */ 238980d55b2SAntonio Quartulli tt_global_entry->flags |= TT_CLIENT_PENDING; 239cc47f66eSAntonio Quartulli send_roam_adv(bat_priv, tt_global_entry->addr, 240cc47f66eSAntonio Quartulli tt_global_entry->orig_node); 2417683fdc1SAntonio Quartulli } 2427683fdc1SAntonio Quartulli out: 2437683fdc1SAntonio Quartulli if (tt_local_entry) 2447683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 2457683fdc1SAntonio Quartulli if (tt_global_entry) 2467683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 247c6c8fea2SSven Eckelmann } 248c6c8fea2SSven Eckelmann 249a73105b8SAntonio Quartulli int tt_changes_fill_buffer(struct bat_priv *bat_priv, 250c6c8fea2SSven Eckelmann unsigned char *buff, int buff_len) 251c6c8fea2SSven Eckelmann { 252a73105b8SAntonio Quartulli int count = 0, tot_changes = 0; 253a73105b8SAntonio Quartulli struct tt_change_node *entry, *safe; 254c6c8fea2SSven Eckelmann 255a73105b8SAntonio Quartulli if (buff_len > 0) 256a73105b8SAntonio Quartulli tot_changes = buff_len / tt_len(1); 257c6c8fea2SSven Eckelmann 258a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 259a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 260c6c8fea2SSven Eckelmann 261a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 262a73105b8SAntonio Quartulli list) { 263a73105b8SAntonio Quartulli if (count < tot_changes) { 264a73105b8SAntonio Quartulli memcpy(buff + tt_len(count), 265a73105b8SAntonio Quartulli &entry->change, sizeof(struct tt_change)); 266c6c8fea2SSven Eckelmann count++; 267c6c8fea2SSven Eckelmann } 268a73105b8SAntonio Quartulli list_del(&entry->list); 269a73105b8SAntonio Quartulli kfree(entry); 270c6c8fea2SSven Eckelmann } 271a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 272c6c8fea2SSven Eckelmann 273a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 274a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 275a73105b8SAntonio Quartulli kfree(bat_priv->tt_buff); 276a73105b8SAntonio Quartulli bat_priv->tt_buff_len = 0; 277a73105b8SAntonio Quartulli bat_priv->tt_buff = NULL; 278a73105b8SAntonio Quartulli /* We check whether this new OGM has no changes due to size 279a73105b8SAntonio Quartulli * problems */ 280a73105b8SAntonio Quartulli if (buff_len > 0) { 281a73105b8SAntonio Quartulli /** 282a73105b8SAntonio Quartulli * if kmalloc() fails we will reply with the full table 283a73105b8SAntonio Quartulli * instead of providing the diff 284a73105b8SAntonio Quartulli */ 285a73105b8SAntonio Quartulli bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC); 286a73105b8SAntonio Quartulli if (bat_priv->tt_buff) { 287a73105b8SAntonio Quartulli memcpy(bat_priv->tt_buff, buff, buff_len); 288a73105b8SAntonio Quartulli bat_priv->tt_buff_len = buff_len; 289a73105b8SAntonio Quartulli } 290a73105b8SAntonio Quartulli } 291a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 292c6c8fea2SSven Eckelmann 293a73105b8SAntonio Quartulli return tot_changes; 294c6c8fea2SSven Eckelmann } 295c6c8fea2SSven Eckelmann 2962dafb49dSAntonio Quartulli int tt_local_seq_print_text(struct seq_file *seq, void *offset) 297c6c8fea2SSven Eckelmann { 298c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 299c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 3002dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 3012dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry; 30232ae9b22SMarek Lindner struct hard_iface *primary_if; 3037aadf889SMarek Lindner struct hlist_node *node; 304c6c8fea2SSven Eckelmann struct hlist_head *head; 305c6c8fea2SSven Eckelmann size_t buf_size, pos; 306c6c8fea2SSven Eckelmann char *buff; 30732ae9b22SMarek Lindner int i, ret = 0; 308c6c8fea2SSven Eckelmann 30932ae9b22SMarek Lindner primary_if = primary_if_get_selected(bat_priv); 31032ae9b22SMarek Lindner if (!primary_if) { 31132ae9b22SMarek Lindner ret = seq_printf(seq, "BATMAN mesh %s disabled - " 312c6c8fea2SSven Eckelmann "please specify interfaces to enable it\n", 313c6c8fea2SSven Eckelmann net_dev->name); 31432ae9b22SMarek Lindner goto out; 31532ae9b22SMarek Lindner } 31632ae9b22SMarek Lindner 31732ae9b22SMarek Lindner if (primary_if->if_status != IF_ACTIVE) { 31832ae9b22SMarek Lindner ret = seq_printf(seq, "BATMAN mesh %s disabled - " 31932ae9b22SMarek Lindner "primary interface not active\n", 32032ae9b22SMarek Lindner net_dev->name); 32132ae9b22SMarek Lindner goto out; 322c6c8fea2SSven Eckelmann } 323c6c8fea2SSven Eckelmann 324c6c8fea2SSven Eckelmann seq_printf(seq, "Locally retrieved addresses (from %s) " 325a73105b8SAntonio Quartulli "announced via TT (TTVN: %u):\n", 326a73105b8SAntonio Quartulli net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn)); 327c6c8fea2SSven Eckelmann 328c6c8fea2SSven Eckelmann buf_size = 1; 329c6c8fea2SSven Eckelmann /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */ 330c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 331c6c8fea2SSven Eckelmann head = &hash->table[i]; 332c6c8fea2SSven Eckelmann 3337aadf889SMarek Lindner rcu_read_lock(); 3347aadf889SMarek Lindner __hlist_for_each_rcu(node, head) 335c6c8fea2SSven Eckelmann buf_size += 21; 3367aadf889SMarek Lindner rcu_read_unlock(); 337c6c8fea2SSven Eckelmann } 338c6c8fea2SSven Eckelmann 339c6c8fea2SSven Eckelmann buff = kmalloc(buf_size, GFP_ATOMIC); 340c6c8fea2SSven Eckelmann if (!buff) { 34132ae9b22SMarek Lindner ret = -ENOMEM; 34232ae9b22SMarek Lindner goto out; 343c6c8fea2SSven Eckelmann } 3447aadf889SMarek Lindner 345c6c8fea2SSven Eckelmann buff[0] = '\0'; 346c6c8fea2SSven Eckelmann pos = 0; 347c6c8fea2SSven Eckelmann 348c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 349c6c8fea2SSven Eckelmann head = &hash->table[i]; 350c6c8fea2SSven Eckelmann 3517aadf889SMarek Lindner rcu_read_lock(); 3522dafb49dSAntonio Quartulli hlist_for_each_entry_rcu(tt_local_entry, node, 3537aadf889SMarek Lindner head, hash_entry) { 354c6c8fea2SSven Eckelmann pos += snprintf(buff + pos, 22, " * %pM\n", 3552dafb49dSAntonio Quartulli tt_local_entry->addr); 356c6c8fea2SSven Eckelmann } 3577aadf889SMarek Lindner rcu_read_unlock(); 358c6c8fea2SSven Eckelmann } 359c6c8fea2SSven Eckelmann 360c6c8fea2SSven Eckelmann seq_printf(seq, "%s", buff); 361c6c8fea2SSven Eckelmann kfree(buff); 36232ae9b22SMarek Lindner out: 36332ae9b22SMarek Lindner if (primary_if) 36432ae9b22SMarek Lindner hardif_free_ref(primary_if); 36532ae9b22SMarek Lindner return ret; 366c6c8fea2SSven Eckelmann } 367c6c8fea2SSven Eckelmann 368058d0e26SAntonio Quartulli static void tt_local_set_pending(struct bat_priv *bat_priv, 3692dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry, 370058d0e26SAntonio Quartulli uint16_t flags) 371c6c8fea2SSven Eckelmann { 372058d0e26SAntonio Quartulli tt_local_event(bat_priv, tt_local_entry->addr, 373058d0e26SAntonio Quartulli tt_local_entry->flags | flags); 374c6c8fea2SSven Eckelmann 375015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 376015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 377058d0e26SAntonio Quartulli * response issued before the net ttvn increment (consistency check) */ 378058d0e26SAntonio Quartulli tt_local_entry->flags |= TT_CLIENT_PENDING; 379c6c8fea2SSven Eckelmann } 380c6c8fea2SSven Eckelmann 381a73105b8SAntonio Quartulli void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, 382cc47f66eSAntonio Quartulli const char *message, bool roaming) 383c6c8fea2SSven Eckelmann { 3847683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 385c6c8fea2SSven Eckelmann 3862dafb49dSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 3877683fdc1SAntonio Quartulli if (!tt_local_entry) 3887683fdc1SAntonio Quartulli goto out; 3897683fdc1SAntonio Quartulli 390058d0e26SAntonio Quartulli tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | 391ff66c975SAntonio Quartulli (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); 392058d0e26SAntonio Quartulli 393058d0e26SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " 394058d0e26SAntonio Quartulli "%s\n", tt_local_entry->addr, message); 3957683fdc1SAntonio Quartulli out: 3967683fdc1SAntonio Quartulli if (tt_local_entry) 3977683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 398c6c8fea2SSven Eckelmann } 399c6c8fea2SSven Eckelmann 400a73105b8SAntonio Quartulli static void tt_local_purge(struct bat_priv *bat_priv) 401c6c8fea2SSven Eckelmann { 4022dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 4032dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry; 4047aadf889SMarek Lindner struct hlist_node *node, *node_tmp; 405c6c8fea2SSven Eckelmann struct hlist_head *head; 4067683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 4077aadf889SMarek Lindner int i; 408c6c8fea2SSven Eckelmann 409c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 410c6c8fea2SSven Eckelmann head = &hash->table[i]; 4117683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 412c6c8fea2SSven Eckelmann 4137683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 4142dafb49dSAntonio Quartulli hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, 4157aadf889SMarek Lindner head, hash_entry) { 4165fbc1598SAntonio Quartulli if (tt_local_entry->flags & TT_CLIENT_NOPURGE) 4177aadf889SMarek Lindner continue; 418c6c8fea2SSven Eckelmann 419058d0e26SAntonio Quartulli /* entry already marked for deletion */ 420058d0e26SAntonio Quartulli if (tt_local_entry->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", 4317683fdc1SAntonio Quartulli tt_local_entry->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 */ 442a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 4437683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 4447683fdc1SAntonio Quartulli struct hlist_head *head; 4457683fdc1SAntonio Quartulli int i; 446a73105b8SAntonio Quartulli 4472dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 448c6c8fea2SSven Eckelmann return; 449c6c8fea2SSven Eckelmann 450a73105b8SAntonio Quartulli hash = bat_priv->tt_local_hash; 451a73105b8SAntonio Quartulli 452a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 453a73105b8SAntonio Quartulli head = &hash->table[i]; 454a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 455a73105b8SAntonio Quartulli 456a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 457a73105b8SAntonio Quartulli hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, 458a73105b8SAntonio Quartulli head, hash_entry) { 459a73105b8SAntonio Quartulli hlist_del_rcu(node); 4607683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 461a73105b8SAntonio Quartulli } 462a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 463a73105b8SAntonio Quartulli } 464a73105b8SAntonio Quartulli 465a73105b8SAntonio Quartulli hash_destroy(hash); 466a73105b8SAntonio Quartulli 4672dafb49dSAntonio Quartulli bat_priv->tt_local_hash = NULL; 468c6c8fea2SSven Eckelmann } 469c6c8fea2SSven Eckelmann 470a73105b8SAntonio Quartulli static int tt_global_init(struct bat_priv *bat_priv) 471c6c8fea2SSven Eckelmann { 4722dafb49dSAntonio Quartulli if (bat_priv->tt_global_hash) 473c6c8fea2SSven Eckelmann return 1; 474c6c8fea2SSven Eckelmann 4752dafb49dSAntonio Quartulli bat_priv->tt_global_hash = hash_new(1024); 476c6c8fea2SSven Eckelmann 4772dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 478c6c8fea2SSven Eckelmann return 0; 479c6c8fea2SSven Eckelmann 480c6c8fea2SSven Eckelmann return 1; 481c6c8fea2SSven Eckelmann } 482c6c8fea2SSven Eckelmann 483a73105b8SAntonio Quartulli static void tt_changes_list_free(struct bat_priv *bat_priv) 484a73105b8SAntonio Quartulli { 485a73105b8SAntonio Quartulli struct tt_change_node *entry, *safe; 486a73105b8SAntonio Quartulli 487a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 488a73105b8SAntonio Quartulli 489a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 490a73105b8SAntonio Quartulli list) { 491a73105b8SAntonio Quartulli list_del(&entry->list); 492a73105b8SAntonio Quartulli kfree(entry); 493a73105b8SAntonio Quartulli } 494a73105b8SAntonio Quartulli 495a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 496a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 497a73105b8SAntonio Quartulli } 498a73105b8SAntonio Quartulli 499a73105b8SAntonio Quartulli /* caller must hold orig_node refcount */ 500a73105b8SAntonio Quartulli int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, 501bc279080SAntonio Quartulli const unsigned char *tt_addr, uint8_t ttvn, bool roaming, 502bc279080SAntonio Quartulli bool wifi) 503c6c8fea2SSven Eckelmann { 5042dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 505a73105b8SAntonio Quartulli struct orig_node *orig_node_tmp; 5067683fdc1SAntonio Quartulli int ret = 0; 507c6c8fea2SSven Eckelmann 508a73105b8SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, tt_addr); 509c6c8fea2SSven Eckelmann 5102dafb49dSAntonio Quartulli if (!tt_global_entry) { 511a73105b8SAntonio Quartulli tt_global_entry = 512a73105b8SAntonio Quartulli kmalloc(sizeof(*tt_global_entry), 513c6c8fea2SSven Eckelmann GFP_ATOMIC); 5142dafb49dSAntonio Quartulli if (!tt_global_entry) 5157683fdc1SAntonio Quartulli goto out; 5167683fdc1SAntonio Quartulli 517a73105b8SAntonio Quartulli memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN); 518a73105b8SAntonio Quartulli /* Assign the new orig_node */ 519a73105b8SAntonio Quartulli atomic_inc(&orig_node->refcount); 520a73105b8SAntonio Quartulli tt_global_entry->orig_node = orig_node; 521a73105b8SAntonio Quartulli tt_global_entry->ttvn = ttvn; 522cc47f66eSAntonio Quartulli tt_global_entry->flags = NO_FLAGS; 523cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 5247683fdc1SAntonio Quartulli atomic_set(&tt_global_entry->refcount, 2); 5257683fdc1SAntonio Quartulli 5262dafb49dSAntonio Quartulli hash_add(bat_priv->tt_global_hash, compare_gtt, 5272dafb49dSAntonio Quartulli choose_orig, tt_global_entry, 5282dafb49dSAntonio Quartulli &tt_global_entry->hash_entry); 5297683fdc1SAntonio Quartulli atomic_inc(&orig_node->tt_size); 530a73105b8SAntonio Quartulli } else { 531a73105b8SAntonio Quartulli if (tt_global_entry->orig_node != orig_node) { 532a73105b8SAntonio Quartulli atomic_dec(&tt_global_entry->orig_node->tt_size); 533a73105b8SAntonio Quartulli orig_node_tmp = tt_global_entry->orig_node; 534a73105b8SAntonio Quartulli atomic_inc(&orig_node->refcount); 535a73105b8SAntonio Quartulli tt_global_entry->orig_node = orig_node; 536a73105b8SAntonio Quartulli orig_node_free_ref(orig_node_tmp); 537a73105b8SAntonio Quartulli atomic_inc(&orig_node->tt_size); 538a73105b8SAntonio Quartulli } 539cc47f66eSAntonio Quartulli tt_global_entry->ttvn = ttvn; 540cc47f66eSAntonio Quartulli tt_global_entry->flags = NO_FLAGS; 541cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 542c6c8fea2SSven Eckelmann } 543c6c8fea2SSven Eckelmann 544bc279080SAntonio Quartulli if (wifi) 545bc279080SAntonio Quartulli tt_global_entry->flags |= TT_CLIENT_WIFI; 546bc279080SAntonio Quartulli 547a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 548a73105b8SAntonio Quartulli "Creating new global tt entry: %pM (via %pM)\n", 549a73105b8SAntonio Quartulli tt_global_entry->addr, orig_node->orig); 550a73105b8SAntonio Quartulli 551c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 552cc47f66eSAntonio Quartulli tt_local_remove(bat_priv, tt_global_entry->addr, 553cc47f66eSAntonio Quartulli "global tt received", roaming); 5547683fdc1SAntonio Quartulli ret = 1; 5557683fdc1SAntonio Quartulli out: 5567683fdc1SAntonio Quartulli if (tt_global_entry) 5577683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 5587683fdc1SAntonio Quartulli return ret; 559c6c8fea2SSven Eckelmann } 560c6c8fea2SSven Eckelmann 5612dafb49dSAntonio Quartulli int tt_global_seq_print_text(struct seq_file *seq, void *offset) 562c6c8fea2SSven Eckelmann { 563c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 564c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 5652dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 5662dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 56732ae9b22SMarek Lindner struct hard_iface *primary_if; 5687aadf889SMarek Lindner struct hlist_node *node; 569c6c8fea2SSven Eckelmann struct hlist_head *head; 570c6c8fea2SSven Eckelmann size_t buf_size, pos; 571c6c8fea2SSven Eckelmann char *buff; 57232ae9b22SMarek Lindner int i, ret = 0; 573c6c8fea2SSven Eckelmann 57432ae9b22SMarek Lindner primary_if = primary_if_get_selected(bat_priv); 57532ae9b22SMarek Lindner if (!primary_if) { 57632ae9b22SMarek Lindner ret = seq_printf(seq, "BATMAN mesh %s disabled - please " 57732ae9b22SMarek Lindner "specify interfaces to enable it\n", 578c6c8fea2SSven Eckelmann net_dev->name); 57932ae9b22SMarek Lindner goto out; 58032ae9b22SMarek Lindner } 58132ae9b22SMarek Lindner 58232ae9b22SMarek Lindner if (primary_if->if_status != IF_ACTIVE) { 58332ae9b22SMarek Lindner ret = seq_printf(seq, "BATMAN mesh %s disabled - " 58432ae9b22SMarek Lindner "primary interface not active\n", 58532ae9b22SMarek Lindner net_dev->name); 58632ae9b22SMarek Lindner goto out; 587c6c8fea2SSven Eckelmann } 588c6c8fea2SSven Eckelmann 5892dafb49dSAntonio Quartulli seq_printf(seq, 5902dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 591c6c8fea2SSven Eckelmann net_dev->name); 592a73105b8SAntonio Quartulli seq_printf(seq, " %-13s %s %-15s %s\n", 593a73105b8SAntonio Quartulli "Client", "(TTVN)", "Originator", "(Curr TTVN)"); 594c6c8fea2SSven Eckelmann 595c6c8fea2SSven Eckelmann buf_size = 1; 596a73105b8SAntonio Quartulli /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via 597a73105b8SAntonio Quartulli * xx:xx:xx:xx:xx:xx (cur_ttvn)\n"*/ 598c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 599c6c8fea2SSven Eckelmann head = &hash->table[i]; 600c6c8fea2SSven Eckelmann 6017aadf889SMarek Lindner rcu_read_lock(); 6027aadf889SMarek Lindner __hlist_for_each_rcu(node, head) 603a73105b8SAntonio Quartulli buf_size += 59; 6047aadf889SMarek Lindner rcu_read_unlock(); 605c6c8fea2SSven Eckelmann } 606c6c8fea2SSven Eckelmann 607c6c8fea2SSven Eckelmann buff = kmalloc(buf_size, GFP_ATOMIC); 608c6c8fea2SSven Eckelmann if (!buff) { 60932ae9b22SMarek Lindner ret = -ENOMEM; 61032ae9b22SMarek Lindner goto out; 611c6c8fea2SSven Eckelmann } 6127683fdc1SAntonio Quartulli 613c6c8fea2SSven Eckelmann buff[0] = '\0'; 614c6c8fea2SSven Eckelmann pos = 0; 615c6c8fea2SSven Eckelmann 616c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 617c6c8fea2SSven Eckelmann head = &hash->table[i]; 618c6c8fea2SSven Eckelmann 6197aadf889SMarek Lindner rcu_read_lock(); 6202dafb49dSAntonio Quartulli hlist_for_each_entry_rcu(tt_global_entry, node, 6217aadf889SMarek Lindner head, hash_entry) { 622a73105b8SAntonio Quartulli pos += snprintf(buff + pos, 61, 623a73105b8SAntonio Quartulli " * %pM (%3u) via %pM (%3u)\n", 6242dafb49dSAntonio Quartulli tt_global_entry->addr, 625a73105b8SAntonio Quartulli tt_global_entry->ttvn, 626a73105b8SAntonio Quartulli tt_global_entry->orig_node->orig, 627a73105b8SAntonio Quartulli (uint8_t) atomic_read( 628a73105b8SAntonio Quartulli &tt_global_entry->orig_node-> 629a73105b8SAntonio Quartulli last_ttvn)); 630c6c8fea2SSven Eckelmann } 6317aadf889SMarek Lindner rcu_read_unlock(); 632c6c8fea2SSven Eckelmann } 633c6c8fea2SSven Eckelmann 634c6c8fea2SSven Eckelmann seq_printf(seq, "%s", buff); 635c6c8fea2SSven Eckelmann kfree(buff); 63632ae9b22SMarek Lindner out: 63732ae9b22SMarek Lindner if (primary_if) 63832ae9b22SMarek Lindner hardif_free_ref(primary_if); 63932ae9b22SMarek Lindner return ret; 640c6c8fea2SSven Eckelmann } 641c6c8fea2SSven Eckelmann 642a73105b8SAntonio Quartulli static void _tt_global_del(struct bat_priv *bat_priv, 6432dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry, 644747e4221SSven Eckelmann const char *message) 645c6c8fea2SSven Eckelmann { 646a73105b8SAntonio Quartulli if (!tt_global_entry) 6477683fdc1SAntonio Quartulli goto out; 648a73105b8SAntonio Quartulli 649a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 6502dafb49dSAntonio Quartulli "Deleting global tt entry %pM (via %pM): %s\n", 6512dafb49dSAntonio Quartulli tt_global_entry->addr, tt_global_entry->orig_node->orig, 652c6c8fea2SSven Eckelmann message); 653c6c8fea2SSven Eckelmann 654a73105b8SAntonio Quartulli atomic_dec(&tt_global_entry->orig_node->tt_size); 6557683fdc1SAntonio Quartulli 6562dafb49dSAntonio Quartulli hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig, 6572dafb49dSAntonio Quartulli tt_global_entry->addr); 6587683fdc1SAntonio Quartulli out: 6597683fdc1SAntonio Quartulli if (tt_global_entry) 6607683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 661c6c8fea2SSven Eckelmann } 662c6c8fea2SSven Eckelmann 663a73105b8SAntonio Quartulli void tt_global_del(struct bat_priv *bat_priv, 664a73105b8SAntonio Quartulli struct orig_node *orig_node, const unsigned char *addr, 665cc47f66eSAntonio Quartulli const char *message, bool roaming) 666a73105b8SAntonio Quartulli { 6677683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 668a73105b8SAntonio Quartulli 669a73105b8SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 6707683fdc1SAntonio Quartulli if (!tt_global_entry) 6717683fdc1SAntonio Quartulli goto out; 672a73105b8SAntonio Quartulli 6737683fdc1SAntonio Quartulli if (tt_global_entry->orig_node == orig_node) { 674cc47f66eSAntonio Quartulli if (roaming) { 675cc47f66eSAntonio Quartulli tt_global_entry->flags |= TT_CLIENT_ROAM; 676cc47f66eSAntonio Quartulli tt_global_entry->roam_at = jiffies; 677cc47f66eSAntonio Quartulli goto out; 678cc47f66eSAntonio Quartulli } 679a73105b8SAntonio Quartulli _tt_global_del(bat_priv, tt_global_entry, message); 680a73105b8SAntonio Quartulli } 681cc47f66eSAntonio Quartulli out: 6827683fdc1SAntonio Quartulli if (tt_global_entry) 6837683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 684a73105b8SAntonio Quartulli } 685a73105b8SAntonio Quartulli 6862dafb49dSAntonio Quartulli void tt_global_del_orig(struct bat_priv *bat_priv, 687747e4221SSven Eckelmann struct orig_node *orig_node, const char *message) 688c6c8fea2SSven Eckelmann { 6892dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 690a73105b8SAntonio Quartulli int i; 691a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 692a73105b8SAntonio Quartulli struct hlist_node *node, *safe; 693a73105b8SAntonio Quartulli struct hlist_head *head; 6947683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 695c6c8fea2SSven Eckelmann 696a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 697a73105b8SAntonio Quartulli head = &hash->table[i]; 6987683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 699c6c8fea2SSven Eckelmann 7007683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 701a73105b8SAntonio Quartulli hlist_for_each_entry_safe(tt_global_entry, node, safe, 702a73105b8SAntonio Quartulli head, hash_entry) { 7037683fdc1SAntonio Quartulli if (tt_global_entry->orig_node == orig_node) { 7047683fdc1SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 7057683fdc1SAntonio Quartulli "Deleting global tt entry %pM " 7067683fdc1SAntonio Quartulli "(via %pM): originator time out\n", 7077683fdc1SAntonio Quartulli tt_global_entry->addr, 7087683fdc1SAntonio Quartulli tt_global_entry->orig_node->orig); 7097683fdc1SAntonio Quartulli hlist_del_rcu(node); 7107683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 711c6c8fea2SSven Eckelmann } 712a73105b8SAntonio Quartulli } 7137683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 7147683fdc1SAntonio Quartulli } 715a73105b8SAntonio Quartulli atomic_set(&orig_node->tt_size, 0); 716c6c8fea2SSven Eckelmann } 717c6c8fea2SSven Eckelmann 718cc47f66eSAntonio Quartulli static void tt_global_roam_purge(struct bat_priv *bat_priv) 719cc47f66eSAntonio Quartulli { 720cc47f66eSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 721cc47f66eSAntonio Quartulli struct tt_global_entry *tt_global_entry; 722cc47f66eSAntonio Quartulli struct hlist_node *node, *node_tmp; 723cc47f66eSAntonio Quartulli struct hlist_head *head; 7247683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 725cc47f66eSAntonio Quartulli int i; 726cc47f66eSAntonio Quartulli 727cc47f66eSAntonio Quartulli for (i = 0; i < hash->size; i++) { 728cc47f66eSAntonio Quartulli head = &hash->table[i]; 7297683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 730cc47f66eSAntonio Quartulli 7317683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 732cc47f66eSAntonio Quartulli hlist_for_each_entry_safe(tt_global_entry, node, node_tmp, 733cc47f66eSAntonio Quartulli head, hash_entry) { 734cc47f66eSAntonio Quartulli if (!(tt_global_entry->flags & TT_CLIENT_ROAM)) 735cc47f66eSAntonio Quartulli continue; 736cc47f66eSAntonio Quartulli if (!is_out_of_time(tt_global_entry->roam_at, 737cc47f66eSAntonio Quartulli TT_CLIENT_ROAM_TIMEOUT * 1000)) 738cc47f66eSAntonio Quartulli continue; 739cc47f66eSAntonio Quartulli 7407683fdc1SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Deleting global " 7417683fdc1SAntonio Quartulli "tt entry (%pM): Roaming timeout\n", 7427683fdc1SAntonio Quartulli tt_global_entry->addr); 7437683fdc1SAntonio Quartulli atomic_dec(&tt_global_entry->orig_node->tt_size); 7447683fdc1SAntonio Quartulli hlist_del_rcu(node); 7457683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 746cc47f66eSAntonio Quartulli } 7477683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 748cc47f66eSAntonio Quartulli } 749cc47f66eSAntonio Quartulli 750cc47f66eSAntonio Quartulli } 751cc47f66eSAntonio Quartulli 752a73105b8SAntonio Quartulli static void tt_global_table_free(struct bat_priv *bat_priv) 753c6c8fea2SSven Eckelmann { 7547683fdc1SAntonio Quartulli struct hashtable_t *hash; 7557683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 7567683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry; 7577683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 7587683fdc1SAntonio Quartulli struct hlist_head *head; 7597683fdc1SAntonio Quartulli int i; 7607683fdc1SAntonio Quartulli 7612dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 762c6c8fea2SSven Eckelmann return; 763c6c8fea2SSven Eckelmann 7647683fdc1SAntonio Quartulli hash = bat_priv->tt_global_hash; 7657683fdc1SAntonio Quartulli 7667683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 7677683fdc1SAntonio Quartulli head = &hash->table[i]; 7687683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 7697683fdc1SAntonio Quartulli 7707683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 7717683fdc1SAntonio Quartulli hlist_for_each_entry_safe(tt_global_entry, node, node_tmp, 7727683fdc1SAntonio Quartulli head, hash_entry) { 7737683fdc1SAntonio Quartulli hlist_del_rcu(node); 7747683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 7757683fdc1SAntonio Quartulli } 7767683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 7777683fdc1SAntonio Quartulli } 7787683fdc1SAntonio Quartulli 7797683fdc1SAntonio Quartulli hash_destroy(hash); 7807683fdc1SAntonio Quartulli 7812dafb49dSAntonio Quartulli bat_priv->tt_global_hash = NULL; 782c6c8fea2SSven Eckelmann } 783c6c8fea2SSven Eckelmann 78459b699cdSAntonio Quartulli static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry, 78559b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry) 78659b699cdSAntonio Quartulli { 78759b699cdSAntonio Quartulli bool ret = false; 78859b699cdSAntonio Quartulli 78959b699cdSAntonio Quartulli if (tt_local_entry->flags & TT_CLIENT_WIFI && 79059b699cdSAntonio Quartulli tt_global_entry->flags & TT_CLIENT_WIFI) 79159b699cdSAntonio Quartulli ret = true; 79259b699cdSAntonio Quartulli 79359b699cdSAntonio Quartulli return ret; 79459b699cdSAntonio Quartulli } 79559b699cdSAntonio Quartulli 796747e4221SSven Eckelmann struct orig_node *transtable_search(struct bat_priv *bat_priv, 7973d393e47SAntonio Quartulli const uint8_t *src, const uint8_t *addr) 798c6c8fea2SSven Eckelmann { 7993d393e47SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 8003d393e47SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 8017b36e8eeSMarek Lindner struct orig_node *orig_node = NULL; 802c6c8fea2SSven Eckelmann 8033d393e47SAntonio Quartulli if (src && atomic_read(&bat_priv->ap_isolation)) { 8043d393e47SAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, src); 8053d393e47SAntonio Quartulli if (!tt_local_entry) 8063d393e47SAntonio Quartulli goto out; 8073d393e47SAntonio Quartulli } 8087aadf889SMarek Lindner 8093d393e47SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 8102dafb49dSAntonio Quartulli if (!tt_global_entry) 8117b36e8eeSMarek Lindner goto out; 812c6c8fea2SSven Eckelmann 8133d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 8143d393e47SAntonio Quartulli * isolation */ 8153d393e47SAntonio Quartulli if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry)) 8163d393e47SAntonio Quartulli goto out; 8173d393e47SAntonio Quartulli 8182dafb49dSAntonio Quartulli if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) 8193d393e47SAntonio Quartulli goto out; 8207b36e8eeSMarek Lindner 821980d55b2SAntonio Quartulli /* A global client marked as PENDING has already moved from that 822980d55b2SAntonio Quartulli * originator */ 823980d55b2SAntonio Quartulli if (tt_global_entry->flags & TT_CLIENT_PENDING) 8243d393e47SAntonio Quartulli goto out; 825980d55b2SAntonio Quartulli 8262dafb49dSAntonio Quartulli orig_node = tt_global_entry->orig_node; 8277b36e8eeSMarek Lindner 8287b36e8eeSMarek Lindner out: 8293d393e47SAntonio Quartulli if (tt_global_entry) 8303d393e47SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 8313d393e47SAntonio Quartulli if (tt_local_entry) 8323d393e47SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 8333d393e47SAntonio Quartulli 8347b36e8eeSMarek Lindner return orig_node; 835c6c8fea2SSven Eckelmann } 836a73105b8SAntonio Quartulli 837a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */ 838a73105b8SAntonio Quartulli uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node) 839a73105b8SAntonio Quartulli { 840a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 841a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 842a73105b8SAntonio Quartulli struct tt_global_entry *tt_global_entry; 843a73105b8SAntonio Quartulli struct hlist_node *node; 844a73105b8SAntonio Quartulli struct hlist_head *head; 845a73105b8SAntonio Quartulli int i, j; 846a73105b8SAntonio Quartulli 847a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 848a73105b8SAntonio Quartulli head = &hash->table[i]; 849a73105b8SAntonio Quartulli 850a73105b8SAntonio Quartulli rcu_read_lock(); 851a73105b8SAntonio Quartulli hlist_for_each_entry_rcu(tt_global_entry, node, 852a73105b8SAntonio Quartulli head, hash_entry) { 853a73105b8SAntonio Quartulli if (compare_eth(tt_global_entry->orig_node, 854a73105b8SAntonio Quartulli orig_node)) { 855cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 856cc47f66eSAntonio Quartulli * consistency only. They don't have to be 857cc47f66eSAntonio Quartulli * taken into account while computing the 858cc47f66eSAntonio Quartulli * global crc */ 859cc47f66eSAntonio Quartulli if (tt_global_entry->flags & TT_CLIENT_ROAM) 860cc47f66eSAntonio Quartulli continue; 861a73105b8SAntonio Quartulli total_one = 0; 862a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 863a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 864a73105b8SAntonio Quartulli tt_global_entry->addr[j]); 865a73105b8SAntonio Quartulli total ^= total_one; 866a73105b8SAntonio Quartulli } 867a73105b8SAntonio Quartulli } 868a73105b8SAntonio Quartulli rcu_read_unlock(); 869a73105b8SAntonio Quartulli } 870a73105b8SAntonio Quartulli 871a73105b8SAntonio Quartulli return total; 872a73105b8SAntonio Quartulli } 873a73105b8SAntonio Quartulli 874a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */ 875a73105b8SAntonio Quartulli uint16_t tt_local_crc(struct bat_priv *bat_priv) 876a73105b8SAntonio Quartulli { 877a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 878a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 879a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 880a73105b8SAntonio Quartulli struct hlist_node *node; 881a73105b8SAntonio Quartulli struct hlist_head *head; 882a73105b8SAntonio Quartulli int i, j; 883a73105b8SAntonio Quartulli 884a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 885a73105b8SAntonio Quartulli head = &hash->table[i]; 886a73105b8SAntonio Quartulli 887a73105b8SAntonio Quartulli rcu_read_lock(); 888a73105b8SAntonio Quartulli hlist_for_each_entry_rcu(tt_local_entry, node, 889a73105b8SAntonio Quartulli head, hash_entry) { 890058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 891058d0e26SAntonio Quartulli * account while computing the CRC */ 892058d0e26SAntonio Quartulli if (tt_local_entry->flags & TT_CLIENT_NEW) 893058d0e26SAntonio Quartulli continue; 894a73105b8SAntonio Quartulli total_one = 0; 895a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 896a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 897a73105b8SAntonio Quartulli tt_local_entry->addr[j]); 898a73105b8SAntonio Quartulli total ^= total_one; 899a73105b8SAntonio Quartulli } 900a73105b8SAntonio Quartulli rcu_read_unlock(); 901a73105b8SAntonio Quartulli } 902a73105b8SAntonio Quartulli 903a73105b8SAntonio Quartulli return total; 904a73105b8SAntonio Quartulli } 905a73105b8SAntonio Quartulli 906a73105b8SAntonio Quartulli static void tt_req_list_free(struct bat_priv *bat_priv) 907a73105b8SAntonio Quartulli { 908a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 909a73105b8SAntonio Quartulli 910a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 911a73105b8SAntonio Quartulli 912a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 913a73105b8SAntonio Quartulli list_del(&node->list); 914a73105b8SAntonio Quartulli kfree(node); 915a73105b8SAntonio Quartulli } 916a73105b8SAntonio Quartulli 917a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 918a73105b8SAntonio Quartulli } 919a73105b8SAntonio Quartulli 920a73105b8SAntonio Quartulli void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node, 921a73105b8SAntonio Quartulli const unsigned char *tt_buff, uint8_t tt_num_changes) 922a73105b8SAntonio Quartulli { 923a73105b8SAntonio Quartulli uint16_t tt_buff_len = tt_len(tt_num_changes); 924a73105b8SAntonio Quartulli 925a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 926a73105b8SAntonio Quartulli * last OGM (the OGM could carry no changes) */ 927a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 928a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 929a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 930a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 931a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 932a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 933a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 934a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 935a73105b8SAntonio Quartulli } 936a73105b8SAntonio Quartulli } 937a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 938a73105b8SAntonio Quartulli } 939a73105b8SAntonio Quartulli 940a73105b8SAntonio Quartulli static void tt_req_purge(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 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 946a73105b8SAntonio Quartulli if (is_out_of_time(node->issued_at, 947a73105b8SAntonio Quartulli TT_REQUEST_TIMEOUT * 1000)) { 948a73105b8SAntonio Quartulli list_del(&node->list); 949a73105b8SAntonio Quartulli kfree(node); 950a73105b8SAntonio Quartulli } 951a73105b8SAntonio Quartulli } 952a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 953a73105b8SAntonio Quartulli } 954a73105b8SAntonio Quartulli 955a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 956a73105b8SAntonio Quartulli * has already been issued for this orig_node, NULL otherwise */ 957a73105b8SAntonio Quartulli static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv, 958a73105b8SAntonio Quartulli struct orig_node *orig_node) 959a73105b8SAntonio Quartulli { 960a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 961a73105b8SAntonio Quartulli 962a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 963a73105b8SAntonio Quartulli list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { 964a73105b8SAntonio Quartulli if (compare_eth(tt_req_node_tmp, orig_node) && 965a73105b8SAntonio Quartulli !is_out_of_time(tt_req_node_tmp->issued_at, 966a73105b8SAntonio Quartulli TT_REQUEST_TIMEOUT * 1000)) 967a73105b8SAntonio Quartulli goto unlock; 968a73105b8SAntonio Quartulli } 969a73105b8SAntonio Quartulli 970a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 971a73105b8SAntonio Quartulli if (!tt_req_node) 972a73105b8SAntonio Quartulli goto unlock; 973a73105b8SAntonio Quartulli 974a73105b8SAntonio Quartulli memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); 975a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 976a73105b8SAntonio Quartulli 977a73105b8SAntonio Quartulli list_add(&tt_req_node->list, &bat_priv->tt_req_list); 978a73105b8SAntonio Quartulli unlock: 979a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 980a73105b8SAntonio Quartulli return tt_req_node; 981a73105b8SAntonio Quartulli } 982a73105b8SAntonio Quartulli 983058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */ 984058d0e26SAntonio Quartulli static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr) 985058d0e26SAntonio Quartulli { 986058d0e26SAntonio Quartulli const struct tt_local_entry *tt_local_entry = entry_ptr; 987058d0e26SAntonio Quartulli 988058d0e26SAntonio Quartulli if (tt_local_entry->flags & TT_CLIENT_NEW) 989058d0e26SAntonio Quartulli return 0; 990058d0e26SAntonio Quartulli return 1; 991058d0e26SAntonio Quartulli } 992058d0e26SAntonio Quartulli 993a73105b8SAntonio Quartulli static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) 994a73105b8SAntonio Quartulli { 995a73105b8SAntonio Quartulli const struct tt_global_entry *tt_global_entry = entry_ptr; 996a73105b8SAntonio Quartulli const struct orig_node *orig_node = data_ptr; 997a73105b8SAntonio Quartulli 998cc47f66eSAntonio Quartulli if (tt_global_entry->flags & TT_CLIENT_ROAM) 999cc47f66eSAntonio Quartulli return 0; 1000cc47f66eSAntonio Quartulli 1001a73105b8SAntonio Quartulli return (tt_global_entry->orig_node == orig_node); 1002a73105b8SAntonio Quartulli } 1003a73105b8SAntonio Quartulli 1004a73105b8SAntonio Quartulli static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, 1005a73105b8SAntonio Quartulli struct hashtable_t *hash, 1006a73105b8SAntonio Quartulli struct hard_iface *primary_if, 1007a73105b8SAntonio Quartulli int (*valid_cb)(const void *, 1008a73105b8SAntonio Quartulli const void *), 1009a73105b8SAntonio Quartulli void *cb_data) 1010a73105b8SAntonio Quartulli { 1011a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 1012a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1013a73105b8SAntonio Quartulli struct tt_change *tt_change; 1014a73105b8SAntonio Quartulli struct hlist_node *node; 1015a73105b8SAntonio Quartulli struct hlist_head *head; 1016a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1017a73105b8SAntonio Quartulli uint16_t tt_tot, tt_count; 1018a73105b8SAntonio Quartulli ssize_t tt_query_size = sizeof(struct tt_query_packet); 1019a73105b8SAntonio Quartulli int i; 1020a73105b8SAntonio Quartulli 1021a73105b8SAntonio Quartulli if (tt_query_size + tt_len > primary_if->soft_iface->mtu) { 1022a73105b8SAntonio Quartulli tt_len = primary_if->soft_iface->mtu - tt_query_size; 1023a73105b8SAntonio Quartulli tt_len -= tt_len % sizeof(struct tt_change); 1024a73105b8SAntonio Quartulli } 1025a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1026a73105b8SAntonio Quartulli 1027a73105b8SAntonio Quartulli skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN); 1028a73105b8SAntonio Quartulli if (!skb) 1029a73105b8SAntonio Quartulli goto out; 1030a73105b8SAntonio Quartulli 1031a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1032a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1033a73105b8SAntonio Quartulli tt_query_size + tt_len); 1034a73105b8SAntonio Quartulli tt_response->ttvn = ttvn; 1035a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1036a73105b8SAntonio Quartulli 1037a73105b8SAntonio Quartulli tt_change = (struct tt_change *)(skb->data + tt_query_size); 1038a73105b8SAntonio Quartulli tt_count = 0; 1039a73105b8SAntonio Quartulli 1040a73105b8SAntonio Quartulli rcu_read_lock(); 1041a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1042a73105b8SAntonio Quartulli head = &hash->table[i]; 1043a73105b8SAntonio Quartulli 1044a73105b8SAntonio Quartulli hlist_for_each_entry_rcu(tt_local_entry, node, 1045a73105b8SAntonio Quartulli head, hash_entry) { 1046a73105b8SAntonio Quartulli if (tt_count == tt_tot) 1047a73105b8SAntonio Quartulli break; 1048a73105b8SAntonio Quartulli 1049a73105b8SAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data))) 1050a73105b8SAntonio Quartulli continue; 1051a73105b8SAntonio Quartulli 1052a73105b8SAntonio Quartulli memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN); 1053a73105b8SAntonio Quartulli tt_change->flags = NO_FLAGS; 1054a73105b8SAntonio Quartulli 1055a73105b8SAntonio Quartulli tt_count++; 1056a73105b8SAntonio Quartulli tt_change++; 1057a73105b8SAntonio Quartulli } 1058a73105b8SAntonio Quartulli } 1059a73105b8SAntonio Quartulli rcu_read_unlock(); 1060a73105b8SAntonio Quartulli 1061a73105b8SAntonio Quartulli out: 1062a73105b8SAntonio Quartulli return skb; 1063a73105b8SAntonio Quartulli } 1064a73105b8SAntonio Quartulli 1065a73105b8SAntonio Quartulli int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_orig_node, 1066a73105b8SAntonio Quartulli uint8_t ttvn, uint16_t tt_crc, bool full_table) 1067a73105b8SAntonio Quartulli { 1068a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1069a73105b8SAntonio Quartulli struct tt_query_packet *tt_request; 1070a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1071a73105b8SAntonio Quartulli struct hard_iface *primary_if; 1072a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node = NULL; 1073a73105b8SAntonio Quartulli int ret = 1; 1074a73105b8SAntonio Quartulli 1075a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1076a73105b8SAntonio Quartulli if (!primary_if) 1077a73105b8SAntonio Quartulli goto out; 1078a73105b8SAntonio Quartulli 1079a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 1080a73105b8SAntonio Quartulli * reply from the same orig_node yet */ 1081a73105b8SAntonio Quartulli tt_req_node = new_tt_req_node(bat_priv, dst_orig_node); 1082a73105b8SAntonio Quartulli if (!tt_req_node) 1083a73105b8SAntonio Quartulli goto out; 1084a73105b8SAntonio Quartulli 1085a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN); 1086a73105b8SAntonio Quartulli if (!skb) 1087a73105b8SAntonio Quartulli goto out; 1088a73105b8SAntonio Quartulli 1089a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1090a73105b8SAntonio Quartulli 1091a73105b8SAntonio Quartulli tt_request = (struct tt_query_packet *)skb_put(skb, 1092a73105b8SAntonio Quartulli sizeof(struct tt_query_packet)); 1093a73105b8SAntonio Quartulli 1094a73105b8SAntonio Quartulli tt_request->packet_type = BAT_TT_QUERY; 1095a73105b8SAntonio Quartulli tt_request->version = COMPAT_VERSION; 1096a73105b8SAntonio Quartulli memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1097a73105b8SAntonio Quartulli memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); 1098a73105b8SAntonio Quartulli tt_request->ttl = TTL; 1099a73105b8SAntonio Quartulli tt_request->ttvn = ttvn; 1100a73105b8SAntonio Quartulli tt_request->tt_data = tt_crc; 1101a73105b8SAntonio Quartulli tt_request->flags = TT_REQUEST; 1102a73105b8SAntonio Quartulli 1103a73105b8SAntonio Quartulli if (full_table) 1104a73105b8SAntonio Quartulli tt_request->flags |= TT_FULL_TABLE; 1105a73105b8SAntonio Quartulli 1106a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(dst_orig_node); 1107a73105b8SAntonio Quartulli if (!neigh_node) 1108a73105b8SAntonio Quartulli goto out; 1109a73105b8SAntonio Quartulli 1110a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM " 1111a73105b8SAntonio Quartulli "[%c]\n", dst_orig_node->orig, neigh_node->addr, 1112a73105b8SAntonio Quartulli (full_table ? 'F' : '.')); 1113a73105b8SAntonio Quartulli 1114a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1115a73105b8SAntonio Quartulli ret = 0; 1116a73105b8SAntonio Quartulli 1117a73105b8SAntonio Quartulli out: 1118a73105b8SAntonio Quartulli if (neigh_node) 1119a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1120a73105b8SAntonio Quartulli if (primary_if) 1121a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1122a73105b8SAntonio Quartulli if (ret) 1123a73105b8SAntonio Quartulli kfree_skb(skb); 1124a73105b8SAntonio Quartulli if (ret && tt_req_node) { 1125a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1126a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 1127a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1128a73105b8SAntonio Quartulli kfree(tt_req_node); 1129a73105b8SAntonio Quartulli } 1130a73105b8SAntonio Quartulli return ret; 1131a73105b8SAntonio Quartulli } 1132a73105b8SAntonio Quartulli 1133a73105b8SAntonio Quartulli static bool send_other_tt_response(struct bat_priv *bat_priv, 1134a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1135a73105b8SAntonio Quartulli { 1136a73105b8SAntonio Quartulli struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL; 1137a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1138a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1139a73105b8SAntonio Quartulli uint8_t orig_ttvn, req_ttvn, ttvn; 1140a73105b8SAntonio Quartulli int ret = false; 1141a73105b8SAntonio Quartulli unsigned char *tt_buff; 1142a73105b8SAntonio Quartulli bool full_table; 1143a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1144a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1145a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1146a73105b8SAntonio Quartulli 1147a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1148a73105b8SAntonio Quartulli "Received TT_REQUEST from %pM for " 1149a73105b8SAntonio Quartulli "ttvn: %u (%pM) [%c]\n", tt_request->src, 1150a73105b8SAntonio Quartulli tt_request->ttvn, tt_request->dst, 1151a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1152a73105b8SAntonio Quartulli 1153a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 1154a73105b8SAntonio Quartulli req_dst_orig_node = get_orig_node(bat_priv, tt_request->dst); 1155a73105b8SAntonio Quartulli if (!req_dst_orig_node) 1156a73105b8SAntonio Quartulli goto out; 1157a73105b8SAntonio Quartulli 1158a73105b8SAntonio Quartulli res_dst_orig_node = get_orig_node(bat_priv, tt_request->src); 1159a73105b8SAntonio Quartulli if (!res_dst_orig_node) 1160a73105b8SAntonio Quartulli goto out; 1161a73105b8SAntonio Quartulli 1162a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(res_dst_orig_node); 1163a73105b8SAntonio Quartulli if (!neigh_node) 1164a73105b8SAntonio Quartulli goto out; 1165a73105b8SAntonio Quartulli 1166a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1167a73105b8SAntonio Quartulli if (!primary_if) 1168a73105b8SAntonio Quartulli goto out; 1169a73105b8SAntonio Quartulli 1170a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1171a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1172a73105b8SAntonio Quartulli 1173015758d0SAntonio Quartulli /* I don't have the requested data */ 1174a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 1175a73105b8SAntonio Quartulli tt_request->tt_data != req_dst_orig_node->tt_crc) 1176a73105b8SAntonio Quartulli goto out; 1177a73105b8SAntonio Quartulli 1178015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 1179a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || 1180a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 1181a73105b8SAntonio Quartulli full_table = true; 1182a73105b8SAntonio Quartulli else 1183a73105b8SAntonio Quartulli full_table = false; 1184a73105b8SAntonio Quartulli 1185a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 1186a73105b8SAntonio Quartulli * I'll send only one packet with as much TT entries as I can */ 1187a73105b8SAntonio Quartulli if (!full_table) { 1188a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 1189a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 1190a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1191a73105b8SAntonio Quartulli 1192a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1193a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1194a73105b8SAntonio Quartulli if (!skb) 1195a73105b8SAntonio Quartulli goto unlock; 1196a73105b8SAntonio Quartulli 1197a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1198a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1199a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1200a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1201a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1202a73105b8SAntonio Quartulli 1203a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1204a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 1205a73105b8SAntonio Quartulli memcpy(tt_buff, req_dst_orig_node->tt_buff, 1206a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 1207a73105b8SAntonio Quartulli 1208a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1209a73105b8SAntonio Quartulli } else { 1210a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) * 1211a73105b8SAntonio Quartulli sizeof(struct tt_change); 1212a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1213a73105b8SAntonio Quartulli 1214a73105b8SAntonio Quartulli skb = tt_response_fill_table(tt_len, ttvn, 1215a73105b8SAntonio Quartulli bat_priv->tt_global_hash, 1216a73105b8SAntonio Quartulli primary_if, tt_global_valid_entry, 1217a73105b8SAntonio Quartulli req_dst_orig_node); 1218a73105b8SAntonio Quartulli if (!skb) 1219a73105b8SAntonio Quartulli goto out; 1220a73105b8SAntonio Quartulli 1221a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1222a73105b8SAntonio Quartulli } 1223a73105b8SAntonio Quartulli 1224a73105b8SAntonio Quartulli tt_response->packet_type = BAT_TT_QUERY; 1225a73105b8SAntonio Quartulli tt_response->version = COMPAT_VERSION; 1226a73105b8SAntonio Quartulli tt_response->ttl = TTL; 1227a73105b8SAntonio Quartulli memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); 1228a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1229a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1230a73105b8SAntonio Quartulli 1231a73105b8SAntonio Quartulli if (full_table) 1232a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1233a73105b8SAntonio Quartulli 1234a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1235a73105b8SAntonio Quartulli "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n", 1236a73105b8SAntonio Quartulli res_dst_orig_node->orig, neigh_node->addr, 1237a73105b8SAntonio Quartulli req_dst_orig_node->orig, req_ttvn); 1238a73105b8SAntonio Quartulli 1239a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1240a73105b8SAntonio Quartulli ret = true; 1241a73105b8SAntonio Quartulli goto out; 1242a73105b8SAntonio Quartulli 1243a73105b8SAntonio Quartulli unlock: 1244a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1245a73105b8SAntonio Quartulli 1246a73105b8SAntonio Quartulli out: 1247a73105b8SAntonio Quartulli if (res_dst_orig_node) 1248a73105b8SAntonio Quartulli orig_node_free_ref(res_dst_orig_node); 1249a73105b8SAntonio Quartulli if (req_dst_orig_node) 1250a73105b8SAntonio Quartulli orig_node_free_ref(req_dst_orig_node); 1251a73105b8SAntonio Quartulli if (neigh_node) 1252a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1253a73105b8SAntonio Quartulli if (primary_if) 1254a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1255a73105b8SAntonio Quartulli if (!ret) 1256a73105b8SAntonio Quartulli kfree_skb(skb); 1257a73105b8SAntonio Quartulli return ret; 1258a73105b8SAntonio Quartulli 1259a73105b8SAntonio Quartulli } 1260a73105b8SAntonio Quartulli static bool send_my_tt_response(struct bat_priv *bat_priv, 1261a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1262a73105b8SAntonio Quartulli { 1263a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1264a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1265a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1266a73105b8SAntonio Quartulli uint8_t my_ttvn, req_ttvn, ttvn; 1267a73105b8SAntonio Quartulli int ret = false; 1268a73105b8SAntonio Quartulli unsigned char *tt_buff; 1269a73105b8SAntonio Quartulli bool full_table; 1270a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1271a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1272a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1273a73105b8SAntonio Quartulli 1274a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1275a73105b8SAntonio Quartulli "Received TT_REQUEST from %pM for " 1276a73105b8SAntonio Quartulli "ttvn: %u (me) [%c]\n", tt_request->src, 1277a73105b8SAntonio Quartulli tt_request->ttvn, 1278a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1279a73105b8SAntonio Quartulli 1280a73105b8SAntonio Quartulli 1281a73105b8SAntonio Quartulli my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1282a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1283a73105b8SAntonio Quartulli 1284a73105b8SAntonio Quartulli orig_node = get_orig_node(bat_priv, tt_request->src); 1285a73105b8SAntonio Quartulli if (!orig_node) 1286a73105b8SAntonio Quartulli goto out; 1287a73105b8SAntonio Quartulli 1288a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(orig_node); 1289a73105b8SAntonio Quartulli if (!neigh_node) 1290a73105b8SAntonio Quartulli goto out; 1291a73105b8SAntonio Quartulli 1292a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1293a73105b8SAntonio Quartulli if (!primary_if) 1294a73105b8SAntonio Quartulli goto out; 1295a73105b8SAntonio Quartulli 1296a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 1297a73105b8SAntonio Quartulli * is too big send the whole local translation table */ 1298a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn || 1299a73105b8SAntonio Quartulli !bat_priv->tt_buff) 1300a73105b8SAntonio Quartulli full_table = true; 1301a73105b8SAntonio Quartulli else 1302a73105b8SAntonio Quartulli full_table = false; 1303a73105b8SAntonio Quartulli 1304a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 1305a73105b8SAntonio Quartulli * I'll send only one packet with as much TT entries as I can */ 1306a73105b8SAntonio Quartulli if (!full_table) { 1307a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 1308a73105b8SAntonio Quartulli tt_len = bat_priv->tt_buff_len; 1309a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1310a73105b8SAntonio Quartulli 1311a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1312a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1313a73105b8SAntonio Quartulli if (!skb) 1314a73105b8SAntonio Quartulli goto unlock; 1315a73105b8SAntonio Quartulli 1316a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1317a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1318a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1319a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1320a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1321a73105b8SAntonio Quartulli 1322a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1323a73105b8SAntonio Quartulli memcpy(tt_buff, bat_priv->tt_buff, 1324a73105b8SAntonio Quartulli bat_priv->tt_buff_len); 1325a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1326a73105b8SAntonio Quartulli } else { 1327a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) * 1328a73105b8SAntonio Quartulli sizeof(struct tt_change); 1329a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1330a73105b8SAntonio Quartulli 1331a73105b8SAntonio Quartulli skb = tt_response_fill_table(tt_len, ttvn, 1332a73105b8SAntonio Quartulli bat_priv->tt_local_hash, 1333058d0e26SAntonio Quartulli primary_if, tt_local_valid_entry, 1334058d0e26SAntonio Quartulli NULL); 1335a73105b8SAntonio Quartulli if (!skb) 1336a73105b8SAntonio Quartulli goto out; 1337a73105b8SAntonio Quartulli 1338a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1339a73105b8SAntonio Quartulli } 1340a73105b8SAntonio Quartulli 1341a73105b8SAntonio Quartulli tt_response->packet_type = BAT_TT_QUERY; 1342a73105b8SAntonio Quartulli tt_response->version = COMPAT_VERSION; 1343a73105b8SAntonio Quartulli tt_response->ttl = TTL; 1344a73105b8SAntonio Quartulli memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1345a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1346a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1347a73105b8SAntonio Quartulli 1348a73105b8SAntonio Quartulli if (full_table) 1349a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1350a73105b8SAntonio Quartulli 1351a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1352a73105b8SAntonio Quartulli "Sending TT_RESPONSE to %pM via %pM [%c]\n", 1353a73105b8SAntonio Quartulli orig_node->orig, neigh_node->addr, 1354a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1355a73105b8SAntonio Quartulli 1356a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1357a73105b8SAntonio Quartulli ret = true; 1358a73105b8SAntonio Quartulli goto out; 1359a73105b8SAntonio Quartulli 1360a73105b8SAntonio Quartulli unlock: 1361a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1362a73105b8SAntonio Quartulli out: 1363a73105b8SAntonio Quartulli if (orig_node) 1364a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1365a73105b8SAntonio Quartulli if (neigh_node) 1366a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1367a73105b8SAntonio Quartulli if (primary_if) 1368a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1369a73105b8SAntonio Quartulli if (!ret) 1370a73105b8SAntonio Quartulli kfree_skb(skb); 1371a73105b8SAntonio Quartulli /* This packet was for me, so it doesn't need to be re-routed */ 1372a73105b8SAntonio Quartulli return true; 1373a73105b8SAntonio Quartulli } 1374a73105b8SAntonio Quartulli 1375a73105b8SAntonio Quartulli bool send_tt_response(struct bat_priv *bat_priv, 1376a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1377a73105b8SAntonio Quartulli { 1378a73105b8SAntonio Quartulli if (is_my_mac(tt_request->dst)) 1379a73105b8SAntonio Quartulli return send_my_tt_response(bat_priv, tt_request); 1380a73105b8SAntonio Quartulli else 1381a73105b8SAntonio Quartulli return send_other_tt_response(bat_priv, tt_request); 1382a73105b8SAntonio Quartulli } 1383a73105b8SAntonio Quartulli 1384a73105b8SAntonio Quartulli static void _tt_update_changes(struct bat_priv *bat_priv, 1385a73105b8SAntonio Quartulli struct orig_node *orig_node, 1386a73105b8SAntonio Quartulli struct tt_change *tt_change, 1387a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 1388a73105b8SAntonio Quartulli { 1389a73105b8SAntonio Quartulli int i; 1390a73105b8SAntonio Quartulli 1391a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 13925fbc1598SAntonio Quartulli if ((tt_change + i)->flags & TT_CLIENT_DEL) 1393a73105b8SAntonio Quartulli tt_global_del(bat_priv, orig_node, 1394a73105b8SAntonio Quartulli (tt_change + i)->addr, 1395cc47f66eSAntonio Quartulli "tt removed by changes", 1396cc47f66eSAntonio Quartulli (tt_change + i)->flags & TT_CLIENT_ROAM); 1397a73105b8SAntonio Quartulli else 1398a73105b8SAntonio Quartulli if (!tt_global_add(bat_priv, orig_node, 1399bc279080SAntonio Quartulli (tt_change + i)->addr, ttvn, false, 1400bc279080SAntonio Quartulli (tt_change + i)->flags & 1401bc279080SAntonio Quartulli TT_CLIENT_WIFI)) 1402a73105b8SAntonio Quartulli /* In case of problem while storing a 1403a73105b8SAntonio Quartulli * global_entry, we stop the updating 1404a73105b8SAntonio Quartulli * procedure without committing the 1405a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 1406a73105b8SAntonio Quartulli * corrupted data on tt_request 1407a73105b8SAntonio Quartulli */ 1408a73105b8SAntonio Quartulli return; 1409a73105b8SAntonio Quartulli } 1410a73105b8SAntonio Quartulli } 1411a73105b8SAntonio Quartulli 1412a73105b8SAntonio Quartulli static void tt_fill_gtable(struct bat_priv *bat_priv, 1413a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1414a73105b8SAntonio Quartulli { 1415a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1416a73105b8SAntonio Quartulli 1417a73105b8SAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_response->src); 1418a73105b8SAntonio Quartulli if (!orig_node) 1419a73105b8SAntonio Quartulli goto out; 1420a73105b8SAntonio Quartulli 1421a73105b8SAntonio Quartulli /* Purge the old table first.. */ 1422a73105b8SAntonio Quartulli tt_global_del_orig(bat_priv, orig_node, "Received full table"); 1423a73105b8SAntonio Quartulli 1424a73105b8SAntonio Quartulli _tt_update_changes(bat_priv, orig_node, 1425a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1), 1426a73105b8SAntonio Quartulli tt_response->tt_data, tt_response->ttvn); 1427a73105b8SAntonio Quartulli 1428a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1429a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1430a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1431a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 1432a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1433a73105b8SAntonio Quartulli 1434a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, tt_response->ttvn); 1435a73105b8SAntonio Quartulli 1436a73105b8SAntonio Quartulli out: 1437a73105b8SAntonio Quartulli if (orig_node) 1438a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1439a73105b8SAntonio Quartulli } 1440a73105b8SAntonio Quartulli 1441a73105b8SAntonio Quartulli void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node, 1442a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 1443a73105b8SAntonio Quartulli struct tt_change *tt_change) 1444a73105b8SAntonio Quartulli { 1445a73105b8SAntonio Quartulli _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes, 1446a73105b8SAntonio Quartulli ttvn); 1447a73105b8SAntonio Quartulli 1448a73105b8SAntonio Quartulli tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change, 1449a73105b8SAntonio Quartulli tt_num_changes); 1450a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 1451a73105b8SAntonio Quartulli } 1452a73105b8SAntonio Quartulli 1453a73105b8SAntonio Quartulli bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) 1454a73105b8SAntonio Quartulli { 14557683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 14567683fdc1SAntonio Quartulli bool ret = false; 1457a73105b8SAntonio Quartulli 1458a73105b8SAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 14597683fdc1SAntonio Quartulli if (!tt_local_entry) 14607683fdc1SAntonio Quartulli goto out; 1461058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 1462058d0e26SAntonio Quartulli * consistency purpose) */ 1463058d0e26SAntonio Quartulli if (tt_local_entry->flags & TT_CLIENT_PENDING) 1464058d0e26SAntonio Quartulli goto out; 14657683fdc1SAntonio Quartulli ret = true; 14667683fdc1SAntonio Quartulli out: 1467a73105b8SAntonio Quartulli if (tt_local_entry) 14687683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 14697683fdc1SAntonio Quartulli return ret; 1470a73105b8SAntonio Quartulli } 1471a73105b8SAntonio Quartulli 1472a73105b8SAntonio Quartulli void handle_tt_response(struct bat_priv *bat_priv, 1473a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1474a73105b8SAntonio Quartulli { 1475a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1476a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1477a73105b8SAntonio Quartulli 1478a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for " 1479a73105b8SAntonio Quartulli "ttvn %d t_size: %d [%c]\n", 1480a73105b8SAntonio Quartulli tt_response->src, tt_response->ttvn, 1481a73105b8SAntonio Quartulli tt_response->tt_data, 1482a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1483a73105b8SAntonio Quartulli 1484a73105b8SAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_response->src); 1485a73105b8SAntonio Quartulli if (!orig_node) 1486a73105b8SAntonio Quartulli goto out; 1487a73105b8SAntonio Quartulli 1488a73105b8SAntonio Quartulli if (tt_response->flags & TT_FULL_TABLE) 1489a73105b8SAntonio Quartulli tt_fill_gtable(bat_priv, tt_response); 1490a73105b8SAntonio Quartulli else 1491a73105b8SAntonio Quartulli tt_update_changes(bat_priv, orig_node, tt_response->tt_data, 1492a73105b8SAntonio Quartulli tt_response->ttvn, 1493a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1)); 1494a73105b8SAntonio Quartulli 1495a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 1496a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1497a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 1498a73105b8SAntonio Quartulli if (!compare_eth(node->addr, tt_response->src)) 1499a73105b8SAntonio Quartulli continue; 1500a73105b8SAntonio Quartulli list_del(&node->list); 1501a73105b8SAntonio Quartulli kfree(node); 1502a73105b8SAntonio Quartulli } 1503a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1504a73105b8SAntonio Quartulli 1505a73105b8SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 1506a73105b8SAntonio Quartulli orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); 1507cc47f66eSAntonio Quartulli /* Roaming phase is over: tables are in sync again. I can 1508cc47f66eSAntonio Quartulli * unset the flag */ 1509cc47f66eSAntonio Quartulli orig_node->tt_poss_change = false; 1510a73105b8SAntonio Quartulli out: 1511a73105b8SAntonio Quartulli if (orig_node) 1512a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1513a73105b8SAntonio Quartulli } 1514a73105b8SAntonio Quartulli 1515a73105b8SAntonio Quartulli int tt_init(struct bat_priv *bat_priv) 1516a73105b8SAntonio Quartulli { 1517a73105b8SAntonio Quartulli if (!tt_local_init(bat_priv)) 1518a73105b8SAntonio Quartulli return 0; 1519a73105b8SAntonio Quartulli 1520a73105b8SAntonio Quartulli if (!tt_global_init(bat_priv)) 1521a73105b8SAntonio Quartulli return 0; 1522a73105b8SAntonio Quartulli 1523a73105b8SAntonio Quartulli tt_start_timer(bat_priv); 1524a73105b8SAntonio Quartulli 1525a73105b8SAntonio Quartulli return 1; 1526a73105b8SAntonio Quartulli } 1527a73105b8SAntonio Quartulli 1528cc47f66eSAntonio Quartulli static void tt_roam_list_free(struct bat_priv *bat_priv) 1529a73105b8SAntonio Quartulli { 1530cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1531a73105b8SAntonio Quartulli 1532cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1533a73105b8SAntonio Quartulli 1534cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1535cc47f66eSAntonio Quartulli list_del(&node->list); 1536cc47f66eSAntonio Quartulli kfree(node); 1537cc47f66eSAntonio Quartulli } 1538cc47f66eSAntonio Quartulli 1539cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1540cc47f66eSAntonio Quartulli } 1541cc47f66eSAntonio Quartulli 1542cc47f66eSAntonio Quartulli static void tt_roam_purge(struct bat_priv *bat_priv) 1543cc47f66eSAntonio Quartulli { 1544cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1545cc47f66eSAntonio Quartulli 1546cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1547cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1548cc47f66eSAntonio Quartulli if (!is_out_of_time(node->first_time, 1549cc47f66eSAntonio Quartulli ROAMING_MAX_TIME * 1000)) 1550cc47f66eSAntonio Quartulli continue; 1551cc47f66eSAntonio Quartulli 1552cc47f66eSAntonio Quartulli list_del(&node->list); 1553cc47f66eSAntonio Quartulli kfree(node); 1554cc47f66eSAntonio Quartulli } 1555cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1556cc47f66eSAntonio Quartulli } 1557cc47f66eSAntonio Quartulli 1558cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 1559cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 1560cc47f66eSAntonio Quartulli * will not be sent. 1561cc47f66eSAntonio Quartulli * 1562cc47f66eSAntonio Quartulli * returns true if the ROAMING_ADV can be sent, false otherwise */ 1563cc47f66eSAntonio Quartulli static bool tt_check_roam_count(struct bat_priv *bat_priv, 1564cc47f66eSAntonio Quartulli uint8_t *client) 1565cc47f66eSAntonio Quartulli { 1566cc47f66eSAntonio Quartulli struct tt_roam_node *tt_roam_node; 1567cc47f66eSAntonio Quartulli bool ret = false; 1568cc47f66eSAntonio Quartulli 1569cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1570cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 1571cc47f66eSAntonio Quartulli * reply from the same orig_node yet */ 1572cc47f66eSAntonio Quartulli list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) { 1573cc47f66eSAntonio Quartulli if (!compare_eth(tt_roam_node->addr, client)) 1574cc47f66eSAntonio Quartulli continue; 1575cc47f66eSAntonio Quartulli 1576cc47f66eSAntonio Quartulli if (is_out_of_time(tt_roam_node->first_time, 1577cc47f66eSAntonio Quartulli ROAMING_MAX_TIME * 1000)) 1578cc47f66eSAntonio Quartulli continue; 1579cc47f66eSAntonio Quartulli 1580cc47f66eSAntonio Quartulli if (!atomic_dec_not_zero(&tt_roam_node->counter)) 1581cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 1582cc47f66eSAntonio Quartulli goto unlock; 1583cc47f66eSAntonio Quartulli ret = true; 1584cc47f66eSAntonio Quartulli break; 1585cc47f66eSAntonio Quartulli } 1586cc47f66eSAntonio Quartulli 1587cc47f66eSAntonio Quartulli if (!ret) { 1588cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 1589cc47f66eSAntonio Quartulli if (!tt_roam_node) 1590cc47f66eSAntonio Quartulli goto unlock; 1591cc47f66eSAntonio Quartulli 1592cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 1593cc47f66eSAntonio Quartulli atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1); 1594cc47f66eSAntonio Quartulli memcpy(tt_roam_node->addr, client, ETH_ALEN); 1595cc47f66eSAntonio Quartulli 1596cc47f66eSAntonio Quartulli list_add(&tt_roam_node->list, &bat_priv->tt_roam_list); 1597cc47f66eSAntonio Quartulli ret = true; 1598cc47f66eSAntonio Quartulli } 1599cc47f66eSAntonio Quartulli 1600cc47f66eSAntonio Quartulli unlock: 1601cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1602cc47f66eSAntonio Quartulli return ret; 1603cc47f66eSAntonio Quartulli } 1604cc47f66eSAntonio Quartulli 1605cc47f66eSAntonio Quartulli void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 1606cc47f66eSAntonio Quartulli struct orig_node *orig_node) 1607cc47f66eSAntonio Quartulli { 1608cc47f66eSAntonio Quartulli struct neigh_node *neigh_node = NULL; 1609cc47f66eSAntonio Quartulli struct sk_buff *skb = NULL; 1610cc47f66eSAntonio Quartulli struct roam_adv_packet *roam_adv_packet; 1611cc47f66eSAntonio Quartulli int ret = 1; 1612cc47f66eSAntonio Quartulli struct hard_iface *primary_if; 1613cc47f66eSAntonio Quartulli 1614cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 1615cc47f66eSAntonio Quartulli * already roamed to us too many times */ 1616cc47f66eSAntonio Quartulli if (!tt_check_roam_count(bat_priv, client)) 1617cc47f66eSAntonio Quartulli goto out; 1618cc47f66eSAntonio Quartulli 1619cc47f66eSAntonio Quartulli skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN); 1620cc47f66eSAntonio Quartulli if (!skb) 1621cc47f66eSAntonio Quartulli goto out; 1622cc47f66eSAntonio Quartulli 1623cc47f66eSAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1624cc47f66eSAntonio Quartulli 1625cc47f66eSAntonio Quartulli roam_adv_packet = (struct roam_adv_packet *)skb_put(skb, 1626cc47f66eSAntonio Quartulli sizeof(struct roam_adv_packet)); 1627cc47f66eSAntonio Quartulli 1628cc47f66eSAntonio Quartulli roam_adv_packet->packet_type = BAT_ROAM_ADV; 1629cc47f66eSAntonio Quartulli roam_adv_packet->version = COMPAT_VERSION; 1630cc47f66eSAntonio Quartulli roam_adv_packet->ttl = TTL; 1631cc47f66eSAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1632cc47f66eSAntonio Quartulli if (!primary_if) 1633cc47f66eSAntonio Quartulli goto out; 1634cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1635cc47f66eSAntonio Quartulli hardif_free_ref(primary_if); 1636cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); 1637cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->client, client, ETH_ALEN); 1638cc47f66eSAntonio Quartulli 1639cc47f66eSAntonio Quartulli neigh_node = orig_node_get_router(orig_node); 1640cc47f66eSAntonio Quartulli if (!neigh_node) 1641cc47f66eSAntonio Quartulli goto out; 1642cc47f66eSAntonio Quartulli 1643cc47f66eSAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1644cc47f66eSAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM) via %pM\n", 1645cc47f66eSAntonio Quartulli orig_node->orig, client, neigh_node->addr); 1646cc47f66eSAntonio Quartulli 1647cc47f66eSAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1648cc47f66eSAntonio Quartulli ret = 0; 1649cc47f66eSAntonio Quartulli 1650cc47f66eSAntonio Quartulli out: 1651cc47f66eSAntonio Quartulli if (neigh_node) 1652cc47f66eSAntonio Quartulli neigh_node_free_ref(neigh_node); 1653cc47f66eSAntonio Quartulli if (ret) 1654cc47f66eSAntonio Quartulli kfree_skb(skb); 1655cc47f66eSAntonio Quartulli return; 1656a73105b8SAntonio Quartulli } 1657a73105b8SAntonio Quartulli 1658a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work) 1659a73105b8SAntonio Quartulli { 1660a73105b8SAntonio Quartulli struct delayed_work *delayed_work = 1661a73105b8SAntonio Quartulli container_of(work, struct delayed_work, work); 1662a73105b8SAntonio Quartulli struct bat_priv *bat_priv = 1663a73105b8SAntonio Quartulli container_of(delayed_work, struct bat_priv, tt_work); 1664a73105b8SAntonio Quartulli 1665a73105b8SAntonio Quartulli tt_local_purge(bat_priv); 1666cc47f66eSAntonio Quartulli tt_global_roam_purge(bat_priv); 1667a73105b8SAntonio Quartulli tt_req_purge(bat_priv); 1668cc47f66eSAntonio Quartulli tt_roam_purge(bat_priv); 1669a73105b8SAntonio Quartulli 1670a73105b8SAntonio Quartulli tt_start_timer(bat_priv); 1671a73105b8SAntonio Quartulli } 1672cc47f66eSAntonio Quartulli 1673cc47f66eSAntonio Quartulli void tt_free(struct bat_priv *bat_priv) 1674cc47f66eSAntonio Quartulli { 1675cc47f66eSAntonio Quartulli cancel_delayed_work_sync(&bat_priv->tt_work); 1676cc47f66eSAntonio Quartulli 1677cc47f66eSAntonio Quartulli tt_local_table_free(bat_priv); 1678cc47f66eSAntonio Quartulli tt_global_table_free(bat_priv); 1679cc47f66eSAntonio Quartulli tt_req_list_free(bat_priv); 1680cc47f66eSAntonio Quartulli tt_changes_list_free(bat_priv); 1681cc47f66eSAntonio Quartulli tt_roam_list_free(bat_priv); 1682cc47f66eSAntonio Quartulli 1683cc47f66eSAntonio Quartulli kfree(bat_priv->tt_buff); 1684cc47f66eSAntonio Quartulli } 1685058d0e26SAntonio Quartulli 1686058d0e26SAntonio Quartulli /* This function will reset the specified flags from all the entries in 1687058d0e26SAntonio Quartulli * the given hash table and will increment num_local_tt for each involved 1688058d0e26SAntonio Quartulli * entry */ 1689058d0e26SAntonio Quartulli static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags) 1690058d0e26SAntonio Quartulli { 1691058d0e26SAntonio Quartulli int i; 1692058d0e26SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 1693058d0e26SAntonio Quartulli struct hlist_head *head; 1694058d0e26SAntonio Quartulli struct hlist_node *node; 1695058d0e26SAntonio Quartulli struct tt_local_entry *tt_local_entry; 1696058d0e26SAntonio Quartulli 1697058d0e26SAntonio Quartulli if (!hash) 1698058d0e26SAntonio Quartulli return; 1699058d0e26SAntonio Quartulli 1700058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1701058d0e26SAntonio Quartulli head = &hash->table[i]; 1702058d0e26SAntonio Quartulli 1703058d0e26SAntonio Quartulli rcu_read_lock(); 1704058d0e26SAntonio Quartulli hlist_for_each_entry_rcu(tt_local_entry, node, 1705058d0e26SAntonio Quartulli head, hash_entry) { 1706058d0e26SAntonio Quartulli tt_local_entry->flags &= ~flags; 1707058d0e26SAntonio Quartulli atomic_inc(&bat_priv->num_local_tt); 1708058d0e26SAntonio Quartulli } 1709058d0e26SAntonio Quartulli rcu_read_unlock(); 1710058d0e26SAntonio Quartulli } 1711058d0e26SAntonio Quartulli 1712058d0e26SAntonio Quartulli } 1713058d0e26SAntonio Quartulli 1714058d0e26SAntonio Quartulli /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ 1715058d0e26SAntonio Quartulli static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) 1716058d0e26SAntonio Quartulli { 1717058d0e26SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 1718058d0e26SAntonio Quartulli struct tt_local_entry *tt_local_entry; 1719058d0e26SAntonio Quartulli struct hlist_node *node, *node_tmp; 1720058d0e26SAntonio Quartulli struct hlist_head *head; 1721058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 1722058d0e26SAntonio Quartulli int i; 1723058d0e26SAntonio Quartulli 1724058d0e26SAntonio Quartulli if (!hash) 1725058d0e26SAntonio Quartulli return; 1726058d0e26SAntonio Quartulli 1727058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1728058d0e26SAntonio Quartulli head = &hash->table[i]; 1729058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 1730058d0e26SAntonio Quartulli 1731058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 1732058d0e26SAntonio Quartulli hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, 1733058d0e26SAntonio Quartulli head, hash_entry) { 1734058d0e26SAntonio Quartulli if (!(tt_local_entry->flags & TT_CLIENT_PENDING)) 1735058d0e26SAntonio Quartulli continue; 1736058d0e26SAntonio Quartulli 1737058d0e26SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " 1738058d0e26SAntonio Quartulli "(%pM): pending\n", tt_local_entry->addr); 1739058d0e26SAntonio Quartulli 1740058d0e26SAntonio Quartulli atomic_dec(&bat_priv->num_local_tt); 1741058d0e26SAntonio Quartulli hlist_del_rcu(node); 1742058d0e26SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 1743058d0e26SAntonio Quartulli } 1744058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 1745058d0e26SAntonio Quartulli } 1746058d0e26SAntonio Quartulli 1747058d0e26SAntonio Quartulli } 1748058d0e26SAntonio Quartulli 1749058d0e26SAntonio Quartulli void tt_commit_changes(struct bat_priv *bat_priv) 1750058d0e26SAntonio Quartulli { 1751058d0e26SAntonio Quartulli tt_local_reset_flags(bat_priv, TT_CLIENT_NEW); 1752058d0e26SAntonio Quartulli tt_local_purge_pending_clients(bat_priv); 1753058d0e26SAntonio Quartulli 1754058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 1755058d0e26SAntonio Quartulli atomic_inc(&bat_priv->ttvn); 1756058d0e26SAntonio Quartulli bat_priv->tt_poss_change = false; 1757058d0e26SAntonio Quartulli } 175859b699cdSAntonio Quartulli 175959b699cdSAntonio Quartulli bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst) 176059b699cdSAntonio Quartulli { 176159b699cdSAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 176259b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 176359b699cdSAntonio Quartulli bool ret = true; 176459b699cdSAntonio Quartulli 176559b699cdSAntonio Quartulli if (!atomic_read(&bat_priv->ap_isolation)) 176659b699cdSAntonio Quartulli return false; 176759b699cdSAntonio Quartulli 176859b699cdSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, dst); 176959b699cdSAntonio Quartulli if (!tt_local_entry) 177059b699cdSAntonio Quartulli goto out; 177159b699cdSAntonio Quartulli 177259b699cdSAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, src); 177359b699cdSAntonio Quartulli if (!tt_global_entry) 177459b699cdSAntonio Quartulli goto out; 177559b699cdSAntonio Quartulli 177659b699cdSAntonio Quartulli if (_is_ap_isolated(tt_local_entry, tt_global_entry)) 177759b699cdSAntonio Quartulli goto out; 177859b699cdSAntonio Quartulli 177959b699cdSAntonio Quartulli ret = false; 178059b699cdSAntonio Quartulli 178159b699cdSAntonio Quartulli out: 178259b699cdSAntonio Quartulli if (tt_global_entry) 178359b699cdSAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 178459b699cdSAntonio Quartulli if (tt_local_entry) 178559b699cdSAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 178659b699cdSAntonio Quartulli return ret; 178759b699cdSAntonio Quartulli } 1788