1c6c8fea2SSven Eckelmann /* 2567db7b0SSven Eckelmann * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: 3c6c8fea2SSven Eckelmann * 435c133a0SAntonio Quartulli * Marek Lindner, Simon Wunderlich, Antonio Quartulli 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" 3020ff9d59SSimon Wunderlich #include "bridge_loop_avoidance.h" 31c6c8fea2SSven Eckelmann 32a73105b8SAntonio Quartulli #include <linux/crc16.h> 33a73105b8SAntonio Quartulli 34de7aae65SSven Eckelmann static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 35de7aae65SSven Eckelmann struct orig_node *orig_node); 36a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work); 37db08e6e5SSimon Wunderlich static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry); 38c6c8fea2SSven Eckelmann 397aadf889SMarek Lindner /* returns 1 if they are the same mac addr */ 4048100bacSAntonio Quartulli static int compare_tt(const struct hlist_node *node, const void *data2) 417aadf889SMarek Lindner { 4248100bacSAntonio Quartulli const void *data1 = container_of(node, struct tt_common_entry, 43747e4221SSven Eckelmann hash_entry); 447aadf889SMarek Lindner 457aadf889SMarek Lindner return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); 467aadf889SMarek Lindner } 477aadf889SMarek Lindner 48a73105b8SAntonio Quartulli static void tt_start_timer(struct bat_priv *bat_priv) 49c6c8fea2SSven Eckelmann { 50a73105b8SAntonio Quartulli INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge); 51a73105b8SAntonio Quartulli queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 52a73105b8SAntonio Quartulli msecs_to_jiffies(5000)); 53c6c8fea2SSven Eckelmann } 54c6c8fea2SSven Eckelmann 5548100bacSAntonio Quartulli static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash, 56747e4221SSven Eckelmann const void *data) 577aadf889SMarek Lindner { 587aadf889SMarek Lindner struct hlist_head *head; 597aadf889SMarek Lindner struct hlist_node *node; 6048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL; 61c90681b8SAntonio Quartulli uint32_t index; 627aadf889SMarek Lindner 637aadf889SMarek Lindner if (!hash) 647aadf889SMarek Lindner return NULL; 657aadf889SMarek Lindner 667aadf889SMarek Lindner index = choose_orig(data, hash->size); 677aadf889SMarek Lindner head = &hash->table[index]; 687aadf889SMarek Lindner 697aadf889SMarek Lindner rcu_read_lock(); 7048100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) { 7148100bacSAntonio Quartulli if (!compare_eth(tt_common_entry, data)) 727aadf889SMarek Lindner continue; 737aadf889SMarek Lindner 7448100bacSAntonio Quartulli if (!atomic_inc_not_zero(&tt_common_entry->refcount)) 757683fdc1SAntonio Quartulli continue; 767683fdc1SAntonio Quartulli 7748100bacSAntonio Quartulli tt_common_entry_tmp = tt_common_entry; 787aadf889SMarek Lindner break; 797aadf889SMarek Lindner } 807aadf889SMarek Lindner rcu_read_unlock(); 817aadf889SMarek Lindner 8248100bacSAntonio Quartulli return tt_common_entry_tmp; 8348100bacSAntonio Quartulli } 8448100bacSAntonio Quartulli 8548100bacSAntonio Quartulli static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv, 8648100bacSAntonio Quartulli const void *data) 8748100bacSAntonio Quartulli { 8848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 8948100bacSAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 9048100bacSAntonio Quartulli 9148100bacSAntonio Quartulli tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data); 9248100bacSAntonio Quartulli if (tt_common_entry) 9348100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 9448100bacSAntonio Quartulli struct tt_local_entry, common); 9548100bacSAntonio Quartulli return tt_local_entry; 967aadf889SMarek Lindner } 977aadf889SMarek Lindner 982dafb49dSAntonio Quartulli static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv, 99747e4221SSven Eckelmann const void *data) 1007aadf889SMarek Lindner { 10148100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 10248100bacSAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 1037aadf889SMarek Lindner 10448100bacSAntonio Quartulli tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data); 10548100bacSAntonio Quartulli if (tt_common_entry) 10648100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 10748100bacSAntonio Quartulli struct tt_global_entry, common); 10848100bacSAntonio Quartulli return tt_global_entry; 1097aadf889SMarek Lindner 1107aadf889SMarek Lindner } 1117aadf889SMarek Lindner 1127683fdc1SAntonio Quartulli static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry) 1137683fdc1SAntonio Quartulli { 11448100bacSAntonio Quartulli if (atomic_dec_and_test(&tt_local_entry->common.refcount)) 11548100bacSAntonio Quartulli kfree_rcu(tt_local_entry, common.rcu); 1167683fdc1SAntonio Quartulli } 1177683fdc1SAntonio Quartulli 118531027fcSSimon Wunderlich static void tt_global_entry_free_rcu(struct rcu_head *rcu) 119531027fcSSimon Wunderlich { 12048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 121531027fcSSimon Wunderlich struct tt_global_entry *tt_global_entry; 122531027fcSSimon Wunderlich 12348100bacSAntonio Quartulli tt_common_entry = container_of(rcu, struct tt_common_entry, rcu); 12448100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, 12548100bacSAntonio Quartulli common); 126531027fcSSimon Wunderlich 127531027fcSSimon Wunderlich kfree(tt_global_entry); 128531027fcSSimon Wunderlich } 129531027fcSSimon Wunderlich 1307683fdc1SAntonio Quartulli static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry) 1317683fdc1SAntonio Quartulli { 132db08e6e5SSimon Wunderlich if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { 133db08e6e5SSimon Wunderlich tt_global_del_orig_list(tt_global_entry); 13448100bacSAntonio Quartulli call_rcu(&tt_global_entry->common.rcu, 13548100bacSAntonio Quartulli tt_global_entry_free_rcu); 1367683fdc1SAntonio Quartulli } 137db08e6e5SSimon Wunderlich } 138db08e6e5SSimon Wunderlich 139db08e6e5SSimon Wunderlich static void tt_orig_list_entry_free_rcu(struct rcu_head *rcu) 140db08e6e5SSimon Wunderlich { 141db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 142db08e6e5SSimon Wunderlich 143db08e6e5SSimon Wunderlich orig_entry = container_of(rcu, struct tt_orig_list_entry, rcu); 144db08e6e5SSimon Wunderlich atomic_dec(&orig_entry->orig_node->tt_size); 1457d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_entry->orig_node); 146db08e6e5SSimon Wunderlich kfree(orig_entry); 147db08e6e5SSimon Wunderlich } 148db08e6e5SSimon Wunderlich 149db08e6e5SSimon Wunderlich static void tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry) 150db08e6e5SSimon Wunderlich { 151db08e6e5SSimon Wunderlich call_rcu(&orig_entry->rcu, tt_orig_list_entry_free_rcu); 152db08e6e5SSimon Wunderlich } 1537683fdc1SAntonio Quartulli 154ff66c975SAntonio Quartulli static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr, 155ff66c975SAntonio Quartulli uint8_t flags) 156a73105b8SAntonio Quartulli { 157a73105b8SAntonio Quartulli struct tt_change_node *tt_change_node; 158a73105b8SAntonio Quartulli 159a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 160a73105b8SAntonio Quartulli 161a73105b8SAntonio Quartulli if (!tt_change_node) 162a73105b8SAntonio Quartulli return; 163a73105b8SAntonio Quartulli 164ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 165a73105b8SAntonio Quartulli memcpy(tt_change_node->change.addr, addr, ETH_ALEN); 166a73105b8SAntonio Quartulli 167a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 168a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 169a73105b8SAntonio Quartulli list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list); 170a73105b8SAntonio Quartulli atomic_inc(&bat_priv->tt_local_changes); 171a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 172a73105b8SAntonio Quartulli 173a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_ogm_append_cnt, 0); 174a73105b8SAntonio Quartulli } 175a73105b8SAntonio Quartulli 176a73105b8SAntonio Quartulli int tt_len(int changes_num) 177a73105b8SAntonio Quartulli { 178a73105b8SAntonio Quartulli return changes_num * sizeof(struct tt_change); 179a73105b8SAntonio Quartulli } 180a73105b8SAntonio Quartulli 181a73105b8SAntonio Quartulli static int tt_local_init(struct bat_priv *bat_priv) 182c6c8fea2SSven Eckelmann { 1832dafb49dSAntonio Quartulli if (bat_priv->tt_local_hash) 1845346c35eSSven Eckelmann return 0; 185c6c8fea2SSven Eckelmann 1861a8eaf07SSven Eckelmann bat_priv->tt_local_hash = batadv_hash_new(1024); 187c6c8fea2SSven Eckelmann 1882dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 1895346c35eSSven Eckelmann return -ENOMEM; 190c6c8fea2SSven Eckelmann 1915346c35eSSven Eckelmann return 0; 192c6c8fea2SSven Eckelmann } 193c6c8fea2SSven Eckelmann 194bc279080SAntonio Quartulli void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 195bc279080SAntonio Quartulli int ifindex) 196c6c8fea2SSven Eckelmann { 197c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(soft_iface); 1987683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 1997683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 200db08e6e5SSimon Wunderlich struct hlist_head *head; 201db08e6e5SSimon Wunderlich struct hlist_node *node; 202db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 20380b3f58cSSimon Wunderlich int hash_added; 204c6c8fea2SSven Eckelmann 2052dafb49dSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 206c6c8fea2SSven Eckelmann 2072dafb49dSAntonio Quartulli if (tt_local_entry) { 2082dafb49dSAntonio Quartulli tt_local_entry->last_seen = jiffies; 209521251f2SAntonio Quartulli /* possibly unset the TT_CLIENT_PENDING flag */ 210521251f2SAntonio Quartulli tt_local_entry->common.flags &= ~TT_CLIENT_PENDING; 2117683fdc1SAntonio Quartulli goto out; 212c6c8fea2SSven Eckelmann } 213c6c8fea2SSven Eckelmann 214704509b8SSven Eckelmann tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC); 2152dafb49dSAntonio Quartulli if (!tt_local_entry) 2167683fdc1SAntonio Quartulli goto out; 217a73105b8SAntonio Quartulli 218a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 219a73105b8SAntonio Quartulli "Creating new local tt entry: %pM (ttvn: %d)\n", addr, 220a73105b8SAntonio Quartulli (uint8_t)atomic_read(&bat_priv->ttvn)); 221c6c8fea2SSven Eckelmann 22248100bacSAntonio Quartulli memcpy(tt_local_entry->common.addr, addr, ETH_ALEN); 22348100bacSAntonio Quartulli tt_local_entry->common.flags = NO_FLAGS; 2249563877eSSven Eckelmann if (batadv_is_wifi_iface(ifindex)) 22548100bacSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_WIFI; 22648100bacSAntonio Quartulli atomic_set(&tt_local_entry->common.refcount, 2); 22748100bacSAntonio Quartulli tt_local_entry->last_seen = jiffies; 228c6c8fea2SSven Eckelmann 229c6c8fea2SSven Eckelmann /* the batman interface mac address should never be purged */ 23039901e71SMarek Lindner if (compare_eth(addr, soft_iface->dev_addr)) 23148100bacSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_NOPURGE; 232c6c8fea2SSven Eckelmann 233c40ed2bfSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 234c40ed2bfSAntonio Quartulli * a full table response going out before the next ttvn increment 235c40ed2bfSAntonio Quartulli * (consistency check) */ 236c40ed2bfSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_NEW; 237c40ed2bfSAntonio Quartulli 23880b3f58cSSimon Wunderlich hash_added = hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig, 23980b3f58cSSimon Wunderlich &tt_local_entry->common, 24080b3f58cSSimon Wunderlich &tt_local_entry->common.hash_entry); 24180b3f58cSSimon Wunderlich 24280b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 24380b3f58cSSimon Wunderlich /* remove the reference for the hash */ 24480b3f58cSSimon Wunderlich tt_local_entry_free_ref(tt_local_entry); 24580b3f58cSSimon Wunderlich goto out; 24680b3f58cSSimon Wunderlich } 24780b3f58cSSimon Wunderlich 24848100bacSAntonio Quartulli tt_local_event(bat_priv, addr, tt_local_entry->common.flags); 249ff66c975SAntonio Quartulli 250c6c8fea2SSven Eckelmann /* remove address from global hash if present */ 2512dafb49dSAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 252c6c8fea2SSven Eckelmann 253cc47f66eSAntonio Quartulli /* Check whether it is a roaming! */ 254cc47f66eSAntonio Quartulli if (tt_global_entry) { 255db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 256db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 257db08e6e5SSimon Wunderlich rcu_read_lock(); 258db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 259db08e6e5SSimon Wunderlich orig_entry->orig_node->tt_poss_change = true; 260db08e6e5SSimon Wunderlich 261db08e6e5SSimon Wunderlich send_roam_adv(bat_priv, tt_global_entry->common.addr, 262db08e6e5SSimon Wunderlich orig_entry->orig_node); 263db08e6e5SSimon Wunderlich } 264db08e6e5SSimon Wunderlich rcu_read_unlock(); 265db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 266db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 267db08e6e5SSimon Wunderlich */ 268220b07e9SDavid S. Miller tt_global_entry->common.flags |= TT_CLIENT_ROAM; 26903fc3070SAntonio Quartulli tt_global_entry->roam_at = jiffies; 2707683fdc1SAntonio Quartulli } 2717683fdc1SAntonio Quartulli out: 2727683fdc1SAntonio Quartulli if (tt_local_entry) 2737683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 2747683fdc1SAntonio Quartulli if (tt_global_entry) 2757683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 276c6c8fea2SSven Eckelmann } 277c6c8fea2SSven Eckelmann 278be9aa4c1SMarek Lindner static void tt_realloc_packet_buff(unsigned char **packet_buff, 279be9aa4c1SMarek Lindner int *packet_buff_len, int min_packet_len, 280be9aa4c1SMarek Lindner int new_packet_len) 281c6c8fea2SSven Eckelmann { 282be9aa4c1SMarek Lindner unsigned char *new_buff; 283c6c8fea2SSven Eckelmann 284be9aa4c1SMarek Lindner new_buff = kmalloc(new_packet_len, GFP_ATOMIC); 285be9aa4c1SMarek Lindner 286be9aa4c1SMarek Lindner /* keep old buffer if kmalloc should fail */ 287be9aa4c1SMarek Lindner if (new_buff) { 288be9aa4c1SMarek Lindner memcpy(new_buff, *packet_buff, min_packet_len); 289be9aa4c1SMarek Lindner kfree(*packet_buff); 290be9aa4c1SMarek Lindner *packet_buff = new_buff; 291be9aa4c1SMarek Lindner *packet_buff_len = new_packet_len; 292be9aa4c1SMarek Lindner } 293be9aa4c1SMarek Lindner } 294be9aa4c1SMarek Lindner 295be9aa4c1SMarek Lindner static void tt_prepare_packet_buff(struct bat_priv *bat_priv, 296be9aa4c1SMarek Lindner unsigned char **packet_buff, 297be9aa4c1SMarek Lindner int *packet_buff_len, int min_packet_len) 298be9aa4c1SMarek Lindner { 299be9aa4c1SMarek Lindner struct hard_iface *primary_if; 300be9aa4c1SMarek Lindner int req_len; 301be9aa4c1SMarek Lindner 302be9aa4c1SMarek Lindner primary_if = primary_if_get_selected(bat_priv); 303be9aa4c1SMarek Lindner 304be9aa4c1SMarek Lindner req_len = min_packet_len; 305be9aa4c1SMarek Lindner req_len += tt_len(atomic_read(&bat_priv->tt_local_changes)); 306be9aa4c1SMarek Lindner 307be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 308be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 309be9aa4c1SMarek Lindner */ 310be9aa4c1SMarek Lindner if ((!primary_if) || (req_len > primary_if->soft_iface->mtu)) 311be9aa4c1SMarek Lindner req_len = min_packet_len; 312be9aa4c1SMarek Lindner 313be9aa4c1SMarek Lindner tt_realloc_packet_buff(packet_buff, packet_buff_len, 314be9aa4c1SMarek Lindner min_packet_len, req_len); 315be9aa4c1SMarek Lindner 316be9aa4c1SMarek Lindner if (primary_if) 317be9aa4c1SMarek Lindner hardif_free_ref(primary_if); 318be9aa4c1SMarek Lindner } 319be9aa4c1SMarek Lindner 320be9aa4c1SMarek Lindner static int tt_changes_fill_buff(struct bat_priv *bat_priv, 321be9aa4c1SMarek Lindner unsigned char **packet_buff, 322be9aa4c1SMarek Lindner int *packet_buff_len, int min_packet_len) 323be9aa4c1SMarek Lindner { 324be9aa4c1SMarek Lindner struct tt_change_node *entry, *safe; 325be9aa4c1SMarek Lindner int count = 0, tot_changes = 0, new_len; 326be9aa4c1SMarek Lindner unsigned char *tt_buff; 327be9aa4c1SMarek Lindner 328be9aa4c1SMarek Lindner tt_prepare_packet_buff(bat_priv, packet_buff, 329be9aa4c1SMarek Lindner packet_buff_len, min_packet_len); 330be9aa4c1SMarek Lindner 331be9aa4c1SMarek Lindner new_len = *packet_buff_len - min_packet_len; 332be9aa4c1SMarek Lindner tt_buff = *packet_buff + min_packet_len; 333be9aa4c1SMarek Lindner 334be9aa4c1SMarek Lindner if (new_len > 0) 335be9aa4c1SMarek Lindner tot_changes = new_len / tt_len(1); 336c6c8fea2SSven Eckelmann 337a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 338a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 339c6c8fea2SSven Eckelmann 340a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 341a73105b8SAntonio Quartulli list) { 342a73105b8SAntonio Quartulli if (count < tot_changes) { 343be9aa4c1SMarek Lindner memcpy(tt_buff + tt_len(count), 344a73105b8SAntonio Quartulli &entry->change, sizeof(struct tt_change)); 345c6c8fea2SSven Eckelmann count++; 346c6c8fea2SSven Eckelmann } 347a73105b8SAntonio Quartulli list_del(&entry->list); 348a73105b8SAntonio Quartulli kfree(entry); 349c6c8fea2SSven Eckelmann } 350a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 351c6c8fea2SSven Eckelmann 352a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 353a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 354a73105b8SAntonio Quartulli kfree(bat_priv->tt_buff); 355a73105b8SAntonio Quartulli bat_priv->tt_buff_len = 0; 356a73105b8SAntonio Quartulli bat_priv->tt_buff = NULL; 357be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 358be9aa4c1SMarek Lindner if (new_len > 0) { 359be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 360a73105b8SAntonio Quartulli * instead of providing the diff 361a73105b8SAntonio Quartulli */ 362be9aa4c1SMarek Lindner bat_priv->tt_buff = kmalloc(new_len, GFP_ATOMIC); 363a73105b8SAntonio Quartulli if (bat_priv->tt_buff) { 364be9aa4c1SMarek Lindner memcpy(bat_priv->tt_buff, tt_buff, new_len); 365be9aa4c1SMarek Lindner bat_priv->tt_buff_len = new_len; 366a73105b8SAntonio Quartulli } 367a73105b8SAntonio Quartulli } 368a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 369c6c8fea2SSven Eckelmann 37008ad76ecSMarek Lindner return count; 371c6c8fea2SSven Eckelmann } 372c6c8fea2SSven Eckelmann 3732dafb49dSAntonio Quartulli int tt_local_seq_print_text(struct seq_file *seq, void *offset) 374c6c8fea2SSven Eckelmann { 375c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 376c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 3772dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 37848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 37932ae9b22SMarek Lindner struct hard_iface *primary_if; 3807aadf889SMarek Lindner struct hlist_node *node; 381c6c8fea2SSven Eckelmann struct hlist_head *head; 382c90681b8SAntonio Quartulli uint32_t i; 383c90681b8SAntonio Quartulli int ret = 0; 384c6c8fea2SSven Eckelmann 38532ae9b22SMarek Lindner primary_if = primary_if_get_selected(bat_priv); 38632ae9b22SMarek Lindner if (!primary_if) { 38786ceb360SSven Eckelmann ret = seq_printf(seq, 38886ceb360SSven Eckelmann "BATMAN mesh %s disabled - please specify interfaces to enable it\n", 389c6c8fea2SSven Eckelmann net_dev->name); 39032ae9b22SMarek Lindner goto out; 39132ae9b22SMarek Lindner } 39232ae9b22SMarek Lindner 39332ae9b22SMarek Lindner if (primary_if->if_status != IF_ACTIVE) { 39486ceb360SSven Eckelmann ret = seq_printf(seq, 39586ceb360SSven Eckelmann "BATMAN mesh %s disabled - primary interface not active\n", 39632ae9b22SMarek Lindner net_dev->name); 39732ae9b22SMarek Lindner goto out; 398c6c8fea2SSven Eckelmann } 399c6c8fea2SSven Eckelmann 40086ceb360SSven Eckelmann seq_printf(seq, 40186ceb360SSven Eckelmann "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", 402a73105b8SAntonio Quartulli net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn)); 403c6c8fea2SSven Eckelmann 404c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 405c6c8fea2SSven Eckelmann head = &hash->table[i]; 406c6c8fea2SSven Eckelmann 4077aadf889SMarek Lindner rcu_read_lock(); 40848100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 4097aadf889SMarek Lindner head, hash_entry) { 410d099c2c5SSimon Wunderlich seq_printf(seq, " * %pM [%c%c%c%c%c]\n", 41148100bacSAntonio Quartulli tt_common_entry->addr, 41248100bacSAntonio Quartulli (tt_common_entry->flags & 413df6edb9eSAntonio Quartulli TT_CLIENT_ROAM ? 'R' : '.'), 41448100bacSAntonio Quartulli (tt_common_entry->flags & 415df6edb9eSAntonio Quartulli TT_CLIENT_NOPURGE ? 'P' : '.'), 41648100bacSAntonio Quartulli (tt_common_entry->flags & 417df6edb9eSAntonio Quartulli TT_CLIENT_NEW ? 'N' : '.'), 41848100bacSAntonio Quartulli (tt_common_entry->flags & 419df6edb9eSAntonio Quartulli TT_CLIENT_PENDING ? 'X' : '.'), 42048100bacSAntonio Quartulli (tt_common_entry->flags & 421df6edb9eSAntonio Quartulli TT_CLIENT_WIFI ? 'W' : '.')); 422c6c8fea2SSven Eckelmann } 4237aadf889SMarek Lindner rcu_read_unlock(); 424c6c8fea2SSven Eckelmann } 42532ae9b22SMarek Lindner out: 42632ae9b22SMarek Lindner if (primary_if) 42732ae9b22SMarek Lindner hardif_free_ref(primary_if); 42832ae9b22SMarek Lindner return ret; 429c6c8fea2SSven Eckelmann } 430c6c8fea2SSven Eckelmann 431058d0e26SAntonio Quartulli static void tt_local_set_pending(struct bat_priv *bat_priv, 4322dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry, 433c566dbbeSAntonio Quartulli uint16_t flags, const char *message) 434c6c8fea2SSven Eckelmann { 43548100bacSAntonio Quartulli tt_local_event(bat_priv, tt_local_entry->common.addr, 43648100bacSAntonio Quartulli tt_local_entry->common.flags | flags); 437c6c8fea2SSven Eckelmann 438015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 439015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 440058d0e26SAntonio Quartulli * response issued before the net ttvn increment (consistency check) */ 44148100bacSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_PENDING; 442c566dbbeSAntonio Quartulli 44386ceb360SSven Eckelmann bat_dbg(DBG_TT, bat_priv, 44486ceb360SSven Eckelmann "Local tt entry (%pM) pending to be removed: %s\n", 44586ceb360SSven Eckelmann tt_local_entry->common.addr, message); 446c6c8fea2SSven Eckelmann } 447c6c8fea2SSven Eckelmann 448a73105b8SAntonio Quartulli void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, 449cc47f66eSAntonio Quartulli const char *message, bool roaming) 450c6c8fea2SSven Eckelmann { 4517683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 452c6c8fea2SSven Eckelmann 4532dafb49dSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 4547683fdc1SAntonio Quartulli if (!tt_local_entry) 4557683fdc1SAntonio Quartulli goto out; 4567683fdc1SAntonio Quartulli 457058d0e26SAntonio Quartulli tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | 458c566dbbeSAntonio Quartulli (roaming ? TT_CLIENT_ROAM : NO_FLAGS), message); 4597683fdc1SAntonio Quartulli out: 4607683fdc1SAntonio Quartulli if (tt_local_entry) 4617683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 462c6c8fea2SSven Eckelmann } 463c6c8fea2SSven Eckelmann 464a73105b8SAntonio Quartulli static void tt_local_purge(struct bat_priv *bat_priv) 465c6c8fea2SSven Eckelmann { 4662dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 4672dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry; 46848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 4697aadf889SMarek Lindner struct hlist_node *node, *node_tmp; 470c6c8fea2SSven Eckelmann struct hlist_head *head; 4717683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 472c90681b8SAntonio Quartulli uint32_t i; 473c6c8fea2SSven Eckelmann 474c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 475c6c8fea2SSven Eckelmann head = &hash->table[i]; 4767683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 477c6c8fea2SSven Eckelmann 4787683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 47948100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 4807aadf889SMarek Lindner head, hash_entry) { 48148100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 48248100bacSAntonio Quartulli struct tt_local_entry, 48348100bacSAntonio Quartulli common); 48448100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE) 4857aadf889SMarek Lindner continue; 486c6c8fea2SSven Eckelmann 487058d0e26SAntonio Quartulli /* entry already marked for deletion */ 48848100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_PENDING) 489058d0e26SAntonio Quartulli continue; 490058d0e26SAntonio Quartulli 491a04ccd59SMartin Hundebøll if (!has_timed_out(tt_local_entry->last_seen, 492032b7969SMarek Lindner TT_LOCAL_TIMEOUT)) 4937aadf889SMarek Lindner continue; 4947aadf889SMarek Lindner 495058d0e26SAntonio Quartulli tt_local_set_pending(bat_priv, tt_local_entry, 496c566dbbeSAntonio Quartulli TT_CLIENT_DEL, "timed out"); 497c6c8fea2SSven Eckelmann } 4987683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 499c6c8fea2SSven Eckelmann } 500c6c8fea2SSven Eckelmann 501c6c8fea2SSven Eckelmann } 502c6c8fea2SSven Eckelmann 503a73105b8SAntonio Quartulli static void tt_local_table_free(struct bat_priv *bat_priv) 504c6c8fea2SSven Eckelmann { 505a73105b8SAntonio Quartulli struct hashtable_t *hash; 506a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 50748100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 508a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 5097683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 5107683fdc1SAntonio Quartulli struct hlist_head *head; 511c90681b8SAntonio Quartulli uint32_t i; 512a73105b8SAntonio Quartulli 5132dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 514c6c8fea2SSven Eckelmann return; 515c6c8fea2SSven Eckelmann 516a73105b8SAntonio Quartulli hash = bat_priv->tt_local_hash; 517a73105b8SAntonio Quartulli 518a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 519a73105b8SAntonio Quartulli head = &hash->table[i]; 520a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 521a73105b8SAntonio Quartulli 522a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 52348100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 524a73105b8SAntonio Quartulli head, hash_entry) { 525a73105b8SAntonio Quartulli hlist_del_rcu(node); 52648100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 52748100bacSAntonio Quartulli struct tt_local_entry, 52848100bacSAntonio Quartulli common); 5297683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 530a73105b8SAntonio Quartulli } 531a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 532a73105b8SAntonio Quartulli } 533a73105b8SAntonio Quartulli 5341a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 535a73105b8SAntonio Quartulli 5362dafb49dSAntonio Quartulli bat_priv->tt_local_hash = NULL; 537c6c8fea2SSven Eckelmann } 538c6c8fea2SSven Eckelmann 539a73105b8SAntonio Quartulli static int tt_global_init(struct bat_priv *bat_priv) 540c6c8fea2SSven Eckelmann { 5412dafb49dSAntonio Quartulli if (bat_priv->tt_global_hash) 5425346c35eSSven Eckelmann return 0; 543c6c8fea2SSven Eckelmann 5441a8eaf07SSven Eckelmann bat_priv->tt_global_hash = batadv_hash_new(1024); 545c6c8fea2SSven Eckelmann 5462dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 5475346c35eSSven Eckelmann return -ENOMEM; 548c6c8fea2SSven Eckelmann 5495346c35eSSven Eckelmann return 0; 550c6c8fea2SSven Eckelmann } 551c6c8fea2SSven Eckelmann 552a73105b8SAntonio Quartulli static void tt_changes_list_free(struct bat_priv *bat_priv) 553a73105b8SAntonio Quartulli { 554a73105b8SAntonio Quartulli struct tt_change_node *entry, *safe; 555a73105b8SAntonio Quartulli 556a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 557a73105b8SAntonio Quartulli 558a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 559a73105b8SAntonio Quartulli list) { 560a73105b8SAntonio Quartulli list_del(&entry->list); 561a73105b8SAntonio Quartulli kfree(entry); 562a73105b8SAntonio Quartulli } 563a73105b8SAntonio Quartulli 564a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 565a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 566a73105b8SAntonio Quartulli } 567a73105b8SAntonio Quartulli 568db08e6e5SSimon Wunderlich /* find out if an orig_node is already in the list of a tt_global_entry. 569db08e6e5SSimon Wunderlich * returns 1 if found, 0 otherwise 570db08e6e5SSimon Wunderlich */ 571db08e6e5SSimon Wunderlich static bool tt_global_entry_has_orig(const struct tt_global_entry *entry, 572db08e6e5SSimon Wunderlich const struct orig_node *orig_node) 573db08e6e5SSimon Wunderlich { 574db08e6e5SSimon Wunderlich struct tt_orig_list_entry *tmp_orig_entry; 575db08e6e5SSimon Wunderlich const struct hlist_head *head; 576db08e6e5SSimon Wunderlich struct hlist_node *node; 577db08e6e5SSimon Wunderlich bool found = false; 578db08e6e5SSimon Wunderlich 579db08e6e5SSimon Wunderlich rcu_read_lock(); 580db08e6e5SSimon Wunderlich head = &entry->orig_list; 581db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) { 582db08e6e5SSimon Wunderlich if (tmp_orig_entry->orig_node == orig_node) { 583db08e6e5SSimon Wunderlich found = true; 584db08e6e5SSimon Wunderlich break; 585db08e6e5SSimon Wunderlich } 586db08e6e5SSimon Wunderlich } 587db08e6e5SSimon Wunderlich rcu_read_unlock(); 588db08e6e5SSimon Wunderlich return found; 589db08e6e5SSimon Wunderlich } 590db08e6e5SSimon Wunderlich 591db08e6e5SSimon Wunderlich static void tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry, 592db08e6e5SSimon Wunderlich struct orig_node *orig_node, 593db08e6e5SSimon Wunderlich int ttvn) 594db08e6e5SSimon Wunderlich { 595db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 596db08e6e5SSimon Wunderlich 597db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 598db08e6e5SSimon Wunderlich if (!orig_entry) 599db08e6e5SSimon Wunderlich return; 600db08e6e5SSimon Wunderlich 601db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 602db08e6e5SSimon Wunderlich atomic_inc(&orig_node->refcount); 603db08e6e5SSimon Wunderlich atomic_inc(&orig_node->tt_size); 604db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 605db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 606db08e6e5SSimon Wunderlich 607db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 608db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 609db08e6e5SSimon Wunderlich &tt_global_entry->orig_list); 610db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 611db08e6e5SSimon Wunderlich } 612db08e6e5SSimon Wunderlich 613a73105b8SAntonio Quartulli /* caller must hold orig_node refcount */ 614a73105b8SAntonio Quartulli int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, 615bc279080SAntonio Quartulli const unsigned char *tt_addr, uint8_t ttvn, bool roaming, 616bc279080SAntonio Quartulli bool wifi) 617c6c8fea2SSven Eckelmann { 618db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry = NULL; 6197683fdc1SAntonio Quartulli int ret = 0; 62080b3f58cSSimon Wunderlich int hash_added; 621c6c8fea2SSven Eckelmann 622a73105b8SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, tt_addr); 623c6c8fea2SSven Eckelmann 6242dafb49dSAntonio Quartulli if (!tt_global_entry) { 625db08e6e5SSimon Wunderlich tt_global_entry = kzalloc(sizeof(*tt_global_entry), 626c6c8fea2SSven Eckelmann GFP_ATOMIC); 6272dafb49dSAntonio Quartulli if (!tt_global_entry) 6287683fdc1SAntonio Quartulli goto out; 6297683fdc1SAntonio Quartulli 63048100bacSAntonio Quartulli memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN); 631db08e6e5SSimon Wunderlich 63248100bacSAntonio Quartulli tt_global_entry->common.flags = NO_FLAGS; 633cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 634db08e6e5SSimon Wunderlich atomic_set(&tt_global_entry->common.refcount, 2); 635db08e6e5SSimon Wunderlich 636db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 637db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 6387683fdc1SAntonio Quartulli 63980b3f58cSSimon Wunderlich hash_added = hash_add(bat_priv->tt_global_hash, compare_tt, 64048100bacSAntonio Quartulli choose_orig, &tt_global_entry->common, 64148100bacSAntonio Quartulli &tt_global_entry->common.hash_entry); 64280b3f58cSSimon Wunderlich 64380b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 64480b3f58cSSimon Wunderlich /* remove the reference for the hash */ 64580b3f58cSSimon Wunderlich tt_global_entry_free_ref(tt_global_entry); 64680b3f58cSSimon Wunderlich goto out_remove; 64780b3f58cSSimon Wunderlich } 648db08e6e5SSimon Wunderlich 649db08e6e5SSimon Wunderlich tt_global_add_orig_entry(tt_global_entry, orig_node, ttvn); 650a73105b8SAntonio Quartulli } else { 651db08e6e5SSimon Wunderlich /* there is already a global entry, use this one. */ 652db08e6e5SSimon Wunderlich 653db08e6e5SSimon Wunderlich /* If there is the TT_CLIENT_ROAM flag set, there is only one 654db08e6e5SSimon Wunderlich * originator left in the list and we previously received a 655db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 656db08e6e5SSimon Wunderlich * 657db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 658db08e6e5SSimon Wunderlich * new one. 659db08e6e5SSimon Wunderlich */ 660db08e6e5SSimon Wunderlich if (tt_global_entry->common.flags & TT_CLIENT_ROAM) { 661db08e6e5SSimon Wunderlich tt_global_del_orig_list(tt_global_entry); 662db08e6e5SSimon Wunderlich tt_global_entry->common.flags &= ~TT_CLIENT_ROAM; 663cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 664c6c8fea2SSven Eckelmann } 665c6c8fea2SSven Eckelmann 666db08e6e5SSimon Wunderlich if (!tt_global_entry_has_orig(tt_global_entry, orig_node)) 667db08e6e5SSimon Wunderlich tt_global_add_orig_entry(tt_global_entry, orig_node, 668db08e6e5SSimon Wunderlich ttvn); 669db08e6e5SSimon Wunderlich } 670db08e6e5SSimon Wunderlich 671bc279080SAntonio Quartulli if (wifi) 67248100bacSAntonio Quartulli tt_global_entry->common.flags |= TT_CLIENT_WIFI; 673bc279080SAntonio Quartulli 674a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 675a73105b8SAntonio Quartulli "Creating new global tt entry: %pM (via %pM)\n", 67648100bacSAntonio Quartulli tt_global_entry->common.addr, orig_node->orig); 677a73105b8SAntonio Quartulli 67880b3f58cSSimon Wunderlich out_remove: 679c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 68048100bacSAntonio Quartulli tt_local_remove(bat_priv, tt_global_entry->common.addr, 681cc47f66eSAntonio Quartulli "global tt received", roaming); 6827683fdc1SAntonio Quartulli ret = 1; 6837683fdc1SAntonio Quartulli out: 6847683fdc1SAntonio Quartulli if (tt_global_entry) 6857683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 6867683fdc1SAntonio Quartulli return ret; 687c6c8fea2SSven Eckelmann } 688c6c8fea2SSven Eckelmann 689db08e6e5SSimon Wunderlich /* print all orig nodes who announce the address for this global entry. 690db08e6e5SSimon Wunderlich * it is assumed that the caller holds rcu_read_lock(); 691db08e6e5SSimon Wunderlich */ 692db08e6e5SSimon Wunderlich static void tt_global_print_entry(struct tt_global_entry *tt_global_entry, 693db08e6e5SSimon Wunderlich struct seq_file *seq) 694db08e6e5SSimon Wunderlich { 695db08e6e5SSimon Wunderlich struct hlist_head *head; 696db08e6e5SSimon Wunderlich struct hlist_node *node; 697db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 698db08e6e5SSimon Wunderlich struct tt_common_entry *tt_common_entry; 699db08e6e5SSimon Wunderlich uint16_t flags; 700db08e6e5SSimon Wunderlich uint8_t last_ttvn; 701db08e6e5SSimon Wunderlich 702db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 703db08e6e5SSimon Wunderlich 704db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 705db08e6e5SSimon Wunderlich 706db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 707db08e6e5SSimon Wunderlich flags = tt_common_entry->flags; 708db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 709db08e6e5SSimon Wunderlich seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n", 710db08e6e5SSimon Wunderlich tt_global_entry->common.addr, orig_entry->ttvn, 711db08e6e5SSimon Wunderlich orig_entry->orig_node->orig, last_ttvn, 712db08e6e5SSimon Wunderlich (flags & TT_CLIENT_ROAM ? 'R' : '.'), 713db08e6e5SSimon Wunderlich (flags & TT_CLIENT_WIFI ? 'W' : '.')); 714db08e6e5SSimon Wunderlich } 715db08e6e5SSimon Wunderlich } 716db08e6e5SSimon Wunderlich 7172dafb49dSAntonio Quartulli int tt_global_seq_print_text(struct seq_file *seq, void *offset) 718c6c8fea2SSven Eckelmann { 719c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 720c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 7212dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 72248100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 7232dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 72432ae9b22SMarek Lindner struct hard_iface *primary_if; 7257aadf889SMarek Lindner struct hlist_node *node; 726c6c8fea2SSven Eckelmann struct hlist_head *head; 727c90681b8SAntonio Quartulli uint32_t i; 728c90681b8SAntonio Quartulli int ret = 0; 729c6c8fea2SSven Eckelmann 73032ae9b22SMarek Lindner primary_if = primary_if_get_selected(bat_priv); 73132ae9b22SMarek Lindner if (!primary_if) { 73286ceb360SSven Eckelmann ret = seq_printf(seq, 73386ceb360SSven Eckelmann "BATMAN mesh %s disabled - please specify interfaces to enable it\n", 734c6c8fea2SSven Eckelmann net_dev->name); 73532ae9b22SMarek Lindner goto out; 73632ae9b22SMarek Lindner } 73732ae9b22SMarek Lindner 73832ae9b22SMarek Lindner if (primary_if->if_status != IF_ACTIVE) { 73986ceb360SSven Eckelmann ret = seq_printf(seq, 74086ceb360SSven Eckelmann "BATMAN mesh %s disabled - primary interface not active\n", 74132ae9b22SMarek Lindner net_dev->name); 74232ae9b22SMarek Lindner goto out; 743c6c8fea2SSven Eckelmann } 744c6c8fea2SSven Eckelmann 7452dafb49dSAntonio Quartulli seq_printf(seq, 7462dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 747c6c8fea2SSven Eckelmann net_dev->name); 748df6edb9eSAntonio Quartulli seq_printf(seq, " %-13s %s %-15s %s %s\n", 749df6edb9eSAntonio Quartulli "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags"); 750c6c8fea2SSven Eckelmann 751c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 752c6c8fea2SSven Eckelmann head = &hash->table[i]; 753c6c8fea2SSven Eckelmann 7547aadf889SMarek Lindner rcu_read_lock(); 75548100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 7567aadf889SMarek Lindner head, hash_entry) { 75748100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 75848100bacSAntonio Quartulli struct tt_global_entry, 75948100bacSAntonio Quartulli common); 760db08e6e5SSimon Wunderlich tt_global_print_entry(tt_global_entry, seq); 761c6c8fea2SSven Eckelmann } 7627aadf889SMarek Lindner rcu_read_unlock(); 763c6c8fea2SSven Eckelmann } 76432ae9b22SMarek Lindner out: 76532ae9b22SMarek Lindner if (primary_if) 76632ae9b22SMarek Lindner hardif_free_ref(primary_if); 76732ae9b22SMarek Lindner return ret; 768c6c8fea2SSven Eckelmann } 769c6c8fea2SSven Eckelmann 770db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 771db08e6e5SSimon Wunderlich static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry) 772db08e6e5SSimon Wunderlich { 773db08e6e5SSimon Wunderlich struct hlist_head *head; 774db08e6e5SSimon Wunderlich struct hlist_node *node, *safe; 775db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 776db08e6e5SSimon Wunderlich 777db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 778db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 779db08e6e5SSimon Wunderlich hlist_for_each_entry_safe(orig_entry, node, safe, head, list) { 780db08e6e5SSimon Wunderlich hlist_del_rcu(node); 781db08e6e5SSimon Wunderlich tt_orig_list_entry_free_ref(orig_entry); 782db08e6e5SSimon Wunderlich } 783db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 784db08e6e5SSimon Wunderlich 785db08e6e5SSimon Wunderlich } 786db08e6e5SSimon Wunderlich 787db08e6e5SSimon Wunderlich static void tt_global_del_orig_entry(struct bat_priv *bat_priv, 788db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry, 789db08e6e5SSimon Wunderlich struct orig_node *orig_node, 790db08e6e5SSimon Wunderlich const char *message) 791db08e6e5SSimon Wunderlich { 792db08e6e5SSimon Wunderlich struct hlist_head *head; 793db08e6e5SSimon Wunderlich struct hlist_node *node, *safe; 794db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 795db08e6e5SSimon Wunderlich 796db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 797db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 798db08e6e5SSimon Wunderlich hlist_for_each_entry_safe(orig_entry, node, safe, head, list) { 799db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 800db08e6e5SSimon Wunderlich bat_dbg(DBG_TT, bat_priv, 801db08e6e5SSimon Wunderlich "Deleting %pM from global tt entry %pM: %s\n", 802db08e6e5SSimon Wunderlich orig_node->orig, tt_global_entry->common.addr, 803db08e6e5SSimon Wunderlich message); 804db08e6e5SSimon Wunderlich hlist_del_rcu(node); 805db08e6e5SSimon Wunderlich tt_orig_list_entry_free_ref(orig_entry); 806db08e6e5SSimon Wunderlich } 807db08e6e5SSimon Wunderlich } 808db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 809db08e6e5SSimon Wunderlich } 810db08e6e5SSimon Wunderlich 811db08e6e5SSimon Wunderlich static void tt_global_del_struct(struct bat_priv *bat_priv, 8122dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry, 813747e4221SSven Eckelmann const char *message) 814c6c8fea2SSven Eckelmann { 815a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 816db08e6e5SSimon Wunderlich "Deleting global tt entry %pM: %s\n", 817db08e6e5SSimon Wunderlich tt_global_entry->common.addr, message); 8187683fdc1SAntonio Quartulli 81948100bacSAntonio Quartulli hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig, 82048100bacSAntonio Quartulli tt_global_entry->common.addr); 8217683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 822db08e6e5SSimon Wunderlich 823c6c8fea2SSven Eckelmann } 824c6c8fea2SSven Eckelmann 825db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 826db08e6e5SSimon Wunderlich * within tt_global entry. If yes, we set the TT_CLIENT_ROAM flag and the timer, 827db08e6e5SSimon Wunderlich * otherwise we simply remove the originator scheduled for deletion. 828db08e6e5SSimon Wunderlich */ 829db08e6e5SSimon Wunderlich static void tt_global_del_roaming(struct bat_priv *bat_priv, 830db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry, 831db08e6e5SSimon Wunderlich struct orig_node *orig_node, 832db08e6e5SSimon Wunderlich const char *message) 833db08e6e5SSimon Wunderlich { 834db08e6e5SSimon Wunderlich bool last_entry = true; 835db08e6e5SSimon Wunderlich struct hlist_head *head; 836db08e6e5SSimon Wunderlich struct hlist_node *node; 837db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 838db08e6e5SSimon Wunderlich 839db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 840db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 841db08e6e5SSimon Wunderlich */ 842db08e6e5SSimon Wunderlich 843db08e6e5SSimon Wunderlich rcu_read_lock(); 844db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 845db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 846db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 847db08e6e5SSimon Wunderlich last_entry = false; 848db08e6e5SSimon Wunderlich break; 849db08e6e5SSimon Wunderlich } 850db08e6e5SSimon Wunderlich } 851db08e6e5SSimon Wunderlich rcu_read_unlock(); 852db08e6e5SSimon Wunderlich 853db08e6e5SSimon Wunderlich if (last_entry) { 854db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 855db08e6e5SSimon Wunderlich tt_global_entry->common.flags |= TT_CLIENT_ROAM; 856db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 857db08e6e5SSimon Wunderlich } else 858db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 859db08e6e5SSimon Wunderlich * one and can still use the other one. 860db08e6e5SSimon Wunderlich */ 861db08e6e5SSimon Wunderlich tt_global_del_orig_entry(bat_priv, tt_global_entry, 862db08e6e5SSimon Wunderlich orig_node, message); 863db08e6e5SSimon Wunderlich } 864db08e6e5SSimon Wunderlich 865db08e6e5SSimon Wunderlich 866db08e6e5SSimon Wunderlich 867de7aae65SSven Eckelmann static void tt_global_del(struct bat_priv *bat_priv, 868de7aae65SSven Eckelmann struct orig_node *orig_node, 869de7aae65SSven Eckelmann const unsigned char *addr, 870cc47f66eSAntonio Quartulli const char *message, bool roaming) 871a73105b8SAntonio Quartulli { 8727683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 873797399b4SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 874a73105b8SAntonio Quartulli 875a73105b8SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 876db08e6e5SSimon Wunderlich if (!tt_global_entry) 8777683fdc1SAntonio Quartulli goto out; 878a73105b8SAntonio Quartulli 879db08e6e5SSimon Wunderlich if (!roaming) { 880db08e6e5SSimon Wunderlich tt_global_del_orig_entry(bat_priv, tt_global_entry, orig_node, 881db08e6e5SSimon Wunderlich message); 88292f90f56SSven Eckelmann 883db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 884db08e6e5SSimon Wunderlich tt_global_del_struct(bat_priv, tt_global_entry, 885db08e6e5SSimon Wunderlich message); 886db08e6e5SSimon Wunderlich 887cc47f66eSAntonio Quartulli goto out; 888cc47f66eSAntonio Quartulli } 88992f90f56SSven Eckelmann 890db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 891db08e6e5SSimon Wunderlich * event, there are two possibilities: 892db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 893db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 894db08e6e5SSimon Wunderlich * it with TT_CLIENT_ROAM, we start a timer and we 895db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 896db08e6e5SSimon Wunderlich * the entry is purged. 897db08e6e5SSimon Wunderlich * 898db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 899db08e6e5SSimon Wunderlich * the originator. 900db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 901db08e6e5SSimon Wunderlich * the global entry, since it is useless now. */ 902db08e6e5SSimon Wunderlich 903db08e6e5SSimon Wunderlich tt_local_entry = tt_local_hash_find(bat_priv, 904db08e6e5SSimon Wunderlich tt_global_entry->common.addr); 905db08e6e5SSimon Wunderlich if (tt_local_entry) { 906db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 907db08e6e5SSimon Wunderlich tt_global_del_orig_list(tt_global_entry); 908db08e6e5SSimon Wunderlich tt_global_del_struct(bat_priv, tt_global_entry, message); 909db08e6e5SSimon Wunderlich } else 910db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 911db08e6e5SSimon Wunderlich tt_global_del_roaming(bat_priv, tt_global_entry, orig_node, 912db08e6e5SSimon Wunderlich message); 913db08e6e5SSimon Wunderlich 91492f90f56SSven Eckelmann 915cc47f66eSAntonio Quartulli out: 9167683fdc1SAntonio Quartulli if (tt_global_entry) 9177683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 918797399b4SAntonio Quartulli if (tt_local_entry) 919797399b4SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 920a73105b8SAntonio Quartulli } 921a73105b8SAntonio Quartulli 9222dafb49dSAntonio Quartulli void tt_global_del_orig(struct bat_priv *bat_priv, 923747e4221SSven Eckelmann struct orig_node *orig_node, const char *message) 924c6c8fea2SSven Eckelmann { 9252dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 92648100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 927c90681b8SAntonio Quartulli uint32_t i; 928a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 929a73105b8SAntonio Quartulli struct hlist_node *node, *safe; 930a73105b8SAntonio Quartulli struct hlist_head *head; 9317683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 932c6c8fea2SSven Eckelmann 9336e801494SSimon Wunderlich if (!hash) 9346e801494SSimon Wunderlich return; 9356e801494SSimon Wunderlich 936a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 937a73105b8SAntonio Quartulli head = &hash->table[i]; 9387683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 939c6c8fea2SSven Eckelmann 9407683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 94148100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, safe, 942a73105b8SAntonio Quartulli head, hash_entry) { 94348100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 94448100bacSAntonio Quartulli struct tt_global_entry, 94548100bacSAntonio Quartulli common); 946db08e6e5SSimon Wunderlich 947db08e6e5SSimon Wunderlich tt_global_del_orig_entry(bat_priv, tt_global_entry, 948db08e6e5SSimon Wunderlich orig_node, message); 949db08e6e5SSimon Wunderlich 950db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) { 9517683fdc1SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 952db08e6e5SSimon Wunderlich "Deleting global tt entry %pM: %s\n", 95348100bacSAntonio Quartulli tt_global_entry->common.addr, 95487944973SAntonio Quartulli message); 9557683fdc1SAntonio Quartulli hlist_del_rcu(node); 9567683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 957c6c8fea2SSven Eckelmann } 958a73105b8SAntonio Quartulli } 9597683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 9607683fdc1SAntonio Quartulli } 961a73105b8SAntonio Quartulli atomic_set(&orig_node->tt_size, 0); 96217071578SAntonio Quartulli orig_node->tt_initialised = false; 963c6c8fea2SSven Eckelmann } 964c6c8fea2SSven Eckelmann 965cc47f66eSAntonio Quartulli static void tt_global_roam_purge(struct bat_priv *bat_priv) 966cc47f66eSAntonio Quartulli { 967cc47f66eSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 96848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 969cc47f66eSAntonio Quartulli struct tt_global_entry *tt_global_entry; 970cc47f66eSAntonio Quartulli struct hlist_node *node, *node_tmp; 971cc47f66eSAntonio Quartulli struct hlist_head *head; 9727683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 973c90681b8SAntonio Quartulli uint32_t i; 974cc47f66eSAntonio Quartulli 975cc47f66eSAntonio Quartulli for (i = 0; i < hash->size; i++) { 976cc47f66eSAntonio Quartulli head = &hash->table[i]; 9777683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 978cc47f66eSAntonio Quartulli 9797683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 98048100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 981cc47f66eSAntonio Quartulli head, hash_entry) { 98248100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 98348100bacSAntonio Quartulli struct tt_global_entry, 98448100bacSAntonio Quartulli common); 98548100bacSAntonio Quartulli if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM)) 986cc47f66eSAntonio Quartulli continue; 987a04ccd59SMartin Hundebøll if (!has_timed_out(tt_global_entry->roam_at, 988032b7969SMarek Lindner TT_CLIENT_ROAM_TIMEOUT)) 989cc47f66eSAntonio Quartulli continue; 990cc47f66eSAntonio Quartulli 99186ceb360SSven Eckelmann bat_dbg(DBG_TT, bat_priv, 99286ceb360SSven Eckelmann "Deleting global tt entry (%pM): Roaming timeout\n", 99348100bacSAntonio Quartulli tt_global_entry->common.addr); 994db08e6e5SSimon Wunderlich 9957683fdc1SAntonio Quartulli hlist_del_rcu(node); 9967683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 997cc47f66eSAntonio Quartulli } 9987683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 999cc47f66eSAntonio Quartulli } 1000cc47f66eSAntonio Quartulli 1001cc47f66eSAntonio Quartulli } 1002cc47f66eSAntonio Quartulli 1003a73105b8SAntonio Quartulli static void tt_global_table_free(struct bat_priv *bat_priv) 1004c6c8fea2SSven Eckelmann { 10057683fdc1SAntonio Quartulli struct hashtable_t *hash; 10067683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 100748100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 10087683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry; 10097683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 10107683fdc1SAntonio Quartulli struct hlist_head *head; 1011c90681b8SAntonio Quartulli uint32_t i; 10127683fdc1SAntonio Quartulli 10132dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 1014c6c8fea2SSven Eckelmann return; 1015c6c8fea2SSven Eckelmann 10167683fdc1SAntonio Quartulli hash = bat_priv->tt_global_hash; 10177683fdc1SAntonio Quartulli 10187683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 10197683fdc1SAntonio Quartulli head = &hash->table[i]; 10207683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 10217683fdc1SAntonio Quartulli 10227683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 102348100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 10247683fdc1SAntonio Quartulli head, hash_entry) { 10257683fdc1SAntonio Quartulli hlist_del_rcu(node); 102648100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 102748100bacSAntonio Quartulli struct tt_global_entry, 102848100bacSAntonio Quartulli common); 10297683fdc1SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 10307683fdc1SAntonio Quartulli } 10317683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 10327683fdc1SAntonio Quartulli } 10337683fdc1SAntonio Quartulli 10341a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 10357683fdc1SAntonio Quartulli 10362dafb49dSAntonio Quartulli bat_priv->tt_global_hash = NULL; 1037c6c8fea2SSven Eckelmann } 1038c6c8fea2SSven Eckelmann 103959b699cdSAntonio Quartulli static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry, 104059b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry) 104159b699cdSAntonio Quartulli { 104259b699cdSAntonio Quartulli bool ret = false; 104359b699cdSAntonio Quartulli 104448100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_WIFI && 104548100bacSAntonio Quartulli tt_global_entry->common.flags & TT_CLIENT_WIFI) 104659b699cdSAntonio Quartulli ret = true; 104759b699cdSAntonio Quartulli 104859b699cdSAntonio Quartulli return ret; 104959b699cdSAntonio Quartulli } 105059b699cdSAntonio Quartulli 1051747e4221SSven Eckelmann struct orig_node *transtable_search(struct bat_priv *bat_priv, 10523d393e47SAntonio Quartulli const uint8_t *src, const uint8_t *addr) 1053c6c8fea2SSven Eckelmann { 10543d393e47SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 10553d393e47SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 10567b36e8eeSMarek Lindner struct orig_node *orig_node = NULL; 1057db08e6e5SSimon Wunderlich struct neigh_node *router = NULL; 1058db08e6e5SSimon Wunderlich struct hlist_head *head; 1059db08e6e5SSimon Wunderlich struct hlist_node *node; 1060db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 1061db08e6e5SSimon Wunderlich int best_tq; 1062c6c8fea2SSven Eckelmann 10633d393e47SAntonio Quartulli if (src && atomic_read(&bat_priv->ap_isolation)) { 10643d393e47SAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, src); 10653d393e47SAntonio Quartulli if (!tt_local_entry) 10663d393e47SAntonio Quartulli goto out; 10673d393e47SAntonio Quartulli } 10687aadf889SMarek Lindner 10693d393e47SAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 10702dafb49dSAntonio Quartulli if (!tt_global_entry) 10717b36e8eeSMarek Lindner goto out; 1072c6c8fea2SSven Eckelmann 10733d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 10743d393e47SAntonio Quartulli * isolation */ 10753d393e47SAntonio Quartulli if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry)) 10763d393e47SAntonio Quartulli goto out; 10773d393e47SAntonio Quartulli 1078db08e6e5SSimon Wunderlich best_tq = 0; 10797b36e8eeSMarek Lindner 1080db08e6e5SSimon Wunderlich rcu_read_lock(); 1081db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1082db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 10837d211efcSSven Eckelmann router = batadv_orig_node_get_router(orig_entry->orig_node); 1084db08e6e5SSimon Wunderlich if (!router) 1085db08e6e5SSimon Wunderlich continue; 10867b36e8eeSMarek Lindner 1087db08e6e5SSimon Wunderlich if (router->tq_avg > best_tq) { 1088db08e6e5SSimon Wunderlich orig_node = orig_entry->orig_node; 1089db08e6e5SSimon Wunderlich best_tq = router->tq_avg; 1090db08e6e5SSimon Wunderlich } 10917d211efcSSven Eckelmann batadv_neigh_node_free_ref(router); 1092db08e6e5SSimon Wunderlich } 1093db08e6e5SSimon Wunderlich /* found anything? */ 1094db08e6e5SSimon Wunderlich if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) 1095db08e6e5SSimon Wunderlich orig_node = NULL; 1096db08e6e5SSimon Wunderlich rcu_read_unlock(); 10977b36e8eeSMarek Lindner out: 10983d393e47SAntonio Quartulli if (tt_global_entry) 10993d393e47SAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 11003d393e47SAntonio Quartulli if (tt_local_entry) 11013d393e47SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 11023d393e47SAntonio Quartulli 11037b36e8eeSMarek Lindner return orig_node; 1104c6c8fea2SSven Eckelmann } 1105a73105b8SAntonio Quartulli 1106a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */ 1107de7aae65SSven Eckelmann static uint16_t tt_global_crc(struct bat_priv *bat_priv, 1108de7aae65SSven Eckelmann struct orig_node *orig_node) 1109a73105b8SAntonio Quartulli { 1110a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1111a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 111248100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1113a73105b8SAntonio Quartulli struct tt_global_entry *tt_global_entry; 1114a73105b8SAntonio Quartulli struct hlist_node *node; 1115a73105b8SAntonio Quartulli struct hlist_head *head; 1116c90681b8SAntonio Quartulli uint32_t i; 1117c90681b8SAntonio Quartulli int j; 1118a73105b8SAntonio Quartulli 1119a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1120a73105b8SAntonio Quartulli head = &hash->table[i]; 1121a73105b8SAntonio Quartulli 1122a73105b8SAntonio Quartulli rcu_read_lock(); 112348100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1124a73105b8SAntonio Quartulli head, hash_entry) { 112548100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 112648100bacSAntonio Quartulli struct tt_global_entry, 112748100bacSAntonio Quartulli common); 1128cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 1129cc47f66eSAntonio Quartulli * consistency only. They don't have to be 1130cc47f66eSAntonio Quartulli * taken into account while computing the 1131db08e6e5SSimon Wunderlich * global crc 1132db08e6e5SSimon Wunderlich */ 1133db08e6e5SSimon Wunderlich if (tt_global_entry->common.flags & TT_CLIENT_ROAM) 1134cc47f66eSAntonio Quartulli continue; 1135db08e6e5SSimon Wunderlich 1136db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 1137db08e6e5SSimon Wunderlich * originator 1138db08e6e5SSimon Wunderlich */ 1139db08e6e5SSimon Wunderlich if (!tt_global_entry_has_orig(tt_global_entry, 1140db08e6e5SSimon Wunderlich orig_node)) 1141db08e6e5SSimon Wunderlich continue; 1142db08e6e5SSimon Wunderlich 1143a73105b8SAntonio Quartulli total_one = 0; 1144a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1145a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 1146db08e6e5SSimon Wunderlich tt_global_entry->common.addr[j]); 1147a73105b8SAntonio Quartulli total ^= total_one; 1148a73105b8SAntonio Quartulli } 1149a73105b8SAntonio Quartulli rcu_read_unlock(); 1150a73105b8SAntonio Quartulli } 1151a73105b8SAntonio Quartulli 1152a73105b8SAntonio Quartulli return total; 1153a73105b8SAntonio Quartulli } 1154a73105b8SAntonio Quartulli 1155a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */ 1156be9aa4c1SMarek Lindner static uint16_t batadv_tt_local_crc(struct bat_priv *bat_priv) 1157a73105b8SAntonio Quartulli { 1158a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1159a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 116048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1161a73105b8SAntonio Quartulli struct hlist_node *node; 1162a73105b8SAntonio Quartulli struct hlist_head *head; 1163c90681b8SAntonio Quartulli uint32_t i; 1164c90681b8SAntonio Quartulli int j; 1165a73105b8SAntonio Quartulli 1166a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1167a73105b8SAntonio Quartulli head = &hash->table[i]; 1168a73105b8SAntonio Quartulli 1169a73105b8SAntonio Quartulli rcu_read_lock(); 117048100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1171a73105b8SAntonio Quartulli head, hash_entry) { 1172058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 1173058d0e26SAntonio Quartulli * account while computing the CRC */ 117448100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_NEW) 1175058d0e26SAntonio Quartulli continue; 1176a73105b8SAntonio Quartulli total_one = 0; 1177a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1178a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 117948100bacSAntonio Quartulli tt_common_entry->addr[j]); 1180a73105b8SAntonio Quartulli total ^= total_one; 1181a73105b8SAntonio Quartulli } 1182a73105b8SAntonio Quartulli rcu_read_unlock(); 1183a73105b8SAntonio Quartulli } 1184a73105b8SAntonio Quartulli 1185a73105b8SAntonio Quartulli return total; 1186a73105b8SAntonio Quartulli } 1187a73105b8SAntonio Quartulli 1188a73105b8SAntonio Quartulli static void tt_req_list_free(struct bat_priv *bat_priv) 1189a73105b8SAntonio Quartulli { 1190a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1191a73105b8SAntonio Quartulli 1192a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1193a73105b8SAntonio Quartulli 1194a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 1195a73105b8SAntonio Quartulli list_del(&node->list); 1196a73105b8SAntonio Quartulli kfree(node); 1197a73105b8SAntonio Quartulli } 1198a73105b8SAntonio Quartulli 1199a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1200a73105b8SAntonio Quartulli } 1201a73105b8SAntonio Quartulli 1202de7aae65SSven Eckelmann static void tt_save_orig_buffer(struct bat_priv *bat_priv, 1203de7aae65SSven Eckelmann struct orig_node *orig_node, 1204de7aae65SSven Eckelmann const unsigned char *tt_buff, 1205de7aae65SSven Eckelmann uint8_t tt_num_changes) 1206a73105b8SAntonio Quartulli { 1207a73105b8SAntonio Quartulli uint16_t tt_buff_len = tt_len(tt_num_changes); 1208a73105b8SAntonio Quartulli 1209a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 1210a73105b8SAntonio Quartulli * last OGM (the OGM could carry no changes) */ 1211a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1212a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 1213a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1214a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1215a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 1216a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 1217a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 1218a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 1219a73105b8SAntonio Quartulli } 1220a73105b8SAntonio Quartulli } 1221a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1222a73105b8SAntonio Quartulli } 1223a73105b8SAntonio Quartulli 1224a73105b8SAntonio Quartulli static void tt_req_purge(struct bat_priv *bat_priv) 1225a73105b8SAntonio Quartulli { 1226a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1227a73105b8SAntonio Quartulli 1228a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1229a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 1230032b7969SMarek Lindner if (has_timed_out(node->issued_at, TT_REQUEST_TIMEOUT)) { 1231a73105b8SAntonio Quartulli list_del(&node->list); 1232a73105b8SAntonio Quartulli kfree(node); 1233a73105b8SAntonio Quartulli } 1234a73105b8SAntonio Quartulli } 1235a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1236a73105b8SAntonio Quartulli } 1237a73105b8SAntonio Quartulli 1238a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 1239a73105b8SAntonio Quartulli * has already been issued for this orig_node, NULL otherwise */ 1240a73105b8SAntonio Quartulli static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv, 1241a73105b8SAntonio Quartulli struct orig_node *orig_node) 1242a73105b8SAntonio Quartulli { 1243a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 1244a73105b8SAntonio Quartulli 1245a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1246a73105b8SAntonio Quartulli list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { 1247a73105b8SAntonio Quartulli if (compare_eth(tt_req_node_tmp, orig_node) && 1248a04ccd59SMartin Hundebøll !has_timed_out(tt_req_node_tmp->issued_at, 1249032b7969SMarek Lindner TT_REQUEST_TIMEOUT)) 1250a73105b8SAntonio Quartulli goto unlock; 1251a73105b8SAntonio Quartulli } 1252a73105b8SAntonio Quartulli 1253a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 1254a73105b8SAntonio Quartulli if (!tt_req_node) 1255a73105b8SAntonio Quartulli goto unlock; 1256a73105b8SAntonio Quartulli 1257a73105b8SAntonio Quartulli memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); 1258a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 1259a73105b8SAntonio Quartulli 1260a73105b8SAntonio Quartulli list_add(&tt_req_node->list, &bat_priv->tt_req_list); 1261a73105b8SAntonio Quartulli unlock: 1262a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1263a73105b8SAntonio Quartulli return tt_req_node; 1264a73105b8SAntonio Quartulli } 1265a73105b8SAntonio Quartulli 1266058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */ 1267058d0e26SAntonio Quartulli static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr) 1268058d0e26SAntonio Quartulli { 126948100bacSAntonio Quartulli const struct tt_common_entry *tt_common_entry = entry_ptr; 1270058d0e26SAntonio Quartulli 127148100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_NEW) 1272058d0e26SAntonio Quartulli return 0; 1273058d0e26SAntonio Quartulli return 1; 1274058d0e26SAntonio Quartulli } 1275058d0e26SAntonio Quartulli 1276a73105b8SAntonio Quartulli static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) 1277a73105b8SAntonio Quartulli { 127848100bacSAntonio Quartulli const struct tt_common_entry *tt_common_entry = entry_ptr; 127948100bacSAntonio Quartulli const struct tt_global_entry *tt_global_entry; 1280a73105b8SAntonio Quartulli const struct orig_node *orig_node = data_ptr; 1281a73105b8SAntonio Quartulli 128248100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_ROAM) 1283cc47f66eSAntonio Quartulli return 0; 1284cc47f66eSAntonio Quartulli 128548100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, 128648100bacSAntonio Quartulli common); 128748100bacSAntonio Quartulli 1288db08e6e5SSimon Wunderlich return tt_global_entry_has_orig(tt_global_entry, orig_node); 1289a73105b8SAntonio Quartulli } 1290a73105b8SAntonio Quartulli 1291a73105b8SAntonio Quartulli static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, 1292a73105b8SAntonio Quartulli struct hashtable_t *hash, 1293a73105b8SAntonio Quartulli struct hard_iface *primary_if, 1294a73105b8SAntonio Quartulli int (*valid_cb)(const void *, 1295a73105b8SAntonio Quartulli const void *), 1296a73105b8SAntonio Quartulli void *cb_data) 1297a73105b8SAntonio Quartulli { 129848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1299a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1300a73105b8SAntonio Quartulli struct tt_change *tt_change; 1301a73105b8SAntonio Quartulli struct hlist_node *node; 1302a73105b8SAntonio Quartulli struct hlist_head *head; 1303a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1304a73105b8SAntonio Quartulli uint16_t tt_tot, tt_count; 1305a73105b8SAntonio Quartulli ssize_t tt_query_size = sizeof(struct tt_query_packet); 1306c90681b8SAntonio Quartulli uint32_t i; 1307a73105b8SAntonio Quartulli 1308a73105b8SAntonio Quartulli if (tt_query_size + tt_len > primary_if->soft_iface->mtu) { 1309a73105b8SAntonio Quartulli tt_len = primary_if->soft_iface->mtu - tt_query_size; 1310a73105b8SAntonio Quartulli tt_len -= tt_len % sizeof(struct tt_change); 1311a73105b8SAntonio Quartulli } 1312a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1313a73105b8SAntonio Quartulli 1314a73105b8SAntonio Quartulli skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN); 1315a73105b8SAntonio Quartulli if (!skb) 1316a73105b8SAntonio Quartulli goto out; 1317a73105b8SAntonio Quartulli 1318a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1319a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1320a73105b8SAntonio Quartulli tt_query_size + tt_len); 1321a73105b8SAntonio Quartulli tt_response->ttvn = ttvn; 1322a73105b8SAntonio Quartulli 1323a73105b8SAntonio Quartulli tt_change = (struct tt_change *)(skb->data + tt_query_size); 1324a73105b8SAntonio Quartulli tt_count = 0; 1325a73105b8SAntonio Quartulli 1326a73105b8SAntonio Quartulli rcu_read_lock(); 1327a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1328a73105b8SAntonio Quartulli head = &hash->table[i]; 1329a73105b8SAntonio Quartulli 133048100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1331a73105b8SAntonio Quartulli head, hash_entry) { 1332a73105b8SAntonio Quartulli if (tt_count == tt_tot) 1333a73105b8SAntonio Quartulli break; 1334a73105b8SAntonio Quartulli 133548100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 1336a73105b8SAntonio Quartulli continue; 1337a73105b8SAntonio Quartulli 133848100bacSAntonio Quartulli memcpy(tt_change->addr, tt_common_entry->addr, 133948100bacSAntonio Quartulli ETH_ALEN); 1340a73105b8SAntonio Quartulli tt_change->flags = NO_FLAGS; 1341a73105b8SAntonio Quartulli 1342a73105b8SAntonio Quartulli tt_count++; 1343a73105b8SAntonio Quartulli tt_change++; 1344a73105b8SAntonio Quartulli } 1345a73105b8SAntonio Quartulli } 1346a73105b8SAntonio Quartulli rcu_read_unlock(); 1347a73105b8SAntonio Quartulli 13489d852393SAntonio Quartulli /* store in the message the number of entries we have successfully 13499d852393SAntonio Quartulli * copied */ 13509d852393SAntonio Quartulli tt_response->tt_data = htons(tt_count); 13519d852393SAntonio Quartulli 1352a73105b8SAntonio Quartulli out: 1353a73105b8SAntonio Quartulli return skb; 1354a73105b8SAntonio Quartulli } 1355a73105b8SAntonio Quartulli 1356a943cac1SMarek Lindner static int send_tt_request(struct bat_priv *bat_priv, 1357a943cac1SMarek Lindner struct orig_node *dst_orig_node, 1358a73105b8SAntonio Quartulli uint8_t ttvn, uint16_t tt_crc, bool full_table) 1359a73105b8SAntonio Quartulli { 1360a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1361a73105b8SAntonio Quartulli struct tt_query_packet *tt_request; 1362a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1363a73105b8SAntonio Quartulli struct hard_iface *primary_if; 1364a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node = NULL; 1365a73105b8SAntonio Quartulli int ret = 1; 1366a73105b8SAntonio Quartulli 1367a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1368a73105b8SAntonio Quartulli if (!primary_if) 1369a73105b8SAntonio Quartulli goto out; 1370a73105b8SAntonio Quartulli 1371a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 1372a73105b8SAntonio Quartulli * reply from the same orig_node yet */ 1373a73105b8SAntonio Quartulli tt_req_node = new_tt_req_node(bat_priv, dst_orig_node); 1374a73105b8SAntonio Quartulli if (!tt_req_node) 1375a73105b8SAntonio Quartulli goto out; 1376a73105b8SAntonio Quartulli 1377a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN); 1378a73105b8SAntonio Quartulli if (!skb) 1379a73105b8SAntonio Quartulli goto out; 1380a73105b8SAntonio Quartulli 1381a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1382a73105b8SAntonio Quartulli 1383a73105b8SAntonio Quartulli tt_request = (struct tt_query_packet *)skb_put(skb, 1384a73105b8SAntonio Quartulli sizeof(struct tt_query_packet)); 1385a73105b8SAntonio Quartulli 138676543d14SSven Eckelmann tt_request->header.packet_type = BAT_TT_QUERY; 138776543d14SSven Eckelmann tt_request->header.version = COMPAT_VERSION; 1388a73105b8SAntonio Quartulli memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1389a73105b8SAntonio Quartulli memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); 139076543d14SSven Eckelmann tt_request->header.ttl = TTL; 1391a73105b8SAntonio Quartulli tt_request->ttvn = ttvn; 13926d2003fcSAntonio Quartulli tt_request->tt_data = htons(tt_crc); 1393a73105b8SAntonio Quartulli tt_request->flags = TT_REQUEST; 1394a73105b8SAntonio Quartulli 1395a73105b8SAntonio Quartulli if (full_table) 1396a73105b8SAntonio Quartulli tt_request->flags |= TT_FULL_TABLE; 1397a73105b8SAntonio Quartulli 13987d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(dst_orig_node); 1399a73105b8SAntonio Quartulli if (!neigh_node) 1400a73105b8SAntonio Quartulli goto out; 1401a73105b8SAntonio Quartulli 140286ceb360SSven Eckelmann bat_dbg(DBG_TT, bat_priv, 140386ceb360SSven Eckelmann "Sending TT_REQUEST to %pM via %pM [%c]\n", 140486ceb360SSven Eckelmann dst_orig_node->orig, neigh_node->addr, 1405a73105b8SAntonio Quartulli (full_table ? 'F' : '.')); 1406a73105b8SAntonio Quartulli 1407f8214865SMartin Hundebøll batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_TX); 1408f8214865SMartin Hundebøll 14099455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1410a73105b8SAntonio Quartulli ret = 0; 1411a73105b8SAntonio Quartulli 1412a73105b8SAntonio Quartulli out: 1413a73105b8SAntonio Quartulli if (neigh_node) 14147d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1415a73105b8SAntonio Quartulli if (primary_if) 1416a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1417a73105b8SAntonio Quartulli if (ret) 1418a73105b8SAntonio Quartulli kfree_skb(skb); 1419a73105b8SAntonio Quartulli if (ret && tt_req_node) { 1420a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1421a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 1422a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1423a73105b8SAntonio Quartulli kfree(tt_req_node); 1424a73105b8SAntonio Quartulli } 1425a73105b8SAntonio Quartulli return ret; 1426a73105b8SAntonio Quartulli } 1427a73105b8SAntonio Quartulli 1428a73105b8SAntonio Quartulli static bool send_other_tt_response(struct bat_priv *bat_priv, 1429a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1430a73105b8SAntonio Quartulli { 1431a73105b8SAntonio Quartulli struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL; 1432a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1433a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1434a73105b8SAntonio Quartulli uint8_t orig_ttvn, req_ttvn, ttvn; 1435a73105b8SAntonio Quartulli int ret = false; 1436a73105b8SAntonio Quartulli unsigned char *tt_buff; 1437a73105b8SAntonio Quartulli bool full_table; 1438a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1439a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1440a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1441a73105b8SAntonio Quartulli 1442a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 144386ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 144486ceb360SSven Eckelmann tt_request->src, tt_request->ttvn, tt_request->dst, 1445a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1446a73105b8SAntonio Quartulli 1447a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 1448eb7e2a1eSAntonio Quartulli req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst); 1449a73105b8SAntonio Quartulli if (!req_dst_orig_node) 1450a73105b8SAntonio Quartulli goto out; 1451a73105b8SAntonio Quartulli 1452eb7e2a1eSAntonio Quartulli res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src); 1453a73105b8SAntonio Quartulli if (!res_dst_orig_node) 1454a73105b8SAntonio Quartulli goto out; 1455a73105b8SAntonio Quartulli 14567d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(res_dst_orig_node); 1457a73105b8SAntonio Quartulli if (!neigh_node) 1458a73105b8SAntonio Quartulli goto out; 1459a73105b8SAntonio Quartulli 1460a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1461a73105b8SAntonio Quartulli if (!primary_if) 1462a73105b8SAntonio Quartulli goto out; 1463a73105b8SAntonio Quartulli 1464a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1465a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1466a73105b8SAntonio Quartulli 1467015758d0SAntonio Quartulli /* I don't have the requested data */ 1468a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 1469f25bd58aSAl Viro tt_request->tt_data != htons(req_dst_orig_node->tt_crc)) 1470a73105b8SAntonio Quartulli goto out; 1471a73105b8SAntonio Quartulli 1472015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 1473a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || 1474a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 1475a73105b8SAntonio Quartulli full_table = true; 1476a73105b8SAntonio Quartulli else 1477a73105b8SAntonio Quartulli full_table = false; 1478a73105b8SAntonio Quartulli 1479a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 1480a73105b8SAntonio Quartulli * I'll send only one packet with as much TT entries as I can */ 1481a73105b8SAntonio Quartulli if (!full_table) { 1482a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 1483a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 1484a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1485a73105b8SAntonio Quartulli 1486a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1487a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1488a73105b8SAntonio Quartulli if (!skb) 1489a73105b8SAntonio Quartulli goto unlock; 1490a73105b8SAntonio Quartulli 1491a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1492a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1493a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1494a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1495a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1496a73105b8SAntonio Quartulli 1497a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1498a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 1499a73105b8SAntonio Quartulli memcpy(tt_buff, req_dst_orig_node->tt_buff, 1500a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 1501a73105b8SAntonio Quartulli 1502a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1503a73105b8SAntonio Quartulli } else { 1504a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) * 1505a73105b8SAntonio Quartulli sizeof(struct tt_change); 1506a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1507a73105b8SAntonio Quartulli 1508a73105b8SAntonio Quartulli skb = tt_response_fill_table(tt_len, ttvn, 1509a73105b8SAntonio Quartulli bat_priv->tt_global_hash, 1510a73105b8SAntonio Quartulli primary_if, tt_global_valid_entry, 1511a73105b8SAntonio Quartulli req_dst_orig_node); 1512a73105b8SAntonio Quartulli if (!skb) 1513a73105b8SAntonio Quartulli goto out; 1514a73105b8SAntonio Quartulli 1515a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1516a73105b8SAntonio Quartulli } 1517a73105b8SAntonio Quartulli 151876543d14SSven Eckelmann tt_response->header.packet_type = BAT_TT_QUERY; 151976543d14SSven Eckelmann tt_response->header.version = COMPAT_VERSION; 152076543d14SSven Eckelmann tt_response->header.ttl = TTL; 1521a73105b8SAntonio Quartulli memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); 1522a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1523a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1524a73105b8SAntonio Quartulli 1525a73105b8SAntonio Quartulli if (full_table) 1526a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1527a73105b8SAntonio Quartulli 1528a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1529a73105b8SAntonio Quartulli "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n", 1530a73105b8SAntonio Quartulli res_dst_orig_node->orig, neigh_node->addr, 1531a73105b8SAntonio Quartulli req_dst_orig_node->orig, req_ttvn); 1532a73105b8SAntonio Quartulli 1533f8214865SMartin Hundebøll batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX); 1534f8214865SMartin Hundebøll 15359455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1536a73105b8SAntonio Quartulli ret = true; 1537a73105b8SAntonio Quartulli goto out; 1538a73105b8SAntonio Quartulli 1539a73105b8SAntonio Quartulli unlock: 1540a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1541a73105b8SAntonio Quartulli 1542a73105b8SAntonio Quartulli out: 1543a73105b8SAntonio Quartulli if (res_dst_orig_node) 15447d211efcSSven Eckelmann batadv_orig_node_free_ref(res_dst_orig_node); 1545a73105b8SAntonio Quartulli if (req_dst_orig_node) 15467d211efcSSven Eckelmann batadv_orig_node_free_ref(req_dst_orig_node); 1547a73105b8SAntonio Quartulli if (neigh_node) 15487d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1549a73105b8SAntonio Quartulli if (primary_if) 1550a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1551a73105b8SAntonio Quartulli if (!ret) 1552a73105b8SAntonio Quartulli kfree_skb(skb); 1553a73105b8SAntonio Quartulli return ret; 1554a73105b8SAntonio Quartulli 1555a73105b8SAntonio Quartulli } 1556a73105b8SAntonio Quartulli static bool send_my_tt_response(struct bat_priv *bat_priv, 1557a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1558a73105b8SAntonio Quartulli { 1559a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1560a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1561a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1562a73105b8SAntonio Quartulli uint8_t my_ttvn, req_ttvn, ttvn; 1563a73105b8SAntonio Quartulli int ret = false; 1564a73105b8SAntonio Quartulli unsigned char *tt_buff; 1565a73105b8SAntonio Quartulli bool full_table; 1566a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1567a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1568a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1569a73105b8SAntonio Quartulli 1570a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 157186ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 157286ceb360SSven Eckelmann tt_request->src, tt_request->ttvn, 1573a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1574a73105b8SAntonio Quartulli 1575a73105b8SAntonio Quartulli 1576a73105b8SAntonio Quartulli my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1577a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1578a73105b8SAntonio Quartulli 1579eb7e2a1eSAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_request->src); 1580a73105b8SAntonio Quartulli if (!orig_node) 1581a73105b8SAntonio Quartulli goto out; 1582a73105b8SAntonio Quartulli 15837d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(orig_node); 1584a73105b8SAntonio Quartulli if (!neigh_node) 1585a73105b8SAntonio Quartulli goto out; 1586a73105b8SAntonio Quartulli 1587a73105b8SAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1588a73105b8SAntonio Quartulli if (!primary_if) 1589a73105b8SAntonio Quartulli goto out; 1590a73105b8SAntonio Quartulli 1591a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 1592a73105b8SAntonio Quartulli * is too big send the whole local translation table */ 1593a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn || 1594a73105b8SAntonio Quartulli !bat_priv->tt_buff) 1595a73105b8SAntonio Quartulli full_table = true; 1596a73105b8SAntonio Quartulli else 1597a73105b8SAntonio Quartulli full_table = false; 1598a73105b8SAntonio Quartulli 1599a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 1600a73105b8SAntonio Quartulli * I'll send only one packet with as much TT entries as I can */ 1601a73105b8SAntonio Quartulli if (!full_table) { 1602a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 1603a73105b8SAntonio Quartulli tt_len = bat_priv->tt_buff_len; 1604a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1605a73105b8SAntonio Quartulli 1606a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1607a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1608a73105b8SAntonio Quartulli if (!skb) 1609a73105b8SAntonio Quartulli goto unlock; 1610a73105b8SAntonio Quartulli 1611a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1612a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1613a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1614a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1615a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1616a73105b8SAntonio Quartulli 1617a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1618a73105b8SAntonio Quartulli memcpy(tt_buff, bat_priv->tt_buff, 1619a73105b8SAntonio Quartulli bat_priv->tt_buff_len); 1620a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1621a73105b8SAntonio Quartulli } else { 1622a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) * 1623a73105b8SAntonio Quartulli sizeof(struct tt_change); 1624a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1625a73105b8SAntonio Quartulli 1626a73105b8SAntonio Quartulli skb = tt_response_fill_table(tt_len, ttvn, 1627a73105b8SAntonio Quartulli bat_priv->tt_local_hash, 1628058d0e26SAntonio Quartulli primary_if, tt_local_valid_entry, 1629058d0e26SAntonio Quartulli NULL); 1630a73105b8SAntonio Quartulli if (!skb) 1631a73105b8SAntonio Quartulli goto out; 1632a73105b8SAntonio Quartulli 1633a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1634a73105b8SAntonio Quartulli } 1635a73105b8SAntonio Quartulli 163676543d14SSven Eckelmann tt_response->header.packet_type = BAT_TT_QUERY; 163776543d14SSven Eckelmann tt_response->header.version = COMPAT_VERSION; 163876543d14SSven Eckelmann tt_response->header.ttl = TTL; 1639a73105b8SAntonio Quartulli memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1640a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1641a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1642a73105b8SAntonio Quartulli 1643a73105b8SAntonio Quartulli if (full_table) 1644a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1645a73105b8SAntonio Quartulli 1646a73105b8SAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1647a73105b8SAntonio Quartulli "Sending TT_RESPONSE to %pM via %pM [%c]\n", 1648a73105b8SAntonio Quartulli orig_node->orig, neigh_node->addr, 1649a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1650a73105b8SAntonio Quartulli 1651f8214865SMartin Hundebøll batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX); 1652f8214865SMartin Hundebøll 16539455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1654a73105b8SAntonio Quartulli ret = true; 1655a73105b8SAntonio Quartulli goto out; 1656a73105b8SAntonio Quartulli 1657a73105b8SAntonio Quartulli unlock: 1658a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1659a73105b8SAntonio Quartulli out: 1660a73105b8SAntonio Quartulli if (orig_node) 16617d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1662a73105b8SAntonio Quartulli if (neigh_node) 16637d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1664a73105b8SAntonio Quartulli if (primary_if) 1665a73105b8SAntonio Quartulli hardif_free_ref(primary_if); 1666a73105b8SAntonio Quartulli if (!ret) 1667a73105b8SAntonio Quartulli kfree_skb(skb); 1668a73105b8SAntonio Quartulli /* This packet was for me, so it doesn't need to be re-routed */ 1669a73105b8SAntonio Quartulli return true; 1670a73105b8SAntonio Quartulli } 1671a73105b8SAntonio Quartulli 1672a73105b8SAntonio Quartulli bool send_tt_response(struct bat_priv *bat_priv, 1673a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1674a73105b8SAntonio Quartulli { 167520ff9d59SSimon Wunderlich if (is_my_mac(tt_request->dst)) { 167620ff9d59SSimon Wunderlich /* don't answer backbone gws! */ 167708adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src)) 167820ff9d59SSimon Wunderlich return true; 167920ff9d59SSimon Wunderlich 1680a73105b8SAntonio Quartulli return send_my_tt_response(bat_priv, tt_request); 168120ff9d59SSimon Wunderlich } else { 1682a73105b8SAntonio Quartulli return send_other_tt_response(bat_priv, tt_request); 1683a73105b8SAntonio Quartulli } 168420ff9d59SSimon Wunderlich } 1685a73105b8SAntonio Quartulli 1686a73105b8SAntonio Quartulli static void _tt_update_changes(struct bat_priv *bat_priv, 1687a73105b8SAntonio Quartulli struct orig_node *orig_node, 1688a73105b8SAntonio Quartulli struct tt_change *tt_change, 1689a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 1690a73105b8SAntonio Quartulli { 1691a73105b8SAntonio Quartulli int i; 1692a73105b8SAntonio Quartulli 1693a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 16945fbc1598SAntonio Quartulli if ((tt_change + i)->flags & TT_CLIENT_DEL) 1695a73105b8SAntonio Quartulli tt_global_del(bat_priv, orig_node, 1696a73105b8SAntonio Quartulli (tt_change + i)->addr, 1697cc47f66eSAntonio Quartulli "tt removed by changes", 1698cc47f66eSAntonio Quartulli (tt_change + i)->flags & TT_CLIENT_ROAM); 1699a73105b8SAntonio Quartulli else 1700a73105b8SAntonio Quartulli if (!tt_global_add(bat_priv, orig_node, 1701bc279080SAntonio Quartulli (tt_change + i)->addr, ttvn, false, 1702bc279080SAntonio Quartulli (tt_change + i)->flags & 1703bc279080SAntonio Quartulli TT_CLIENT_WIFI)) 1704a73105b8SAntonio Quartulli /* In case of problem while storing a 1705a73105b8SAntonio Quartulli * global_entry, we stop the updating 1706a73105b8SAntonio Quartulli * procedure without committing the 1707a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 1708a73105b8SAntonio Quartulli * corrupted data on tt_request 1709a73105b8SAntonio Quartulli */ 1710a73105b8SAntonio Quartulli return; 1711a73105b8SAntonio Quartulli } 171217071578SAntonio Quartulli orig_node->tt_initialised = true; 1713a73105b8SAntonio Quartulli } 1714a73105b8SAntonio Quartulli 1715a73105b8SAntonio Quartulli static void tt_fill_gtable(struct bat_priv *bat_priv, 1716a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1717a73105b8SAntonio Quartulli { 1718a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1719a73105b8SAntonio Quartulli 1720a73105b8SAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_response->src); 1721a73105b8SAntonio Quartulli if (!orig_node) 1722a73105b8SAntonio Quartulli goto out; 1723a73105b8SAntonio Quartulli 1724a73105b8SAntonio Quartulli /* Purge the old table first.. */ 1725a73105b8SAntonio Quartulli tt_global_del_orig(bat_priv, orig_node, "Received full table"); 1726a73105b8SAntonio Quartulli 1727a73105b8SAntonio Quartulli _tt_update_changes(bat_priv, orig_node, 1728a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1), 1729f25bd58aSAl Viro ntohs(tt_response->tt_data), tt_response->ttvn); 1730a73105b8SAntonio Quartulli 1731a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1732a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1733a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1734a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 1735a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1736a73105b8SAntonio Quartulli 1737a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, tt_response->ttvn); 1738a73105b8SAntonio Quartulli 1739a73105b8SAntonio Quartulli out: 1740a73105b8SAntonio Quartulli if (orig_node) 17417d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1742a73105b8SAntonio Quartulli } 1743a73105b8SAntonio Quartulli 1744a943cac1SMarek Lindner static void tt_update_changes(struct bat_priv *bat_priv, 1745a943cac1SMarek Lindner struct orig_node *orig_node, 1746a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 1747a73105b8SAntonio Quartulli struct tt_change *tt_change) 1748a73105b8SAntonio Quartulli { 1749a73105b8SAntonio Quartulli _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes, 1750a73105b8SAntonio Quartulli ttvn); 1751a73105b8SAntonio Quartulli 1752a73105b8SAntonio Quartulli tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change, 1753a73105b8SAntonio Quartulli tt_num_changes); 1754a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 1755a73105b8SAntonio Quartulli } 1756a73105b8SAntonio Quartulli 1757a73105b8SAntonio Quartulli bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) 1758a73105b8SAntonio Quartulli { 17597683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 17607683fdc1SAntonio Quartulli bool ret = false; 1761a73105b8SAntonio Quartulli 1762a73105b8SAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, addr); 17637683fdc1SAntonio Quartulli if (!tt_local_entry) 17647683fdc1SAntonio Quartulli goto out; 1765058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 1766058d0e26SAntonio Quartulli * consistency purpose) */ 176748100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_PENDING) 1768058d0e26SAntonio Quartulli goto out; 17697683fdc1SAntonio Quartulli ret = true; 17707683fdc1SAntonio Quartulli out: 1771a73105b8SAntonio Quartulli if (tt_local_entry) 17727683fdc1SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 17737683fdc1SAntonio Quartulli return ret; 1774a73105b8SAntonio Quartulli } 1775a73105b8SAntonio Quartulli 1776a73105b8SAntonio Quartulli void handle_tt_response(struct bat_priv *bat_priv, 1777a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1778a73105b8SAntonio Quartulli { 1779a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1780a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1781a73105b8SAntonio Quartulli 178286ceb360SSven Eckelmann bat_dbg(DBG_TT, bat_priv, 178386ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 1784f25bd58aSAl Viro tt_response->src, tt_response->ttvn, 1785f25bd58aSAl Viro ntohs(tt_response->tt_data), 1786a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1787a73105b8SAntonio Quartulli 178820ff9d59SSimon Wunderlich /* we should have never asked a backbone gw */ 178908adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src)) 179020ff9d59SSimon Wunderlich goto out; 179120ff9d59SSimon Wunderlich 1792a73105b8SAntonio Quartulli orig_node = orig_hash_find(bat_priv, tt_response->src); 1793a73105b8SAntonio Quartulli if (!orig_node) 1794a73105b8SAntonio Quartulli goto out; 1795a73105b8SAntonio Quartulli 1796a73105b8SAntonio Quartulli if (tt_response->flags & TT_FULL_TABLE) 1797a73105b8SAntonio Quartulli tt_fill_gtable(bat_priv, tt_response); 1798a73105b8SAntonio Quartulli else 1799f25bd58aSAl Viro tt_update_changes(bat_priv, orig_node, 1800f25bd58aSAl Viro ntohs(tt_response->tt_data), 1801a73105b8SAntonio Quartulli tt_response->ttvn, 1802a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1)); 1803a73105b8SAntonio Quartulli 1804a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 1805a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1806a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 1807a73105b8SAntonio Quartulli if (!compare_eth(node->addr, tt_response->src)) 1808a73105b8SAntonio Quartulli continue; 1809a73105b8SAntonio Quartulli list_del(&node->list); 1810a73105b8SAntonio Quartulli kfree(node); 1811a73105b8SAntonio Quartulli } 1812a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1813a73105b8SAntonio Quartulli 1814a73105b8SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 1815a73105b8SAntonio Quartulli orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); 1816cc47f66eSAntonio Quartulli /* Roaming phase is over: tables are in sync again. I can 1817cc47f66eSAntonio Quartulli * unset the flag */ 1818cc47f66eSAntonio Quartulli orig_node->tt_poss_change = false; 1819a73105b8SAntonio Quartulli out: 1820a73105b8SAntonio Quartulli if (orig_node) 18217d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1822a73105b8SAntonio Quartulli } 1823a73105b8SAntonio Quartulli 1824a73105b8SAntonio Quartulli int tt_init(struct bat_priv *bat_priv) 1825a73105b8SAntonio Quartulli { 18265346c35eSSven Eckelmann int ret; 1827a73105b8SAntonio Quartulli 18285346c35eSSven Eckelmann ret = tt_local_init(bat_priv); 18295346c35eSSven Eckelmann if (ret < 0) 18305346c35eSSven Eckelmann return ret; 18315346c35eSSven Eckelmann 18325346c35eSSven Eckelmann ret = tt_global_init(bat_priv); 18335346c35eSSven Eckelmann if (ret < 0) 18345346c35eSSven Eckelmann return ret; 1835a73105b8SAntonio Quartulli 1836a73105b8SAntonio Quartulli tt_start_timer(bat_priv); 1837a73105b8SAntonio Quartulli 1838a73105b8SAntonio Quartulli return 1; 1839a73105b8SAntonio Quartulli } 1840a73105b8SAntonio Quartulli 1841cc47f66eSAntonio Quartulli static void tt_roam_list_free(struct bat_priv *bat_priv) 1842a73105b8SAntonio Quartulli { 1843cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1844a73105b8SAntonio Quartulli 1845cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1846a73105b8SAntonio Quartulli 1847cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1848cc47f66eSAntonio Quartulli list_del(&node->list); 1849cc47f66eSAntonio Quartulli kfree(node); 1850cc47f66eSAntonio Quartulli } 1851cc47f66eSAntonio Quartulli 1852cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1853cc47f66eSAntonio Quartulli } 1854cc47f66eSAntonio Quartulli 1855cc47f66eSAntonio Quartulli static void tt_roam_purge(struct bat_priv *bat_priv) 1856cc47f66eSAntonio Quartulli { 1857cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1858cc47f66eSAntonio Quartulli 1859cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1860cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1861032b7969SMarek Lindner if (!has_timed_out(node->first_time, ROAMING_MAX_TIME)) 1862cc47f66eSAntonio Quartulli continue; 1863cc47f66eSAntonio Quartulli 1864cc47f66eSAntonio Quartulli list_del(&node->list); 1865cc47f66eSAntonio Quartulli kfree(node); 1866cc47f66eSAntonio Quartulli } 1867cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1868cc47f66eSAntonio Quartulli } 1869cc47f66eSAntonio Quartulli 1870cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 1871cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 1872cc47f66eSAntonio Quartulli * will not be sent. 1873cc47f66eSAntonio Quartulli * 1874cc47f66eSAntonio Quartulli * returns true if the ROAMING_ADV can be sent, false otherwise */ 1875cc47f66eSAntonio Quartulli static bool tt_check_roam_count(struct bat_priv *bat_priv, 1876cc47f66eSAntonio Quartulli uint8_t *client) 1877cc47f66eSAntonio Quartulli { 1878cc47f66eSAntonio Quartulli struct tt_roam_node *tt_roam_node; 1879cc47f66eSAntonio Quartulli bool ret = false; 1880cc47f66eSAntonio Quartulli 1881cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1882cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 1883cc47f66eSAntonio Quartulli * reply from the same orig_node yet */ 1884cc47f66eSAntonio Quartulli list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) { 1885cc47f66eSAntonio Quartulli if (!compare_eth(tt_roam_node->addr, client)) 1886cc47f66eSAntonio Quartulli continue; 1887cc47f66eSAntonio Quartulli 1888032b7969SMarek Lindner if (has_timed_out(tt_roam_node->first_time, ROAMING_MAX_TIME)) 1889cc47f66eSAntonio Quartulli continue; 1890cc47f66eSAntonio Quartulli 1891cc47f66eSAntonio Quartulli if (!atomic_dec_not_zero(&tt_roam_node->counter)) 1892cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 1893cc47f66eSAntonio Quartulli goto unlock; 1894cc47f66eSAntonio Quartulli ret = true; 1895cc47f66eSAntonio Quartulli break; 1896cc47f66eSAntonio Quartulli } 1897cc47f66eSAntonio Quartulli 1898cc47f66eSAntonio Quartulli if (!ret) { 1899cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 1900cc47f66eSAntonio Quartulli if (!tt_roam_node) 1901cc47f66eSAntonio Quartulli goto unlock; 1902cc47f66eSAntonio Quartulli 1903cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 1904cc47f66eSAntonio Quartulli atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1); 1905cc47f66eSAntonio Quartulli memcpy(tt_roam_node->addr, client, ETH_ALEN); 1906cc47f66eSAntonio Quartulli 1907cc47f66eSAntonio Quartulli list_add(&tt_roam_node->list, &bat_priv->tt_roam_list); 1908cc47f66eSAntonio Quartulli ret = true; 1909cc47f66eSAntonio Quartulli } 1910cc47f66eSAntonio Quartulli 1911cc47f66eSAntonio Quartulli unlock: 1912cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1913cc47f66eSAntonio Quartulli return ret; 1914cc47f66eSAntonio Quartulli } 1915cc47f66eSAntonio Quartulli 1916de7aae65SSven Eckelmann static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 1917cc47f66eSAntonio Quartulli struct orig_node *orig_node) 1918cc47f66eSAntonio Quartulli { 1919cc47f66eSAntonio Quartulli struct neigh_node *neigh_node = NULL; 1920cc47f66eSAntonio Quartulli struct sk_buff *skb = NULL; 1921cc47f66eSAntonio Quartulli struct roam_adv_packet *roam_adv_packet; 1922cc47f66eSAntonio Quartulli int ret = 1; 1923cc47f66eSAntonio Quartulli struct hard_iface *primary_if; 1924cc47f66eSAntonio Quartulli 1925cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 1926cc47f66eSAntonio Quartulli * already roamed to us too many times */ 1927cc47f66eSAntonio Quartulli if (!tt_check_roam_count(bat_priv, client)) 1928cc47f66eSAntonio Quartulli goto out; 1929cc47f66eSAntonio Quartulli 1930cc47f66eSAntonio Quartulli skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN); 1931cc47f66eSAntonio Quartulli if (!skb) 1932cc47f66eSAntonio Quartulli goto out; 1933cc47f66eSAntonio Quartulli 1934cc47f66eSAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1935cc47f66eSAntonio Quartulli 1936cc47f66eSAntonio Quartulli roam_adv_packet = (struct roam_adv_packet *)skb_put(skb, 1937cc47f66eSAntonio Quartulli sizeof(struct roam_adv_packet)); 1938cc47f66eSAntonio Quartulli 193976543d14SSven Eckelmann roam_adv_packet->header.packet_type = BAT_ROAM_ADV; 194076543d14SSven Eckelmann roam_adv_packet->header.version = COMPAT_VERSION; 194176543d14SSven Eckelmann roam_adv_packet->header.ttl = TTL; 1942cc47f66eSAntonio Quartulli primary_if = primary_if_get_selected(bat_priv); 1943cc47f66eSAntonio Quartulli if (!primary_if) 1944cc47f66eSAntonio Quartulli goto out; 1945cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1946cc47f66eSAntonio Quartulli hardif_free_ref(primary_if); 1947cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); 1948cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->client, client, ETH_ALEN); 1949cc47f66eSAntonio Quartulli 19507d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(orig_node); 1951cc47f66eSAntonio Quartulli if (!neigh_node) 1952cc47f66eSAntonio Quartulli goto out; 1953cc47f66eSAntonio Quartulli 1954cc47f66eSAntonio Quartulli bat_dbg(DBG_TT, bat_priv, 1955cc47f66eSAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM) via %pM\n", 1956cc47f66eSAntonio Quartulli orig_node->orig, client, neigh_node->addr); 1957cc47f66eSAntonio Quartulli 1958f8214865SMartin Hundebøll batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_TX); 1959f8214865SMartin Hundebøll 19609455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1961cc47f66eSAntonio Quartulli ret = 0; 1962cc47f66eSAntonio Quartulli 1963cc47f66eSAntonio Quartulli out: 1964cc47f66eSAntonio Quartulli if (neigh_node) 19657d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1966cc47f66eSAntonio Quartulli if (ret) 1967cc47f66eSAntonio Quartulli kfree_skb(skb); 1968cc47f66eSAntonio Quartulli return; 1969a73105b8SAntonio Quartulli } 1970a73105b8SAntonio Quartulli 1971a73105b8SAntonio Quartulli static void tt_purge(struct work_struct *work) 1972a73105b8SAntonio Quartulli { 1973a73105b8SAntonio Quartulli struct delayed_work *delayed_work = 1974a73105b8SAntonio Quartulli container_of(work, struct delayed_work, work); 1975a73105b8SAntonio Quartulli struct bat_priv *bat_priv = 1976a73105b8SAntonio Quartulli container_of(delayed_work, struct bat_priv, tt_work); 1977a73105b8SAntonio Quartulli 1978a73105b8SAntonio Quartulli tt_local_purge(bat_priv); 1979cc47f66eSAntonio Quartulli tt_global_roam_purge(bat_priv); 1980a73105b8SAntonio Quartulli tt_req_purge(bat_priv); 1981cc47f66eSAntonio Quartulli tt_roam_purge(bat_priv); 1982a73105b8SAntonio Quartulli 1983a73105b8SAntonio Quartulli tt_start_timer(bat_priv); 1984a73105b8SAntonio Quartulli } 1985cc47f66eSAntonio Quartulli 1986cc47f66eSAntonio Quartulli void tt_free(struct bat_priv *bat_priv) 1987cc47f66eSAntonio Quartulli { 1988cc47f66eSAntonio Quartulli cancel_delayed_work_sync(&bat_priv->tt_work); 1989cc47f66eSAntonio Quartulli 1990cc47f66eSAntonio Quartulli tt_local_table_free(bat_priv); 1991cc47f66eSAntonio Quartulli tt_global_table_free(bat_priv); 1992cc47f66eSAntonio Quartulli tt_req_list_free(bat_priv); 1993cc47f66eSAntonio Quartulli tt_changes_list_free(bat_priv); 1994cc47f66eSAntonio Quartulli tt_roam_list_free(bat_priv); 1995cc47f66eSAntonio Quartulli 1996cc47f66eSAntonio Quartulli kfree(bat_priv->tt_buff); 1997cc47f66eSAntonio Quartulli } 1998058d0e26SAntonio Quartulli 1999697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries 2000697f2531SAntonio Quartulli * in the given hash table and returns the number of modified entries */ 2001697f2531SAntonio Quartulli static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags, 2002697f2531SAntonio Quartulli bool enable) 2003058d0e26SAntonio Quartulli { 2004c90681b8SAntonio Quartulli uint32_t i; 2005697f2531SAntonio Quartulli uint16_t changed_num = 0; 2006058d0e26SAntonio Quartulli struct hlist_head *head; 2007058d0e26SAntonio Quartulli struct hlist_node *node; 200848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 2009058d0e26SAntonio Quartulli 2010058d0e26SAntonio Quartulli if (!hash) 2011697f2531SAntonio Quartulli goto out; 2012058d0e26SAntonio Quartulli 2013058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2014058d0e26SAntonio Quartulli head = &hash->table[i]; 2015058d0e26SAntonio Quartulli 2016058d0e26SAntonio Quartulli rcu_read_lock(); 201748100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 2018058d0e26SAntonio Quartulli head, hash_entry) { 2019697f2531SAntonio Quartulli if (enable) { 2020697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 2021697f2531SAntonio Quartulli continue; 2022697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 2023697f2531SAntonio Quartulli } else { 202448100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 202531901264SAntonio Quartulli continue; 202648100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 2027697f2531SAntonio Quartulli } 2028697f2531SAntonio Quartulli changed_num++; 2029058d0e26SAntonio Quartulli } 2030058d0e26SAntonio Quartulli rcu_read_unlock(); 2031058d0e26SAntonio Quartulli } 2032697f2531SAntonio Quartulli out: 2033697f2531SAntonio Quartulli return changed_num; 2034058d0e26SAntonio Quartulli } 2035058d0e26SAntonio Quartulli 2036058d0e26SAntonio Quartulli /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ 2037058d0e26SAntonio Quartulli static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) 2038058d0e26SAntonio Quartulli { 2039058d0e26SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 204048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 2041058d0e26SAntonio Quartulli struct tt_local_entry *tt_local_entry; 2042058d0e26SAntonio Quartulli struct hlist_node *node, *node_tmp; 2043058d0e26SAntonio Quartulli struct hlist_head *head; 2044058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 2045c90681b8SAntonio Quartulli uint32_t i; 2046058d0e26SAntonio Quartulli 2047058d0e26SAntonio Quartulli if (!hash) 2048058d0e26SAntonio Quartulli return; 2049058d0e26SAntonio Quartulli 2050058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2051058d0e26SAntonio Quartulli head = &hash->table[i]; 2052058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 2053058d0e26SAntonio Quartulli 2054058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 205548100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 2056058d0e26SAntonio Quartulli head, hash_entry) { 205748100bacSAntonio Quartulli if (!(tt_common_entry->flags & TT_CLIENT_PENDING)) 2058058d0e26SAntonio Quartulli continue; 2059058d0e26SAntonio Quartulli 206086ceb360SSven Eckelmann bat_dbg(DBG_TT, bat_priv, 206186ceb360SSven Eckelmann "Deleting local tt entry (%pM): pending\n", 206286ceb360SSven Eckelmann tt_common_entry->addr); 2063058d0e26SAntonio Quartulli 2064058d0e26SAntonio Quartulli atomic_dec(&bat_priv->num_local_tt); 2065058d0e26SAntonio Quartulli hlist_del_rcu(node); 206648100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 206748100bacSAntonio Quartulli struct tt_local_entry, 206848100bacSAntonio Quartulli common); 2069058d0e26SAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 2070058d0e26SAntonio Quartulli } 2071058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 2072058d0e26SAntonio Quartulli } 2073058d0e26SAntonio Quartulli 2074058d0e26SAntonio Quartulli } 2075058d0e26SAntonio Quartulli 2076be9aa4c1SMarek Lindner static int tt_commit_changes(struct bat_priv *bat_priv, 2077be9aa4c1SMarek Lindner unsigned char **packet_buff, int *packet_buff_len, 2078be9aa4c1SMarek Lindner int packet_min_len) 2079058d0e26SAntonio Quartulli { 2080be9aa4c1SMarek Lindner uint16_t changed_num = 0; 2081be9aa4c1SMarek Lindner 2082be9aa4c1SMarek Lindner if (atomic_read(&bat_priv->tt_local_changes) < 1) 2083be9aa4c1SMarek Lindner return -ENOENT; 2084be9aa4c1SMarek Lindner 2085be9aa4c1SMarek Lindner changed_num = tt_set_flags(bat_priv->tt_local_hash, 2086697f2531SAntonio Quartulli TT_CLIENT_NEW, false); 2087be9aa4c1SMarek Lindner 2088be9aa4c1SMarek Lindner /* all reset entries have to be counted as local entries */ 2089697f2531SAntonio Quartulli atomic_add(changed_num, &bat_priv->num_local_tt); 2090058d0e26SAntonio Quartulli tt_local_purge_pending_clients(bat_priv); 2091be9aa4c1SMarek Lindner bat_priv->tt_crc = batadv_tt_local_crc(bat_priv); 2092058d0e26SAntonio Quartulli 2093058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 2094058d0e26SAntonio Quartulli atomic_inc(&bat_priv->ttvn); 2095db08e6e5SSimon Wunderlich bat_dbg(DBG_TT, bat_priv, "Local changes committed, updating to ttvn %u\n", 2096db08e6e5SSimon Wunderlich (uint8_t)atomic_read(&bat_priv->ttvn)); 2097058d0e26SAntonio Quartulli bat_priv->tt_poss_change = false; 2098be9aa4c1SMarek Lindner 2099be9aa4c1SMarek Lindner /* reset the sending counter */ 2100be9aa4c1SMarek Lindner atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX); 2101be9aa4c1SMarek Lindner 2102be9aa4c1SMarek Lindner return tt_changes_fill_buff(bat_priv, packet_buff, 2103be9aa4c1SMarek Lindner packet_buff_len, packet_min_len); 2104be9aa4c1SMarek Lindner } 2105be9aa4c1SMarek Lindner 2106be9aa4c1SMarek Lindner /* when calling this function (hard_iface == primary_if) has to be true */ 2107be9aa4c1SMarek Lindner int batadv_tt_append_diff(struct bat_priv *bat_priv, 2108be9aa4c1SMarek Lindner unsigned char **packet_buff, int *packet_buff_len, 2109be9aa4c1SMarek Lindner int packet_min_len) 2110be9aa4c1SMarek Lindner { 2111be9aa4c1SMarek Lindner int tt_num_changes; 2112be9aa4c1SMarek Lindner 2113be9aa4c1SMarek Lindner /* if at least one change happened */ 2114be9aa4c1SMarek Lindner tt_num_changes = tt_commit_changes(bat_priv, packet_buff, 2115be9aa4c1SMarek Lindner packet_buff_len, packet_min_len); 2116be9aa4c1SMarek Lindner 2117be9aa4c1SMarek Lindner /* if the changes have been sent often enough */ 2118be9aa4c1SMarek Lindner if ((tt_num_changes < 0) && 2119be9aa4c1SMarek Lindner (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))) { 2120be9aa4c1SMarek Lindner tt_realloc_packet_buff(packet_buff, packet_buff_len, 2121be9aa4c1SMarek Lindner packet_min_len, packet_min_len); 2122be9aa4c1SMarek Lindner tt_num_changes = 0; 2123be9aa4c1SMarek Lindner } 2124be9aa4c1SMarek Lindner 2125be9aa4c1SMarek Lindner return tt_num_changes; 2126058d0e26SAntonio Quartulli } 212759b699cdSAntonio Quartulli 212859b699cdSAntonio Quartulli bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst) 212959b699cdSAntonio Quartulli { 213059b699cdSAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 213159b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 213259b699cdSAntonio Quartulli bool ret = true; 213359b699cdSAntonio Quartulli 213459b699cdSAntonio Quartulli if (!atomic_read(&bat_priv->ap_isolation)) 213559b699cdSAntonio Quartulli return false; 213659b699cdSAntonio Quartulli 213759b699cdSAntonio Quartulli tt_local_entry = tt_local_hash_find(bat_priv, dst); 213859b699cdSAntonio Quartulli if (!tt_local_entry) 213959b699cdSAntonio Quartulli goto out; 214059b699cdSAntonio Quartulli 214159b699cdSAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, src); 214259b699cdSAntonio Quartulli if (!tt_global_entry) 214359b699cdSAntonio Quartulli goto out; 214459b699cdSAntonio Quartulli 214559b699cdSAntonio Quartulli if (_is_ap_isolated(tt_local_entry, tt_global_entry)) 214659b699cdSAntonio Quartulli goto out; 214759b699cdSAntonio Quartulli 214859b699cdSAntonio Quartulli ret = false; 214959b699cdSAntonio Quartulli 215059b699cdSAntonio Quartulli out: 215159b699cdSAntonio Quartulli if (tt_global_entry) 215259b699cdSAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 215359b699cdSAntonio Quartulli if (tt_local_entry) 215459b699cdSAntonio Quartulli tt_local_entry_free_ref(tt_local_entry); 215559b699cdSAntonio Quartulli return ret; 215659b699cdSAntonio Quartulli } 2157a943cac1SMarek Lindner 2158a943cac1SMarek Lindner void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, 2159a943cac1SMarek Lindner const unsigned char *tt_buff, uint8_t tt_num_changes, 2160a943cac1SMarek Lindner uint8_t ttvn, uint16_t tt_crc) 2161a943cac1SMarek Lindner { 2162a943cac1SMarek Lindner uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); 2163a943cac1SMarek Lindner bool full_table = true; 2164a943cac1SMarek Lindner 216520ff9d59SSimon Wunderlich /* don't care about a backbone gateways updates. */ 216608adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) 216720ff9d59SSimon Wunderlich return; 216820ff9d59SSimon Wunderlich 216917071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 217017071578SAntonio Quartulli * increased by one -> we can apply the attached changes */ 217117071578SAntonio Quartulli if ((!orig_node->tt_initialised && ttvn == 1) || 217217071578SAntonio Quartulli ttvn - orig_ttvn == 1) { 2173a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 2174a943cac1SMarek Lindner * because they have already been sent TT_OGM_APPEND_MAX times. 2175a943cac1SMarek Lindner * In this case send a tt request */ 2176a943cac1SMarek Lindner if (!tt_num_changes) { 2177a943cac1SMarek Lindner full_table = false; 2178a943cac1SMarek Lindner goto request_table; 2179a943cac1SMarek Lindner } 2180a943cac1SMarek Lindner 2181a943cac1SMarek Lindner tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn, 2182a943cac1SMarek Lindner (struct tt_change *)tt_buff); 2183a943cac1SMarek Lindner 2184a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 2185a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 2186a943cac1SMarek Lindner * in the global table */ 2187a943cac1SMarek Lindner orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); 2188a943cac1SMarek Lindner 2189a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 2190a943cac1SMarek Lindner * because a single value could represent different states 2191a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 2192a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 2193a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 2194a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 2195a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 2196a943cac1SMarek Lindner * inconsistency */ 2197a943cac1SMarek Lindner if (orig_node->tt_crc != tt_crc) 2198a943cac1SMarek Lindner goto request_table; 2199a943cac1SMarek Lindner 2200a943cac1SMarek Lindner /* Roaming phase is over: tables are in sync again. I can 2201a943cac1SMarek Lindner * unset the flag */ 2202a943cac1SMarek Lindner orig_node->tt_poss_change = false; 2203a943cac1SMarek Lindner } else { 2204a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 2205a943cac1SMarek Lindner * in sync anymore -> request fresh tt data */ 2206db08e6e5SSimon Wunderlich 220717071578SAntonio Quartulli if (!orig_node->tt_initialised || ttvn != orig_ttvn || 220817071578SAntonio Quartulli orig_node->tt_crc != tt_crc) { 2209a943cac1SMarek Lindner request_table: 221086ceb360SSven Eckelmann bat_dbg(DBG_TT, bat_priv, 221186ceb360SSven Eckelmann "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %u last_crc: %u num_changes: %u)\n", 221286ceb360SSven Eckelmann orig_node->orig, ttvn, orig_ttvn, tt_crc, 221386ceb360SSven Eckelmann orig_node->tt_crc, tt_num_changes); 2214a943cac1SMarek Lindner send_tt_request(bat_priv, orig_node, ttvn, tt_crc, 2215a943cac1SMarek Lindner full_table); 2216a943cac1SMarek Lindner return; 2217a943cac1SMarek Lindner } 2218a943cac1SMarek Lindner } 2219a943cac1SMarek Lindner } 22203275e7ccSAntonio Quartulli 22213275e7ccSAntonio Quartulli /* returns true whether we know that the client has moved from its old 22223275e7ccSAntonio Quartulli * originator to another one. This entry is kept is still kept for consistency 22233275e7ccSAntonio Quartulli * purposes 22243275e7ccSAntonio Quartulli */ 22253275e7ccSAntonio Quartulli bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr) 22263275e7ccSAntonio Quartulli { 22273275e7ccSAntonio Quartulli struct tt_global_entry *tt_global_entry; 22283275e7ccSAntonio Quartulli bool ret = false; 22293275e7ccSAntonio Quartulli 22303275e7ccSAntonio Quartulli tt_global_entry = tt_global_hash_find(bat_priv, addr); 22313275e7ccSAntonio Quartulli if (!tt_global_entry) 22323275e7ccSAntonio Quartulli goto out; 22333275e7ccSAntonio Quartulli 22343275e7ccSAntonio Quartulli ret = tt_global_entry->common.flags & TT_CLIENT_ROAM; 22353275e7ccSAntonio Quartulli tt_global_entry_free_ref(tt_global_entry); 22363275e7ccSAntonio Quartulli out: 22373275e7ccSAntonio Quartulli return ret; 22383275e7ccSAntonio Quartulli } 2239