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 784747e4221SSven Eckelmann struct orig_node *transtable_search(struct bat_priv *bat_priv, 785747e4221SSven Eckelmann const uint8_t *addr) 786c6c8fea2SSven Eckelmann { 7872dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 7887b36e8eeSMarek Lindner struct orig_node *orig_node = NULL; 789c6c8fea2SSven Eckelmann 7902dafb49dSAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 7917aadf889SMarek Lindner 7922dafb49dSAntonio Quartulli if (!tt_global_entry) 7937b36e8eeSMarek Lindner goto out; 794c6c8fea2SSven Eckelmann 7952dafb49dSAntonio Quartulli if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) 7967683fdc1SAntonio Quartulli goto free_tt; 7977b36e8eeSMarek Lindner 798980d55b2SAntonio Quartulli /* A global client marked as PENDING has already moved from that 799980d55b2SAntonio Quartulli * originator */ 800980d55b2SAntonio Quartulli if (tt_global_entry->flags & TT_CLIENT_PENDING) 801980d55b2SAntonio Quartulli goto free_tt; 802980d55b2SAntonio Quartulli 8032dafb49dSAntonio Quartulli orig_node = tt_global_entry->orig_node; 8047b36e8eeSMarek Lindner 8057683fdc1SAntonio Quartulli free_tt: 8067683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 8077b36e8eeSMarek Lindner out: 8087b36e8eeSMarek Lindner return orig_node; 809c6c8fea2SSven Eckelmann } 810a73105b8SAntonio Quartulli 811a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */ 812a73105b8SAntonio Quartulli uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node) 813a73105b8SAntonio Quartulli { 814a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 815a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 816a73105b8SAntonio Quartulli struct tt_global_entry *tt_global_entry; 817a73105b8SAntonio Quartulli struct hlist_node *node; 818a73105b8SAntonio Quartulli struct hlist_head *head; 819a73105b8SAntonio Quartulli int i, j; 820a73105b8SAntonio Quartulli 821a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 822a73105b8SAntonio Quartulli head = &hash->table[i]; 823a73105b8SAntonio Quartulli 824a73105b8SAntonio Quartulli rcu_read_lock(); 825a73105b8SAntonio Quartulli hlist_for_each_entry_rcu(tt_global_entry, node, 826a73105b8SAntonio Quartulli head, hash_entry) { 827a73105b8SAntonio Quartulli if (compare_eth(tt_global_entry->orig_node, 828a73105b8SAntonio Quartulli orig_node)) { 829cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 830cc47f66eSAntonio Quartulli * consistency only. They don't have to be 831cc47f66eSAntonio Quartulli * taken into account while computing the 832cc47f66eSAntonio Quartulli * global crc */ 833cc47f66eSAntonio Quartulli if (tt_global_entry->flags & TT_CLIENT_ROAM) 834cc47f66eSAntonio Quartulli continue; 835a73105b8SAntonio Quartulli total_one = 0; 836a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 837a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 838a73105b8SAntonio Quartulli tt_global_entry->addr[j]); 839a73105b8SAntonio Quartulli total ^= total_one; 840a73105b8SAntonio Quartulli } 841a73105b8SAntonio Quartulli } 842a73105b8SAntonio Quartulli rcu_read_unlock(); 843a73105b8SAntonio Quartulli } 844a73105b8SAntonio Quartulli 845a73105b8SAntonio Quartulli return total; 846a73105b8SAntonio Quartulli } 847a73105b8SAntonio Quartulli 848a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */ 849a73105b8SAntonio Quartulli uint16_t tt_local_crc(struct bat_priv *bat_priv) 850a73105b8SAntonio Quartulli { 851a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 852a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 853a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 854a73105b8SAntonio Quartulli struct hlist_node *node; 855a73105b8SAntonio Quartulli struct hlist_head *head; 856a73105b8SAntonio Quartulli int i, j; 857a73105b8SAntonio Quartulli 858a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 859a73105b8SAntonio Quartulli head = &hash->table[i]; 860a73105b8SAntonio Quartulli 861a73105b8SAntonio Quartulli rcu_read_lock(); 862a73105b8SAntonio Quartulli hlist_for_each_entry_rcu(tt_local_entry, node, 863a73105b8SAntonio Quartulli head, hash_entry) { 864058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 865058d0e26SAntonio Quartulli * account while computing the CRC */ 866058d0e26SAntonio Quartulli if (tt_local_entry->flags & TT_CLIENT_NEW) 867058d0e26SAntonio Quartulli continue; 868a73105b8SAntonio Quartulli total_one = 0; 869a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 870a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 871a73105b8SAntonio Quartulli tt_local_entry->addr[j]); 872a73105b8SAntonio Quartulli total ^= total_one; 873a73105b8SAntonio Quartulli } 874a73105b8SAntonio Quartulli rcu_read_unlock(); 875a73105b8SAntonio Quartulli } 876a73105b8SAntonio Quartulli 877a73105b8SAntonio Quartulli return total; 878a73105b8SAntonio Quartulli } 879a73105b8SAntonio Quartulli 880a73105b8SAntonio Quartulli static void tt_req_list_free(struct bat_priv *bat_priv) 881a73105b8SAntonio Quartulli { 882a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 883a73105b8SAntonio Quartulli 884a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 885a73105b8SAntonio Quartulli 886a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 887a73105b8SAntonio Quartulli list_del(&node->list); 888a73105b8SAntonio Quartulli kfree(node); 889a73105b8SAntonio Quartulli } 890a73105b8SAntonio Quartulli 891a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 892a73105b8SAntonio Quartulli } 893a73105b8SAntonio Quartulli 894a73105b8SAntonio Quartulli void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node, 895a73105b8SAntonio Quartulli const unsigned char *tt_buff, uint8_t tt_num_changes) 896a73105b8SAntonio Quartulli { 897a73105b8SAntonio Quartulli uint16_t tt_buff_len = tt_len(tt_num_changes); 898a73105b8SAntonio Quartulli 899a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 900a73105b8SAntonio Quartulli * last OGM (the OGM could carry no changes) */ 901a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 902a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 903a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 904a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 905a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 906a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 907a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 908a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 909a73105b8SAntonio Quartulli } 910a73105b8SAntonio Quartulli } 911a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 912a73105b8SAntonio Quartulli } 913a73105b8SAntonio Quartulli 914a73105b8SAntonio Quartulli static void tt_req_purge(struct bat_priv *bat_priv) 915a73105b8SAntonio Quartulli { 916a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 917a73105b8SAntonio Quartulli 918a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 919a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 920a73105b8SAntonio Quartulli if (is_out_of_time(node->issued_at, 921a73105b8SAntonio Quartulli TT_REQUEST_TIMEOUT * 1000)) { 922a73105b8SAntonio Quartulli list_del(&node->list); 923a73105b8SAntonio Quartulli kfree(node); 924a73105b8SAntonio Quartulli } 925a73105b8SAntonio Quartulli } 926a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 927a73105b8SAntonio Quartulli } 928a73105b8SAntonio Quartulli 929a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 930a73105b8SAntonio Quartulli * has already been issued for this orig_node, NULL otherwise */ 931a73105b8SAntonio Quartulli static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv, 932a73105b8SAntonio Quartulli struct orig_node *orig_node) 933a73105b8SAntonio Quartulli { 934a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 935a73105b8SAntonio Quartulli 936a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 937a73105b8SAntonio Quartulli list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { 938a73105b8SAntonio Quartulli if (compare_eth(tt_req_node_tmp, orig_node) && 939a73105b8SAntonio Quartulli !is_out_of_time(tt_req_node_tmp->issued_at, 940a73105b8SAntonio Quartulli TT_REQUEST_TIMEOUT * 1000)) 941a73105b8SAntonio Quartulli goto unlock; 942a73105b8SAntonio Quartulli } 943a73105b8SAntonio Quartulli 944a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 945a73105b8SAntonio Quartulli if (!tt_req_node) 946a73105b8SAntonio Quartulli goto unlock; 947a73105b8SAntonio Quartulli 948a73105b8SAntonio Quartulli memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); 949a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 950a73105b8SAntonio Quartulli 951a73105b8SAntonio Quartulli list_add(&tt_req_node->list, &bat_priv->tt_req_list); 952a73105b8SAntonio Quartulli unlock: 953a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 954a73105b8SAntonio Quartulli return tt_req_node; 955a73105b8SAntonio Quartulli } 956a73105b8SAntonio Quartulli 957058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */ 958058d0e26SAntonio Quartulli static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr) 959058d0e26SAntonio Quartulli { 960058d0e26SAntonio Quartulli const struct tt_local_entry *tt_local_entry = entry_ptr; 961058d0e26SAntonio Quartulli 962058d0e26SAntonio Quartulli if (tt_local_entry->flags & TT_CLIENT_NEW) 963058d0e26SAntonio Quartulli return 0; 964058d0e26SAntonio Quartulli return 1; 965058d0e26SAntonio Quartulli } 966058d0e26SAntonio Quartulli 967a73105b8SAntonio Quartulli static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) 968a73105b8SAntonio Quartulli { 969a73105b8SAntonio Quartulli const struct tt_global_entry *tt_global_entry = entry_ptr; 970a73105b8SAntonio Quartulli const struct orig_node *orig_node = data_ptr; 971a73105b8SAntonio Quartulli 972cc47f66eSAntonio Quartulli if (tt_global_entry->flags & TT_CLIENT_ROAM) 973cc47f66eSAntonio Quartulli return 0; 974cc47f66eSAntonio Quartulli 975a73105b8SAntonio Quartulli return (tt_global_entry->orig_node == orig_node); 976a73105b8SAntonio Quartulli } 977a73105b8SAntonio Quartulli 978a73105b8SAntonio Quartulli static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, 979a73105b8SAntonio Quartulli struct hashtable_t *hash, 980a73105b8SAntonio Quartulli struct hard_iface *primary_if, 981a73105b8SAntonio Quartulli int (*valid_cb)(const void *, 982a73105b8SAntonio Quartulli const void *), 983a73105b8SAntonio Quartulli void *cb_data) 984a73105b8SAntonio Quartulli { 985a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 986a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 987a73105b8SAntonio Quartulli struct tt_change *tt_change; 988a73105b8SAntonio Quartulli struct hlist_node *node; 989a73105b8SAntonio Quartulli struct hlist_head *head; 990a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 991a73105b8SAntonio Quartulli uint16_t tt_tot, tt_count; 992a73105b8SAntonio Quartulli ssize_t tt_query_size = sizeof(struct tt_query_packet); 993a73105b8SAntonio Quartulli int i; 994a73105b8SAntonio Quartulli 995a73105b8SAntonio Quartulli if (tt_query_size + tt_len > primary_if->soft_iface->mtu) { 996a73105b8SAntonio Quartulli tt_len = primary_if->soft_iface->mtu - tt_query_size; 997a73105b8SAntonio Quartulli tt_len -= tt_len % sizeof(struct tt_change); 998a73105b8SAntonio Quartulli } 999a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1000a73105b8SAntonio Quartulli 1001a73105b8SAntonio Quartulli skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN); 1002a73105b8SAntonio Quartulli if (!skb) 1003a73105b8SAntonio Quartulli goto out; 1004a73105b8SAntonio Quartulli 1005a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1006a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1007a73105b8SAntonio Quartulli tt_query_size + tt_len); 1008a73105b8SAntonio Quartulli tt_response->ttvn = ttvn; 1009a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1010a73105b8SAntonio Quartulli 1011a73105b8SAntonio Quartulli tt_change = (struct tt_change *)(skb->data + tt_query_size); 1012a73105b8SAntonio Quartulli tt_count = 0; 1013a73105b8SAntonio Quartulli 1014a73105b8SAntonio Quartulli rcu_read_lock(); 1015a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1016a73105b8SAntonio Quartulli head = &hash->table[i]; 1017a73105b8SAntonio Quartulli 1018a73105b8SAntonio Quartulli hlist_for_each_entry_rcu(tt_local_entry, node, 1019a73105b8SAntonio Quartulli head, hash_entry) { 1020a73105b8SAntonio Quartulli if (tt_count == tt_tot) 1021a73105b8SAntonio Quartulli break; 1022a73105b8SAntonio Quartulli 1023a73105b8SAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data))) 1024a73105b8SAntonio Quartulli continue; 1025a73105b8SAntonio Quartulli 1026a73105b8SAntonio Quartulli memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN); 1027a73105b8SAntonio Quartulli tt_change->flags = NO_FLAGS; 1028a73105b8SAntonio Quartulli 1029a73105b8SAntonio Quartulli tt_count++; 1030a73105b8SAntonio Quartulli tt_change++; 1031a73105b8SAntonio Quartulli } 1032a73105b8SAntonio Quartulli } 1033a73105b8SAntonio Quartulli rcu_read_unlock(); 1034a73105b8SAntonio Quartulli 1035a73105b8SAntonio Quartulli out: 1036a73105b8SAntonio Quartulli return skb; 1037a73105b8SAntonio Quartulli } 1038a73105b8SAntonio Quartulli 1039a73105b8SAntonio Quartulli int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_orig_node, 1040a73105b8SAntonio Quartulli uint8_t ttvn, uint16_t tt_crc, bool full_table) 1041a73105b8SAntonio Quartulli { 1042a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1043a73105b8SAntonio Quartulli struct tt_query_packet *tt_request; 1044a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1045a73105b8SAntonio Quartulli struct hard_iface *primary_if; 1046a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node = NULL; 1047a73105b8SAntonio Quartulli int ret = 1; 1048a73105b8SAntonio Quartulli 1049a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1050a73105b8SAntonio Quartulli if (!primary_if) 1051a73105b8SAntonio Quartulli goto out; 1052a73105b8SAntonio Quartulli 1053a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 1054a73105b8SAntonio Quartulli * reply from the same orig_node yet */ 1055a73105b8SAntonio Quartulli tt_req_node = new_tt_req_node(bat_priv, dst_orig_node); 1056a73105b8SAntonio Quartulli if (!tt_req_node) 1057a73105b8SAntonio Quartulli goto out; 1058a73105b8SAntonio Quartulli 1059a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN); 1060a73105b8SAntonio Quartulli if (!skb) 1061a73105b8SAntonio Quartulli goto out; 1062a73105b8SAntonio Quartulli 1063a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1064a73105b8SAntonio Quartulli 1065a73105b8SAntonio Quartulli tt_request = (struct tt_query_packet *)skb_put(skb, 1066a73105b8SAntonio Quartulli sizeof(struct tt_query_packet)); 1067a73105b8SAntonio Quartulli 1068a73105b8SAntonio Quartulli tt_request->packet_type = BAT_TT_QUERY; 1069a73105b8SAntonio Quartulli tt_request->version = COMPAT_VERSION; 1070a73105b8SAntonio Quartulli memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1071a73105b8SAntonio Quartulli memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); 1072a73105b8SAntonio Quartulli tt_request->ttl = TTL; 1073a73105b8SAntonio Quartulli tt_request->ttvn = ttvn; 1074a73105b8SAntonio Quartulli tt_request->tt_data = tt_crc; 1075a73105b8SAntonio Quartulli tt_request->flags = TT_REQUEST; 1076a73105b8SAntonio Quartulli 1077a73105b8SAntonio Quartulli if (full_table) 1078a73105b8SAntonio Quartulli tt_request->flags |= TT_FULL_TABLE; 1079a73105b8SAntonio Quartulli 1080a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(dst_orig_node); 1081a73105b8SAntonio Quartulli if (!neigh_node) 1082a73105b8SAntonio Quartulli goto out; 1083a73105b8SAntonio Quartulli 1084a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM " 1085a73105b8SAntonio Quartulli "[%c]\n", dst_orig_node->orig, neigh_node->addr, 1086a73105b8SAntonio Quartulli (full_table ? 'F' : '.')); 1087a73105b8SAntonio Quartulli 1088a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1089a73105b8SAntonio Quartulli ret = 0; 1090a73105b8SAntonio Quartulli 1091a73105b8SAntonio Quartulli out: 1092a73105b8SAntonio Quartulli if (neigh_node) 1093a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1094a73105b8SAntonio Quartulli if (primary_if) 1095a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1096a73105b8SAntonio Quartulli if (ret) 1097a73105b8SAntonio Quartulli kfree_skb(skb); 1098a73105b8SAntonio Quartulli if (ret && tt_req_node) { 1099a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1100a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 1101a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1102a73105b8SAntonio Quartulli kfree(tt_req_node); 1103a73105b8SAntonio Quartulli } 1104a73105b8SAntonio Quartulli return ret; 1105a73105b8SAntonio Quartulli } 1106a73105b8SAntonio Quartulli 1107a73105b8SAntonio Quartulli static bool send_other_tt_response(struct bat_priv *bat_priv, 1108a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1109a73105b8SAntonio Quartulli { 1110a73105b8SAntonio Quartulli struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL; 1111a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1112a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1113a73105b8SAntonio Quartulli uint8_t orig_ttvn, req_ttvn, ttvn; 1114a73105b8SAntonio Quartulli int ret = false; 1115a73105b8SAntonio Quartulli unsigned char *tt_buff; 1116a73105b8SAntonio Quartulli bool full_table; 1117a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1118a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1119a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1120a73105b8SAntonio Quartulli 1121a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1122a73105b8SAntonio Quartulli "Received TT_REQUEST from %pM for " 1123a73105b8SAntonio Quartulli "ttvn: %u (%pM) [%c]\n", tt_request->src, 1124a73105b8SAntonio Quartulli tt_request->ttvn, tt_request->dst, 1125a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1126a73105b8SAntonio Quartulli 1127a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 1128a73105b8SAntonio Quartulli req_dst_orig_node = get_orig_node(bat_priv, tt_request->dst); 1129a73105b8SAntonio Quartulli if (!req_dst_orig_node) 1130a73105b8SAntonio Quartulli goto out; 1131a73105b8SAntonio Quartulli 1132a73105b8SAntonio Quartulli res_dst_orig_node = get_orig_node(bat_priv, tt_request->src); 1133a73105b8SAntonio Quartulli if (!res_dst_orig_node) 1134a73105b8SAntonio Quartulli goto out; 1135a73105b8SAntonio Quartulli 1136a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(res_dst_orig_node); 1137a73105b8SAntonio Quartulli if (!neigh_node) 1138a73105b8SAntonio Quartulli goto out; 1139a73105b8SAntonio Quartulli 1140a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1141a73105b8SAntonio Quartulli if (!primary_if) 1142a73105b8SAntonio Quartulli goto out; 1143a73105b8SAntonio Quartulli 1144a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1145a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1146a73105b8SAntonio Quartulli 1147015758d0SAntonio Quartulli /* I don't have the requested data */ 1148a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 1149a73105b8SAntonio Quartulli tt_request->tt_data != req_dst_orig_node->tt_crc) 1150a73105b8SAntonio Quartulli goto out; 1151a73105b8SAntonio Quartulli 1152015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 1153a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || 1154a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 1155a73105b8SAntonio Quartulli full_table = true; 1156a73105b8SAntonio Quartulli else 1157a73105b8SAntonio Quartulli full_table = false; 1158a73105b8SAntonio Quartulli 1159a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 1160a73105b8SAntonio Quartulli * I'll send only one packet with as much TT entries as I can */ 1161a73105b8SAntonio Quartulli if (!full_table) { 1162a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 1163a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 1164a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1165a73105b8SAntonio Quartulli 1166a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1167a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1168a73105b8SAntonio Quartulli if (!skb) 1169a73105b8SAntonio Quartulli goto unlock; 1170a73105b8SAntonio Quartulli 1171a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1172a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1173a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1174a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1175a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1176a73105b8SAntonio Quartulli 1177a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1178a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 1179a73105b8SAntonio Quartulli memcpy(tt_buff, req_dst_orig_node->tt_buff, 1180a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 1181a73105b8SAntonio Quartulli 1182a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1183a73105b8SAntonio Quartulli } else { 1184a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) * 1185a73105b8SAntonio Quartulli sizeof(struct tt_change); 1186a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1187a73105b8SAntonio Quartulli 1188a73105b8SAntonio Quartulli skb = tt_response_fill_table(tt_len, ttvn, 1189a73105b8SAntonio Quartulli bat_priv->tt_global_hash, 1190a73105b8SAntonio Quartulli primary_if, tt_global_valid_entry, 1191a73105b8SAntonio Quartulli req_dst_orig_node); 1192a73105b8SAntonio Quartulli if (!skb) 1193a73105b8SAntonio Quartulli goto out; 1194a73105b8SAntonio Quartulli 1195a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1196a73105b8SAntonio Quartulli } 1197a73105b8SAntonio Quartulli 1198a73105b8SAntonio Quartulli tt_response->packet_type = BAT_TT_QUERY; 1199a73105b8SAntonio Quartulli tt_response->version = COMPAT_VERSION; 1200a73105b8SAntonio Quartulli tt_response->ttl = TTL; 1201a73105b8SAntonio Quartulli memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); 1202a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1203a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1204a73105b8SAntonio Quartulli 1205a73105b8SAntonio Quartulli if (full_table) 1206a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1207a73105b8SAntonio Quartulli 1208a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1209a73105b8SAntonio Quartulli "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n", 1210a73105b8SAntonio Quartulli res_dst_orig_node->orig, neigh_node->addr, 1211a73105b8SAntonio Quartulli req_dst_orig_node->orig, req_ttvn); 1212a73105b8SAntonio Quartulli 1213a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1214a73105b8SAntonio Quartulli ret = true; 1215a73105b8SAntonio Quartulli goto out; 1216a73105b8SAntonio Quartulli 1217a73105b8SAntonio Quartulli unlock: 1218a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1219a73105b8SAntonio Quartulli 1220a73105b8SAntonio Quartulli out: 1221a73105b8SAntonio Quartulli if (res_dst_orig_node) 1222a73105b8SAntonio Quartulli orig_node_free_ref(res_dst_orig_node); 1223a73105b8SAntonio Quartulli if (req_dst_orig_node) 1224a73105b8SAntonio Quartulli orig_node_free_ref(req_dst_orig_node); 1225a73105b8SAntonio Quartulli if (neigh_node) 1226a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1227a73105b8SAntonio Quartulli if (primary_if) 1228a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1229a73105b8SAntonio Quartulli if (!ret) 1230a73105b8SAntonio Quartulli kfree_skb(skb); 1231a73105b8SAntonio Quartulli return ret; 1232a73105b8SAntonio Quartulli 1233a73105b8SAntonio Quartulli } 1234a73105b8SAntonio Quartulli static bool send_my_tt_response(struct bat_priv *bat_priv, 1235a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1236a73105b8SAntonio Quartulli { 1237a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1238a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1239a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1240a73105b8SAntonio Quartulli uint8_t my_ttvn, req_ttvn, ttvn; 1241a73105b8SAntonio Quartulli int ret = false; 1242a73105b8SAntonio Quartulli unsigned char *tt_buff; 1243a73105b8SAntonio Quartulli bool full_table; 1244a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1245a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1246a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1247a73105b8SAntonio Quartulli 1248a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1249a73105b8SAntonio Quartulli "Received TT_REQUEST from %pM for " 1250a73105b8SAntonio Quartulli "ttvn: %u (me) [%c]\n", tt_request->src, 1251a73105b8SAntonio Quartulli tt_request->ttvn, 1252a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1253a73105b8SAntonio Quartulli 1254a73105b8SAntonio Quartulli 1255a73105b8SAntonio Quartulli my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1256a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1257a73105b8SAntonio Quartulli 1258a73105b8SAntonio Quartulli orig_node = get_orig_node(bat_priv, tt_request->src); 1259a73105b8SAntonio Quartulli if (!orig_node) 1260a73105b8SAntonio Quartulli goto out; 1261a73105b8SAntonio Quartulli 1262a73105b8SAntonio Quartulli neigh_node = orig_node_get_router(orig_node); 1263a73105b8SAntonio Quartulli if (!neigh_node) 1264a73105b8SAntonio Quartulli goto out; 1265a73105b8SAntonio Quartulli 1266a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1267a73105b8SAntonio Quartulli if (!primary_if) 1268a73105b8SAntonio Quartulli goto out; 1269a73105b8SAntonio Quartulli 1270a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 1271a73105b8SAntonio Quartulli * is too big send the whole local translation table */ 1272a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn || 1273a73105b8SAntonio Quartulli !bat_priv->tt_buff) 1274a73105b8SAntonio Quartulli full_table = true; 1275a73105b8SAntonio Quartulli else 1276a73105b8SAntonio Quartulli full_table = false; 1277a73105b8SAntonio Quartulli 1278a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 1279a73105b8SAntonio Quartulli * I'll send only one packet with as much TT entries as I can */ 1280a73105b8SAntonio Quartulli if (!full_table) { 1281a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 1282a73105b8SAntonio Quartulli tt_len = bat_priv->tt_buff_len; 1283a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1284a73105b8SAntonio Quartulli 1285a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1286a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1287a73105b8SAntonio Quartulli if (!skb) 1288a73105b8SAntonio Quartulli goto unlock; 1289a73105b8SAntonio Quartulli 1290a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1291a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1292a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1293a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1294a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1295a73105b8SAntonio Quartulli 1296a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1297a73105b8SAntonio Quartulli memcpy(tt_buff, bat_priv->tt_buff, 1298a73105b8SAntonio Quartulli bat_priv->tt_buff_len); 1299a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1300a73105b8SAntonio Quartulli } else { 1301a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) * 1302a73105b8SAntonio Quartulli sizeof(struct tt_change); 1303a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1304a73105b8SAntonio Quartulli 1305a73105b8SAntonio Quartulli skb = tt_response_fill_table(tt_len, ttvn, 1306a73105b8SAntonio Quartulli bat_priv->tt_local_hash, 1307058d0e26SAntonio Quartulli primary_if, tt_local_valid_entry, 1308058d0e26SAntonio Quartulli NULL); 1309a73105b8SAntonio Quartulli if (!skb) 1310a73105b8SAntonio Quartulli goto out; 1311a73105b8SAntonio Quartulli 1312a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1313a73105b8SAntonio Quartulli } 1314a73105b8SAntonio Quartulli 1315a73105b8SAntonio Quartulli tt_response->packet_type = BAT_TT_QUERY; 1316a73105b8SAntonio Quartulli tt_response->version = COMPAT_VERSION; 1317a73105b8SAntonio Quartulli tt_response->ttl = TTL; 1318a73105b8SAntonio Quartulli memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1319a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1320a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1321a73105b8SAntonio Quartulli 1322a73105b8SAntonio Quartulli if (full_table) 1323a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1324a73105b8SAntonio Quartulli 1325a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1326a73105b8SAntonio Quartulli "Sending TT_RESPONSE to %pM via %pM [%c]\n", 1327a73105b8SAntonio Quartulli orig_node->orig, neigh_node->addr, 1328a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1329a73105b8SAntonio Quartulli 1330a73105b8SAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1331a73105b8SAntonio Quartulli ret = true; 1332a73105b8SAntonio Quartulli goto out; 1333a73105b8SAntonio Quartulli 1334a73105b8SAntonio Quartulli unlock: 1335a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1336a73105b8SAntonio Quartulli out: 1337a73105b8SAntonio Quartulli if (orig_node) 1338a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1339a73105b8SAntonio Quartulli if (neigh_node) 1340a73105b8SAntonio Quartulli neigh_node_free_ref(neigh_node); 1341a73105b8SAntonio Quartulli if (primary_if) 1342a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1343a73105b8SAntonio Quartulli if (!ret) 1344a73105b8SAntonio Quartulli kfree_skb(skb); 1345a73105b8SAntonio Quartulli /* This packet was for me, so it doesn't need to be re-routed */ 1346a73105b8SAntonio Quartulli return true; 1347a73105b8SAntonio Quartulli } 1348a73105b8SAntonio Quartulli 1349a73105b8SAntonio Quartulli bool send_tt_response(struct bat_priv *bat_priv, 1350a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1351a73105b8SAntonio Quartulli { 1352a73105b8SAntonio Quartulli if (is_my_mac(tt_request->dst)) 1353a73105b8SAntonio Quartulli return send_my_tt_response(bat_priv, tt_request); 1354a73105b8SAntonio Quartulli else 1355a73105b8SAntonio Quartulli return send_other_tt_response(bat_priv, tt_request); 1356a73105b8SAntonio Quartulli } 1357a73105b8SAntonio Quartulli 1358a73105b8SAntonio Quartulli static void _tt_update_changes(struct bat_priv *bat_priv, 1359a73105b8SAntonio Quartulli struct orig_node *orig_node, 1360a73105b8SAntonio Quartulli struct tt_change *tt_change, 1361a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 1362a73105b8SAntonio Quartulli { 1363a73105b8SAntonio Quartulli int i; 1364a73105b8SAntonio Quartulli 1365a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 13665fbc1598SAntonio Quartulli if ((tt_change + i)->flags & TT_CLIENT_DEL) 1367a73105b8SAntonio Quartulli tt_global_del(bat_priv, orig_node, 1368a73105b8SAntonio Quartulli (tt_change + i)->addr, 1369cc47f66eSAntonio Quartulli "tt removed by changes", 1370cc47f66eSAntonio Quartulli (tt_change + i)->flags & TT_CLIENT_ROAM); 1371a73105b8SAntonio Quartulli else 1372a73105b8SAntonio Quartulli if (!tt_global_add(bat_priv, orig_node, 1373bc279080SAntonio Quartulli (tt_change + i)->addr, ttvn, false, 1374bc279080SAntonio Quartulli (tt_change + i)->flags & 1375bc279080SAntonio Quartulli TT_CLIENT_WIFI)) 1376a73105b8SAntonio Quartulli /* In case of problem while storing a 1377a73105b8SAntonio Quartulli * global_entry, we stop the updating 1378a73105b8SAntonio Quartulli * procedure without committing the 1379a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 1380a73105b8SAntonio Quartulli * corrupted data on tt_request 1381a73105b8SAntonio Quartulli */ 1382a73105b8SAntonio Quartulli return; 1383a73105b8SAntonio Quartulli } 1384a73105b8SAntonio Quartulli } 1385a73105b8SAntonio Quartulli 1386a73105b8SAntonio Quartulli static void tt_fill_gtable(struct bat_priv *bat_priv, 1387a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1388a73105b8SAntonio Quartulli { 1389a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1390a73105b8SAntonio Quartulli 1391a73105b8SAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_response->src); 1392a73105b8SAntonio Quartulli if (!orig_node) 1393a73105b8SAntonio Quartulli goto out; 1394a73105b8SAntonio Quartulli 1395a73105b8SAntonio Quartulli /* Purge the old table first.. */ 1396a73105b8SAntonio Quartulli tt_global_del_orig(bat_priv, orig_node, "Received full table"); 1397a73105b8SAntonio Quartulli 1398a73105b8SAntonio Quartulli _tt_update_changes(bat_priv, orig_node, 1399a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1), 1400a73105b8SAntonio Quartulli tt_response->tt_data, tt_response->ttvn); 1401a73105b8SAntonio Quartulli 1402a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1403a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1404a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1405a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 1406a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1407a73105b8SAntonio Quartulli 1408a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, tt_response->ttvn); 1409a73105b8SAntonio Quartulli 1410a73105b8SAntonio Quartulli out: 1411a73105b8SAntonio Quartulli if (orig_node) 1412a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1413a73105b8SAntonio Quartulli } 1414a73105b8SAntonio Quartulli 1415a73105b8SAntonio Quartulli void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node, 1416a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 1417a73105b8SAntonio Quartulli struct tt_change *tt_change) 1418a73105b8SAntonio Quartulli { 1419a73105b8SAntonio Quartulli _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes, 1420a73105b8SAntonio Quartulli ttvn); 1421a73105b8SAntonio Quartulli 1422a73105b8SAntonio Quartulli tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change, 1423a73105b8SAntonio Quartulli tt_num_changes); 1424a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 1425a73105b8SAntonio Quartulli } 1426a73105b8SAntonio Quartulli 1427a73105b8SAntonio Quartulli bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) 1428a73105b8SAntonio Quartulli { 14297683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 14307683fdc1SAntonio Quartulli bool ret = false; 1431a73105b8SAntonio Quartulli 1432a73105b8SAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 14337683fdc1SAntonio Quartulli if (!tt_local_entry) 14347683fdc1SAntonio Quartulli goto out; 1435058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 1436058d0e26SAntonio Quartulli * consistency purpose) */ 1437058d0e26SAntonio Quartulli if (tt_local_entry->flags & TT_CLIENT_PENDING) 1438058d0e26SAntonio Quartulli goto out; 14397683fdc1SAntonio Quartulli ret = true; 14407683fdc1SAntonio Quartulli out: 1441a73105b8SAntonio Quartulli if (tt_local_entry) 14427683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 14437683fdc1SAntonio Quartulli return ret; 1444a73105b8SAntonio Quartulli } 1445a73105b8SAntonio Quartulli 1446a73105b8SAntonio Quartulli void handle_tt_response(struct bat_priv *bat_priv, 1447a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1448a73105b8SAntonio Quartulli { 1449a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1450a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1451a73105b8SAntonio Quartulli 1452a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for " 1453a73105b8SAntonio Quartulli "ttvn %d t_size: %d [%c]\n", 1454a73105b8SAntonio Quartulli tt_response->src, tt_response->ttvn, 1455a73105b8SAntonio Quartulli tt_response->tt_data, 1456a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1457a73105b8SAntonio Quartulli 1458a73105b8SAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_response->src); 1459a73105b8SAntonio Quartulli if (!orig_node) 1460a73105b8SAntonio Quartulli goto out; 1461a73105b8SAntonio Quartulli 1462a73105b8SAntonio Quartulli if (tt_response->flags & TT_FULL_TABLE) 1463a73105b8SAntonio Quartulli tt_fill_gtable(bat_priv, tt_response); 1464a73105b8SAntonio Quartulli else 1465a73105b8SAntonio Quartulli tt_update_changes(bat_priv, orig_node, tt_response->tt_data, 1466a73105b8SAntonio Quartulli tt_response->ttvn, 1467a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1)); 1468a73105b8SAntonio Quartulli 1469a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 1470a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1471a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 1472a73105b8SAntonio Quartulli if (!compare_eth(node->addr, tt_response->src)) 1473a73105b8SAntonio Quartulli continue; 1474a73105b8SAntonio Quartulli list_del(&node->list); 1475a73105b8SAntonio Quartulli kfree(node); 1476a73105b8SAntonio Quartulli } 1477a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1478a73105b8SAntonio Quartulli 1479a73105b8SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 1480a73105b8SAntonio Quartulli orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); 1481cc47f66eSAntonio Quartulli /* Roaming phase is over: tables are in sync again. I can 1482cc47f66eSAntonio Quartulli * unset the flag */ 1483cc47f66eSAntonio Quartulli orig_node->tt_poss_change = false; 1484a73105b8SAntonio Quartulli out: 1485a73105b8SAntonio Quartulli if (orig_node) 1486a73105b8SAntonio Quartulli orig_node_free_ref(orig_node); 1487a73105b8SAntonio Quartulli } 1488a73105b8SAntonio Quartulli 1489a73105b8SAntonio Quartulli int tt_init(struct bat_priv *bat_priv) 1490a73105b8SAntonio Quartulli { 1491a73105b8SAntonio Quartulli if (!tt_local_init(bat_priv)) 1492a73105b8SAntonio Quartulli return 0; 1493a73105b8SAntonio Quartulli 1494a73105b8SAntonio Quartulli if (!tt_global_init(bat_priv)) 1495a73105b8SAntonio Quartulli return 0; 1496a73105b8SAntonio Quartulli 1497a73105b8SAntonio Quartulli tt_start_timer(bat_priv); 1498a73105b8SAntonio Quartulli 1499a73105b8SAntonio Quartulli return 1; 1500a73105b8SAntonio Quartulli } 1501a73105b8SAntonio Quartulli 1502cc47f66eSAntonio Quartulli static void tt_roam_list_free(struct bat_priv *bat_priv) 1503a73105b8SAntonio Quartulli { 1504cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1505a73105b8SAntonio Quartulli 1506cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1507a73105b8SAntonio Quartulli 1508cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1509cc47f66eSAntonio Quartulli list_del(&node->list); 1510cc47f66eSAntonio Quartulli kfree(node); 1511cc47f66eSAntonio Quartulli } 1512cc47f66eSAntonio Quartulli 1513cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1514cc47f66eSAntonio Quartulli } 1515cc47f66eSAntonio Quartulli 1516cc47f66eSAntonio Quartulli static void tt_roam_purge(struct bat_priv *bat_priv) 1517cc47f66eSAntonio Quartulli { 1518cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1519cc47f66eSAntonio Quartulli 1520cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1521cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1522cc47f66eSAntonio Quartulli if (!is_out_of_time(node->first_time, 1523cc47f66eSAntonio Quartulli ROAMING_MAX_TIME * 1000)) 1524cc47f66eSAntonio Quartulli continue; 1525cc47f66eSAntonio Quartulli 1526cc47f66eSAntonio Quartulli list_del(&node->list); 1527cc47f66eSAntonio Quartulli kfree(node); 1528cc47f66eSAntonio Quartulli } 1529cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1530cc47f66eSAntonio Quartulli } 1531cc47f66eSAntonio Quartulli 1532cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 1533cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 1534cc47f66eSAntonio Quartulli * will not be sent. 1535cc47f66eSAntonio Quartulli * 1536cc47f66eSAntonio Quartulli * returns true if the ROAMING_ADV can be sent, false otherwise */ 1537cc47f66eSAntonio Quartulli static bool tt_check_roam_count(struct bat_priv *bat_priv, 1538cc47f66eSAntonio Quartulli uint8_t *client) 1539cc47f66eSAntonio Quartulli { 1540cc47f66eSAntonio Quartulli struct tt_roam_node *tt_roam_node; 1541cc47f66eSAntonio Quartulli bool ret = false; 1542cc47f66eSAntonio Quartulli 1543cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1544cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 1545cc47f66eSAntonio Quartulli * reply from the same orig_node yet */ 1546cc47f66eSAntonio Quartulli list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) { 1547cc47f66eSAntonio Quartulli if (!compare_eth(tt_roam_node->addr, client)) 1548cc47f66eSAntonio Quartulli continue; 1549cc47f66eSAntonio Quartulli 1550cc47f66eSAntonio Quartulli if (is_out_of_time(tt_roam_node->first_time, 1551cc47f66eSAntonio Quartulli ROAMING_MAX_TIME * 1000)) 1552cc47f66eSAntonio Quartulli continue; 1553cc47f66eSAntonio Quartulli 1554cc47f66eSAntonio Quartulli if (!atomic_dec_not_zero(&tt_roam_node->counter)) 1555cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 1556cc47f66eSAntonio Quartulli goto unlock; 1557cc47f66eSAntonio Quartulli ret = true; 1558cc47f66eSAntonio Quartulli break; 1559cc47f66eSAntonio Quartulli } 1560cc47f66eSAntonio Quartulli 1561cc47f66eSAntonio Quartulli if (!ret) { 1562cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 1563cc47f66eSAntonio Quartulli if (!tt_roam_node) 1564cc47f66eSAntonio Quartulli goto unlock; 1565cc47f66eSAntonio Quartulli 1566cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 1567cc47f66eSAntonio Quartulli atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1); 1568cc47f66eSAntonio Quartulli memcpy(tt_roam_node->addr, client, ETH_ALEN); 1569cc47f66eSAntonio Quartulli 1570cc47f66eSAntonio Quartulli list_add(&tt_roam_node->list, &bat_priv->tt_roam_list); 1571cc47f66eSAntonio Quartulli ret = true; 1572cc47f66eSAntonio Quartulli } 1573cc47f66eSAntonio Quartulli 1574cc47f66eSAntonio Quartulli unlock: 1575cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1576cc47f66eSAntonio Quartulli return ret; 1577cc47f66eSAntonio Quartulli } 1578cc47f66eSAntonio Quartulli 1579cc47f66eSAntonio Quartulli void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 1580cc47f66eSAntonio Quartulli struct orig_node *orig_node) 1581cc47f66eSAntonio Quartulli { 1582cc47f66eSAntonio Quartulli struct neigh_node *neigh_node = NULL; 1583cc47f66eSAntonio Quartulli struct sk_buff *skb = NULL; 1584cc47f66eSAntonio Quartulli struct roam_adv_packet *roam_adv_packet; 1585cc47f66eSAntonio Quartulli int ret = 1; 1586cc47f66eSAntonio Quartulli struct hard_iface *primary_if; 1587cc47f66eSAntonio Quartulli 1588cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 1589cc47f66eSAntonio Quartulli * already roamed to us too many times */ 1590cc47f66eSAntonio Quartulli if (!tt_check_roam_count(bat_priv, client)) 1591cc47f66eSAntonio Quartulli goto out; 1592cc47f66eSAntonio Quartulli 1593cc47f66eSAntonio Quartulli skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN); 1594cc47f66eSAntonio Quartulli if (!skb) 1595cc47f66eSAntonio Quartulli goto out; 1596cc47f66eSAntonio Quartulli 1597cc47f66eSAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1598cc47f66eSAntonio Quartulli 1599cc47f66eSAntonio Quartulli roam_adv_packet = (struct roam_adv_packet *)skb_put(skb, 1600cc47f66eSAntonio Quartulli sizeof(struct roam_adv_packet)); 1601cc47f66eSAntonio Quartulli 1602cc47f66eSAntonio Quartulli roam_adv_packet->packet_type = BAT_ROAM_ADV; 1603cc47f66eSAntonio Quartulli roam_adv_packet->version = COMPAT_VERSION; 1604cc47f66eSAntonio Quartulli roam_adv_packet->ttl = TTL; 1605cc47f66eSAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1606cc47f66eSAntonio Quartulli if (!primary_if) 1607cc47f66eSAntonio Quartulli goto out; 1608cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1609cc47f66eSAntonio Quartulli hardif_free_ref(primary_if); 1610cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); 1611cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->client, client, ETH_ALEN); 1612cc47f66eSAntonio Quartulli 1613cc47f66eSAntonio Quartulli neigh_node = orig_node_get_router(orig_node); 1614cc47f66eSAntonio Quartulli if (!neigh_node) 1615cc47f66eSAntonio Quartulli goto out; 1616cc47f66eSAntonio Quartulli 1617cc47f66eSAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1618cc47f66eSAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM) via %pM\n", 1619cc47f66eSAntonio Quartulli orig_node->orig, client, neigh_node->addr); 1620cc47f66eSAntonio Quartulli 1621cc47f66eSAntonio Quartulli send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1622cc47f66eSAntonio Quartulli ret = 0; 1623cc47f66eSAntonio Quartulli 1624cc47f66eSAntonio Quartulli out: 1625cc47f66eSAntonio Quartulli if (neigh_node) 1626cc47f66eSAntonio Quartulli neigh_node_free_ref(neigh_node); 1627cc47f66eSAntonio Quartulli if (ret) 1628cc47f66eSAntonio Quartulli kfree_skb(skb); 1629cc47f66eSAntonio Quartulli return; 1630a73105b8SAntonio Quartulli } 1631a73105b8SAntonio Quartulli 1632a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work) 1633a73105b8SAntonio Quartulli { 1634a73105b8SAntonio Quartulli struct delayed_work *delayed_work = 1635a73105b8SAntonio Quartulli container_of(work, struct delayed_work, work); 1636a73105b8SAntonio Quartulli struct bat_priv *bat_priv = 1637a73105b8SAntonio Quartulli container_of(delayed_work, struct bat_priv, tt_work); 1638a73105b8SAntonio Quartulli 1639a73105b8SAntonio Quartulli tt_local_purge(bat_priv); 1640cc47f66eSAntonio Quartulli tt_global_roam_purge(bat_priv); 1641a73105b8SAntonio Quartulli tt_req_purge(bat_priv); 1642cc47f66eSAntonio Quartulli tt_roam_purge(bat_priv); 1643a73105b8SAntonio Quartulli 1644a73105b8SAntonio Quartulli tt_start_timer(bat_priv); 1645a73105b8SAntonio Quartulli } 1646cc47f66eSAntonio Quartulli 1647cc47f66eSAntonio Quartulli void tt_free(struct bat_priv *bat_priv) 1648cc47f66eSAntonio Quartulli { 1649cc47f66eSAntonio Quartulli cancel_delayed_work_sync(&bat_priv->tt_work); 1650cc47f66eSAntonio Quartulli 1651cc47f66eSAntonio Quartulli tt_local_table_free(bat_priv); 1652cc47f66eSAntonio Quartulli tt_global_table_free(bat_priv); 1653cc47f66eSAntonio Quartulli tt_req_list_free(bat_priv); 1654cc47f66eSAntonio Quartulli tt_changes_list_free(bat_priv); 1655cc47f66eSAntonio Quartulli tt_roam_list_free(bat_priv); 1656cc47f66eSAntonio Quartulli 1657cc47f66eSAntonio Quartulli kfree(bat_priv->tt_buff); 1658cc47f66eSAntonio Quartulli } 1659058d0e26SAntonio Quartulli 1660058d0e26SAntonio Quartulli /* This function will reset the specified flags from all the entries in 1661058d0e26SAntonio Quartulli * the given hash table and will increment num_local_tt for each involved 1662058d0e26SAntonio Quartulli * entry */ 1663058d0e26SAntonio Quartulli static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags) 1664058d0e26SAntonio Quartulli { 1665058d0e26SAntonio Quartulli int i; 1666058d0e26SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 1667058d0e26SAntonio Quartulli struct hlist_head *head; 1668058d0e26SAntonio Quartulli struct hlist_node *node; 1669058d0e26SAntonio Quartulli struct tt_local_entry *tt_local_entry; 1670058d0e26SAntonio Quartulli 1671058d0e26SAntonio Quartulli if (!hash) 1672058d0e26SAntonio Quartulli return; 1673058d0e26SAntonio Quartulli 1674058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1675058d0e26SAntonio Quartulli head = &hash->table[i]; 1676058d0e26SAntonio Quartulli 1677058d0e26SAntonio Quartulli rcu_read_lock(); 1678058d0e26SAntonio Quartulli hlist_for_each_entry_rcu(tt_local_entry, node, 1679058d0e26SAntonio Quartulli head, hash_entry) { 1680058d0e26SAntonio Quartulli tt_local_entry->flags &= ~flags; 1681058d0e26SAntonio Quartulli atomic_inc(&bat_priv->num_local_tt); 1682058d0e26SAntonio Quartulli } 1683058d0e26SAntonio Quartulli rcu_read_unlock(); 1684058d0e26SAntonio Quartulli } 1685058d0e26SAntonio Quartulli 1686058d0e26SAntonio Quartulli } 1687058d0e26SAntonio Quartulli 1688058d0e26SAntonio Quartulli /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ 1689058d0e26SAntonio Quartulli static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) 1690058d0e26SAntonio Quartulli { 1691058d0e26SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 1692058d0e26SAntonio Quartulli struct tt_local_entry *tt_local_entry; 1693058d0e26SAntonio Quartulli struct hlist_node *node, *node_tmp; 1694058d0e26SAntonio Quartulli struct hlist_head *head; 1695058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 1696058d0e26SAntonio Quartulli int i; 1697058d0e26SAntonio Quartulli 1698058d0e26SAntonio Quartulli if (!hash) 1699058d0e26SAntonio Quartulli return; 1700058d0e26SAntonio Quartulli 1701058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1702058d0e26SAntonio Quartulli head = &hash->table[i]; 1703058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 1704058d0e26SAntonio Quartulli 1705058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 1706058d0e26SAntonio Quartulli hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, 1707058d0e26SAntonio Quartulli head, hash_entry) { 1708058d0e26SAntonio Quartulli if (!(tt_local_entry->flags & TT_CLIENT_PENDING)) 1709058d0e26SAntonio Quartulli continue; 1710058d0e26SAntonio Quartulli 1711058d0e26SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " 1712058d0e26SAntonio Quartulli "(%pM): pending\n", tt_local_entry->addr); 1713058d0e26SAntonio Quartulli 1714058d0e26SAntonio Quartulli atomic_dec(&bat_priv->num_local_tt); 1715058d0e26SAntonio Quartulli hlist_del_rcu(node); 1716058d0e26SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 1717058d0e26SAntonio Quartulli } 1718058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 1719058d0e26SAntonio Quartulli } 1720058d0e26SAntonio Quartulli 1721058d0e26SAntonio Quartulli } 1722058d0e26SAntonio Quartulli 1723058d0e26SAntonio Quartulli void tt_commit_changes(struct bat_priv *bat_priv) 1724058d0e26SAntonio Quartulli { 1725058d0e26SAntonio Quartulli tt_local_reset_flags(bat_priv, TT_CLIENT_NEW); 1726058d0e26SAntonio Quartulli tt_local_purge_pending_clients(bat_priv); 1727058d0e26SAntonio Quartulli 1728058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 1729058d0e26SAntonio Quartulli atomic_inc(&bat_priv->ttvn); 1730058d0e26SAntonio Quartulli bat_priv->tt_poss_change = false; 1731058d0e26SAntonio Quartulli } 1732