19cfc7bd6SSven Eckelmann /* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: 2c6c8fea2SSven Eckelmann * 335c133a0SAntonio Quartulli * Marek Lindner, Simon Wunderlich, Antonio Quartulli 4c6c8fea2SSven Eckelmann * 5c6c8fea2SSven Eckelmann * This program is free software; you can redistribute it and/or 6c6c8fea2SSven Eckelmann * modify it under the terms of version 2 of the GNU General Public 7c6c8fea2SSven Eckelmann * License as published by the Free Software Foundation. 8c6c8fea2SSven Eckelmann * 9c6c8fea2SSven Eckelmann * This program is distributed in the hope that it will be useful, but 10c6c8fea2SSven Eckelmann * WITHOUT ANY WARRANTY; without even the implied warranty of 11c6c8fea2SSven Eckelmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12c6c8fea2SSven Eckelmann * General Public License for more details. 13c6c8fea2SSven Eckelmann * 14c6c8fea2SSven Eckelmann * You should have received a copy of the GNU General Public License 15c6c8fea2SSven Eckelmann * along with this program; if not, write to the Free Software 16c6c8fea2SSven Eckelmann * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17c6c8fea2SSven Eckelmann * 02110-1301, USA 18c6c8fea2SSven Eckelmann */ 19c6c8fea2SSven Eckelmann 20c6c8fea2SSven Eckelmann #include "main.h" 21c6c8fea2SSven Eckelmann #include "translation-table.h" 22c6c8fea2SSven Eckelmann #include "soft-interface.h" 2332ae9b22SMarek Lindner #include "hard-interface.h" 24a73105b8SAntonio Quartulli #include "send.h" 25c6c8fea2SSven Eckelmann #include "hash.h" 26c6c8fea2SSven Eckelmann #include "originator.h" 27a73105b8SAntonio Quartulli #include "routing.h" 2820ff9d59SSimon Wunderlich #include "bridge_loop_avoidance.h" 29c6c8fea2SSven Eckelmann 30a73105b8SAntonio Quartulli #include <linux/crc16.h> 31a73105b8SAntonio Quartulli 32a513088dSSven Eckelmann static void batadv_send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 33de7aae65SSven Eckelmann struct orig_node *orig_node); 34a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work); 35a513088dSSven Eckelmann static void 36a513088dSSven Eckelmann batadv_tt_global_del_orig_list(struct tt_global_entry *tt_global_entry); 37c6c8fea2SSven Eckelmann 387aadf889SMarek Lindner /* returns 1 if they are the same mac addr */ 39a513088dSSven Eckelmann static int batadv_compare_tt(const struct hlist_node *node, const void *data2) 407aadf889SMarek Lindner { 4148100bacSAntonio Quartulli const void *data1 = container_of(node, struct tt_common_entry, 42747e4221SSven Eckelmann hash_entry); 437aadf889SMarek Lindner 447aadf889SMarek Lindner return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); 457aadf889SMarek Lindner } 467aadf889SMarek Lindner 47a513088dSSven Eckelmann static void batadv_tt_start_timer(struct bat_priv *bat_priv) 48c6c8fea2SSven Eckelmann { 49a513088dSSven Eckelmann INIT_DELAYED_WORK(&bat_priv->tt_work, batadv_tt_purge); 503193e8fdSSven Eckelmann queue_delayed_work(batadv_event_workqueue, &bat_priv->tt_work, 51a73105b8SAntonio Quartulli msecs_to_jiffies(5000)); 52c6c8fea2SSven Eckelmann } 53c6c8fea2SSven Eckelmann 54a513088dSSven Eckelmann static struct tt_common_entry *batadv_tt_hash_find(struct hashtable_t *hash, 55747e4221SSven Eckelmann const void *data) 567aadf889SMarek Lindner { 577aadf889SMarek Lindner struct hlist_head *head; 587aadf889SMarek Lindner struct hlist_node *node; 5948100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL; 60c90681b8SAntonio Quartulli uint32_t index; 617aadf889SMarek Lindner 627aadf889SMarek Lindner if (!hash) 637aadf889SMarek Lindner return NULL; 647aadf889SMarek Lindner 65da641193SSven Eckelmann index = batadv_choose_orig(data, hash->size); 667aadf889SMarek Lindner head = &hash->table[index]; 677aadf889SMarek Lindner 687aadf889SMarek Lindner rcu_read_lock(); 6948100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) { 701eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_common_entry, data)) 717aadf889SMarek Lindner continue; 727aadf889SMarek Lindner 7348100bacSAntonio Quartulli if (!atomic_inc_not_zero(&tt_common_entry->refcount)) 747683fdc1SAntonio Quartulli continue; 757683fdc1SAntonio Quartulli 7648100bacSAntonio Quartulli tt_common_entry_tmp = tt_common_entry; 777aadf889SMarek Lindner break; 787aadf889SMarek Lindner } 797aadf889SMarek Lindner rcu_read_unlock(); 807aadf889SMarek Lindner 8148100bacSAntonio Quartulli return tt_common_entry_tmp; 8248100bacSAntonio Quartulli } 8348100bacSAntonio Quartulli 84a513088dSSven Eckelmann static struct tt_local_entry * 85a513088dSSven Eckelmann batadv_tt_local_hash_find(struct bat_priv *bat_priv, const void *data) 8648100bacSAntonio Quartulli { 8748100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 8848100bacSAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 8948100bacSAntonio Quartulli 90a513088dSSven Eckelmann tt_common_entry = batadv_tt_hash_find(bat_priv->tt_local_hash, data); 9148100bacSAntonio Quartulli if (tt_common_entry) 9248100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 9348100bacSAntonio Quartulli struct tt_local_entry, common); 9448100bacSAntonio Quartulli return tt_local_entry; 957aadf889SMarek Lindner } 967aadf889SMarek Lindner 97a513088dSSven Eckelmann static struct tt_global_entry * 98a513088dSSven Eckelmann batadv_tt_global_hash_find(struct bat_priv *bat_priv, const void *data) 997aadf889SMarek Lindner { 10048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 10148100bacSAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 1027aadf889SMarek Lindner 103a513088dSSven Eckelmann tt_common_entry = batadv_tt_hash_find(bat_priv->tt_global_hash, data); 10448100bacSAntonio Quartulli if (tt_common_entry) 10548100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 10648100bacSAntonio Quartulli struct tt_global_entry, common); 10748100bacSAntonio Quartulli return tt_global_entry; 1087aadf889SMarek Lindner 1097aadf889SMarek Lindner } 1107aadf889SMarek Lindner 111a513088dSSven Eckelmann static void 112a513088dSSven Eckelmann batadv_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 118a513088dSSven Eckelmann static void batadv_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 130a513088dSSven Eckelmann static void 131a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry) 1327683fdc1SAntonio Quartulli { 133db08e6e5SSimon Wunderlich if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { 134a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 13548100bacSAntonio Quartulli call_rcu(&tt_global_entry->common.rcu, 136a513088dSSven Eckelmann batadv_tt_global_entry_free_rcu); 1377683fdc1SAntonio Quartulli } 138db08e6e5SSimon Wunderlich } 139db08e6e5SSimon Wunderlich 140a513088dSSven Eckelmann static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) 141db08e6e5SSimon Wunderlich { 142db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 143db08e6e5SSimon Wunderlich 144db08e6e5SSimon Wunderlich orig_entry = container_of(rcu, struct tt_orig_list_entry, rcu); 1457d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_entry->orig_node); 146db08e6e5SSimon Wunderlich kfree(orig_entry); 147db08e6e5SSimon Wunderlich } 148db08e6e5SSimon Wunderlich 149a513088dSSven Eckelmann static void 150a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry) 151db08e6e5SSimon Wunderlich { 15229cb99deSAntonio Quartulli /* to avoid race conditions, immediately decrease the tt counter */ 15329cb99deSAntonio Quartulli atomic_dec(&orig_entry->orig_node->tt_size); 154a513088dSSven Eckelmann call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); 155db08e6e5SSimon Wunderlich } 1567683fdc1SAntonio Quartulli 157a513088dSSven Eckelmann static void batadv_tt_local_event(struct bat_priv *bat_priv, 158a513088dSSven Eckelmann const uint8_t *addr, uint8_t flags) 159a73105b8SAntonio Quartulli { 1603b643de5SAntonio Quartulli struct tt_change_node *tt_change_node, *entry, *safe; 1613b643de5SAntonio Quartulli bool event_removed = false; 1623b643de5SAntonio Quartulli bool del_op_requested, del_op_entry; 163a73105b8SAntonio Quartulli 164a73105b8SAntonio Quartulli tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); 165a73105b8SAntonio Quartulli 166a73105b8SAntonio Quartulli if (!tt_change_node) 167a73105b8SAntonio Quartulli return; 168a73105b8SAntonio Quartulli 169ff66c975SAntonio Quartulli tt_change_node->change.flags = flags; 170a73105b8SAntonio Quartulli memcpy(tt_change_node->change.addr, addr, ETH_ALEN); 171a73105b8SAntonio Quartulli 172acd34afaSSven Eckelmann del_op_requested = flags & BATADV_TT_CLIENT_DEL; 1733b643de5SAntonio Quartulli 1743b643de5SAntonio Quartulli /* check for ADD+DEL or DEL+ADD events */ 175a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 1763b643de5SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 1773b643de5SAntonio Quartulli list) { 1783b643de5SAntonio Quartulli if (!batadv_compare_eth(entry->change.addr, addr)) 1793b643de5SAntonio Quartulli continue; 1803b643de5SAntonio Quartulli 1813b643de5SAntonio Quartulli /* DEL+ADD in the same orig interval have no effect and can be 1823b643de5SAntonio Quartulli * removed to avoid silly behaviour on the receiver side. The 1833b643de5SAntonio Quartulli * other way around (ADD+DEL) can happen in case of roaming of 1843b643de5SAntonio Quartulli * a client still in the NEW state. Roaming of NEW clients is 1853b643de5SAntonio Quartulli * now possible due to automatically recognition of "temporary" 1863b643de5SAntonio Quartulli * clients 1873b643de5SAntonio Quartulli */ 188acd34afaSSven Eckelmann del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; 1893b643de5SAntonio Quartulli if (!del_op_requested && del_op_entry) 1903b643de5SAntonio Quartulli goto del; 1913b643de5SAntonio Quartulli if (del_op_requested && !del_op_entry) 1923b643de5SAntonio Quartulli goto del; 1933b643de5SAntonio Quartulli continue; 1943b643de5SAntonio Quartulli del: 1953b643de5SAntonio Quartulli list_del(&entry->list); 1963b643de5SAntonio Quartulli kfree(entry); 1973b643de5SAntonio Quartulli event_removed = true; 1983b643de5SAntonio Quartulli goto unlock; 1993b643de5SAntonio Quartulli } 2003b643de5SAntonio Quartulli 201a73105b8SAntonio Quartulli /* track the change in the OGMinterval list */ 202a73105b8SAntonio Quartulli list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list); 2033b643de5SAntonio Quartulli 2043b643de5SAntonio Quartulli unlock: 205a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 206a73105b8SAntonio Quartulli 2073b643de5SAntonio Quartulli if (event_removed) 2083b643de5SAntonio Quartulli atomic_dec(&bat_priv->tt_local_changes); 2093b643de5SAntonio Quartulli else 2103b643de5SAntonio Quartulli atomic_inc(&bat_priv->tt_local_changes); 211a73105b8SAntonio Quartulli } 212a73105b8SAntonio Quartulli 21308c36d3eSSven Eckelmann int batadv_tt_len(int changes_num) 214a73105b8SAntonio Quartulli { 215a73105b8SAntonio Quartulli return changes_num * sizeof(struct tt_change); 216a73105b8SAntonio Quartulli } 217a73105b8SAntonio Quartulli 218a513088dSSven Eckelmann static int batadv_tt_local_init(struct bat_priv *bat_priv) 219c6c8fea2SSven Eckelmann { 2202dafb49dSAntonio Quartulli if (bat_priv->tt_local_hash) 2215346c35eSSven Eckelmann return 0; 222c6c8fea2SSven Eckelmann 2231a8eaf07SSven Eckelmann bat_priv->tt_local_hash = batadv_hash_new(1024); 224c6c8fea2SSven Eckelmann 2252dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 2265346c35eSSven Eckelmann return -ENOMEM; 227c6c8fea2SSven Eckelmann 2285346c35eSSven Eckelmann return 0; 229c6c8fea2SSven Eckelmann } 230c6c8fea2SSven Eckelmann 23108c36d3eSSven Eckelmann void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 232bc279080SAntonio Quartulli int ifindex) 233c6c8fea2SSven Eckelmann { 234c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(soft_iface); 2357683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 2367683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 237db08e6e5SSimon Wunderlich struct hlist_head *head; 238db08e6e5SSimon Wunderlich struct hlist_node *node; 239db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 24080b3f58cSSimon Wunderlich int hash_added; 241c6c8fea2SSven Eckelmann 242a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 243c6c8fea2SSven Eckelmann 2442dafb49dSAntonio Quartulli if (tt_local_entry) { 2452dafb49dSAntonio Quartulli tt_local_entry->last_seen = jiffies; 246acd34afaSSven Eckelmann /* possibly unset the BATADV_TT_CLIENT_PENDING flag */ 247acd34afaSSven Eckelmann tt_local_entry->common.flags &= ~BATADV_TT_CLIENT_PENDING; 2487683fdc1SAntonio Quartulli goto out; 249c6c8fea2SSven Eckelmann } 250c6c8fea2SSven Eckelmann 251704509b8SSven Eckelmann tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC); 2522dafb49dSAntonio Quartulli if (!tt_local_entry) 2537683fdc1SAntonio Quartulli goto out; 254a73105b8SAntonio Quartulli 25539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 256a73105b8SAntonio Quartulli "Creating new local tt entry: %pM (ttvn: %d)\n", addr, 257a73105b8SAntonio Quartulli (uint8_t)atomic_read(&bat_priv->ttvn)); 258c6c8fea2SSven Eckelmann 25948100bacSAntonio Quartulli memcpy(tt_local_entry->common.addr, addr, ETH_ALEN); 26042d0b044SSven Eckelmann tt_local_entry->common.flags = BATADV_NO_FLAGS; 2619563877eSSven Eckelmann if (batadv_is_wifi_iface(ifindex)) 262acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_WIFI; 26348100bacSAntonio Quartulli atomic_set(&tt_local_entry->common.refcount, 2); 26448100bacSAntonio Quartulli tt_local_entry->last_seen = jiffies; 265c6c8fea2SSven Eckelmann 266c6c8fea2SSven Eckelmann /* the batman interface mac address should never be purged */ 2671eda58bfSSven Eckelmann if (batadv_compare_eth(addr, soft_iface->dev_addr)) 268acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_NOPURGE; 269c6c8fea2SSven Eckelmann 270c40ed2bfSAntonio Quartulli /* The local entry has to be marked as NEW to avoid to send it in 271c40ed2bfSAntonio Quartulli * a full table response going out before the next ttvn increment 2729cfc7bd6SSven Eckelmann * (consistency check) 2739cfc7bd6SSven Eckelmann */ 274acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_NEW; 275c40ed2bfSAntonio Quartulli 276a513088dSSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt_local_hash, batadv_compare_tt, 277da641193SSven Eckelmann batadv_choose_orig, 27880b3f58cSSimon Wunderlich &tt_local_entry->common, 27980b3f58cSSimon Wunderlich &tt_local_entry->common.hash_entry); 28080b3f58cSSimon Wunderlich 28180b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 28280b3f58cSSimon Wunderlich /* remove the reference for the hash */ 283a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 28480b3f58cSSimon Wunderlich goto out; 28580b3f58cSSimon Wunderlich } 28680b3f58cSSimon Wunderlich 287a513088dSSven Eckelmann batadv_tt_local_event(bat_priv, addr, tt_local_entry->common.flags); 288ff66c975SAntonio Quartulli 289c6c8fea2SSven Eckelmann /* remove address from global hash if present */ 290a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 291c6c8fea2SSven Eckelmann 292cc47f66eSAntonio Quartulli /* Check whether it is a roaming! */ 293cc47f66eSAntonio Quartulli if (tt_global_entry) { 294db08e6e5SSimon Wunderlich /* These node are probably going to update their tt table */ 295db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 296db08e6e5SSimon Wunderlich rcu_read_lock(); 297db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 298db08e6e5SSimon Wunderlich orig_entry->orig_node->tt_poss_change = true; 299db08e6e5SSimon Wunderlich 300a513088dSSven Eckelmann batadv_send_roam_adv(bat_priv, 301a513088dSSven Eckelmann tt_global_entry->common.addr, 302db08e6e5SSimon Wunderlich orig_entry->orig_node); 303db08e6e5SSimon Wunderlich } 304db08e6e5SSimon Wunderlich rcu_read_unlock(); 305db08e6e5SSimon Wunderlich /* The global entry has to be marked as ROAMING and 306db08e6e5SSimon Wunderlich * has to be kept for consistency purpose 307db08e6e5SSimon Wunderlich */ 308acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 30903fc3070SAntonio Quartulli tt_global_entry->roam_at = jiffies; 3107683fdc1SAntonio Quartulli } 3117683fdc1SAntonio Quartulli out: 3127683fdc1SAntonio Quartulli if (tt_local_entry) 313a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 3147683fdc1SAntonio Quartulli if (tt_global_entry) 315a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 316c6c8fea2SSven Eckelmann } 317c6c8fea2SSven Eckelmann 318a513088dSSven Eckelmann static void batadv_tt_realloc_packet_buff(unsigned char **packet_buff, 319a513088dSSven Eckelmann int *packet_buff_len, 320a513088dSSven Eckelmann int min_packet_len, 321be9aa4c1SMarek Lindner int new_packet_len) 322c6c8fea2SSven Eckelmann { 323be9aa4c1SMarek Lindner unsigned char *new_buff; 324c6c8fea2SSven Eckelmann 325be9aa4c1SMarek Lindner new_buff = kmalloc(new_packet_len, GFP_ATOMIC); 326be9aa4c1SMarek Lindner 327be9aa4c1SMarek Lindner /* keep old buffer if kmalloc should fail */ 328be9aa4c1SMarek Lindner if (new_buff) { 329be9aa4c1SMarek Lindner memcpy(new_buff, *packet_buff, min_packet_len); 330be9aa4c1SMarek Lindner kfree(*packet_buff); 331be9aa4c1SMarek Lindner *packet_buff = new_buff; 332be9aa4c1SMarek Lindner *packet_buff_len = new_packet_len; 333be9aa4c1SMarek Lindner } 334be9aa4c1SMarek Lindner } 335be9aa4c1SMarek Lindner 336a513088dSSven Eckelmann static void batadv_tt_prepare_packet_buff(struct bat_priv *bat_priv, 337be9aa4c1SMarek Lindner unsigned char **packet_buff, 338a513088dSSven Eckelmann int *packet_buff_len, 339a513088dSSven Eckelmann int min_packet_len) 340be9aa4c1SMarek Lindner { 341be9aa4c1SMarek Lindner struct hard_iface *primary_if; 342be9aa4c1SMarek Lindner int req_len; 343be9aa4c1SMarek Lindner 344e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 345be9aa4c1SMarek Lindner 346be9aa4c1SMarek Lindner req_len = min_packet_len; 34708c36d3eSSven Eckelmann req_len += batadv_tt_len(atomic_read(&bat_priv->tt_local_changes)); 348be9aa4c1SMarek Lindner 349be9aa4c1SMarek Lindner /* if we have too many changes for one packet don't send any 350be9aa4c1SMarek Lindner * and wait for the tt table request which will be fragmented 351be9aa4c1SMarek Lindner */ 352be9aa4c1SMarek Lindner if ((!primary_if) || (req_len > primary_if->soft_iface->mtu)) 353be9aa4c1SMarek Lindner req_len = min_packet_len; 354be9aa4c1SMarek Lindner 355a513088dSSven Eckelmann batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, 356be9aa4c1SMarek Lindner min_packet_len, req_len); 357be9aa4c1SMarek Lindner 358be9aa4c1SMarek Lindner if (primary_if) 359e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 360be9aa4c1SMarek Lindner } 361be9aa4c1SMarek Lindner 362a513088dSSven Eckelmann static int batadv_tt_changes_fill_buff(struct bat_priv *bat_priv, 363be9aa4c1SMarek Lindner unsigned char **packet_buff, 364a513088dSSven Eckelmann int *packet_buff_len, 365a513088dSSven Eckelmann int min_packet_len) 366be9aa4c1SMarek Lindner { 367be9aa4c1SMarek Lindner struct tt_change_node *entry, *safe; 368be9aa4c1SMarek Lindner int count = 0, tot_changes = 0, new_len; 369be9aa4c1SMarek Lindner unsigned char *tt_buff; 370be9aa4c1SMarek Lindner 371a513088dSSven Eckelmann batadv_tt_prepare_packet_buff(bat_priv, packet_buff, 372be9aa4c1SMarek Lindner packet_buff_len, min_packet_len); 373be9aa4c1SMarek Lindner 374be9aa4c1SMarek Lindner new_len = *packet_buff_len - min_packet_len; 375be9aa4c1SMarek Lindner tt_buff = *packet_buff + min_packet_len; 376be9aa4c1SMarek Lindner 377be9aa4c1SMarek Lindner if (new_len > 0) 37808c36d3eSSven Eckelmann tot_changes = new_len / batadv_tt_len(1); 379c6c8fea2SSven Eckelmann 380a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 381a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 382c6c8fea2SSven Eckelmann 383a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 384a73105b8SAntonio Quartulli list) { 385a73105b8SAntonio Quartulli if (count < tot_changes) { 38608c36d3eSSven Eckelmann memcpy(tt_buff + batadv_tt_len(count), 387a73105b8SAntonio Quartulli &entry->change, sizeof(struct tt_change)); 388c6c8fea2SSven Eckelmann count++; 389c6c8fea2SSven Eckelmann } 390a73105b8SAntonio Quartulli list_del(&entry->list); 391a73105b8SAntonio Quartulli kfree(entry); 392c6c8fea2SSven Eckelmann } 393a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 394c6c8fea2SSven Eckelmann 395a73105b8SAntonio Quartulli /* Keep the buffer for possible tt_request */ 396a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 397a73105b8SAntonio Quartulli kfree(bat_priv->tt_buff); 398a73105b8SAntonio Quartulli bat_priv->tt_buff_len = 0; 399a73105b8SAntonio Quartulli bat_priv->tt_buff = NULL; 400be9aa4c1SMarek Lindner /* check whether this new OGM has no changes due to size problems */ 401be9aa4c1SMarek Lindner if (new_len > 0) { 402be9aa4c1SMarek Lindner /* if kmalloc() fails we will reply with the full table 403a73105b8SAntonio Quartulli * instead of providing the diff 404a73105b8SAntonio Quartulli */ 405be9aa4c1SMarek Lindner bat_priv->tt_buff = kmalloc(new_len, GFP_ATOMIC); 406a73105b8SAntonio Quartulli if (bat_priv->tt_buff) { 407be9aa4c1SMarek Lindner memcpy(bat_priv->tt_buff, tt_buff, new_len); 408be9aa4c1SMarek Lindner bat_priv->tt_buff_len = new_len; 409a73105b8SAntonio Quartulli } 410a73105b8SAntonio Quartulli } 411a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 412c6c8fea2SSven Eckelmann 41308ad76ecSMarek Lindner return count; 414c6c8fea2SSven Eckelmann } 415c6c8fea2SSven Eckelmann 41608c36d3eSSven Eckelmann int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) 417c6c8fea2SSven Eckelmann { 418c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 419c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 4202dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 42148100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 42232ae9b22SMarek Lindner struct hard_iface *primary_if; 4237aadf889SMarek Lindner struct hlist_node *node; 424c6c8fea2SSven Eckelmann struct hlist_head *head; 425c90681b8SAntonio Quartulli uint32_t i; 426c90681b8SAntonio Quartulli int ret = 0; 427c6c8fea2SSven Eckelmann 428e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 42932ae9b22SMarek Lindner if (!primary_if) { 43086ceb360SSven Eckelmann ret = seq_printf(seq, 43186ceb360SSven Eckelmann "BATMAN mesh %s disabled - please specify interfaces to enable it\n", 432c6c8fea2SSven Eckelmann net_dev->name); 43332ae9b22SMarek Lindner goto out; 43432ae9b22SMarek Lindner } 43532ae9b22SMarek Lindner 436e9a4f295SSven Eckelmann if (primary_if->if_status != BATADV_IF_ACTIVE) { 43786ceb360SSven Eckelmann ret = seq_printf(seq, 43886ceb360SSven Eckelmann "BATMAN mesh %s disabled - primary interface not active\n", 43932ae9b22SMarek Lindner net_dev->name); 44032ae9b22SMarek Lindner goto out; 441c6c8fea2SSven Eckelmann } 442c6c8fea2SSven Eckelmann 44386ceb360SSven Eckelmann seq_printf(seq, 44486ceb360SSven Eckelmann "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", 445a73105b8SAntonio Quartulli net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn)); 446c6c8fea2SSven Eckelmann 447c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 448c6c8fea2SSven Eckelmann head = &hash->table[i]; 449c6c8fea2SSven Eckelmann 4507aadf889SMarek Lindner rcu_read_lock(); 45148100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 4527aadf889SMarek Lindner head, hash_entry) { 453d099c2c5SSimon Wunderlich seq_printf(seq, " * %pM [%c%c%c%c%c]\n", 45448100bacSAntonio Quartulli tt_common_entry->addr, 45548100bacSAntonio Quartulli (tt_common_entry->flags & 456acd34afaSSven Eckelmann BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 45748100bacSAntonio Quartulli (tt_common_entry->flags & 458acd34afaSSven Eckelmann BATADV_TT_CLIENT_NOPURGE ? 'P' : '.'), 45948100bacSAntonio Quartulli (tt_common_entry->flags & 460acd34afaSSven Eckelmann BATADV_TT_CLIENT_NEW ? 'N' : '.'), 46148100bacSAntonio Quartulli (tt_common_entry->flags & 462acd34afaSSven Eckelmann BATADV_TT_CLIENT_PENDING ? 'X' : '.'), 46348100bacSAntonio Quartulli (tt_common_entry->flags & 464acd34afaSSven Eckelmann BATADV_TT_CLIENT_WIFI ? 'W' : '.')); 465c6c8fea2SSven Eckelmann } 4667aadf889SMarek Lindner rcu_read_unlock(); 467c6c8fea2SSven Eckelmann } 46832ae9b22SMarek Lindner out: 46932ae9b22SMarek Lindner if (primary_if) 470e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 47132ae9b22SMarek Lindner return ret; 472c6c8fea2SSven Eckelmann } 473c6c8fea2SSven Eckelmann 474a513088dSSven Eckelmann static void batadv_tt_local_set_pending(struct bat_priv *bat_priv, 4752dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry, 476c566dbbeSAntonio Quartulli uint16_t flags, const char *message) 477c6c8fea2SSven Eckelmann { 478a513088dSSven Eckelmann batadv_tt_local_event(bat_priv, tt_local_entry->common.addr, 47948100bacSAntonio Quartulli tt_local_entry->common.flags | flags); 480c6c8fea2SSven Eckelmann 481015758d0SAntonio Quartulli /* The local client has to be marked as "pending to be removed" but has 482015758d0SAntonio Quartulli * to be kept in the table in order to send it in a full table 4839cfc7bd6SSven Eckelmann * response issued before the net ttvn increment (consistency check) 4849cfc7bd6SSven Eckelmann */ 485acd34afaSSven Eckelmann tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; 486c566dbbeSAntonio Quartulli 48739c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 48886ceb360SSven Eckelmann "Local tt entry (%pM) pending to be removed: %s\n", 48986ceb360SSven Eckelmann tt_local_entry->common.addr, message); 490c6c8fea2SSven Eckelmann } 491c6c8fea2SSven Eckelmann 49208c36d3eSSven Eckelmann void batadv_tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, 493cc47f66eSAntonio Quartulli const char *message, bool roaming) 494c6c8fea2SSven Eckelmann { 4957683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 49642d0b044SSven Eckelmann uint16_t flags; 497c6c8fea2SSven Eckelmann 498a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 4997683fdc1SAntonio Quartulli if (!tt_local_entry) 5007683fdc1SAntonio Quartulli goto out; 5017683fdc1SAntonio Quartulli 502acd34afaSSven Eckelmann flags = BATADV_TT_CLIENT_DEL; 50342d0b044SSven Eckelmann if (roaming) 504acd34afaSSven Eckelmann flags |= BATADV_TT_CLIENT_ROAM; 50542d0b044SSven Eckelmann 50642d0b044SSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, message); 5077683fdc1SAntonio Quartulli out: 5087683fdc1SAntonio Quartulli if (tt_local_entry) 509a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 510c6c8fea2SSven Eckelmann } 511c6c8fea2SSven Eckelmann 512acd34afaSSven Eckelmann static void batadv_tt_local_purge_list(struct bat_priv *bat_priv, 513acd34afaSSven Eckelmann struct hlist_head *head) 514c6c8fea2SSven Eckelmann { 5152dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry; 51648100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 5177aadf889SMarek Lindner struct hlist_node *node, *node_tmp; 518acd34afaSSven Eckelmann 519acd34afaSSven Eckelmann hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, head, 520acd34afaSSven Eckelmann hash_entry) { 521acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common_entry, 522acd34afaSSven Eckelmann struct tt_local_entry, common); 523acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) 524acd34afaSSven Eckelmann continue; 525acd34afaSSven Eckelmann 526acd34afaSSven Eckelmann /* entry already marked for deletion */ 527acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 528acd34afaSSven Eckelmann continue; 529acd34afaSSven Eckelmann 530acd34afaSSven Eckelmann if (!batadv_has_timed_out(tt_local_entry->last_seen, 531acd34afaSSven Eckelmann BATADV_TT_LOCAL_TIMEOUT)) 532acd34afaSSven Eckelmann continue; 533acd34afaSSven Eckelmann 534acd34afaSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 535acd34afaSSven Eckelmann BATADV_TT_CLIENT_DEL, "timed out"); 536acd34afaSSven Eckelmann } 537acd34afaSSven Eckelmann } 538acd34afaSSven Eckelmann 539acd34afaSSven Eckelmann static void batadv_tt_local_purge(struct bat_priv *bat_priv) 540acd34afaSSven Eckelmann { 541acd34afaSSven Eckelmann struct hashtable_t *hash = bat_priv->tt_local_hash; 542c6c8fea2SSven Eckelmann struct hlist_head *head; 5437683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 544c90681b8SAntonio Quartulli uint32_t i; 545c6c8fea2SSven Eckelmann 546c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 547c6c8fea2SSven Eckelmann head = &hash->table[i]; 5487683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 549c6c8fea2SSven Eckelmann 5507683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 551acd34afaSSven Eckelmann batadv_tt_local_purge_list(bat_priv, head); 5527683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 553c6c8fea2SSven Eckelmann } 554c6c8fea2SSven Eckelmann 555c6c8fea2SSven Eckelmann } 556c6c8fea2SSven Eckelmann 557a513088dSSven Eckelmann static void batadv_tt_local_table_free(struct bat_priv *bat_priv) 558c6c8fea2SSven Eckelmann { 559a73105b8SAntonio Quartulli struct hashtable_t *hash; 560a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 56148100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 562a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 5637683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 5647683fdc1SAntonio Quartulli struct hlist_head *head; 565c90681b8SAntonio Quartulli uint32_t i; 566a73105b8SAntonio Quartulli 5672dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 568c6c8fea2SSven Eckelmann return; 569c6c8fea2SSven Eckelmann 570a73105b8SAntonio Quartulli hash = bat_priv->tt_local_hash; 571a73105b8SAntonio Quartulli 572a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 573a73105b8SAntonio Quartulli head = &hash->table[i]; 574a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 575a73105b8SAntonio Quartulli 576a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 57748100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 578a73105b8SAntonio Quartulli head, hash_entry) { 579a73105b8SAntonio Quartulli hlist_del_rcu(node); 58048100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 58148100bacSAntonio Quartulli struct tt_local_entry, 58248100bacSAntonio Quartulli common); 583a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 584a73105b8SAntonio Quartulli } 585a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 586a73105b8SAntonio Quartulli } 587a73105b8SAntonio Quartulli 5881a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 589a73105b8SAntonio Quartulli 5902dafb49dSAntonio Quartulli bat_priv->tt_local_hash = NULL; 591c6c8fea2SSven Eckelmann } 592c6c8fea2SSven Eckelmann 593a513088dSSven Eckelmann static int batadv_tt_global_init(struct bat_priv *bat_priv) 594c6c8fea2SSven Eckelmann { 5952dafb49dSAntonio Quartulli if (bat_priv->tt_global_hash) 5965346c35eSSven Eckelmann return 0; 597c6c8fea2SSven Eckelmann 5981a8eaf07SSven Eckelmann bat_priv->tt_global_hash = batadv_hash_new(1024); 599c6c8fea2SSven Eckelmann 6002dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 6015346c35eSSven Eckelmann return -ENOMEM; 602c6c8fea2SSven Eckelmann 6035346c35eSSven Eckelmann return 0; 604c6c8fea2SSven Eckelmann } 605c6c8fea2SSven Eckelmann 606a513088dSSven Eckelmann static void batadv_tt_changes_list_free(struct bat_priv *bat_priv) 607a73105b8SAntonio Quartulli { 608a73105b8SAntonio Quartulli struct tt_change_node *entry, *safe; 609a73105b8SAntonio Quartulli 610a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 611a73105b8SAntonio Quartulli 612a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 613a73105b8SAntonio Quartulli list) { 614a73105b8SAntonio Quartulli list_del(&entry->list); 615a73105b8SAntonio Quartulli kfree(entry); 616a73105b8SAntonio Quartulli } 617a73105b8SAntonio Quartulli 618a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 619a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 620a73105b8SAntonio Quartulli } 621a73105b8SAntonio Quartulli 622db08e6e5SSimon Wunderlich /* find out if an orig_node is already in the list of a tt_global_entry. 623db08e6e5SSimon Wunderlich * returns 1 if found, 0 otherwise 624db08e6e5SSimon Wunderlich */ 625a513088dSSven Eckelmann static bool batadv_tt_global_entry_has_orig(const struct tt_global_entry *entry, 626db08e6e5SSimon Wunderlich const struct orig_node *orig_node) 627db08e6e5SSimon Wunderlich { 628db08e6e5SSimon Wunderlich struct tt_orig_list_entry *tmp_orig_entry; 629db08e6e5SSimon Wunderlich const struct hlist_head *head; 630db08e6e5SSimon Wunderlich struct hlist_node *node; 631db08e6e5SSimon Wunderlich bool found = false; 632db08e6e5SSimon Wunderlich 633db08e6e5SSimon Wunderlich rcu_read_lock(); 634db08e6e5SSimon Wunderlich head = &entry->orig_list; 635db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) { 636db08e6e5SSimon Wunderlich if (tmp_orig_entry->orig_node == orig_node) { 637db08e6e5SSimon Wunderlich found = true; 638db08e6e5SSimon Wunderlich break; 639db08e6e5SSimon Wunderlich } 640db08e6e5SSimon Wunderlich } 641db08e6e5SSimon Wunderlich rcu_read_unlock(); 642db08e6e5SSimon Wunderlich return found; 643db08e6e5SSimon Wunderlich } 644db08e6e5SSimon Wunderlich 645a513088dSSven Eckelmann static void 646a513088dSSven Eckelmann batadv_tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry, 647a513088dSSven Eckelmann struct orig_node *orig_node, int ttvn) 648db08e6e5SSimon Wunderlich { 649db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 650db08e6e5SSimon Wunderlich 651db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 652db08e6e5SSimon Wunderlich if (!orig_entry) 653db08e6e5SSimon Wunderlich return; 654db08e6e5SSimon Wunderlich 655db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 656db08e6e5SSimon Wunderlich atomic_inc(&orig_node->refcount); 657db08e6e5SSimon Wunderlich atomic_inc(&orig_node->tt_size); 658db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 659db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 660db08e6e5SSimon Wunderlich 661db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 662db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 663db08e6e5SSimon Wunderlich &tt_global_entry->orig_list); 664db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 665db08e6e5SSimon Wunderlich } 666db08e6e5SSimon Wunderlich 667a73105b8SAntonio Quartulli /* caller must hold orig_node refcount */ 66808c36d3eSSven Eckelmann int batadv_tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, 669d4f44692SAntonio Quartulli const unsigned char *tt_addr, uint8_t flags, 670d4f44692SAntonio Quartulli uint8_t ttvn) 671c6c8fea2SSven Eckelmann { 672db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry = NULL; 6737683fdc1SAntonio Quartulli int ret = 0; 67480b3f58cSSimon Wunderlich int hash_added; 675c0a55929SSven Eckelmann struct tt_common_entry *common; 676c6c8fea2SSven Eckelmann 677a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); 678c6c8fea2SSven Eckelmann 6792dafb49dSAntonio Quartulli if (!tt_global_entry) { 680d4f44692SAntonio Quartulli tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); 6812dafb49dSAntonio Quartulli if (!tt_global_entry) 6827683fdc1SAntonio Quartulli goto out; 6837683fdc1SAntonio Quartulli 684c0a55929SSven Eckelmann common = &tt_global_entry->common; 685c0a55929SSven Eckelmann memcpy(common->addr, tt_addr, ETH_ALEN); 686db08e6e5SSimon Wunderlich 687d4f44692SAntonio Quartulli common->flags = flags; 688cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 689c0a55929SSven Eckelmann atomic_set(&common->refcount, 2); 690db08e6e5SSimon Wunderlich 691db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 692db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 6937683fdc1SAntonio Quartulli 694c0a55929SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt_global_hash, 695a513088dSSven Eckelmann batadv_compare_tt, 696a513088dSSven Eckelmann batadv_choose_orig, common, 697a513088dSSven Eckelmann &common->hash_entry); 69880b3f58cSSimon Wunderlich 69980b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 70080b3f58cSSimon Wunderlich /* remove the reference for the hash */ 701a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 70280b3f58cSSimon Wunderlich goto out_remove; 70380b3f58cSSimon Wunderlich } 704db08e6e5SSimon Wunderlich 705a513088dSSven Eckelmann batadv_tt_global_add_orig_entry(tt_global_entry, orig_node, 706a513088dSSven Eckelmann ttvn); 707a73105b8SAntonio Quartulli } else { 708db08e6e5SSimon Wunderlich /* there is already a global entry, use this one. */ 709db08e6e5SSimon Wunderlich 710acd34afaSSven Eckelmann /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 711acd34afaSSven Eckelmann * one originator left in the list and we previously received a 712db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 713db08e6e5SSimon Wunderlich * 714db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 715db08e6e5SSimon Wunderlich * new one. 716db08e6e5SSimon Wunderlich */ 717acd34afaSSven Eckelmann if (tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM) { 718a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 719acd34afaSSven Eckelmann tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 720cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 721c6c8fea2SSven Eckelmann } 722c6c8fea2SSven Eckelmann 723a513088dSSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global_entry, 724a513088dSSven Eckelmann orig_node)) 725a513088dSSven Eckelmann batadv_tt_global_add_orig_entry(tt_global_entry, 726a513088dSSven Eckelmann orig_node, ttvn); 727db08e6e5SSimon Wunderlich } 728db08e6e5SSimon Wunderlich 72939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 730a73105b8SAntonio Quartulli "Creating new global tt entry: %pM (via %pM)\n", 73148100bacSAntonio Quartulli tt_global_entry->common.addr, orig_node->orig); 732a73105b8SAntonio Quartulli 73380b3f58cSSimon Wunderlich out_remove: 734c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 73508c36d3eSSven Eckelmann batadv_tt_local_remove(bat_priv, tt_global_entry->common.addr, 736acd34afaSSven Eckelmann "global tt received", 737acd34afaSSven Eckelmann flags & BATADV_TT_CLIENT_ROAM); 7387683fdc1SAntonio Quartulli ret = 1; 7397683fdc1SAntonio Quartulli out: 7407683fdc1SAntonio Quartulli if (tt_global_entry) 741a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 7427683fdc1SAntonio Quartulli return ret; 743c6c8fea2SSven Eckelmann } 744c6c8fea2SSven Eckelmann 745db08e6e5SSimon Wunderlich /* print all orig nodes who announce the address for this global entry. 746db08e6e5SSimon Wunderlich * it is assumed that the caller holds rcu_read_lock(); 747db08e6e5SSimon Wunderlich */ 748a513088dSSven Eckelmann static void 749a513088dSSven Eckelmann batadv_tt_global_print_entry(struct tt_global_entry *tt_global_entry, 750db08e6e5SSimon Wunderlich struct seq_file *seq) 751db08e6e5SSimon Wunderlich { 752db08e6e5SSimon Wunderlich struct hlist_head *head; 753db08e6e5SSimon Wunderlich struct hlist_node *node; 754db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 755db08e6e5SSimon Wunderlich struct tt_common_entry *tt_common_entry; 756db08e6e5SSimon Wunderlich uint16_t flags; 757db08e6e5SSimon Wunderlich uint8_t last_ttvn; 758db08e6e5SSimon Wunderlich 759db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 760db08e6e5SSimon Wunderlich 761db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 762db08e6e5SSimon Wunderlich 763db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 764db08e6e5SSimon Wunderlich flags = tt_common_entry->flags; 765db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 766db08e6e5SSimon Wunderlich seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n", 767db08e6e5SSimon Wunderlich tt_global_entry->common.addr, orig_entry->ttvn, 768db08e6e5SSimon Wunderlich orig_entry->orig_node->orig, last_ttvn, 769acd34afaSSven Eckelmann (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 770acd34afaSSven Eckelmann (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.')); 771db08e6e5SSimon Wunderlich } 772db08e6e5SSimon Wunderlich } 773db08e6e5SSimon Wunderlich 77408c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 775c6c8fea2SSven Eckelmann { 776c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 777c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 7782dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 77948100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 7802dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 78132ae9b22SMarek Lindner struct hard_iface *primary_if; 7827aadf889SMarek Lindner struct hlist_node *node; 783c6c8fea2SSven Eckelmann struct hlist_head *head; 784c90681b8SAntonio Quartulli uint32_t i; 785c90681b8SAntonio Quartulli int ret = 0; 786c6c8fea2SSven Eckelmann 787e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 78832ae9b22SMarek Lindner if (!primary_if) { 78986ceb360SSven Eckelmann ret = seq_printf(seq, 79086ceb360SSven Eckelmann "BATMAN mesh %s disabled - please specify interfaces to enable it\n", 791c6c8fea2SSven Eckelmann net_dev->name); 79232ae9b22SMarek Lindner goto out; 79332ae9b22SMarek Lindner } 79432ae9b22SMarek Lindner 795e9a4f295SSven Eckelmann if (primary_if->if_status != BATADV_IF_ACTIVE) { 79686ceb360SSven Eckelmann ret = seq_printf(seq, 79786ceb360SSven Eckelmann "BATMAN mesh %s disabled - primary interface not active\n", 79832ae9b22SMarek Lindner net_dev->name); 79932ae9b22SMarek Lindner goto out; 800c6c8fea2SSven Eckelmann } 801c6c8fea2SSven Eckelmann 8022dafb49dSAntonio Quartulli seq_printf(seq, 8032dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 804c6c8fea2SSven Eckelmann net_dev->name); 805df6edb9eSAntonio Quartulli seq_printf(seq, " %-13s %s %-15s %s %s\n", 806df6edb9eSAntonio Quartulli "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags"); 807c6c8fea2SSven Eckelmann 808c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 809c6c8fea2SSven Eckelmann head = &hash->table[i]; 810c6c8fea2SSven Eckelmann 8117aadf889SMarek Lindner rcu_read_lock(); 81248100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 8137aadf889SMarek Lindner head, hash_entry) { 81448100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 81548100bacSAntonio Quartulli struct tt_global_entry, 81648100bacSAntonio Quartulli common); 817a513088dSSven Eckelmann batadv_tt_global_print_entry(tt_global_entry, seq); 818c6c8fea2SSven Eckelmann } 8197aadf889SMarek Lindner rcu_read_unlock(); 820c6c8fea2SSven Eckelmann } 82132ae9b22SMarek Lindner out: 82232ae9b22SMarek Lindner if (primary_if) 823e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 82432ae9b22SMarek Lindner return ret; 825c6c8fea2SSven Eckelmann } 826c6c8fea2SSven Eckelmann 827db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 828a513088dSSven Eckelmann static void 829a513088dSSven Eckelmann batadv_tt_global_del_orig_list(struct tt_global_entry *tt_global_entry) 830db08e6e5SSimon Wunderlich { 831db08e6e5SSimon Wunderlich struct hlist_head *head; 832db08e6e5SSimon Wunderlich struct hlist_node *node, *safe; 833db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 834db08e6e5SSimon Wunderlich 835db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 836db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 837db08e6e5SSimon Wunderlich hlist_for_each_entry_safe(orig_entry, node, safe, head, list) { 838db08e6e5SSimon Wunderlich hlist_del_rcu(node); 839a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 840db08e6e5SSimon Wunderlich } 841db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 842db08e6e5SSimon Wunderlich 843db08e6e5SSimon Wunderlich } 844db08e6e5SSimon Wunderlich 845a513088dSSven Eckelmann static void 846a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(struct bat_priv *bat_priv, 847db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry, 848db08e6e5SSimon Wunderlich struct orig_node *orig_node, 849db08e6e5SSimon Wunderlich const char *message) 850db08e6e5SSimon Wunderlich { 851db08e6e5SSimon Wunderlich struct hlist_head *head; 852db08e6e5SSimon Wunderlich struct hlist_node *node, *safe; 853db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 854db08e6e5SSimon Wunderlich 855db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 856db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 857db08e6e5SSimon Wunderlich hlist_for_each_entry_safe(orig_entry, node, safe, head, list) { 858db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 85939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 860db08e6e5SSimon Wunderlich "Deleting %pM from global tt entry %pM: %s\n", 8611eda58bfSSven Eckelmann orig_node->orig, 8621eda58bfSSven Eckelmann tt_global_entry->common.addr, message); 863db08e6e5SSimon Wunderlich hlist_del_rcu(node); 864a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 865db08e6e5SSimon Wunderlich } 866db08e6e5SSimon Wunderlich } 867db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 868db08e6e5SSimon Wunderlich } 869db08e6e5SSimon Wunderlich 870a513088dSSven Eckelmann static void batadv_tt_global_del_struct(struct bat_priv *bat_priv, 8712dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry, 872747e4221SSven Eckelmann const char *message) 873c6c8fea2SSven Eckelmann { 87439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 87539c75a51SSven Eckelmann "Deleting global tt entry %pM: %s\n", 876db08e6e5SSimon Wunderlich tt_global_entry->common.addr, message); 8777683fdc1SAntonio Quartulli 878a513088dSSven Eckelmann batadv_hash_remove(bat_priv->tt_global_hash, batadv_compare_tt, 879da641193SSven Eckelmann batadv_choose_orig, tt_global_entry->common.addr); 880a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 881db08e6e5SSimon Wunderlich 882c6c8fea2SSven Eckelmann } 883c6c8fea2SSven Eckelmann 884db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 885acd34afaSSven Eckelmann * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the 886acd34afaSSven Eckelmann * timer, otherwise we simply remove the originator scheduled for deletion. 887db08e6e5SSimon Wunderlich */ 888a513088dSSven Eckelmann static void 889a513088dSSven Eckelmann batadv_tt_global_del_roaming(struct bat_priv *bat_priv, 890db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry, 891a513088dSSven Eckelmann struct orig_node *orig_node, const char *message) 892db08e6e5SSimon Wunderlich { 893db08e6e5SSimon Wunderlich bool last_entry = true; 894db08e6e5SSimon Wunderlich struct hlist_head *head; 895db08e6e5SSimon Wunderlich struct hlist_node *node; 896db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 897db08e6e5SSimon Wunderlich 898db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 899db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 900db08e6e5SSimon Wunderlich */ 901db08e6e5SSimon Wunderlich 902db08e6e5SSimon Wunderlich rcu_read_lock(); 903db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 904db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 905db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 906db08e6e5SSimon Wunderlich last_entry = false; 907db08e6e5SSimon Wunderlich break; 908db08e6e5SSimon Wunderlich } 909db08e6e5SSimon Wunderlich } 910db08e6e5SSimon Wunderlich rcu_read_unlock(); 911db08e6e5SSimon Wunderlich 912db08e6e5SSimon Wunderlich if (last_entry) { 913db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 914acd34afaSSven Eckelmann tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; 915db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 916db08e6e5SSimon Wunderlich } else 917db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 918db08e6e5SSimon Wunderlich * one and can still use the other one. 919db08e6e5SSimon Wunderlich */ 920a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 921db08e6e5SSimon Wunderlich orig_node, message); 922db08e6e5SSimon Wunderlich } 923db08e6e5SSimon Wunderlich 924db08e6e5SSimon Wunderlich 925db08e6e5SSimon Wunderlich 926a513088dSSven Eckelmann static void batadv_tt_global_del(struct bat_priv *bat_priv, 927de7aae65SSven Eckelmann struct orig_node *orig_node, 928de7aae65SSven Eckelmann const unsigned char *addr, 929cc47f66eSAntonio Quartulli const char *message, bool roaming) 930a73105b8SAntonio Quartulli { 9317683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 932a513088dSSven Eckelmann struct tt_local_entry *local_entry = NULL; 933a73105b8SAntonio Quartulli 934a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 935db08e6e5SSimon Wunderlich if (!tt_global_entry) 9367683fdc1SAntonio Quartulli goto out; 937a73105b8SAntonio Quartulli 938db08e6e5SSimon Wunderlich if (!roaming) { 939a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 940a513088dSSven Eckelmann orig_node, message); 94192f90f56SSven Eckelmann 942db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 943a513088dSSven Eckelmann batadv_tt_global_del_struct(bat_priv, tt_global_entry, 944db08e6e5SSimon Wunderlich message); 945db08e6e5SSimon Wunderlich 946cc47f66eSAntonio Quartulli goto out; 947cc47f66eSAntonio Quartulli } 94892f90f56SSven Eckelmann 949db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 950db08e6e5SSimon Wunderlich * event, there are two possibilities: 951db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 952db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 953acd34afaSSven Eckelmann * it with BATADV_TT_CLIENT_ROAM, we start a timer and we 954db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 955db08e6e5SSimon Wunderlich * the entry is purged. 956db08e6e5SSimon Wunderlich * 957db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 958db08e6e5SSimon Wunderlich * the originator. 959db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 9609cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 9619cfc7bd6SSven Eckelmann */ 962a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 963db08e6e5SSimon Wunderlich tt_global_entry->common.addr); 964a513088dSSven Eckelmann if (local_entry) { 965db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 966a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 967a513088dSSven Eckelmann batadv_tt_global_del_struct(bat_priv, tt_global_entry, message); 968db08e6e5SSimon Wunderlich } else 969db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 970a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 971a513088dSSven Eckelmann orig_node, message); 972db08e6e5SSimon Wunderlich 97392f90f56SSven Eckelmann 974cc47f66eSAntonio Quartulli out: 9757683fdc1SAntonio Quartulli if (tt_global_entry) 976a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 977a513088dSSven Eckelmann if (local_entry) 978a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(local_entry); 979a73105b8SAntonio Quartulli } 980a73105b8SAntonio Quartulli 98108c36d3eSSven Eckelmann void batadv_tt_global_del_orig(struct bat_priv *bat_priv, 982747e4221SSven Eckelmann struct orig_node *orig_node, const char *message) 983c6c8fea2SSven Eckelmann { 984a513088dSSven Eckelmann struct tt_global_entry *global_entry; 98548100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 986c90681b8SAntonio Quartulli uint32_t i; 987a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 988a73105b8SAntonio Quartulli struct hlist_node *node, *safe; 989a73105b8SAntonio Quartulli struct hlist_head *head; 9907683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 991c6c8fea2SSven Eckelmann 9926e801494SSimon Wunderlich if (!hash) 9936e801494SSimon Wunderlich return; 9946e801494SSimon Wunderlich 995a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 996a73105b8SAntonio Quartulli head = &hash->table[i]; 9977683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 998c6c8fea2SSven Eckelmann 9997683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 100048100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, safe, 1001a73105b8SAntonio Quartulli head, hash_entry) { 1002a513088dSSven Eckelmann global_entry = container_of(tt_common_entry, 100348100bacSAntonio Quartulli struct tt_global_entry, 100448100bacSAntonio Quartulli common); 1005db08e6e5SSimon Wunderlich 1006a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, global_entry, 1007db08e6e5SSimon Wunderlich orig_node, message); 1008db08e6e5SSimon Wunderlich 1009a513088dSSven Eckelmann if (hlist_empty(&global_entry->orig_list)) { 101039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1011db08e6e5SSimon Wunderlich "Deleting global tt entry %pM: %s\n", 1012a513088dSSven Eckelmann global_entry->common.addr, message); 10137683fdc1SAntonio Quartulli hlist_del_rcu(node); 1014a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(global_entry); 1015c6c8fea2SSven Eckelmann } 1016a73105b8SAntonio Quartulli } 10177683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 10187683fdc1SAntonio Quartulli } 101917071578SAntonio Quartulli orig_node->tt_initialised = false; 1020c6c8fea2SSven Eckelmann } 1021c6c8fea2SSven Eckelmann 102242d0b044SSven Eckelmann static void batadv_tt_global_roam_purge_list(struct bat_priv *bat_priv, 102342d0b044SSven Eckelmann struct hlist_head *head) 1024cc47f66eSAntonio Quartulli { 102548100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1026cc47f66eSAntonio Quartulli struct tt_global_entry *tt_global_entry; 1027cc47f66eSAntonio Quartulli struct hlist_node *node, *node_tmp; 1028cc47f66eSAntonio Quartulli 102942d0b044SSven Eckelmann hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, head, 103042d0b044SSven Eckelmann hash_entry) { 103148100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 103242d0b044SSven Eckelmann struct tt_global_entry, common); 1033acd34afaSSven Eckelmann if (!(tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM)) 1034cc47f66eSAntonio Quartulli continue; 10351eda58bfSSven Eckelmann if (!batadv_has_timed_out(tt_global_entry->roam_at, 103642d0b044SSven Eckelmann BATADV_TT_CLIENT_ROAM_TIMEOUT)) 1037cc47f66eSAntonio Quartulli continue; 1038cc47f66eSAntonio Quartulli 103939c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 104086ceb360SSven Eckelmann "Deleting global tt entry (%pM): Roaming timeout\n", 104148100bacSAntonio Quartulli tt_global_entry->common.addr); 1042db08e6e5SSimon Wunderlich 10437683fdc1SAntonio Quartulli hlist_del_rcu(node); 1044a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1045cc47f66eSAntonio Quartulli } 104642d0b044SSven Eckelmann } 104742d0b044SSven Eckelmann 104842d0b044SSven Eckelmann static void batadv_tt_global_roam_purge(struct bat_priv *bat_priv) 104942d0b044SSven Eckelmann { 105042d0b044SSven Eckelmann struct hashtable_t *hash = bat_priv->tt_global_hash; 105142d0b044SSven Eckelmann struct hlist_head *head; 105242d0b044SSven Eckelmann spinlock_t *list_lock; /* protects write access to the hash lists */ 105342d0b044SSven Eckelmann uint32_t i; 105442d0b044SSven Eckelmann 105542d0b044SSven Eckelmann for (i = 0; i < hash->size; i++) { 105642d0b044SSven Eckelmann head = &hash->table[i]; 105742d0b044SSven Eckelmann list_lock = &hash->list_locks[i]; 105842d0b044SSven Eckelmann 105942d0b044SSven Eckelmann spin_lock_bh(list_lock); 106042d0b044SSven Eckelmann batadv_tt_global_roam_purge_list(bat_priv, head); 10617683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1062cc47f66eSAntonio Quartulli } 1063cc47f66eSAntonio Quartulli 1064cc47f66eSAntonio Quartulli } 1065cc47f66eSAntonio Quartulli 1066a513088dSSven Eckelmann static void batadv_tt_global_table_free(struct bat_priv *bat_priv) 1067c6c8fea2SSven Eckelmann { 10687683fdc1SAntonio Quartulli struct hashtable_t *hash; 10697683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 107048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 10717683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry; 10727683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 10737683fdc1SAntonio Quartulli struct hlist_head *head; 1074c90681b8SAntonio Quartulli uint32_t i; 10757683fdc1SAntonio Quartulli 10762dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 1077c6c8fea2SSven Eckelmann return; 1078c6c8fea2SSven Eckelmann 10797683fdc1SAntonio Quartulli hash = bat_priv->tt_global_hash; 10807683fdc1SAntonio Quartulli 10817683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 10827683fdc1SAntonio Quartulli head = &hash->table[i]; 10837683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 10847683fdc1SAntonio Quartulli 10857683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 108648100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 10877683fdc1SAntonio Quartulli head, hash_entry) { 10887683fdc1SAntonio Quartulli hlist_del_rcu(node); 108948100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 109048100bacSAntonio Quartulli struct tt_global_entry, 109148100bacSAntonio Quartulli common); 1092a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 10937683fdc1SAntonio Quartulli } 10947683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 10957683fdc1SAntonio Quartulli } 10967683fdc1SAntonio Quartulli 10971a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 10987683fdc1SAntonio Quartulli 10992dafb49dSAntonio Quartulli bat_priv->tt_global_hash = NULL; 1100c6c8fea2SSven Eckelmann } 1101c6c8fea2SSven Eckelmann 1102a513088dSSven Eckelmann static bool _batadv_is_ap_isolated(struct tt_local_entry *tt_local_entry, 110359b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry) 110459b699cdSAntonio Quartulli { 110559b699cdSAntonio Quartulli bool ret = false; 110659b699cdSAntonio Quartulli 1107acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && 1108acd34afaSSven Eckelmann tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) 110959b699cdSAntonio Quartulli ret = true; 111059b699cdSAntonio Quartulli 111159b699cdSAntonio Quartulli return ret; 111259b699cdSAntonio Quartulli } 111359b699cdSAntonio Quartulli 111408c36d3eSSven Eckelmann struct orig_node *batadv_transtable_search(struct bat_priv *bat_priv, 111508c36d3eSSven Eckelmann const uint8_t *src, 111608c36d3eSSven Eckelmann const uint8_t *addr) 1117c6c8fea2SSven Eckelmann { 11183d393e47SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 11193d393e47SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 11207b36e8eeSMarek Lindner struct orig_node *orig_node = NULL; 1121db08e6e5SSimon Wunderlich struct neigh_node *router = NULL; 1122db08e6e5SSimon Wunderlich struct hlist_head *head; 1123db08e6e5SSimon Wunderlich struct hlist_node *node; 1124db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 1125db08e6e5SSimon Wunderlich int best_tq; 1126c6c8fea2SSven Eckelmann 11273d393e47SAntonio Quartulli if (src && atomic_read(&bat_priv->ap_isolation)) { 1128a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); 11293d393e47SAntonio Quartulli if (!tt_local_entry) 11303d393e47SAntonio Quartulli goto out; 11313d393e47SAntonio Quartulli } 11327aadf889SMarek Lindner 1133a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 11342dafb49dSAntonio Quartulli if (!tt_global_entry) 11357b36e8eeSMarek Lindner goto out; 1136c6c8fea2SSven Eckelmann 11373d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 11389cfc7bd6SSven Eckelmann * isolation 11399cfc7bd6SSven Eckelmann */ 1140a513088dSSven Eckelmann if (tt_local_entry && 1141a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 11423d393e47SAntonio Quartulli goto out; 11433d393e47SAntonio Quartulli 1144db08e6e5SSimon Wunderlich best_tq = 0; 11457b36e8eeSMarek Lindner 1146db08e6e5SSimon Wunderlich rcu_read_lock(); 1147db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1148db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 11497d211efcSSven Eckelmann router = batadv_orig_node_get_router(orig_entry->orig_node); 1150db08e6e5SSimon Wunderlich if (!router) 1151db08e6e5SSimon Wunderlich continue; 11527b36e8eeSMarek Lindner 1153db08e6e5SSimon Wunderlich if (router->tq_avg > best_tq) { 1154db08e6e5SSimon Wunderlich orig_node = orig_entry->orig_node; 1155db08e6e5SSimon Wunderlich best_tq = router->tq_avg; 1156db08e6e5SSimon Wunderlich } 11577d211efcSSven Eckelmann batadv_neigh_node_free_ref(router); 1158db08e6e5SSimon Wunderlich } 1159db08e6e5SSimon Wunderlich /* found anything? */ 1160db08e6e5SSimon Wunderlich if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) 1161db08e6e5SSimon Wunderlich orig_node = NULL; 1162db08e6e5SSimon Wunderlich rcu_read_unlock(); 11637b36e8eeSMarek Lindner out: 11643d393e47SAntonio Quartulli if (tt_global_entry) 1165a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 11663d393e47SAntonio Quartulli if (tt_local_entry) 1167a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 11683d393e47SAntonio Quartulli 11697b36e8eeSMarek Lindner return orig_node; 1170c6c8fea2SSven Eckelmann } 1171a73105b8SAntonio Quartulli 1172a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */ 1173a513088dSSven Eckelmann static uint16_t batadv_tt_global_crc(struct bat_priv *bat_priv, 1174de7aae65SSven Eckelmann struct orig_node *orig_node) 1175a73105b8SAntonio Quartulli { 1176a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1177a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 1178acd34afaSSven Eckelmann struct tt_common_entry *tt_common; 1179a73105b8SAntonio Quartulli struct tt_global_entry *tt_global_entry; 1180a73105b8SAntonio Quartulli struct hlist_node *node; 1181a73105b8SAntonio Quartulli struct hlist_head *head; 1182c90681b8SAntonio Quartulli uint32_t i; 1183c90681b8SAntonio Quartulli int j; 1184a73105b8SAntonio Quartulli 1185a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1186a73105b8SAntonio Quartulli head = &hash->table[i]; 1187a73105b8SAntonio Quartulli 1188a73105b8SAntonio Quartulli rcu_read_lock(); 1189acd34afaSSven Eckelmann hlist_for_each_entry_rcu(tt_common, node, head, hash_entry) { 1190acd34afaSSven Eckelmann tt_global_entry = container_of(tt_common, 119148100bacSAntonio Quartulli struct tt_global_entry, 119248100bacSAntonio Quartulli common); 1193cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 1194cc47f66eSAntonio Quartulli * consistency only. They don't have to be 1195cc47f66eSAntonio Quartulli * taken into account while computing the 1196db08e6e5SSimon Wunderlich * global crc 1197db08e6e5SSimon Wunderlich */ 1198acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 1199cc47f66eSAntonio Quartulli continue; 1200db08e6e5SSimon Wunderlich 1201db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 1202db08e6e5SSimon Wunderlich * originator 1203db08e6e5SSimon Wunderlich */ 1204a513088dSSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global_entry, 1205db08e6e5SSimon Wunderlich orig_node)) 1206db08e6e5SSimon Wunderlich continue; 1207db08e6e5SSimon Wunderlich 1208a73105b8SAntonio Quartulli total_one = 0; 1209a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1210a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 1211acd34afaSSven Eckelmann tt_common->addr[j]); 1212a73105b8SAntonio Quartulli total ^= total_one; 1213a73105b8SAntonio Quartulli } 1214a73105b8SAntonio Quartulli rcu_read_unlock(); 1215a73105b8SAntonio Quartulli } 1216a73105b8SAntonio Quartulli 1217a73105b8SAntonio Quartulli return total; 1218a73105b8SAntonio Quartulli } 1219a73105b8SAntonio Quartulli 1220a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */ 1221be9aa4c1SMarek Lindner static uint16_t batadv_tt_local_crc(struct bat_priv *bat_priv) 1222a73105b8SAntonio Quartulli { 1223a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1224a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 1225acd34afaSSven Eckelmann struct tt_common_entry *tt_common; 1226a73105b8SAntonio Quartulli struct hlist_node *node; 1227a73105b8SAntonio Quartulli struct hlist_head *head; 1228c90681b8SAntonio Quartulli uint32_t i; 1229c90681b8SAntonio Quartulli int j; 1230a73105b8SAntonio Quartulli 1231a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1232a73105b8SAntonio Quartulli head = &hash->table[i]; 1233a73105b8SAntonio Quartulli 1234a73105b8SAntonio Quartulli rcu_read_lock(); 1235acd34afaSSven Eckelmann hlist_for_each_entry_rcu(tt_common, node, head, hash_entry) { 1236058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 12379cfc7bd6SSven Eckelmann * account while computing the CRC 12389cfc7bd6SSven Eckelmann */ 1239acd34afaSSven Eckelmann if (tt_common->flags & BATADV_TT_CLIENT_NEW) 1240058d0e26SAntonio Quartulli continue; 1241a73105b8SAntonio Quartulli total_one = 0; 1242a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1243a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 1244acd34afaSSven Eckelmann tt_common->addr[j]); 1245a73105b8SAntonio Quartulli total ^= total_one; 1246a73105b8SAntonio Quartulli } 1247a73105b8SAntonio Quartulli rcu_read_unlock(); 1248a73105b8SAntonio Quartulli } 1249a73105b8SAntonio Quartulli 1250a73105b8SAntonio Quartulli return total; 1251a73105b8SAntonio Quartulli } 1252a73105b8SAntonio Quartulli 1253a513088dSSven Eckelmann static void batadv_tt_req_list_free(struct bat_priv *bat_priv) 1254a73105b8SAntonio Quartulli { 1255a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1256a73105b8SAntonio Quartulli 1257a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1258a73105b8SAntonio Quartulli 1259a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 1260a73105b8SAntonio Quartulli list_del(&node->list); 1261a73105b8SAntonio Quartulli kfree(node); 1262a73105b8SAntonio Quartulli } 1263a73105b8SAntonio Quartulli 1264a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1265a73105b8SAntonio Quartulli } 1266a73105b8SAntonio Quartulli 1267a513088dSSven Eckelmann static void batadv_tt_save_orig_buffer(struct bat_priv *bat_priv, 1268de7aae65SSven Eckelmann struct orig_node *orig_node, 1269de7aae65SSven Eckelmann const unsigned char *tt_buff, 1270de7aae65SSven Eckelmann uint8_t tt_num_changes) 1271a73105b8SAntonio Quartulli { 127208c36d3eSSven Eckelmann uint16_t tt_buff_len = batadv_tt_len(tt_num_changes); 1273a73105b8SAntonio Quartulli 1274a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 12759cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 12769cfc7bd6SSven Eckelmann */ 1277a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1278a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 1279a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1280a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1281a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 1282a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 1283a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 1284a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 1285a73105b8SAntonio Quartulli } 1286a73105b8SAntonio Quartulli } 1287a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1288a73105b8SAntonio Quartulli } 1289a73105b8SAntonio Quartulli 1290a513088dSSven Eckelmann static void batadv_tt_req_purge(struct bat_priv *bat_priv) 1291a73105b8SAntonio Quartulli { 1292a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1293a73105b8SAntonio Quartulli 1294a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1295a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 129642d0b044SSven Eckelmann if (batadv_has_timed_out(node->issued_at, 129742d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) { 1298a73105b8SAntonio Quartulli list_del(&node->list); 1299a73105b8SAntonio Quartulli kfree(node); 1300a73105b8SAntonio Quartulli } 1301a73105b8SAntonio Quartulli } 1302a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1303a73105b8SAntonio Quartulli } 1304a73105b8SAntonio Quartulli 1305a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 13069cfc7bd6SSven Eckelmann * has already been issued for this orig_node, NULL otherwise 13079cfc7bd6SSven Eckelmann */ 1308a513088dSSven Eckelmann static struct tt_req_node *batadv_new_tt_req_node(struct bat_priv *bat_priv, 1309a73105b8SAntonio Quartulli struct orig_node *orig_node) 1310a73105b8SAntonio Quartulli { 1311a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 1312a73105b8SAntonio Quartulli 1313a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1314a73105b8SAntonio Quartulli list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { 13151eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 13161eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 131742d0b044SSven Eckelmann BATADV_TT_REQUEST_TIMEOUT)) 1318a73105b8SAntonio Quartulli goto unlock; 1319a73105b8SAntonio Quartulli } 1320a73105b8SAntonio Quartulli 1321a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 1322a73105b8SAntonio Quartulli if (!tt_req_node) 1323a73105b8SAntonio Quartulli goto unlock; 1324a73105b8SAntonio Quartulli 1325a73105b8SAntonio Quartulli memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); 1326a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 1327a73105b8SAntonio Quartulli 1328a73105b8SAntonio Quartulli list_add(&tt_req_node->list, &bat_priv->tt_req_list); 1329a73105b8SAntonio Quartulli unlock: 1330a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1331a73105b8SAntonio Quartulli return tt_req_node; 1332a73105b8SAntonio Quartulli } 1333a73105b8SAntonio Quartulli 1334058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */ 1335a513088dSSven Eckelmann static int batadv_tt_local_valid_entry(const void *entry_ptr, 1336a513088dSSven Eckelmann const void *data_ptr) 1337058d0e26SAntonio Quartulli { 133848100bacSAntonio Quartulli const struct tt_common_entry *tt_common_entry = entry_ptr; 1339058d0e26SAntonio Quartulli 1340acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) 1341058d0e26SAntonio Quartulli return 0; 1342058d0e26SAntonio Quartulli return 1; 1343058d0e26SAntonio Quartulli } 1344058d0e26SAntonio Quartulli 1345a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr, 1346a513088dSSven Eckelmann const void *data_ptr) 1347a73105b8SAntonio Quartulli { 134848100bacSAntonio Quartulli const struct tt_common_entry *tt_common_entry = entry_ptr; 134948100bacSAntonio Quartulli const struct tt_global_entry *tt_global_entry; 1350a73105b8SAntonio Quartulli const struct orig_node *orig_node = data_ptr; 1351a73105b8SAntonio Quartulli 1352acd34afaSSven Eckelmann if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM) 1353cc47f66eSAntonio Quartulli return 0; 1354cc47f66eSAntonio Quartulli 135548100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, 135648100bacSAntonio Quartulli common); 135748100bacSAntonio Quartulli 1358a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 1359a73105b8SAntonio Quartulli } 1360a73105b8SAntonio Quartulli 1361a513088dSSven Eckelmann static struct sk_buff * 1362a513088dSSven Eckelmann batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, 1363a73105b8SAntonio Quartulli struct hashtable_t *hash, 1364a73105b8SAntonio Quartulli struct hard_iface *primary_if, 1365a513088dSSven Eckelmann int (*valid_cb)(const void *, const void *), 1366a73105b8SAntonio Quartulli void *cb_data) 1367a73105b8SAntonio Quartulli { 136848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1369a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1370a73105b8SAntonio Quartulli struct tt_change *tt_change; 1371a73105b8SAntonio Quartulli struct hlist_node *node; 1372a73105b8SAntonio Quartulli struct hlist_head *head; 1373a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1374a73105b8SAntonio Quartulli uint16_t tt_tot, tt_count; 1375a73105b8SAntonio Quartulli ssize_t tt_query_size = sizeof(struct tt_query_packet); 1376c90681b8SAntonio Quartulli uint32_t i; 1377a73105b8SAntonio Quartulli 1378a73105b8SAntonio Quartulli if (tt_query_size + tt_len > primary_if->soft_iface->mtu) { 1379a73105b8SAntonio Quartulli tt_len = primary_if->soft_iface->mtu - tt_query_size; 1380a73105b8SAntonio Quartulli tt_len -= tt_len % sizeof(struct tt_change); 1381a73105b8SAntonio Quartulli } 1382a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1383a73105b8SAntonio Quartulli 1384a73105b8SAntonio Quartulli skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN); 1385a73105b8SAntonio Quartulli if (!skb) 1386a73105b8SAntonio Quartulli goto out; 1387a73105b8SAntonio Quartulli 1388a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1389a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1390a73105b8SAntonio Quartulli tt_query_size + tt_len); 1391a73105b8SAntonio Quartulli tt_response->ttvn = ttvn; 1392a73105b8SAntonio Quartulli 1393a73105b8SAntonio Quartulli tt_change = (struct tt_change *)(skb->data + tt_query_size); 1394a73105b8SAntonio Quartulli tt_count = 0; 1395a73105b8SAntonio Quartulli 1396a73105b8SAntonio Quartulli rcu_read_lock(); 1397a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1398a73105b8SAntonio Quartulli head = &hash->table[i]; 1399a73105b8SAntonio Quartulli 140048100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1401a73105b8SAntonio Quartulli head, hash_entry) { 1402a73105b8SAntonio Quartulli if (tt_count == tt_tot) 1403a73105b8SAntonio Quartulli break; 1404a73105b8SAntonio Quartulli 140548100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 1406a73105b8SAntonio Quartulli continue; 1407a73105b8SAntonio Quartulli 140848100bacSAntonio Quartulli memcpy(tt_change->addr, tt_common_entry->addr, 140948100bacSAntonio Quartulli ETH_ALEN); 141042d0b044SSven Eckelmann tt_change->flags = BATADV_NO_FLAGS; 1411a73105b8SAntonio Quartulli 1412a73105b8SAntonio Quartulli tt_count++; 1413a73105b8SAntonio Quartulli tt_change++; 1414a73105b8SAntonio Quartulli } 1415a73105b8SAntonio Quartulli } 1416a73105b8SAntonio Quartulli rcu_read_unlock(); 1417a73105b8SAntonio Quartulli 14189d852393SAntonio Quartulli /* store in the message the number of entries we have successfully 14199cfc7bd6SSven Eckelmann * copied 14209cfc7bd6SSven Eckelmann */ 14219d852393SAntonio Quartulli tt_response->tt_data = htons(tt_count); 14229d852393SAntonio Quartulli 1423a73105b8SAntonio Quartulli out: 1424a73105b8SAntonio Quartulli return skb; 1425a73105b8SAntonio Quartulli } 1426a73105b8SAntonio Quartulli 1427a513088dSSven Eckelmann static int batadv_send_tt_request(struct bat_priv *bat_priv, 1428a943cac1SMarek Lindner struct orig_node *dst_orig_node, 1429a513088dSSven Eckelmann uint8_t ttvn, uint16_t tt_crc, 1430a513088dSSven Eckelmann bool full_table) 1431a73105b8SAntonio Quartulli { 1432a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1433a73105b8SAntonio Quartulli struct tt_query_packet *tt_request; 1434a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1435a73105b8SAntonio Quartulli struct hard_iface *primary_if; 1436a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node = NULL; 1437a73105b8SAntonio Quartulli int ret = 1; 1438a73105b8SAntonio Quartulli 1439e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1440a73105b8SAntonio Quartulli if (!primary_if) 1441a73105b8SAntonio Quartulli goto out; 1442a73105b8SAntonio Quartulli 1443a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 14449cfc7bd6SSven Eckelmann * reply from the same orig_node yet 14459cfc7bd6SSven Eckelmann */ 1446a513088dSSven Eckelmann tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node); 1447a73105b8SAntonio Quartulli if (!tt_req_node) 1448a73105b8SAntonio Quartulli goto out; 1449a73105b8SAntonio Quartulli 1450a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN); 1451a73105b8SAntonio Quartulli if (!skb) 1452a73105b8SAntonio Quartulli goto out; 1453a73105b8SAntonio Quartulli 1454a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1455a73105b8SAntonio Quartulli 1456a73105b8SAntonio Quartulli tt_request = (struct tt_query_packet *)skb_put(skb, 1457a73105b8SAntonio Quartulli sizeof(struct tt_query_packet)); 1458a73105b8SAntonio Quartulli 1459acd34afaSSven Eckelmann tt_request->header.packet_type = BATADV_TT_QUERY; 14607e071c79SSven Eckelmann tt_request->header.version = BATADV_COMPAT_VERSION; 1461a73105b8SAntonio Quartulli memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1462a73105b8SAntonio Quartulli memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); 146342d0b044SSven Eckelmann tt_request->header.ttl = BATADV_TTL; 1464a73105b8SAntonio Quartulli tt_request->ttvn = ttvn; 14656d2003fcSAntonio Quartulli tt_request->tt_data = htons(tt_crc); 1466acd34afaSSven Eckelmann tt_request->flags = BATADV_TT_REQUEST; 1467a73105b8SAntonio Quartulli 1468a73105b8SAntonio Quartulli if (full_table) 1469acd34afaSSven Eckelmann tt_request->flags |= BATADV_TT_FULL_TABLE; 1470a73105b8SAntonio Quartulli 14717d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(dst_orig_node); 1472a73105b8SAntonio Quartulli if (!neigh_node) 1473a73105b8SAntonio Quartulli goto out; 1474a73105b8SAntonio Quartulli 147539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 147686ceb360SSven Eckelmann "Sending TT_REQUEST to %pM via %pM [%c]\n", 147786ceb360SSven Eckelmann dst_orig_node->orig, neigh_node->addr, 1478a73105b8SAntonio Quartulli (full_table ? 'F' : '.')); 1479a73105b8SAntonio Quartulli 1480d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); 1481f8214865SMartin Hundebøll 14829455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1483a73105b8SAntonio Quartulli ret = 0; 1484a73105b8SAntonio Quartulli 1485a73105b8SAntonio Quartulli out: 1486a73105b8SAntonio Quartulli if (neigh_node) 14877d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1488a73105b8SAntonio Quartulli if (primary_if) 1489e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1490a73105b8SAntonio Quartulli if (ret) 1491a73105b8SAntonio Quartulli kfree_skb(skb); 1492a73105b8SAntonio Quartulli if (ret && tt_req_node) { 1493a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1494a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 1495a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1496a73105b8SAntonio Quartulli kfree(tt_req_node); 1497a73105b8SAntonio Quartulli } 1498a73105b8SAntonio Quartulli return ret; 1499a73105b8SAntonio Quartulli } 1500a73105b8SAntonio Quartulli 1501a513088dSSven Eckelmann static bool batadv_send_other_tt_response(struct bat_priv *bat_priv, 1502a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1503a73105b8SAntonio Quartulli { 1504a73105b8SAntonio Quartulli struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL; 1505a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1506a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1507a73105b8SAntonio Quartulli uint8_t orig_ttvn, req_ttvn, ttvn; 1508a73105b8SAntonio Quartulli int ret = false; 1509a73105b8SAntonio Quartulli unsigned char *tt_buff; 1510a73105b8SAntonio Quartulli bool full_table; 1511a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1512a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1513a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1514a73105b8SAntonio Quartulli 151539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 151686ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 151786ceb360SSven Eckelmann tt_request->src, tt_request->ttvn, tt_request->dst, 1518acd34afaSSven Eckelmann (tt_request->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1519a73105b8SAntonio Quartulli 1520a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 1521da641193SSven Eckelmann req_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->dst); 1522a73105b8SAntonio Quartulli if (!req_dst_orig_node) 1523a73105b8SAntonio Quartulli goto out; 1524a73105b8SAntonio Quartulli 1525da641193SSven Eckelmann res_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); 1526a73105b8SAntonio Quartulli if (!res_dst_orig_node) 1527a73105b8SAntonio Quartulli goto out; 1528a73105b8SAntonio Quartulli 15297d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(res_dst_orig_node); 1530a73105b8SAntonio Quartulli if (!neigh_node) 1531a73105b8SAntonio Quartulli goto out; 1532a73105b8SAntonio Quartulli 1533e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1534a73105b8SAntonio Quartulli if (!primary_if) 1535a73105b8SAntonio Quartulli goto out; 1536a73105b8SAntonio Quartulli 1537a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1538a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1539a73105b8SAntonio Quartulli 1540015758d0SAntonio Quartulli /* I don't have the requested data */ 1541a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 1542f25bd58aSAl Viro tt_request->tt_data != htons(req_dst_orig_node->tt_crc)) 1543a73105b8SAntonio Quartulli goto out; 1544a73105b8SAntonio Quartulli 1545015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 1546acd34afaSSven Eckelmann if (tt_request->flags & BATADV_TT_FULL_TABLE || 1547a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 1548a73105b8SAntonio Quartulli full_table = true; 1549a73105b8SAntonio Quartulli else 1550a73105b8SAntonio Quartulli full_table = false; 1551a73105b8SAntonio Quartulli 1552a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 15539cfc7bd6SSven Eckelmann * I'll send only one packet with as much TT entries as I can 15549cfc7bd6SSven Eckelmann */ 1555a73105b8SAntonio Quartulli if (!full_table) { 1556a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 1557a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 1558a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1559a73105b8SAntonio Quartulli 1560a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1561a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1562a73105b8SAntonio Quartulli if (!skb) 1563a73105b8SAntonio Quartulli goto unlock; 1564a73105b8SAntonio Quartulli 1565a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1566a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1567a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1568a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1569a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1570a73105b8SAntonio Quartulli 1571a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1572a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 1573a73105b8SAntonio Quartulli memcpy(tt_buff, req_dst_orig_node->tt_buff, 1574a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 1575a73105b8SAntonio Quartulli 1576a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1577a73105b8SAntonio Quartulli } else { 1578a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) * 1579a73105b8SAntonio Quartulli sizeof(struct tt_change); 1580a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1581a73105b8SAntonio Quartulli 1582a513088dSSven Eckelmann skb = batadv_tt_response_fill_table(tt_len, ttvn, 1583a73105b8SAntonio Quartulli bat_priv->tt_global_hash, 1584a513088dSSven Eckelmann primary_if, 1585a513088dSSven Eckelmann batadv_tt_global_valid, 1586a73105b8SAntonio Quartulli req_dst_orig_node); 1587a73105b8SAntonio Quartulli if (!skb) 1588a73105b8SAntonio Quartulli goto out; 1589a73105b8SAntonio Quartulli 1590a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1591a73105b8SAntonio Quartulli } 1592a73105b8SAntonio Quartulli 1593acd34afaSSven Eckelmann tt_response->header.packet_type = BATADV_TT_QUERY; 15947e071c79SSven Eckelmann tt_response->header.version = BATADV_COMPAT_VERSION; 159542d0b044SSven Eckelmann tt_response->header.ttl = BATADV_TTL; 1596a73105b8SAntonio Quartulli memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); 1597a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1598acd34afaSSven Eckelmann tt_response->flags = BATADV_TT_RESPONSE; 1599a73105b8SAntonio Quartulli 1600a73105b8SAntonio Quartulli if (full_table) 1601acd34afaSSven Eckelmann tt_response->flags |= BATADV_TT_FULL_TABLE; 1602a73105b8SAntonio Quartulli 160339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1604a73105b8SAntonio Quartulli "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n", 1605a73105b8SAntonio Quartulli res_dst_orig_node->orig, neigh_node->addr, 1606a73105b8SAntonio Quartulli req_dst_orig_node->orig, req_ttvn); 1607a73105b8SAntonio Quartulli 1608d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 1609f8214865SMartin Hundebøll 16109455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1611a73105b8SAntonio Quartulli ret = true; 1612a73105b8SAntonio Quartulli goto out; 1613a73105b8SAntonio Quartulli 1614a73105b8SAntonio Quartulli unlock: 1615a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1616a73105b8SAntonio Quartulli 1617a73105b8SAntonio Quartulli out: 1618a73105b8SAntonio Quartulli if (res_dst_orig_node) 16197d211efcSSven Eckelmann batadv_orig_node_free_ref(res_dst_orig_node); 1620a73105b8SAntonio Quartulli if (req_dst_orig_node) 16217d211efcSSven Eckelmann batadv_orig_node_free_ref(req_dst_orig_node); 1622a73105b8SAntonio Quartulli if (neigh_node) 16237d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1624a73105b8SAntonio Quartulli if (primary_if) 1625e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1626a73105b8SAntonio Quartulli if (!ret) 1627a73105b8SAntonio Quartulli kfree_skb(skb); 1628a73105b8SAntonio Quartulli return ret; 1629a73105b8SAntonio Quartulli 1630a73105b8SAntonio Quartulli } 1631a513088dSSven Eckelmann static bool batadv_send_my_tt_response(struct bat_priv *bat_priv, 1632a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1633a73105b8SAntonio Quartulli { 1634a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1635a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1636a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1637a73105b8SAntonio Quartulli uint8_t my_ttvn, req_ttvn, ttvn; 1638a73105b8SAntonio Quartulli int ret = false; 1639a73105b8SAntonio Quartulli unsigned char *tt_buff; 1640a73105b8SAntonio Quartulli bool full_table; 1641a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1642a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1643a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1644a73105b8SAntonio Quartulli 164539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 164686ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 164786ceb360SSven Eckelmann tt_request->src, tt_request->ttvn, 1648acd34afaSSven Eckelmann (tt_request->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1649a73105b8SAntonio Quartulli 1650a73105b8SAntonio Quartulli 1651a73105b8SAntonio Quartulli my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1652a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1653a73105b8SAntonio Quartulli 1654da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); 1655a73105b8SAntonio Quartulli if (!orig_node) 1656a73105b8SAntonio Quartulli goto out; 1657a73105b8SAntonio Quartulli 16587d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(orig_node); 1659a73105b8SAntonio Quartulli if (!neigh_node) 1660a73105b8SAntonio Quartulli goto out; 1661a73105b8SAntonio Quartulli 1662e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1663a73105b8SAntonio Quartulli if (!primary_if) 1664a73105b8SAntonio Quartulli goto out; 1665a73105b8SAntonio Quartulli 1666a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 16679cfc7bd6SSven Eckelmann * is too big send the whole local translation table 16689cfc7bd6SSven Eckelmann */ 1669acd34afaSSven Eckelmann if (tt_request->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || 1670a73105b8SAntonio Quartulli !bat_priv->tt_buff) 1671a73105b8SAntonio Quartulli full_table = true; 1672a73105b8SAntonio Quartulli else 1673a73105b8SAntonio Quartulli full_table = false; 1674a73105b8SAntonio Quartulli 1675a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 16769cfc7bd6SSven Eckelmann * I'll send only one packet with as much TT entries as I can 16779cfc7bd6SSven Eckelmann */ 1678a73105b8SAntonio Quartulli if (!full_table) { 1679a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 1680a73105b8SAntonio Quartulli tt_len = bat_priv->tt_buff_len; 1681a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1682a73105b8SAntonio Quartulli 1683a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1684a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1685a73105b8SAntonio Quartulli if (!skb) 1686a73105b8SAntonio Quartulli goto unlock; 1687a73105b8SAntonio Quartulli 1688a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1689a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1690a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1691a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1692a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1693a73105b8SAntonio Quartulli 1694a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1695a73105b8SAntonio Quartulli memcpy(tt_buff, bat_priv->tt_buff, 1696a73105b8SAntonio Quartulli bat_priv->tt_buff_len); 1697a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1698a73105b8SAntonio Quartulli } else { 1699a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) * 1700a73105b8SAntonio Quartulli sizeof(struct tt_change); 1701a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1702a73105b8SAntonio Quartulli 1703a513088dSSven Eckelmann skb = batadv_tt_response_fill_table(tt_len, ttvn, 1704a73105b8SAntonio Quartulli bat_priv->tt_local_hash, 1705a513088dSSven Eckelmann primary_if, 1706a513088dSSven Eckelmann batadv_tt_local_valid_entry, 1707058d0e26SAntonio Quartulli NULL); 1708a73105b8SAntonio Quartulli if (!skb) 1709a73105b8SAntonio Quartulli goto out; 1710a73105b8SAntonio Quartulli 1711a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1712a73105b8SAntonio Quartulli } 1713a73105b8SAntonio Quartulli 1714acd34afaSSven Eckelmann tt_response->header.packet_type = BATADV_TT_QUERY; 17157e071c79SSven Eckelmann tt_response->header.version = BATADV_COMPAT_VERSION; 171642d0b044SSven Eckelmann tt_response->header.ttl = BATADV_TTL; 1717a73105b8SAntonio Quartulli memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1718a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1719acd34afaSSven Eckelmann tt_response->flags = BATADV_TT_RESPONSE; 1720a73105b8SAntonio Quartulli 1721a73105b8SAntonio Quartulli if (full_table) 1722acd34afaSSven Eckelmann tt_response->flags |= BATADV_TT_FULL_TABLE; 1723a73105b8SAntonio Quartulli 172439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 1725a73105b8SAntonio Quartulli "Sending TT_RESPONSE to %pM via %pM [%c]\n", 1726a73105b8SAntonio Quartulli orig_node->orig, neigh_node->addr, 1727acd34afaSSven Eckelmann (tt_response->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1728a73105b8SAntonio Quartulli 1729d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); 1730f8214865SMartin Hundebøll 17319455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1732a73105b8SAntonio Quartulli ret = true; 1733a73105b8SAntonio Quartulli goto out; 1734a73105b8SAntonio Quartulli 1735a73105b8SAntonio Quartulli unlock: 1736a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1737a73105b8SAntonio Quartulli out: 1738a73105b8SAntonio Quartulli if (orig_node) 17397d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1740a73105b8SAntonio Quartulli if (neigh_node) 17417d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1742a73105b8SAntonio Quartulli if (primary_if) 1743e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1744a73105b8SAntonio Quartulli if (!ret) 1745a73105b8SAntonio Quartulli kfree_skb(skb); 1746a73105b8SAntonio Quartulli /* This packet was for me, so it doesn't need to be re-routed */ 1747a73105b8SAntonio Quartulli return true; 1748a73105b8SAntonio Quartulli } 1749a73105b8SAntonio Quartulli 175008c36d3eSSven Eckelmann bool batadv_send_tt_response(struct bat_priv *bat_priv, 1751a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1752a73105b8SAntonio Quartulli { 17533193e8fdSSven Eckelmann if (batadv_is_my_mac(tt_request->dst)) { 175420ff9d59SSimon Wunderlich /* don't answer backbone gws! */ 175508adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src)) 175620ff9d59SSimon Wunderlich return true; 175720ff9d59SSimon Wunderlich 1758a513088dSSven Eckelmann return batadv_send_my_tt_response(bat_priv, tt_request); 175920ff9d59SSimon Wunderlich } else { 1760a513088dSSven Eckelmann return batadv_send_other_tt_response(bat_priv, tt_request); 1761a73105b8SAntonio Quartulli } 176220ff9d59SSimon Wunderlich } 1763a73105b8SAntonio Quartulli 1764a513088dSSven Eckelmann static void _batadv_tt_update_changes(struct bat_priv *bat_priv, 1765a73105b8SAntonio Quartulli struct orig_node *orig_node, 1766a73105b8SAntonio Quartulli struct tt_change *tt_change, 1767a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 1768a73105b8SAntonio Quartulli { 1769a73105b8SAntonio Quartulli int i; 1770a513088dSSven Eckelmann int roams; 1771a73105b8SAntonio Quartulli 1772a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 1773acd34afaSSven Eckelmann if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { 1774acd34afaSSven Eckelmann roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; 1775a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 1776a73105b8SAntonio Quartulli (tt_change + i)->addr, 1777cc47f66eSAntonio Quartulli "tt removed by changes", 1778a513088dSSven Eckelmann roams); 177908c36d3eSSven Eckelmann } else { 178008c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 1781d4f44692SAntonio Quartulli (tt_change + i)->addr, 1782d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 1783a73105b8SAntonio Quartulli /* In case of problem while storing a 1784a73105b8SAntonio Quartulli * global_entry, we stop the updating 1785a73105b8SAntonio Quartulli * procedure without committing the 1786a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 1787a73105b8SAntonio Quartulli * corrupted data on tt_request 1788a73105b8SAntonio Quartulli */ 1789a73105b8SAntonio Quartulli return; 1790a73105b8SAntonio Quartulli } 179108c36d3eSSven Eckelmann } 179217071578SAntonio Quartulli orig_node->tt_initialised = true; 1793a73105b8SAntonio Quartulli } 1794a73105b8SAntonio Quartulli 1795a513088dSSven Eckelmann static void batadv_tt_fill_gtable(struct bat_priv *bat_priv, 1796a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1797a73105b8SAntonio Quartulli { 1798a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1799a73105b8SAntonio Quartulli 1800da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); 1801a73105b8SAntonio Quartulli if (!orig_node) 1802a73105b8SAntonio Quartulli goto out; 1803a73105b8SAntonio Quartulli 1804a73105b8SAntonio Quartulli /* Purge the old table first.. */ 180508c36d3eSSven Eckelmann batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table"); 1806a73105b8SAntonio Quartulli 1807a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, 1808a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1), 1809a513088dSSven Eckelmann ntohs(tt_response->tt_data), 1810a513088dSSven Eckelmann tt_response->ttvn); 1811a73105b8SAntonio Quartulli 1812a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1813a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1814a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1815a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 1816a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1817a73105b8SAntonio Quartulli 1818a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, tt_response->ttvn); 1819a73105b8SAntonio Quartulli 1820a73105b8SAntonio Quartulli out: 1821a73105b8SAntonio Quartulli if (orig_node) 18227d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1823a73105b8SAntonio Quartulli } 1824a73105b8SAntonio Quartulli 1825a513088dSSven Eckelmann static void batadv_tt_update_changes(struct bat_priv *bat_priv, 1826a943cac1SMarek Lindner struct orig_node *orig_node, 1827a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 1828a73105b8SAntonio Quartulli struct tt_change *tt_change) 1829a73105b8SAntonio Quartulli { 1830a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 1831a513088dSSven Eckelmann tt_num_changes, ttvn); 1832a73105b8SAntonio Quartulli 1833a513088dSSven Eckelmann batadv_tt_save_orig_buffer(bat_priv, orig_node, 1834a513088dSSven Eckelmann (unsigned char *)tt_change, tt_num_changes); 1835a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 1836a73105b8SAntonio Quartulli } 1837a73105b8SAntonio Quartulli 183808c36d3eSSven Eckelmann bool batadv_is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) 1839a73105b8SAntonio Quartulli { 18407683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 18417683fdc1SAntonio Quartulli bool ret = false; 1842a73105b8SAntonio Quartulli 1843a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 18447683fdc1SAntonio Quartulli if (!tt_local_entry) 18457683fdc1SAntonio Quartulli goto out; 1846058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 18479cfc7bd6SSven Eckelmann * consistency purpose) 18489cfc7bd6SSven Eckelmann */ 1849acd34afaSSven Eckelmann if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 1850058d0e26SAntonio Quartulli goto out; 18517683fdc1SAntonio Quartulli ret = true; 18527683fdc1SAntonio Quartulli out: 1853a73105b8SAntonio Quartulli if (tt_local_entry) 1854a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 18557683fdc1SAntonio Quartulli return ret; 1856a73105b8SAntonio Quartulli } 1857a73105b8SAntonio Quartulli 185808c36d3eSSven Eckelmann void batadv_handle_tt_response(struct bat_priv *bat_priv, 1859a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1860a73105b8SAntonio Quartulli { 1861a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1862a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1863a73105b8SAntonio Quartulli 186439c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 186586ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 1866f25bd58aSAl Viro tt_response->src, tt_response->ttvn, 1867f25bd58aSAl Viro ntohs(tt_response->tt_data), 1868acd34afaSSven Eckelmann (tt_response->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 1869a73105b8SAntonio Quartulli 187020ff9d59SSimon Wunderlich /* we should have never asked a backbone gw */ 187108adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src)) 187220ff9d59SSimon Wunderlich goto out; 187320ff9d59SSimon Wunderlich 1874da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); 1875a73105b8SAntonio Quartulli if (!orig_node) 1876a73105b8SAntonio Quartulli goto out; 1877a73105b8SAntonio Quartulli 1878acd34afaSSven Eckelmann if (tt_response->flags & BATADV_TT_FULL_TABLE) 1879a513088dSSven Eckelmann batadv_tt_fill_gtable(bat_priv, tt_response); 1880a73105b8SAntonio Quartulli else 1881a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, 1882f25bd58aSAl Viro ntohs(tt_response->tt_data), 1883a73105b8SAntonio Quartulli tt_response->ttvn, 1884a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1)); 1885a73105b8SAntonio Quartulli 1886a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 1887a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1888a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 18891eda58bfSSven Eckelmann if (!batadv_compare_eth(node->addr, tt_response->src)) 1890a73105b8SAntonio Quartulli continue; 1891a73105b8SAntonio Quartulli list_del(&node->list); 1892a73105b8SAntonio Quartulli kfree(node); 1893a73105b8SAntonio Quartulli } 1894a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1895a73105b8SAntonio Quartulli 1896a73105b8SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 1897a513088dSSven Eckelmann orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 1898cc47f66eSAntonio Quartulli /* Roaming phase is over: tables are in sync again. I can 18999cfc7bd6SSven Eckelmann * unset the flag 19009cfc7bd6SSven Eckelmann */ 1901cc47f66eSAntonio Quartulli orig_node->tt_poss_change = false; 1902a73105b8SAntonio Quartulli out: 1903a73105b8SAntonio Quartulli if (orig_node) 19047d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1905a73105b8SAntonio Quartulli } 1906a73105b8SAntonio Quartulli 190708c36d3eSSven Eckelmann int batadv_tt_init(struct bat_priv *bat_priv) 1908a73105b8SAntonio Quartulli { 19095346c35eSSven Eckelmann int ret; 1910a73105b8SAntonio Quartulli 1911a513088dSSven Eckelmann ret = batadv_tt_local_init(bat_priv); 19125346c35eSSven Eckelmann if (ret < 0) 19135346c35eSSven Eckelmann return ret; 19145346c35eSSven Eckelmann 1915a513088dSSven Eckelmann ret = batadv_tt_global_init(bat_priv); 19165346c35eSSven Eckelmann if (ret < 0) 19175346c35eSSven Eckelmann return ret; 1918a73105b8SAntonio Quartulli 1919a513088dSSven Eckelmann batadv_tt_start_timer(bat_priv); 1920a73105b8SAntonio Quartulli 1921a73105b8SAntonio Quartulli return 1; 1922a73105b8SAntonio Quartulli } 1923a73105b8SAntonio Quartulli 1924a513088dSSven Eckelmann static void batadv_tt_roam_list_free(struct bat_priv *bat_priv) 1925a73105b8SAntonio Quartulli { 1926cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1927a73105b8SAntonio Quartulli 1928cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1929a73105b8SAntonio Quartulli 1930cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1931cc47f66eSAntonio Quartulli list_del(&node->list); 1932cc47f66eSAntonio Quartulli kfree(node); 1933cc47f66eSAntonio Quartulli } 1934cc47f66eSAntonio Quartulli 1935cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1936cc47f66eSAntonio Quartulli } 1937cc47f66eSAntonio Quartulli 1938a513088dSSven Eckelmann static void batadv_tt_roam_purge(struct bat_priv *bat_priv) 1939cc47f66eSAntonio Quartulli { 1940cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1941cc47f66eSAntonio Quartulli 1942cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1943cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 194442d0b044SSven Eckelmann if (!batadv_has_timed_out(node->first_time, 194542d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 1946cc47f66eSAntonio Quartulli continue; 1947cc47f66eSAntonio Quartulli 1948cc47f66eSAntonio Quartulli list_del(&node->list); 1949cc47f66eSAntonio Quartulli kfree(node); 1950cc47f66eSAntonio Quartulli } 1951cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1952cc47f66eSAntonio Quartulli } 1953cc47f66eSAntonio Quartulli 1954cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 1955cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 1956cc47f66eSAntonio Quartulli * will not be sent. 1957cc47f66eSAntonio Quartulli * 19589cfc7bd6SSven Eckelmann * returns true if the ROAMING_ADV can be sent, false otherwise 19599cfc7bd6SSven Eckelmann */ 1960a513088dSSven Eckelmann static bool batadv_tt_check_roam_count(struct bat_priv *bat_priv, 1961cc47f66eSAntonio Quartulli uint8_t *client) 1962cc47f66eSAntonio Quartulli { 1963cc47f66eSAntonio Quartulli struct tt_roam_node *tt_roam_node; 1964cc47f66eSAntonio Quartulli bool ret = false; 1965cc47f66eSAntonio Quartulli 1966cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1967cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 19689cfc7bd6SSven Eckelmann * reply from the same orig_node yet 19699cfc7bd6SSven Eckelmann */ 1970cc47f66eSAntonio Quartulli list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) { 19711eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 1972cc47f66eSAntonio Quartulli continue; 1973cc47f66eSAntonio Quartulli 19741eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 197542d0b044SSven Eckelmann BATADV_ROAMING_MAX_TIME)) 1976cc47f66eSAntonio Quartulli continue; 1977cc47f66eSAntonio Quartulli 19783e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 1979cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 1980cc47f66eSAntonio Quartulli goto unlock; 1981cc47f66eSAntonio Quartulli ret = true; 1982cc47f66eSAntonio Quartulli break; 1983cc47f66eSAntonio Quartulli } 1984cc47f66eSAntonio Quartulli 1985cc47f66eSAntonio Quartulli if (!ret) { 1986cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 1987cc47f66eSAntonio Quartulli if (!tt_roam_node) 1988cc47f66eSAntonio Quartulli goto unlock; 1989cc47f66eSAntonio Quartulli 1990cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 199142d0b044SSven Eckelmann atomic_set(&tt_roam_node->counter, 199242d0b044SSven Eckelmann BATADV_ROAMING_MAX_COUNT - 1); 1993cc47f66eSAntonio Quartulli memcpy(tt_roam_node->addr, client, ETH_ALEN); 1994cc47f66eSAntonio Quartulli 1995cc47f66eSAntonio Quartulli list_add(&tt_roam_node->list, &bat_priv->tt_roam_list); 1996cc47f66eSAntonio Quartulli ret = true; 1997cc47f66eSAntonio Quartulli } 1998cc47f66eSAntonio Quartulli 1999cc47f66eSAntonio Quartulli unlock: 2000cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 2001cc47f66eSAntonio Quartulli return ret; 2002cc47f66eSAntonio Quartulli } 2003cc47f66eSAntonio Quartulli 2004a513088dSSven Eckelmann static void batadv_send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 2005cc47f66eSAntonio Quartulli struct orig_node *orig_node) 2006cc47f66eSAntonio Quartulli { 2007cc47f66eSAntonio Quartulli struct neigh_node *neigh_node = NULL; 2008cc47f66eSAntonio Quartulli struct sk_buff *skb = NULL; 2009cc47f66eSAntonio Quartulli struct roam_adv_packet *roam_adv_packet; 2010cc47f66eSAntonio Quartulli int ret = 1; 2011cc47f66eSAntonio Quartulli struct hard_iface *primary_if; 2012cc47f66eSAntonio Quartulli 2013cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 20149cfc7bd6SSven Eckelmann * already roamed to us too many times 20159cfc7bd6SSven Eckelmann */ 2016a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 2017cc47f66eSAntonio Quartulli goto out; 2018cc47f66eSAntonio Quartulli 2019cc47f66eSAntonio Quartulli skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN); 2020cc47f66eSAntonio Quartulli if (!skb) 2021cc47f66eSAntonio Quartulli goto out; 2022cc47f66eSAntonio Quartulli 2023cc47f66eSAntonio Quartulli skb_reserve(skb, ETH_HLEN); 2024cc47f66eSAntonio Quartulli 2025cc47f66eSAntonio Quartulli roam_adv_packet = (struct roam_adv_packet *)skb_put(skb, 2026cc47f66eSAntonio Quartulli sizeof(struct roam_adv_packet)); 2027cc47f66eSAntonio Quartulli 2028acd34afaSSven Eckelmann roam_adv_packet->header.packet_type = BATADV_ROAM_ADV; 20297e071c79SSven Eckelmann roam_adv_packet->header.version = BATADV_COMPAT_VERSION; 203042d0b044SSven Eckelmann roam_adv_packet->header.ttl = BATADV_TTL; 2031e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2032cc47f66eSAntonio Quartulli if (!primary_if) 2033cc47f66eSAntonio Quartulli goto out; 2034cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); 2035e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 2036cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); 2037cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->client, client, ETH_ALEN); 2038cc47f66eSAntonio Quartulli 20397d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(orig_node); 2040cc47f66eSAntonio Quartulli if (!neigh_node) 2041cc47f66eSAntonio Quartulli goto out; 2042cc47f66eSAntonio Quartulli 204339c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 2044cc47f66eSAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM) via %pM\n", 2045cc47f66eSAntonio Quartulli orig_node->orig, client, neigh_node->addr); 2046cc47f66eSAntonio Quartulli 2047d69909d2SSven Eckelmann batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); 2048f8214865SMartin Hundebøll 20499455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 2050cc47f66eSAntonio Quartulli ret = 0; 2051cc47f66eSAntonio Quartulli 2052cc47f66eSAntonio Quartulli out: 2053cc47f66eSAntonio Quartulli if (neigh_node) 20547d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 2055cc47f66eSAntonio Quartulli if (ret) 2056cc47f66eSAntonio Quartulli kfree_skb(skb); 2057cc47f66eSAntonio Quartulli return; 2058a73105b8SAntonio Quartulli } 2059a73105b8SAntonio Quartulli 2060a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 2061a73105b8SAntonio Quartulli { 2062a73105b8SAntonio Quartulli struct delayed_work *delayed_work = 2063a73105b8SAntonio Quartulli container_of(work, struct delayed_work, work); 2064a73105b8SAntonio Quartulli struct bat_priv *bat_priv = 2065a73105b8SAntonio Quartulli container_of(delayed_work, struct bat_priv, tt_work); 2066a73105b8SAntonio Quartulli 2067a513088dSSven Eckelmann batadv_tt_local_purge(bat_priv); 2068a513088dSSven Eckelmann batadv_tt_global_roam_purge(bat_priv); 2069a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 2070a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 2071a73105b8SAntonio Quartulli 2072a513088dSSven Eckelmann batadv_tt_start_timer(bat_priv); 2073a73105b8SAntonio Quartulli } 2074cc47f66eSAntonio Quartulli 207508c36d3eSSven Eckelmann void batadv_tt_free(struct bat_priv *bat_priv) 2076cc47f66eSAntonio Quartulli { 2077cc47f66eSAntonio Quartulli cancel_delayed_work_sync(&bat_priv->tt_work); 2078cc47f66eSAntonio Quartulli 2079a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 2080a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 2081a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 2082a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 2083a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 2084cc47f66eSAntonio Quartulli 2085cc47f66eSAntonio Quartulli kfree(bat_priv->tt_buff); 2086cc47f66eSAntonio Quartulli } 2087058d0e26SAntonio Quartulli 2088697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries 20899cfc7bd6SSven Eckelmann * in the given hash table and returns the number of modified entries 20909cfc7bd6SSven Eckelmann */ 2091a513088dSSven Eckelmann static uint16_t batadv_tt_set_flags(struct hashtable_t *hash, uint16_t flags, 2092697f2531SAntonio Quartulli bool enable) 2093058d0e26SAntonio Quartulli { 2094c90681b8SAntonio Quartulli uint32_t i; 2095697f2531SAntonio Quartulli uint16_t changed_num = 0; 2096058d0e26SAntonio Quartulli struct hlist_head *head; 2097058d0e26SAntonio Quartulli struct hlist_node *node; 209848100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 2099058d0e26SAntonio Quartulli 2100058d0e26SAntonio Quartulli if (!hash) 2101697f2531SAntonio Quartulli goto out; 2102058d0e26SAntonio Quartulli 2103058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2104058d0e26SAntonio Quartulli head = &hash->table[i]; 2105058d0e26SAntonio Quartulli 2106058d0e26SAntonio Quartulli rcu_read_lock(); 210748100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 2108058d0e26SAntonio Quartulli head, hash_entry) { 2109697f2531SAntonio Quartulli if (enable) { 2110697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 2111697f2531SAntonio Quartulli continue; 2112697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 2113697f2531SAntonio Quartulli } else { 211448100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 211531901264SAntonio Quartulli continue; 211648100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 2117697f2531SAntonio Quartulli } 2118697f2531SAntonio Quartulli changed_num++; 2119058d0e26SAntonio Quartulli } 2120058d0e26SAntonio Quartulli rcu_read_unlock(); 2121058d0e26SAntonio Quartulli } 2122697f2531SAntonio Quartulli out: 2123697f2531SAntonio Quartulli return changed_num; 2124058d0e26SAntonio Quartulli } 2125058d0e26SAntonio Quartulli 2126acd34afaSSven Eckelmann /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ 2127a513088dSSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct bat_priv *bat_priv) 2128058d0e26SAntonio Quartulli { 2129058d0e26SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 2130acd34afaSSven Eckelmann struct tt_common_entry *tt_common; 2131058d0e26SAntonio Quartulli struct tt_local_entry *tt_local_entry; 2132058d0e26SAntonio Quartulli struct hlist_node *node, *node_tmp; 2133058d0e26SAntonio Quartulli struct hlist_head *head; 2134058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 2135c90681b8SAntonio Quartulli uint32_t i; 2136058d0e26SAntonio Quartulli 2137058d0e26SAntonio Quartulli if (!hash) 2138058d0e26SAntonio Quartulli return; 2139058d0e26SAntonio Quartulli 2140058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2141058d0e26SAntonio Quartulli head = &hash->table[i]; 2142058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 2143058d0e26SAntonio Quartulli 2144058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 2145acd34afaSSven Eckelmann hlist_for_each_entry_safe(tt_common, node, node_tmp, head, 2146acd34afaSSven Eckelmann hash_entry) { 2147acd34afaSSven Eckelmann if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) 2148058d0e26SAntonio Quartulli continue; 2149058d0e26SAntonio Quartulli 215039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 215186ceb360SSven Eckelmann "Deleting local tt entry (%pM): pending\n", 2152acd34afaSSven Eckelmann tt_common->addr); 2153058d0e26SAntonio Quartulli 2154058d0e26SAntonio Quartulli atomic_dec(&bat_priv->num_local_tt); 2155058d0e26SAntonio Quartulli hlist_del_rcu(node); 2156acd34afaSSven Eckelmann tt_local_entry = container_of(tt_common, 215748100bacSAntonio Quartulli struct tt_local_entry, 215848100bacSAntonio Quartulli common); 2159a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 2160058d0e26SAntonio Quartulli } 2161058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 2162058d0e26SAntonio Quartulli } 2163058d0e26SAntonio Quartulli 2164058d0e26SAntonio Quartulli } 2165058d0e26SAntonio Quartulli 2166a513088dSSven Eckelmann static int batadv_tt_commit_changes(struct bat_priv *bat_priv, 2167a513088dSSven Eckelmann unsigned char **packet_buff, 2168a513088dSSven Eckelmann int *packet_buff_len, int packet_min_len) 2169058d0e26SAntonio Quartulli { 2170be9aa4c1SMarek Lindner uint16_t changed_num = 0; 2171be9aa4c1SMarek Lindner 2172be9aa4c1SMarek Lindner if (atomic_read(&bat_priv->tt_local_changes) < 1) 2173be9aa4c1SMarek Lindner return -ENOENT; 2174be9aa4c1SMarek Lindner 2175a513088dSSven Eckelmann changed_num = batadv_tt_set_flags(bat_priv->tt_local_hash, 2176acd34afaSSven Eckelmann BATADV_TT_CLIENT_NEW, false); 2177be9aa4c1SMarek Lindner 2178be9aa4c1SMarek Lindner /* all reset entries have to be counted as local entries */ 2179697f2531SAntonio Quartulli atomic_add(changed_num, &bat_priv->num_local_tt); 2180a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 2181be9aa4c1SMarek Lindner bat_priv->tt_crc = batadv_tt_local_crc(bat_priv); 2182058d0e26SAntonio Quartulli 2183058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 2184058d0e26SAntonio Quartulli atomic_inc(&bat_priv->ttvn); 218539c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 21861eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 2187db08e6e5SSimon Wunderlich (uint8_t)atomic_read(&bat_priv->ttvn)); 2188058d0e26SAntonio Quartulli bat_priv->tt_poss_change = false; 2189be9aa4c1SMarek Lindner 2190be9aa4c1SMarek Lindner /* reset the sending counter */ 219142d0b044SSven Eckelmann atomic_set(&bat_priv->tt_ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 2192be9aa4c1SMarek Lindner 2193a513088dSSven Eckelmann return batadv_tt_changes_fill_buff(bat_priv, packet_buff, 2194be9aa4c1SMarek Lindner packet_buff_len, packet_min_len); 2195be9aa4c1SMarek Lindner } 2196be9aa4c1SMarek Lindner 2197be9aa4c1SMarek Lindner /* when calling this function (hard_iface == primary_if) has to be true */ 2198be9aa4c1SMarek Lindner int batadv_tt_append_diff(struct bat_priv *bat_priv, 2199be9aa4c1SMarek Lindner unsigned char **packet_buff, int *packet_buff_len, 2200be9aa4c1SMarek Lindner int packet_min_len) 2201be9aa4c1SMarek Lindner { 2202be9aa4c1SMarek Lindner int tt_num_changes; 2203be9aa4c1SMarek Lindner 2204be9aa4c1SMarek Lindner /* if at least one change happened */ 2205a513088dSSven Eckelmann tt_num_changes = batadv_tt_commit_changes(bat_priv, packet_buff, 2206a513088dSSven Eckelmann packet_buff_len, 2207a513088dSSven Eckelmann packet_min_len); 2208be9aa4c1SMarek Lindner 2209be9aa4c1SMarek Lindner /* if the changes have been sent often enough */ 2210be9aa4c1SMarek Lindner if ((tt_num_changes < 0) && 22113e34819eSSven Eckelmann (!batadv_atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))) { 2212a513088dSSven Eckelmann batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, 2213be9aa4c1SMarek Lindner packet_min_len, packet_min_len); 2214be9aa4c1SMarek Lindner tt_num_changes = 0; 2215be9aa4c1SMarek Lindner } 2216be9aa4c1SMarek Lindner 2217be9aa4c1SMarek Lindner return tt_num_changes; 2218058d0e26SAntonio Quartulli } 221959b699cdSAntonio Quartulli 222008c36d3eSSven Eckelmann bool batadv_is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, 222108c36d3eSSven Eckelmann uint8_t *dst) 222259b699cdSAntonio Quartulli { 222359b699cdSAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 222459b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 22255870adc6SMarek Lindner bool ret = false; 222659b699cdSAntonio Quartulli 222759b699cdSAntonio Quartulli if (!atomic_read(&bat_priv->ap_isolation)) 22285870adc6SMarek Lindner goto out; 222959b699cdSAntonio Quartulli 2230a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst); 223159b699cdSAntonio Quartulli if (!tt_local_entry) 223259b699cdSAntonio Quartulli goto out; 223359b699cdSAntonio Quartulli 2234a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, src); 223559b699cdSAntonio Quartulli if (!tt_global_entry) 223659b699cdSAntonio Quartulli goto out; 223759b699cdSAntonio Quartulli 22381f129fefSAntonio Quartulli if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 223959b699cdSAntonio Quartulli goto out; 224059b699cdSAntonio Quartulli 22415870adc6SMarek Lindner ret = true; 224259b699cdSAntonio Quartulli 224359b699cdSAntonio Quartulli out: 224459b699cdSAntonio Quartulli if (tt_global_entry) 2245a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 224659b699cdSAntonio Quartulli if (tt_local_entry) 2247a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 224859b699cdSAntonio Quartulli return ret; 224959b699cdSAntonio Quartulli } 2250a943cac1SMarek Lindner 225108c36d3eSSven Eckelmann void batadv_tt_update_orig(struct bat_priv *bat_priv, 225208c36d3eSSven Eckelmann struct orig_node *orig_node, 2253a943cac1SMarek Lindner const unsigned char *tt_buff, uint8_t tt_num_changes, 2254a943cac1SMarek Lindner uint8_t ttvn, uint16_t tt_crc) 2255a943cac1SMarek Lindner { 2256a943cac1SMarek Lindner uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); 2257a943cac1SMarek Lindner bool full_table = true; 2258a943cac1SMarek Lindner 225920ff9d59SSimon Wunderlich /* don't care about a backbone gateways updates. */ 226008adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) 226120ff9d59SSimon Wunderlich return; 226220ff9d59SSimon Wunderlich 226317071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 22649cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 22659cfc7bd6SSven Eckelmann */ 226617071578SAntonio Quartulli if ((!orig_node->tt_initialised && ttvn == 1) || 226717071578SAntonio Quartulli ttvn - orig_ttvn == 1) { 2268a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 226942d0b044SSven Eckelmann * because they have already been sent BATADV_TT_OGM_APPEND_MAX 227042d0b044SSven Eckelmann * times. 22719cfc7bd6SSven Eckelmann * In this case send a tt request 22729cfc7bd6SSven Eckelmann */ 2273a943cac1SMarek Lindner if (!tt_num_changes) { 2274a943cac1SMarek Lindner full_table = false; 2275a943cac1SMarek Lindner goto request_table; 2276a943cac1SMarek Lindner } 2277a943cac1SMarek Lindner 2278a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 2279a513088dSSven Eckelmann ttvn, (struct tt_change *)tt_buff); 2280a943cac1SMarek Lindner 2281a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 2282a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 22839cfc7bd6SSven Eckelmann * in the global table 22849cfc7bd6SSven Eckelmann */ 2285a513088dSSven Eckelmann orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 2286a943cac1SMarek Lindner 2287a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 2288a943cac1SMarek Lindner * because a single value could represent different states 2289a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 2290a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 2291a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 2292a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 2293a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 22949cfc7bd6SSven Eckelmann * inconsistency 22959cfc7bd6SSven Eckelmann */ 2296a943cac1SMarek Lindner if (orig_node->tt_crc != tt_crc) 2297a943cac1SMarek Lindner goto request_table; 2298a943cac1SMarek Lindner 2299a943cac1SMarek Lindner /* Roaming phase is over: tables are in sync again. I can 23009cfc7bd6SSven Eckelmann * unset the flag 23019cfc7bd6SSven Eckelmann */ 2302a943cac1SMarek Lindner orig_node->tt_poss_change = false; 2303a943cac1SMarek Lindner } else { 2304a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 23059cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 23069cfc7bd6SSven Eckelmann */ 230717071578SAntonio Quartulli if (!orig_node->tt_initialised || ttvn != orig_ttvn || 230817071578SAntonio Quartulli orig_node->tt_crc != tt_crc) { 2309a943cac1SMarek Lindner request_table: 231039c75a51SSven Eckelmann batadv_dbg(BATADV_DBG_TT, bat_priv, 231186ceb360SSven 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", 231286ceb360SSven Eckelmann orig_node->orig, ttvn, orig_ttvn, tt_crc, 231386ceb360SSven Eckelmann orig_node->tt_crc, tt_num_changes); 2314a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 2315a513088dSSven Eckelmann tt_crc, full_table); 2316a943cac1SMarek Lindner return; 2317a943cac1SMarek Lindner } 2318a943cac1SMarek Lindner } 2319a943cac1SMarek Lindner } 23203275e7ccSAntonio Quartulli 23213275e7ccSAntonio Quartulli /* returns true whether we know that the client has moved from its old 23223275e7ccSAntonio Quartulli * originator to another one. This entry is kept is still kept for consistency 23233275e7ccSAntonio Quartulli * purposes 23243275e7ccSAntonio Quartulli */ 232508c36d3eSSven Eckelmann bool batadv_tt_global_client_is_roaming(struct bat_priv *bat_priv, 232608c36d3eSSven Eckelmann uint8_t *addr) 23273275e7ccSAntonio Quartulli { 23283275e7ccSAntonio Quartulli struct tt_global_entry *tt_global_entry; 23293275e7ccSAntonio Quartulli bool ret = false; 23303275e7ccSAntonio Quartulli 2331a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 23323275e7ccSAntonio Quartulli if (!tt_global_entry) 23333275e7ccSAntonio Quartulli goto out; 23343275e7ccSAntonio Quartulli 2335acd34afaSSven Eckelmann ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; 2336a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 23373275e7ccSAntonio Quartulli out: 23383275e7ccSAntonio Quartulli return ret; 23393275e7ccSAntonio Quartulli } 2340