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 1723b643de5SAntonio Quartulli del_op_requested = flags & 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 */ 1883b643de5SAntonio Quartulli del_op_entry = entry->change.flags & 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; 246521251f2SAntonio Quartulli /* possibly unset the TT_CLIENT_PENDING flag */ 247521251f2SAntonio Quartulli tt_local_entry->common.flags &= ~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 2551eda58bfSSven Eckelmann batadv_dbg(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); 26048100bacSAntonio Quartulli tt_local_entry->common.flags = NO_FLAGS; 2619563877eSSven Eckelmann if (batadv_is_wifi_iface(ifindex)) 26248100bacSAntonio Quartulli tt_local_entry->common.flags |= 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)) 26848100bacSAntonio Quartulli tt_local_entry->common.flags |= 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 */ 274c40ed2bfSAntonio Quartulli tt_local_entry->common.flags |= 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 */ 308220b07e9SDavid S. Miller tt_global_entry->common.flags |= 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 43632ae9b22SMarek Lindner if (primary_if->if_status != 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 & 456df6edb9eSAntonio Quartulli TT_CLIENT_ROAM ? 'R' : '.'), 45748100bacSAntonio Quartulli (tt_common_entry->flags & 458df6edb9eSAntonio Quartulli TT_CLIENT_NOPURGE ? 'P' : '.'), 45948100bacSAntonio Quartulli (tt_common_entry->flags & 460df6edb9eSAntonio Quartulli TT_CLIENT_NEW ? 'N' : '.'), 46148100bacSAntonio Quartulli (tt_common_entry->flags & 462df6edb9eSAntonio Quartulli TT_CLIENT_PENDING ? 'X' : '.'), 46348100bacSAntonio Quartulli (tt_common_entry->flags & 464df6edb9eSAntonio Quartulli 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 */ 48548100bacSAntonio Quartulli tt_local_entry->common.flags |= TT_CLIENT_PENDING; 486c566dbbeSAntonio Quartulli 4871eda58bfSSven Eckelmann batadv_dbg(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; 496c6c8fea2SSven Eckelmann 497a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 4987683fdc1SAntonio Quartulli if (!tt_local_entry) 4997683fdc1SAntonio Quartulli goto out; 5007683fdc1SAntonio Quartulli 501a513088dSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | 502a513088dSSven Eckelmann (roaming ? TT_CLIENT_ROAM : NO_FLAGS), 503a513088dSSven Eckelmann message); 5047683fdc1SAntonio Quartulli out: 5057683fdc1SAntonio Quartulli if (tt_local_entry) 506a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 507c6c8fea2SSven Eckelmann } 508c6c8fea2SSven Eckelmann 509a513088dSSven Eckelmann static void batadv_tt_local_purge(struct bat_priv *bat_priv) 510c6c8fea2SSven Eckelmann { 5112dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 5122dafb49dSAntonio Quartulli struct tt_local_entry *tt_local_entry; 51348100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 5147aadf889SMarek Lindner struct hlist_node *node, *node_tmp; 515c6c8fea2SSven Eckelmann struct hlist_head *head; 5167683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 517c90681b8SAntonio Quartulli uint32_t i; 518c6c8fea2SSven Eckelmann 519c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 520c6c8fea2SSven Eckelmann head = &hash->table[i]; 5217683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 522c6c8fea2SSven Eckelmann 5237683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 52448100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 5257aadf889SMarek Lindner head, hash_entry) { 52648100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 52748100bacSAntonio Quartulli struct tt_local_entry, 52848100bacSAntonio Quartulli common); 52948100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE) 5307aadf889SMarek Lindner continue; 531c6c8fea2SSven Eckelmann 532058d0e26SAntonio Quartulli /* entry already marked for deletion */ 53348100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_PENDING) 534058d0e26SAntonio Quartulli continue; 535058d0e26SAntonio Quartulli 5361eda58bfSSven Eckelmann if (!batadv_has_timed_out(tt_local_entry->last_seen, 537032b7969SMarek Lindner TT_LOCAL_TIMEOUT)) 5387aadf889SMarek Lindner continue; 5397aadf889SMarek Lindner 540a513088dSSven Eckelmann batadv_tt_local_set_pending(bat_priv, tt_local_entry, 541c566dbbeSAntonio Quartulli TT_CLIENT_DEL, "timed out"); 542c6c8fea2SSven Eckelmann } 5437683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 544c6c8fea2SSven Eckelmann } 545c6c8fea2SSven Eckelmann 546c6c8fea2SSven Eckelmann } 547c6c8fea2SSven Eckelmann 548a513088dSSven Eckelmann static void batadv_tt_local_table_free(struct bat_priv *bat_priv) 549c6c8fea2SSven Eckelmann { 550a73105b8SAntonio Quartulli struct hashtable_t *hash; 551a73105b8SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 55248100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 553a73105b8SAntonio Quartulli struct tt_local_entry *tt_local_entry; 5547683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 5557683fdc1SAntonio Quartulli struct hlist_head *head; 556c90681b8SAntonio Quartulli uint32_t i; 557a73105b8SAntonio Quartulli 5582dafb49dSAntonio Quartulli if (!bat_priv->tt_local_hash) 559c6c8fea2SSven Eckelmann return; 560c6c8fea2SSven Eckelmann 561a73105b8SAntonio Quartulli hash = bat_priv->tt_local_hash; 562a73105b8SAntonio Quartulli 563a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 564a73105b8SAntonio Quartulli head = &hash->table[i]; 565a73105b8SAntonio Quartulli list_lock = &hash->list_locks[i]; 566a73105b8SAntonio Quartulli 567a73105b8SAntonio Quartulli spin_lock_bh(list_lock); 56848100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 569a73105b8SAntonio Quartulli head, hash_entry) { 570a73105b8SAntonio Quartulli hlist_del_rcu(node); 57148100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 57248100bacSAntonio Quartulli struct tt_local_entry, 57348100bacSAntonio Quartulli common); 574a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 575a73105b8SAntonio Quartulli } 576a73105b8SAntonio Quartulli spin_unlock_bh(list_lock); 577a73105b8SAntonio Quartulli } 578a73105b8SAntonio Quartulli 5791a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 580a73105b8SAntonio Quartulli 5812dafb49dSAntonio Quartulli bat_priv->tt_local_hash = NULL; 582c6c8fea2SSven Eckelmann } 583c6c8fea2SSven Eckelmann 584a513088dSSven Eckelmann static int batadv_tt_global_init(struct bat_priv *bat_priv) 585c6c8fea2SSven Eckelmann { 5862dafb49dSAntonio Quartulli if (bat_priv->tt_global_hash) 5875346c35eSSven Eckelmann return 0; 588c6c8fea2SSven Eckelmann 5891a8eaf07SSven Eckelmann bat_priv->tt_global_hash = batadv_hash_new(1024); 590c6c8fea2SSven Eckelmann 5912dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 5925346c35eSSven Eckelmann return -ENOMEM; 593c6c8fea2SSven Eckelmann 5945346c35eSSven Eckelmann return 0; 595c6c8fea2SSven Eckelmann } 596c6c8fea2SSven Eckelmann 597a513088dSSven Eckelmann static void batadv_tt_changes_list_free(struct bat_priv *bat_priv) 598a73105b8SAntonio Quartulli { 599a73105b8SAntonio Quartulli struct tt_change_node *entry, *safe; 600a73105b8SAntonio Quartulli 601a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_changes_list_lock); 602a73105b8SAntonio Quartulli 603a73105b8SAntonio Quartulli list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, 604a73105b8SAntonio Quartulli list) { 605a73105b8SAntonio Quartulli list_del(&entry->list); 606a73105b8SAntonio Quartulli kfree(entry); 607a73105b8SAntonio Quartulli } 608a73105b8SAntonio Quartulli 609a73105b8SAntonio Quartulli atomic_set(&bat_priv->tt_local_changes, 0); 610a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_changes_list_lock); 611a73105b8SAntonio Quartulli } 612a73105b8SAntonio Quartulli 613db08e6e5SSimon Wunderlich /* find out if an orig_node is already in the list of a tt_global_entry. 614db08e6e5SSimon Wunderlich * returns 1 if found, 0 otherwise 615db08e6e5SSimon Wunderlich */ 616a513088dSSven Eckelmann static bool batadv_tt_global_entry_has_orig(const struct tt_global_entry *entry, 617db08e6e5SSimon Wunderlich const struct orig_node *orig_node) 618db08e6e5SSimon Wunderlich { 619db08e6e5SSimon Wunderlich struct tt_orig_list_entry *tmp_orig_entry; 620db08e6e5SSimon Wunderlich const struct hlist_head *head; 621db08e6e5SSimon Wunderlich struct hlist_node *node; 622db08e6e5SSimon Wunderlich bool found = false; 623db08e6e5SSimon Wunderlich 624db08e6e5SSimon Wunderlich rcu_read_lock(); 625db08e6e5SSimon Wunderlich head = &entry->orig_list; 626db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) { 627db08e6e5SSimon Wunderlich if (tmp_orig_entry->orig_node == orig_node) { 628db08e6e5SSimon Wunderlich found = true; 629db08e6e5SSimon Wunderlich break; 630db08e6e5SSimon Wunderlich } 631db08e6e5SSimon Wunderlich } 632db08e6e5SSimon Wunderlich rcu_read_unlock(); 633db08e6e5SSimon Wunderlich return found; 634db08e6e5SSimon Wunderlich } 635db08e6e5SSimon Wunderlich 636a513088dSSven Eckelmann static void 637a513088dSSven Eckelmann batadv_tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry, 638a513088dSSven Eckelmann struct orig_node *orig_node, int ttvn) 639db08e6e5SSimon Wunderlich { 640db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 641db08e6e5SSimon Wunderlich 642db08e6e5SSimon Wunderlich orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 643db08e6e5SSimon Wunderlich if (!orig_entry) 644db08e6e5SSimon Wunderlich return; 645db08e6e5SSimon Wunderlich 646db08e6e5SSimon Wunderlich INIT_HLIST_NODE(&orig_entry->list); 647db08e6e5SSimon Wunderlich atomic_inc(&orig_node->refcount); 648db08e6e5SSimon Wunderlich atomic_inc(&orig_node->tt_size); 649db08e6e5SSimon Wunderlich orig_entry->orig_node = orig_node; 650db08e6e5SSimon Wunderlich orig_entry->ttvn = ttvn; 651db08e6e5SSimon Wunderlich 652db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 653db08e6e5SSimon Wunderlich hlist_add_head_rcu(&orig_entry->list, 654db08e6e5SSimon Wunderlich &tt_global_entry->orig_list); 655db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 656db08e6e5SSimon Wunderlich } 657db08e6e5SSimon Wunderlich 658a73105b8SAntonio Quartulli /* caller must hold orig_node refcount */ 65908c36d3eSSven Eckelmann int batadv_tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, 660d4f44692SAntonio Quartulli const unsigned char *tt_addr, uint8_t flags, 661d4f44692SAntonio Quartulli uint8_t ttvn) 662c6c8fea2SSven Eckelmann { 663db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry = NULL; 6647683fdc1SAntonio Quartulli int ret = 0; 66580b3f58cSSimon Wunderlich int hash_added; 666c0a55929SSven Eckelmann struct tt_common_entry *common; 667c6c8fea2SSven Eckelmann 668a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); 669c6c8fea2SSven Eckelmann 6702dafb49dSAntonio Quartulli if (!tt_global_entry) { 671d4f44692SAntonio Quartulli tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); 6722dafb49dSAntonio Quartulli if (!tt_global_entry) 6737683fdc1SAntonio Quartulli goto out; 6747683fdc1SAntonio Quartulli 675c0a55929SSven Eckelmann common = &tt_global_entry->common; 676c0a55929SSven Eckelmann memcpy(common->addr, tt_addr, ETH_ALEN); 677db08e6e5SSimon Wunderlich 678d4f44692SAntonio Quartulli common->flags = flags; 679cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 680c0a55929SSven Eckelmann atomic_set(&common->refcount, 2); 681db08e6e5SSimon Wunderlich 682db08e6e5SSimon Wunderlich INIT_HLIST_HEAD(&tt_global_entry->orig_list); 683db08e6e5SSimon Wunderlich spin_lock_init(&tt_global_entry->list_lock); 6847683fdc1SAntonio Quartulli 685c0a55929SSven Eckelmann hash_added = batadv_hash_add(bat_priv->tt_global_hash, 686a513088dSSven Eckelmann batadv_compare_tt, 687a513088dSSven Eckelmann batadv_choose_orig, common, 688a513088dSSven Eckelmann &common->hash_entry); 68980b3f58cSSimon Wunderlich 69080b3f58cSSimon Wunderlich if (unlikely(hash_added != 0)) { 69180b3f58cSSimon Wunderlich /* remove the reference for the hash */ 692a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 69380b3f58cSSimon Wunderlich goto out_remove; 69480b3f58cSSimon Wunderlich } 695db08e6e5SSimon Wunderlich 696a513088dSSven Eckelmann batadv_tt_global_add_orig_entry(tt_global_entry, orig_node, 697a513088dSSven Eckelmann ttvn); 698a73105b8SAntonio Quartulli } else { 699db08e6e5SSimon Wunderlich /* there is already a global entry, use this one. */ 700db08e6e5SSimon Wunderlich 701db08e6e5SSimon Wunderlich /* If there is the TT_CLIENT_ROAM flag set, there is only one 702db08e6e5SSimon Wunderlich * originator left in the list and we previously received a 703db08e6e5SSimon Wunderlich * delete + roaming change for this originator. 704db08e6e5SSimon Wunderlich * 705db08e6e5SSimon Wunderlich * We should first delete the old originator before adding the 706db08e6e5SSimon Wunderlich * new one. 707db08e6e5SSimon Wunderlich */ 708db08e6e5SSimon Wunderlich if (tt_global_entry->common.flags & TT_CLIENT_ROAM) { 709a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 710db08e6e5SSimon Wunderlich tt_global_entry->common.flags &= ~TT_CLIENT_ROAM; 711cc47f66eSAntonio Quartulli tt_global_entry->roam_at = 0; 712c6c8fea2SSven Eckelmann } 713c6c8fea2SSven Eckelmann 714a513088dSSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global_entry, 715a513088dSSven Eckelmann orig_node)) 716a513088dSSven Eckelmann batadv_tt_global_add_orig_entry(tt_global_entry, 717a513088dSSven Eckelmann orig_node, ttvn); 718db08e6e5SSimon Wunderlich } 719db08e6e5SSimon Wunderlich 7201eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 721a73105b8SAntonio Quartulli "Creating new global tt entry: %pM (via %pM)\n", 72248100bacSAntonio Quartulli tt_global_entry->common.addr, orig_node->orig); 723a73105b8SAntonio Quartulli 72480b3f58cSSimon Wunderlich out_remove: 725c6c8fea2SSven Eckelmann /* remove address from local hash if present */ 72608c36d3eSSven Eckelmann batadv_tt_local_remove(bat_priv, tt_global_entry->common.addr, 727d4f44692SAntonio Quartulli "global tt received", flags & TT_CLIENT_ROAM); 7287683fdc1SAntonio Quartulli ret = 1; 7297683fdc1SAntonio Quartulli out: 7307683fdc1SAntonio Quartulli if (tt_global_entry) 731a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 7327683fdc1SAntonio Quartulli return ret; 733c6c8fea2SSven Eckelmann } 734c6c8fea2SSven Eckelmann 735db08e6e5SSimon Wunderlich /* print all orig nodes who announce the address for this global entry. 736db08e6e5SSimon Wunderlich * it is assumed that the caller holds rcu_read_lock(); 737db08e6e5SSimon Wunderlich */ 738a513088dSSven Eckelmann static void 739a513088dSSven Eckelmann batadv_tt_global_print_entry(struct tt_global_entry *tt_global_entry, 740db08e6e5SSimon Wunderlich struct seq_file *seq) 741db08e6e5SSimon Wunderlich { 742db08e6e5SSimon Wunderlich struct hlist_head *head; 743db08e6e5SSimon Wunderlich struct hlist_node *node; 744db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 745db08e6e5SSimon Wunderlich struct tt_common_entry *tt_common_entry; 746db08e6e5SSimon Wunderlich uint16_t flags; 747db08e6e5SSimon Wunderlich uint8_t last_ttvn; 748db08e6e5SSimon Wunderlich 749db08e6e5SSimon Wunderlich tt_common_entry = &tt_global_entry->common; 750db08e6e5SSimon Wunderlich 751db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 752db08e6e5SSimon Wunderlich 753db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 754db08e6e5SSimon Wunderlich flags = tt_common_entry->flags; 755db08e6e5SSimon Wunderlich last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 756db08e6e5SSimon Wunderlich seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n", 757db08e6e5SSimon Wunderlich tt_global_entry->common.addr, orig_entry->ttvn, 758db08e6e5SSimon Wunderlich orig_entry->orig_node->orig, last_ttvn, 759db08e6e5SSimon Wunderlich (flags & TT_CLIENT_ROAM ? 'R' : '.'), 760db08e6e5SSimon Wunderlich (flags & TT_CLIENT_WIFI ? 'W' : '.')); 761db08e6e5SSimon Wunderlich } 762db08e6e5SSimon Wunderlich } 763db08e6e5SSimon Wunderlich 76408c36d3eSSven Eckelmann int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) 765c6c8fea2SSven Eckelmann { 766c6c8fea2SSven Eckelmann struct net_device *net_dev = (struct net_device *)seq->private; 767c6c8fea2SSven Eckelmann struct bat_priv *bat_priv = netdev_priv(net_dev); 7682dafb49dSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 76948100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 7702dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry; 77132ae9b22SMarek Lindner struct hard_iface *primary_if; 7727aadf889SMarek Lindner struct hlist_node *node; 773c6c8fea2SSven Eckelmann struct hlist_head *head; 774c90681b8SAntonio Quartulli uint32_t i; 775c90681b8SAntonio Quartulli int ret = 0; 776c6c8fea2SSven Eckelmann 777e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 77832ae9b22SMarek Lindner if (!primary_if) { 77986ceb360SSven Eckelmann ret = seq_printf(seq, 78086ceb360SSven Eckelmann "BATMAN mesh %s disabled - please specify interfaces to enable it\n", 781c6c8fea2SSven Eckelmann net_dev->name); 78232ae9b22SMarek Lindner goto out; 78332ae9b22SMarek Lindner } 78432ae9b22SMarek Lindner 78532ae9b22SMarek Lindner if (primary_if->if_status != IF_ACTIVE) { 78686ceb360SSven Eckelmann ret = seq_printf(seq, 78786ceb360SSven Eckelmann "BATMAN mesh %s disabled - primary interface not active\n", 78832ae9b22SMarek Lindner net_dev->name); 78932ae9b22SMarek Lindner goto out; 790c6c8fea2SSven Eckelmann } 791c6c8fea2SSven Eckelmann 7922dafb49dSAntonio Quartulli seq_printf(seq, 7932dafb49dSAntonio Quartulli "Globally announced TT entries received via the mesh %s\n", 794c6c8fea2SSven Eckelmann net_dev->name); 795df6edb9eSAntonio Quartulli seq_printf(seq, " %-13s %s %-15s %s %s\n", 796df6edb9eSAntonio Quartulli "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags"); 797c6c8fea2SSven Eckelmann 798c6c8fea2SSven Eckelmann for (i = 0; i < hash->size; i++) { 799c6c8fea2SSven Eckelmann head = &hash->table[i]; 800c6c8fea2SSven Eckelmann 8017aadf889SMarek Lindner rcu_read_lock(); 80248100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 8037aadf889SMarek Lindner head, hash_entry) { 80448100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 80548100bacSAntonio Quartulli struct tt_global_entry, 80648100bacSAntonio Quartulli common); 807a513088dSSven Eckelmann batadv_tt_global_print_entry(tt_global_entry, seq); 808c6c8fea2SSven Eckelmann } 8097aadf889SMarek Lindner rcu_read_unlock(); 810c6c8fea2SSven Eckelmann } 81132ae9b22SMarek Lindner out: 81232ae9b22SMarek Lindner if (primary_if) 813e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 81432ae9b22SMarek Lindner return ret; 815c6c8fea2SSven Eckelmann } 816c6c8fea2SSven Eckelmann 817db08e6e5SSimon Wunderlich /* deletes the orig list of a tt_global_entry */ 818a513088dSSven Eckelmann static void 819a513088dSSven Eckelmann batadv_tt_global_del_orig_list(struct tt_global_entry *tt_global_entry) 820db08e6e5SSimon Wunderlich { 821db08e6e5SSimon Wunderlich struct hlist_head *head; 822db08e6e5SSimon Wunderlich struct hlist_node *node, *safe; 823db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 824db08e6e5SSimon Wunderlich 825db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 826db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 827db08e6e5SSimon Wunderlich hlist_for_each_entry_safe(orig_entry, node, safe, head, list) { 828db08e6e5SSimon Wunderlich hlist_del_rcu(node); 829a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 830db08e6e5SSimon Wunderlich } 831db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 832db08e6e5SSimon Wunderlich 833db08e6e5SSimon Wunderlich } 834db08e6e5SSimon Wunderlich 835a513088dSSven Eckelmann static void 836a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(struct bat_priv *bat_priv, 837db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry, 838db08e6e5SSimon Wunderlich struct orig_node *orig_node, 839db08e6e5SSimon Wunderlich const char *message) 840db08e6e5SSimon Wunderlich { 841db08e6e5SSimon Wunderlich struct hlist_head *head; 842db08e6e5SSimon Wunderlich struct hlist_node *node, *safe; 843db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 844db08e6e5SSimon Wunderlich 845db08e6e5SSimon Wunderlich spin_lock_bh(&tt_global_entry->list_lock); 846db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 847db08e6e5SSimon Wunderlich hlist_for_each_entry_safe(orig_entry, node, safe, head, list) { 848db08e6e5SSimon Wunderlich if (orig_entry->orig_node == orig_node) { 8491eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 850db08e6e5SSimon Wunderlich "Deleting %pM from global tt entry %pM: %s\n", 8511eda58bfSSven Eckelmann orig_node->orig, 8521eda58bfSSven Eckelmann tt_global_entry->common.addr, message); 853db08e6e5SSimon Wunderlich hlist_del_rcu(node); 854a513088dSSven Eckelmann batadv_tt_orig_list_entry_free_ref(orig_entry); 855db08e6e5SSimon Wunderlich } 856db08e6e5SSimon Wunderlich } 857db08e6e5SSimon Wunderlich spin_unlock_bh(&tt_global_entry->list_lock); 858db08e6e5SSimon Wunderlich } 859db08e6e5SSimon Wunderlich 860a513088dSSven Eckelmann static void batadv_tt_global_del_struct(struct bat_priv *bat_priv, 8612dafb49dSAntonio Quartulli struct tt_global_entry *tt_global_entry, 862747e4221SSven Eckelmann const char *message) 863c6c8fea2SSven Eckelmann { 8641eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, "Deleting global tt entry %pM: %s\n", 865db08e6e5SSimon Wunderlich tt_global_entry->common.addr, message); 8667683fdc1SAntonio Quartulli 867a513088dSSven Eckelmann batadv_hash_remove(bat_priv->tt_global_hash, batadv_compare_tt, 868da641193SSven Eckelmann batadv_choose_orig, tt_global_entry->common.addr); 869a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 870db08e6e5SSimon Wunderlich 871c6c8fea2SSven Eckelmann } 872c6c8fea2SSven Eckelmann 873db08e6e5SSimon Wunderlich /* If the client is to be deleted, we check if it is the last origantor entry 874db08e6e5SSimon Wunderlich * within tt_global entry. If yes, we set the TT_CLIENT_ROAM flag and the timer, 875db08e6e5SSimon Wunderlich * otherwise we simply remove the originator scheduled for deletion. 876db08e6e5SSimon Wunderlich */ 877a513088dSSven Eckelmann static void 878a513088dSSven Eckelmann batadv_tt_global_del_roaming(struct bat_priv *bat_priv, 879db08e6e5SSimon Wunderlich struct tt_global_entry *tt_global_entry, 880a513088dSSven Eckelmann struct orig_node *orig_node, const char *message) 881db08e6e5SSimon Wunderlich { 882db08e6e5SSimon Wunderlich bool last_entry = true; 883db08e6e5SSimon Wunderlich struct hlist_head *head; 884db08e6e5SSimon Wunderlich struct hlist_node *node; 885db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 886db08e6e5SSimon Wunderlich 887db08e6e5SSimon Wunderlich /* no local entry exists, case 1: 888db08e6e5SSimon Wunderlich * Check if this is the last one or if other entries exist. 889db08e6e5SSimon Wunderlich */ 890db08e6e5SSimon Wunderlich 891db08e6e5SSimon Wunderlich rcu_read_lock(); 892db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 893db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 894db08e6e5SSimon Wunderlich if (orig_entry->orig_node != orig_node) { 895db08e6e5SSimon Wunderlich last_entry = false; 896db08e6e5SSimon Wunderlich break; 897db08e6e5SSimon Wunderlich } 898db08e6e5SSimon Wunderlich } 899db08e6e5SSimon Wunderlich rcu_read_unlock(); 900db08e6e5SSimon Wunderlich 901db08e6e5SSimon Wunderlich if (last_entry) { 902db08e6e5SSimon Wunderlich /* its the last one, mark for roaming. */ 903db08e6e5SSimon Wunderlich tt_global_entry->common.flags |= TT_CLIENT_ROAM; 904db08e6e5SSimon Wunderlich tt_global_entry->roam_at = jiffies; 905db08e6e5SSimon Wunderlich } else 906db08e6e5SSimon Wunderlich /* there is another entry, we can simply delete this 907db08e6e5SSimon Wunderlich * one and can still use the other one. 908db08e6e5SSimon Wunderlich */ 909a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 910db08e6e5SSimon Wunderlich orig_node, message); 911db08e6e5SSimon Wunderlich } 912db08e6e5SSimon Wunderlich 913db08e6e5SSimon Wunderlich 914db08e6e5SSimon Wunderlich 915a513088dSSven Eckelmann static void batadv_tt_global_del(struct bat_priv *bat_priv, 916de7aae65SSven Eckelmann struct orig_node *orig_node, 917de7aae65SSven Eckelmann const unsigned char *addr, 918cc47f66eSAntonio Quartulli const char *message, bool roaming) 919a73105b8SAntonio Quartulli { 9207683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 921a513088dSSven Eckelmann struct tt_local_entry *local_entry = NULL; 922a73105b8SAntonio Quartulli 923a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 924db08e6e5SSimon Wunderlich if (!tt_global_entry) 9257683fdc1SAntonio Quartulli goto out; 926a73105b8SAntonio Quartulli 927db08e6e5SSimon Wunderlich if (!roaming) { 928a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 929a513088dSSven Eckelmann orig_node, message); 93092f90f56SSven Eckelmann 931db08e6e5SSimon Wunderlich if (hlist_empty(&tt_global_entry->orig_list)) 932a513088dSSven Eckelmann batadv_tt_global_del_struct(bat_priv, tt_global_entry, 933db08e6e5SSimon Wunderlich message); 934db08e6e5SSimon Wunderlich 935cc47f66eSAntonio Quartulli goto out; 936cc47f66eSAntonio Quartulli } 93792f90f56SSven Eckelmann 938db08e6e5SSimon Wunderlich /* if we are deleting a global entry due to a roam 939db08e6e5SSimon Wunderlich * event, there are two possibilities: 940db08e6e5SSimon Wunderlich * 1) the client roamed from node A to node B => if there 941db08e6e5SSimon Wunderlich * is only one originator left for this client, we mark 942db08e6e5SSimon Wunderlich * it with TT_CLIENT_ROAM, we start a timer and we 943db08e6e5SSimon Wunderlich * wait for node B to claim it. In case of timeout 944db08e6e5SSimon Wunderlich * the entry is purged. 945db08e6e5SSimon Wunderlich * 946db08e6e5SSimon Wunderlich * If there are other originators left, we directly delete 947db08e6e5SSimon Wunderlich * the originator. 948db08e6e5SSimon Wunderlich * 2) the client roamed to us => we can directly delete 9499cfc7bd6SSven Eckelmann * the global entry, since it is useless now. 9509cfc7bd6SSven Eckelmann */ 951a513088dSSven Eckelmann local_entry = batadv_tt_local_hash_find(bat_priv, 952db08e6e5SSimon Wunderlich tt_global_entry->common.addr); 953a513088dSSven Eckelmann if (local_entry) { 954db08e6e5SSimon Wunderlich /* local entry exists, case 2: client roamed to us. */ 955a513088dSSven Eckelmann batadv_tt_global_del_orig_list(tt_global_entry); 956a513088dSSven Eckelmann batadv_tt_global_del_struct(bat_priv, tt_global_entry, message); 957db08e6e5SSimon Wunderlich } else 958db08e6e5SSimon Wunderlich /* no local entry exists, case 1: check for roaming */ 959a513088dSSven Eckelmann batadv_tt_global_del_roaming(bat_priv, tt_global_entry, 960a513088dSSven Eckelmann orig_node, message); 961db08e6e5SSimon Wunderlich 96292f90f56SSven Eckelmann 963cc47f66eSAntonio Quartulli out: 9647683fdc1SAntonio Quartulli if (tt_global_entry) 965a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 966a513088dSSven Eckelmann if (local_entry) 967a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(local_entry); 968a73105b8SAntonio Quartulli } 969a73105b8SAntonio Quartulli 97008c36d3eSSven Eckelmann void batadv_tt_global_del_orig(struct bat_priv *bat_priv, 971747e4221SSven Eckelmann struct orig_node *orig_node, const char *message) 972c6c8fea2SSven Eckelmann { 973a513088dSSven Eckelmann struct tt_global_entry *global_entry; 97448100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 975c90681b8SAntonio Quartulli uint32_t i; 976a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 977a73105b8SAntonio Quartulli struct hlist_node *node, *safe; 978a73105b8SAntonio Quartulli struct hlist_head *head; 9797683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 980c6c8fea2SSven Eckelmann 9816e801494SSimon Wunderlich if (!hash) 9826e801494SSimon Wunderlich return; 9836e801494SSimon Wunderlich 984a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 985a73105b8SAntonio Quartulli head = &hash->table[i]; 9867683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 987c6c8fea2SSven Eckelmann 9887683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 98948100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, safe, 990a73105b8SAntonio Quartulli head, hash_entry) { 991a513088dSSven Eckelmann global_entry = container_of(tt_common_entry, 99248100bacSAntonio Quartulli struct tt_global_entry, 99348100bacSAntonio Quartulli common); 994db08e6e5SSimon Wunderlich 995a513088dSSven Eckelmann batadv_tt_global_del_orig_entry(bat_priv, global_entry, 996db08e6e5SSimon Wunderlich orig_node, message); 997db08e6e5SSimon Wunderlich 998a513088dSSven Eckelmann if (hlist_empty(&global_entry->orig_list)) { 9991eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 1000db08e6e5SSimon Wunderlich "Deleting global tt entry %pM: %s\n", 1001a513088dSSven Eckelmann global_entry->common.addr, message); 10027683fdc1SAntonio Quartulli hlist_del_rcu(node); 1003a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(global_entry); 1004c6c8fea2SSven Eckelmann } 1005a73105b8SAntonio Quartulli } 10067683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 10077683fdc1SAntonio Quartulli } 100817071578SAntonio Quartulli orig_node->tt_initialised = false; 1009c6c8fea2SSven Eckelmann } 1010c6c8fea2SSven Eckelmann 1011a513088dSSven Eckelmann static void batadv_tt_global_roam_purge(struct bat_priv *bat_priv) 1012cc47f66eSAntonio Quartulli { 1013cc47f66eSAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 101448100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1015cc47f66eSAntonio Quartulli struct tt_global_entry *tt_global_entry; 1016cc47f66eSAntonio Quartulli struct hlist_node *node, *node_tmp; 1017cc47f66eSAntonio Quartulli struct hlist_head *head; 10187683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 1019c90681b8SAntonio Quartulli uint32_t i; 1020cc47f66eSAntonio Quartulli 1021cc47f66eSAntonio Quartulli for (i = 0; i < hash->size; i++) { 1022cc47f66eSAntonio Quartulli head = &hash->table[i]; 10237683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 1024cc47f66eSAntonio Quartulli 10257683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 102648100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 1027cc47f66eSAntonio Quartulli head, hash_entry) { 102848100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 102948100bacSAntonio Quartulli struct tt_global_entry, 103048100bacSAntonio Quartulli common); 103148100bacSAntonio Quartulli if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM)) 1032cc47f66eSAntonio Quartulli continue; 10331eda58bfSSven Eckelmann if (!batadv_has_timed_out(tt_global_entry->roam_at, 1034032b7969SMarek Lindner TT_CLIENT_ROAM_TIMEOUT)) 1035cc47f66eSAntonio Quartulli continue; 1036cc47f66eSAntonio Quartulli 10371eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 103886ceb360SSven Eckelmann "Deleting global tt entry (%pM): Roaming timeout\n", 103948100bacSAntonio Quartulli tt_global_entry->common.addr); 1040db08e6e5SSimon Wunderlich 10417683fdc1SAntonio Quartulli hlist_del_rcu(node); 1042a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 1043cc47f66eSAntonio Quartulli } 10447683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 1045cc47f66eSAntonio Quartulli } 1046cc47f66eSAntonio Quartulli 1047cc47f66eSAntonio Quartulli } 1048cc47f66eSAntonio Quartulli 1049a513088dSSven Eckelmann static void batadv_tt_global_table_free(struct bat_priv *bat_priv) 1050c6c8fea2SSven Eckelmann { 10517683fdc1SAntonio Quartulli struct hashtable_t *hash; 10527683fdc1SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 105348100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 10547683fdc1SAntonio Quartulli struct tt_global_entry *tt_global_entry; 10557683fdc1SAntonio Quartulli struct hlist_node *node, *node_tmp; 10567683fdc1SAntonio Quartulli struct hlist_head *head; 1057c90681b8SAntonio Quartulli uint32_t i; 10587683fdc1SAntonio Quartulli 10592dafb49dSAntonio Quartulli if (!bat_priv->tt_global_hash) 1060c6c8fea2SSven Eckelmann return; 1061c6c8fea2SSven Eckelmann 10627683fdc1SAntonio Quartulli hash = bat_priv->tt_global_hash; 10637683fdc1SAntonio Quartulli 10647683fdc1SAntonio Quartulli for (i = 0; i < hash->size; i++) { 10657683fdc1SAntonio Quartulli head = &hash->table[i]; 10667683fdc1SAntonio Quartulli list_lock = &hash->list_locks[i]; 10677683fdc1SAntonio Quartulli 10687683fdc1SAntonio Quartulli spin_lock_bh(list_lock); 106948100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 10707683fdc1SAntonio Quartulli head, hash_entry) { 10717683fdc1SAntonio Quartulli hlist_del_rcu(node); 107248100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 107348100bacSAntonio Quartulli struct tt_global_entry, 107448100bacSAntonio Quartulli common); 1075a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 10767683fdc1SAntonio Quartulli } 10777683fdc1SAntonio Quartulli spin_unlock_bh(list_lock); 10787683fdc1SAntonio Quartulli } 10797683fdc1SAntonio Quartulli 10801a8eaf07SSven Eckelmann batadv_hash_destroy(hash); 10817683fdc1SAntonio Quartulli 10822dafb49dSAntonio Quartulli bat_priv->tt_global_hash = NULL; 1083c6c8fea2SSven Eckelmann } 1084c6c8fea2SSven Eckelmann 1085a513088dSSven Eckelmann static bool _batadv_is_ap_isolated(struct tt_local_entry *tt_local_entry, 108659b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry) 108759b699cdSAntonio Quartulli { 108859b699cdSAntonio Quartulli bool ret = false; 108959b699cdSAntonio Quartulli 109048100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_WIFI && 109148100bacSAntonio Quartulli tt_global_entry->common.flags & TT_CLIENT_WIFI) 109259b699cdSAntonio Quartulli ret = true; 109359b699cdSAntonio Quartulli 109459b699cdSAntonio Quartulli return ret; 109559b699cdSAntonio Quartulli } 109659b699cdSAntonio Quartulli 109708c36d3eSSven Eckelmann struct orig_node *batadv_transtable_search(struct bat_priv *bat_priv, 109808c36d3eSSven Eckelmann const uint8_t *src, 109908c36d3eSSven Eckelmann const uint8_t *addr) 1100c6c8fea2SSven Eckelmann { 11013d393e47SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 11023d393e47SAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 11037b36e8eeSMarek Lindner struct orig_node *orig_node = NULL; 1104db08e6e5SSimon Wunderlich struct neigh_node *router = NULL; 1105db08e6e5SSimon Wunderlich struct hlist_head *head; 1106db08e6e5SSimon Wunderlich struct hlist_node *node; 1107db08e6e5SSimon Wunderlich struct tt_orig_list_entry *orig_entry; 1108db08e6e5SSimon Wunderlich int best_tq; 1109c6c8fea2SSven Eckelmann 11103d393e47SAntonio Quartulli if (src && atomic_read(&bat_priv->ap_isolation)) { 1111a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); 11123d393e47SAntonio Quartulli if (!tt_local_entry) 11133d393e47SAntonio Quartulli goto out; 11143d393e47SAntonio Quartulli } 11157aadf889SMarek Lindner 1116a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 11172dafb49dSAntonio Quartulli if (!tt_global_entry) 11187b36e8eeSMarek Lindner goto out; 1119c6c8fea2SSven Eckelmann 11203d393e47SAntonio Quartulli /* check whether the clients should not communicate due to AP 11219cfc7bd6SSven Eckelmann * isolation 11229cfc7bd6SSven Eckelmann */ 1123a513088dSSven Eckelmann if (tt_local_entry && 1124a513088dSSven Eckelmann _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 11253d393e47SAntonio Quartulli goto out; 11263d393e47SAntonio Quartulli 1127db08e6e5SSimon Wunderlich best_tq = 0; 11287b36e8eeSMarek Lindner 1129db08e6e5SSimon Wunderlich rcu_read_lock(); 1130db08e6e5SSimon Wunderlich head = &tt_global_entry->orig_list; 1131db08e6e5SSimon Wunderlich hlist_for_each_entry_rcu(orig_entry, node, head, list) { 11327d211efcSSven Eckelmann router = batadv_orig_node_get_router(orig_entry->orig_node); 1133db08e6e5SSimon Wunderlich if (!router) 1134db08e6e5SSimon Wunderlich continue; 11357b36e8eeSMarek Lindner 1136db08e6e5SSimon Wunderlich if (router->tq_avg > best_tq) { 1137db08e6e5SSimon Wunderlich orig_node = orig_entry->orig_node; 1138db08e6e5SSimon Wunderlich best_tq = router->tq_avg; 1139db08e6e5SSimon Wunderlich } 11407d211efcSSven Eckelmann batadv_neigh_node_free_ref(router); 1141db08e6e5SSimon Wunderlich } 1142db08e6e5SSimon Wunderlich /* found anything? */ 1143db08e6e5SSimon Wunderlich if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) 1144db08e6e5SSimon Wunderlich orig_node = NULL; 1145db08e6e5SSimon Wunderlich rcu_read_unlock(); 11467b36e8eeSMarek Lindner out: 11473d393e47SAntonio Quartulli if (tt_global_entry) 1148a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 11493d393e47SAntonio Quartulli if (tt_local_entry) 1150a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 11513d393e47SAntonio Quartulli 11527b36e8eeSMarek Lindner return orig_node; 1153c6c8fea2SSven Eckelmann } 1154a73105b8SAntonio Quartulli 1155a73105b8SAntonio Quartulli /* Calculates the checksum of the local table of a given orig_node */ 1156a513088dSSven Eckelmann static uint16_t batadv_tt_global_crc(struct bat_priv *bat_priv, 1157de7aae65SSven Eckelmann struct orig_node *orig_node) 1158a73105b8SAntonio Quartulli { 1159a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1160a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_global_hash; 116148100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1162a73105b8SAntonio Quartulli struct tt_global_entry *tt_global_entry; 1163a73105b8SAntonio Quartulli struct hlist_node *node; 1164a73105b8SAntonio Quartulli struct hlist_head *head; 1165c90681b8SAntonio Quartulli uint32_t i; 1166c90681b8SAntonio Quartulli int j; 1167a73105b8SAntonio Quartulli 1168a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1169a73105b8SAntonio Quartulli head = &hash->table[i]; 1170a73105b8SAntonio Quartulli 1171a73105b8SAntonio Quartulli rcu_read_lock(); 117248100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1173a73105b8SAntonio Quartulli head, hash_entry) { 117448100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, 117548100bacSAntonio Quartulli struct tt_global_entry, 117648100bacSAntonio Quartulli common); 1177cc47f66eSAntonio Quartulli /* Roaming clients are in the global table for 1178cc47f66eSAntonio Quartulli * consistency only. They don't have to be 1179cc47f66eSAntonio Quartulli * taken into account while computing the 1180db08e6e5SSimon Wunderlich * global crc 1181db08e6e5SSimon Wunderlich */ 1182db08e6e5SSimon Wunderlich if (tt_global_entry->common.flags & TT_CLIENT_ROAM) 1183cc47f66eSAntonio Quartulli continue; 1184db08e6e5SSimon Wunderlich 1185db08e6e5SSimon Wunderlich /* find out if this global entry is announced by this 1186db08e6e5SSimon Wunderlich * originator 1187db08e6e5SSimon Wunderlich */ 1188a513088dSSven Eckelmann if (!batadv_tt_global_entry_has_orig(tt_global_entry, 1189db08e6e5SSimon Wunderlich orig_node)) 1190db08e6e5SSimon Wunderlich continue; 1191db08e6e5SSimon Wunderlich 1192a73105b8SAntonio Quartulli total_one = 0; 1193a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1194a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 1195db08e6e5SSimon Wunderlich tt_global_entry->common.addr[j]); 1196a73105b8SAntonio Quartulli total ^= total_one; 1197a73105b8SAntonio Quartulli } 1198a73105b8SAntonio Quartulli rcu_read_unlock(); 1199a73105b8SAntonio Quartulli } 1200a73105b8SAntonio Quartulli 1201a73105b8SAntonio Quartulli return total; 1202a73105b8SAntonio Quartulli } 1203a73105b8SAntonio Quartulli 1204a73105b8SAntonio Quartulli /* Calculates the checksum of the local table */ 1205be9aa4c1SMarek Lindner static uint16_t batadv_tt_local_crc(struct bat_priv *bat_priv) 1206a73105b8SAntonio Quartulli { 1207a73105b8SAntonio Quartulli uint16_t total = 0, total_one; 1208a73105b8SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 120948100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1210a73105b8SAntonio Quartulli struct hlist_node *node; 1211a73105b8SAntonio Quartulli struct hlist_head *head; 1212c90681b8SAntonio Quartulli uint32_t i; 1213c90681b8SAntonio Quartulli int j; 1214a73105b8SAntonio Quartulli 1215a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1216a73105b8SAntonio Quartulli head = &hash->table[i]; 1217a73105b8SAntonio Quartulli 1218a73105b8SAntonio Quartulli rcu_read_lock(); 121948100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1220a73105b8SAntonio Quartulli head, hash_entry) { 1221058d0e26SAntonio Quartulli /* not yet committed clients have not to be taken into 12229cfc7bd6SSven Eckelmann * account while computing the CRC 12239cfc7bd6SSven Eckelmann */ 122448100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_NEW) 1225058d0e26SAntonio Quartulli continue; 1226a73105b8SAntonio Quartulli total_one = 0; 1227a73105b8SAntonio Quartulli for (j = 0; j < ETH_ALEN; j++) 1228a73105b8SAntonio Quartulli total_one = crc16_byte(total_one, 122948100bacSAntonio Quartulli tt_common_entry->addr[j]); 1230a73105b8SAntonio Quartulli total ^= total_one; 1231a73105b8SAntonio Quartulli } 1232a73105b8SAntonio Quartulli rcu_read_unlock(); 1233a73105b8SAntonio Quartulli } 1234a73105b8SAntonio Quartulli 1235a73105b8SAntonio Quartulli return total; 1236a73105b8SAntonio Quartulli } 1237a73105b8SAntonio Quartulli 1238a513088dSSven Eckelmann static void batadv_tt_req_list_free(struct bat_priv *bat_priv) 1239a73105b8SAntonio Quartulli { 1240a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1241a73105b8SAntonio Quartulli 1242a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1243a73105b8SAntonio Quartulli 1244a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 1245a73105b8SAntonio Quartulli list_del(&node->list); 1246a73105b8SAntonio Quartulli kfree(node); 1247a73105b8SAntonio Quartulli } 1248a73105b8SAntonio Quartulli 1249a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1250a73105b8SAntonio Quartulli } 1251a73105b8SAntonio Quartulli 1252a513088dSSven Eckelmann static void batadv_tt_save_orig_buffer(struct bat_priv *bat_priv, 1253de7aae65SSven Eckelmann struct orig_node *orig_node, 1254de7aae65SSven Eckelmann const unsigned char *tt_buff, 1255de7aae65SSven Eckelmann uint8_t tt_num_changes) 1256a73105b8SAntonio Quartulli { 125708c36d3eSSven Eckelmann uint16_t tt_buff_len = batadv_tt_len(tt_num_changes); 1258a73105b8SAntonio Quartulli 1259a73105b8SAntonio Quartulli /* Replace the old buffer only if I received something in the 12609cfc7bd6SSven Eckelmann * last OGM (the OGM could carry no changes) 12619cfc7bd6SSven Eckelmann */ 1262a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1263a73105b8SAntonio Quartulli if (tt_buff_len > 0) { 1264a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1265a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1266a73105b8SAntonio Quartulli orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 1267a73105b8SAntonio Quartulli if (orig_node->tt_buff) { 1268a73105b8SAntonio Quartulli memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 1269a73105b8SAntonio Quartulli orig_node->tt_buff_len = tt_buff_len; 1270a73105b8SAntonio Quartulli } 1271a73105b8SAntonio Quartulli } 1272a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1273a73105b8SAntonio Quartulli } 1274a73105b8SAntonio Quartulli 1275a513088dSSven Eckelmann static void batadv_tt_req_purge(struct bat_priv *bat_priv) 1276a73105b8SAntonio Quartulli { 1277a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1278a73105b8SAntonio Quartulli 1279a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1280a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 12811eda58bfSSven Eckelmann if (batadv_has_timed_out(node->issued_at, TT_REQUEST_TIMEOUT)) { 1282a73105b8SAntonio Quartulli list_del(&node->list); 1283a73105b8SAntonio Quartulli kfree(node); 1284a73105b8SAntonio Quartulli } 1285a73105b8SAntonio Quartulli } 1286a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1287a73105b8SAntonio Quartulli } 1288a73105b8SAntonio Quartulli 1289a73105b8SAntonio Quartulli /* returns the pointer to the new tt_req_node struct if no request 12909cfc7bd6SSven Eckelmann * has already been issued for this orig_node, NULL otherwise 12919cfc7bd6SSven Eckelmann */ 1292a513088dSSven Eckelmann static struct tt_req_node *batadv_new_tt_req_node(struct bat_priv *bat_priv, 1293a73105b8SAntonio Quartulli struct orig_node *orig_node) 1294a73105b8SAntonio Quartulli { 1295a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; 1296a73105b8SAntonio Quartulli 1297a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1298a73105b8SAntonio Quartulli list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { 12991eda58bfSSven Eckelmann if (batadv_compare_eth(tt_req_node_tmp, orig_node) && 13001eda58bfSSven Eckelmann !batadv_has_timed_out(tt_req_node_tmp->issued_at, 1301032b7969SMarek Lindner TT_REQUEST_TIMEOUT)) 1302a73105b8SAntonio Quartulli goto unlock; 1303a73105b8SAntonio Quartulli } 1304a73105b8SAntonio Quartulli 1305a73105b8SAntonio Quartulli tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); 1306a73105b8SAntonio Quartulli if (!tt_req_node) 1307a73105b8SAntonio Quartulli goto unlock; 1308a73105b8SAntonio Quartulli 1309a73105b8SAntonio Quartulli memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); 1310a73105b8SAntonio Quartulli tt_req_node->issued_at = jiffies; 1311a73105b8SAntonio Quartulli 1312a73105b8SAntonio Quartulli list_add(&tt_req_node->list, &bat_priv->tt_req_list); 1313a73105b8SAntonio Quartulli unlock: 1314a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1315a73105b8SAntonio Quartulli return tt_req_node; 1316a73105b8SAntonio Quartulli } 1317a73105b8SAntonio Quartulli 1318058d0e26SAntonio Quartulli /* data_ptr is useless here, but has to be kept to respect the prototype */ 1319a513088dSSven Eckelmann static int batadv_tt_local_valid_entry(const void *entry_ptr, 1320a513088dSSven Eckelmann const void *data_ptr) 1321058d0e26SAntonio Quartulli { 132248100bacSAntonio Quartulli const struct tt_common_entry *tt_common_entry = entry_ptr; 1323058d0e26SAntonio Quartulli 132448100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_NEW) 1325058d0e26SAntonio Quartulli return 0; 1326058d0e26SAntonio Quartulli return 1; 1327058d0e26SAntonio Quartulli } 1328058d0e26SAntonio Quartulli 1329a513088dSSven Eckelmann static int batadv_tt_global_valid(const void *entry_ptr, 1330a513088dSSven Eckelmann const void *data_ptr) 1331a73105b8SAntonio Quartulli { 133248100bacSAntonio Quartulli const struct tt_common_entry *tt_common_entry = entry_ptr; 133348100bacSAntonio Quartulli const struct tt_global_entry *tt_global_entry; 1334a73105b8SAntonio Quartulli const struct orig_node *orig_node = data_ptr; 1335a73105b8SAntonio Quartulli 133648100bacSAntonio Quartulli if (tt_common_entry->flags & TT_CLIENT_ROAM) 1337cc47f66eSAntonio Quartulli return 0; 1338cc47f66eSAntonio Quartulli 133948100bacSAntonio Quartulli tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, 134048100bacSAntonio Quartulli common); 134148100bacSAntonio Quartulli 1342a513088dSSven Eckelmann return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); 1343a73105b8SAntonio Quartulli } 1344a73105b8SAntonio Quartulli 1345a513088dSSven Eckelmann static struct sk_buff * 1346a513088dSSven Eckelmann batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, 1347a73105b8SAntonio Quartulli struct hashtable_t *hash, 1348a73105b8SAntonio Quartulli struct hard_iface *primary_if, 1349a513088dSSven Eckelmann int (*valid_cb)(const void *, const void *), 1350a73105b8SAntonio Quartulli void *cb_data) 1351a73105b8SAntonio Quartulli { 135248100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 1353a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1354a73105b8SAntonio Quartulli struct tt_change *tt_change; 1355a73105b8SAntonio Quartulli struct hlist_node *node; 1356a73105b8SAntonio Quartulli struct hlist_head *head; 1357a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1358a73105b8SAntonio Quartulli uint16_t tt_tot, tt_count; 1359a73105b8SAntonio Quartulli ssize_t tt_query_size = sizeof(struct tt_query_packet); 1360c90681b8SAntonio Quartulli uint32_t i; 1361a73105b8SAntonio Quartulli 1362a73105b8SAntonio Quartulli if (tt_query_size + tt_len > primary_if->soft_iface->mtu) { 1363a73105b8SAntonio Quartulli tt_len = primary_if->soft_iface->mtu - tt_query_size; 1364a73105b8SAntonio Quartulli tt_len -= tt_len % sizeof(struct tt_change); 1365a73105b8SAntonio Quartulli } 1366a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1367a73105b8SAntonio Quartulli 1368a73105b8SAntonio Quartulli skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN); 1369a73105b8SAntonio Quartulli if (!skb) 1370a73105b8SAntonio Quartulli goto out; 1371a73105b8SAntonio Quartulli 1372a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1373a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1374a73105b8SAntonio Quartulli tt_query_size + tt_len); 1375a73105b8SAntonio Quartulli tt_response->ttvn = ttvn; 1376a73105b8SAntonio Quartulli 1377a73105b8SAntonio Quartulli tt_change = (struct tt_change *)(skb->data + tt_query_size); 1378a73105b8SAntonio Quartulli tt_count = 0; 1379a73105b8SAntonio Quartulli 1380a73105b8SAntonio Quartulli rcu_read_lock(); 1381a73105b8SAntonio Quartulli for (i = 0; i < hash->size; i++) { 1382a73105b8SAntonio Quartulli head = &hash->table[i]; 1383a73105b8SAntonio Quartulli 138448100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 1385a73105b8SAntonio Quartulli head, hash_entry) { 1386a73105b8SAntonio Quartulli if (tt_count == tt_tot) 1387a73105b8SAntonio Quartulli break; 1388a73105b8SAntonio Quartulli 138948100bacSAntonio Quartulli if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) 1390a73105b8SAntonio Quartulli continue; 1391a73105b8SAntonio Quartulli 139248100bacSAntonio Quartulli memcpy(tt_change->addr, tt_common_entry->addr, 139348100bacSAntonio Quartulli ETH_ALEN); 1394a73105b8SAntonio Quartulli tt_change->flags = NO_FLAGS; 1395a73105b8SAntonio Quartulli 1396a73105b8SAntonio Quartulli tt_count++; 1397a73105b8SAntonio Quartulli tt_change++; 1398a73105b8SAntonio Quartulli } 1399a73105b8SAntonio Quartulli } 1400a73105b8SAntonio Quartulli rcu_read_unlock(); 1401a73105b8SAntonio Quartulli 14029d852393SAntonio Quartulli /* store in the message the number of entries we have successfully 14039cfc7bd6SSven Eckelmann * copied 14049cfc7bd6SSven Eckelmann */ 14059d852393SAntonio Quartulli tt_response->tt_data = htons(tt_count); 14069d852393SAntonio Quartulli 1407a73105b8SAntonio Quartulli out: 1408a73105b8SAntonio Quartulli return skb; 1409a73105b8SAntonio Quartulli } 1410a73105b8SAntonio Quartulli 1411a513088dSSven Eckelmann static int batadv_send_tt_request(struct bat_priv *bat_priv, 1412a943cac1SMarek Lindner struct orig_node *dst_orig_node, 1413a513088dSSven Eckelmann uint8_t ttvn, uint16_t tt_crc, 1414a513088dSSven Eckelmann bool full_table) 1415a73105b8SAntonio Quartulli { 1416a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1417a73105b8SAntonio Quartulli struct tt_query_packet *tt_request; 1418a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1419a73105b8SAntonio Quartulli struct hard_iface *primary_if; 1420a73105b8SAntonio Quartulli struct tt_req_node *tt_req_node = NULL; 1421a73105b8SAntonio Quartulli int ret = 1; 1422a73105b8SAntonio Quartulli 1423e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1424a73105b8SAntonio Quartulli if (!primary_if) 1425a73105b8SAntonio Quartulli goto out; 1426a73105b8SAntonio Quartulli 1427a73105b8SAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 14289cfc7bd6SSven Eckelmann * reply from the same orig_node yet 14299cfc7bd6SSven Eckelmann */ 1430a513088dSSven Eckelmann tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node); 1431a73105b8SAntonio Quartulli if (!tt_req_node) 1432a73105b8SAntonio Quartulli goto out; 1433a73105b8SAntonio Quartulli 1434a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN); 1435a73105b8SAntonio Quartulli if (!skb) 1436a73105b8SAntonio Quartulli goto out; 1437a73105b8SAntonio Quartulli 1438a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1439a73105b8SAntonio Quartulli 1440a73105b8SAntonio Quartulli tt_request = (struct tt_query_packet *)skb_put(skb, 1441a73105b8SAntonio Quartulli sizeof(struct tt_query_packet)); 1442a73105b8SAntonio Quartulli 144376543d14SSven Eckelmann tt_request->header.packet_type = BAT_TT_QUERY; 144476543d14SSven Eckelmann tt_request->header.version = COMPAT_VERSION; 1445a73105b8SAntonio Quartulli memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1446a73105b8SAntonio Quartulli memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); 144776543d14SSven Eckelmann tt_request->header.ttl = TTL; 1448a73105b8SAntonio Quartulli tt_request->ttvn = ttvn; 14496d2003fcSAntonio Quartulli tt_request->tt_data = htons(tt_crc); 1450a73105b8SAntonio Quartulli tt_request->flags = TT_REQUEST; 1451a73105b8SAntonio Quartulli 1452a73105b8SAntonio Quartulli if (full_table) 1453a73105b8SAntonio Quartulli tt_request->flags |= TT_FULL_TABLE; 1454a73105b8SAntonio Quartulli 14557d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(dst_orig_node); 1456a73105b8SAntonio Quartulli if (!neigh_node) 1457a73105b8SAntonio Quartulli goto out; 1458a73105b8SAntonio Quartulli 14591eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 146086ceb360SSven Eckelmann "Sending TT_REQUEST to %pM via %pM [%c]\n", 146186ceb360SSven Eckelmann dst_orig_node->orig, neigh_node->addr, 1462a73105b8SAntonio Quartulli (full_table ? 'F' : '.')); 1463a73105b8SAntonio Quartulli 1464f8214865SMartin Hundebøll batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_TX); 1465f8214865SMartin Hundebøll 14669455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1467a73105b8SAntonio Quartulli ret = 0; 1468a73105b8SAntonio Quartulli 1469a73105b8SAntonio Quartulli out: 1470a73105b8SAntonio Quartulli if (neigh_node) 14717d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1472a73105b8SAntonio Quartulli if (primary_if) 1473e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1474a73105b8SAntonio Quartulli if (ret) 1475a73105b8SAntonio Quartulli kfree_skb(skb); 1476a73105b8SAntonio Quartulli if (ret && tt_req_node) { 1477a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1478a73105b8SAntonio Quartulli list_del(&tt_req_node->list); 1479a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1480a73105b8SAntonio Quartulli kfree(tt_req_node); 1481a73105b8SAntonio Quartulli } 1482a73105b8SAntonio Quartulli return ret; 1483a73105b8SAntonio Quartulli } 1484a73105b8SAntonio Quartulli 1485a513088dSSven Eckelmann static bool batadv_send_other_tt_response(struct bat_priv *bat_priv, 1486a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1487a73105b8SAntonio Quartulli { 1488a73105b8SAntonio Quartulli struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL; 1489a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1490a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1491a73105b8SAntonio Quartulli uint8_t orig_ttvn, req_ttvn, ttvn; 1492a73105b8SAntonio Quartulli int ret = false; 1493a73105b8SAntonio Quartulli unsigned char *tt_buff; 1494a73105b8SAntonio Quartulli bool full_table; 1495a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1496a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1497a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1498a73105b8SAntonio Quartulli 14991eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 150086ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", 150186ceb360SSven Eckelmann tt_request->src, tt_request->ttvn, tt_request->dst, 1502a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1503a73105b8SAntonio Quartulli 1504a73105b8SAntonio Quartulli /* Let's get the orig node of the REAL destination */ 1505da641193SSven Eckelmann req_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->dst); 1506a73105b8SAntonio Quartulli if (!req_dst_orig_node) 1507a73105b8SAntonio Quartulli goto out; 1508a73105b8SAntonio Quartulli 1509da641193SSven Eckelmann res_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); 1510a73105b8SAntonio Quartulli if (!res_dst_orig_node) 1511a73105b8SAntonio Quartulli goto out; 1512a73105b8SAntonio Quartulli 15137d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(res_dst_orig_node); 1514a73105b8SAntonio Quartulli if (!neigh_node) 1515a73105b8SAntonio Quartulli goto out; 1516a73105b8SAntonio Quartulli 1517e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1518a73105b8SAntonio Quartulli if (!primary_if) 1519a73105b8SAntonio Quartulli goto out; 1520a73105b8SAntonio Quartulli 1521a73105b8SAntonio Quartulli orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1522a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1523a73105b8SAntonio Quartulli 1524015758d0SAntonio Quartulli /* I don't have the requested data */ 1525a73105b8SAntonio Quartulli if (orig_ttvn != req_ttvn || 1526f25bd58aSAl Viro tt_request->tt_data != htons(req_dst_orig_node->tt_crc)) 1527a73105b8SAntonio Quartulli goto out; 1528a73105b8SAntonio Quartulli 1529015758d0SAntonio Quartulli /* If the full table has been explicitly requested */ 1530a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || 1531a73105b8SAntonio Quartulli !req_dst_orig_node->tt_buff) 1532a73105b8SAntonio Quartulli full_table = true; 1533a73105b8SAntonio Quartulli else 1534a73105b8SAntonio Quartulli full_table = false; 1535a73105b8SAntonio Quartulli 1536a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 15379cfc7bd6SSven Eckelmann * I'll send only one packet with as much TT entries as I can 15389cfc7bd6SSven Eckelmann */ 1539a73105b8SAntonio Quartulli if (!full_table) { 1540a73105b8SAntonio Quartulli spin_lock_bh(&req_dst_orig_node->tt_buff_lock); 1541a73105b8SAntonio Quartulli tt_len = req_dst_orig_node->tt_buff_len; 1542a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1543a73105b8SAntonio Quartulli 1544a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1545a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1546a73105b8SAntonio Quartulli if (!skb) 1547a73105b8SAntonio Quartulli goto unlock; 1548a73105b8SAntonio Quartulli 1549a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1550a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1551a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1552a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1553a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1554a73105b8SAntonio Quartulli 1555a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1556a73105b8SAntonio Quartulli /* Copy the last orig_node's OGM buffer */ 1557a73105b8SAntonio Quartulli memcpy(tt_buff, req_dst_orig_node->tt_buff, 1558a73105b8SAntonio Quartulli req_dst_orig_node->tt_buff_len); 1559a73105b8SAntonio Quartulli 1560a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1561a73105b8SAntonio Quartulli } else { 1562a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) * 1563a73105b8SAntonio Quartulli sizeof(struct tt_change); 1564a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); 1565a73105b8SAntonio Quartulli 1566a513088dSSven Eckelmann skb = batadv_tt_response_fill_table(tt_len, ttvn, 1567a73105b8SAntonio Quartulli bat_priv->tt_global_hash, 1568a513088dSSven Eckelmann primary_if, 1569a513088dSSven Eckelmann batadv_tt_global_valid, 1570a73105b8SAntonio Quartulli req_dst_orig_node); 1571a73105b8SAntonio Quartulli if (!skb) 1572a73105b8SAntonio Quartulli goto out; 1573a73105b8SAntonio Quartulli 1574a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1575a73105b8SAntonio Quartulli } 1576a73105b8SAntonio Quartulli 157776543d14SSven Eckelmann tt_response->header.packet_type = BAT_TT_QUERY; 157876543d14SSven Eckelmann tt_response->header.version = COMPAT_VERSION; 157976543d14SSven Eckelmann tt_response->header.ttl = TTL; 1580a73105b8SAntonio Quartulli memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); 1581a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1582a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1583a73105b8SAntonio Quartulli 1584a73105b8SAntonio Quartulli if (full_table) 1585a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1586a73105b8SAntonio Quartulli 15871eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 1588a73105b8SAntonio Quartulli "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n", 1589a73105b8SAntonio Quartulli res_dst_orig_node->orig, neigh_node->addr, 1590a73105b8SAntonio Quartulli req_dst_orig_node->orig, req_ttvn); 1591a73105b8SAntonio Quartulli 1592f8214865SMartin Hundebøll batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX); 1593f8214865SMartin Hundebøll 15949455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1595a73105b8SAntonio Quartulli ret = true; 1596a73105b8SAntonio Quartulli goto out; 1597a73105b8SAntonio Quartulli 1598a73105b8SAntonio Quartulli unlock: 1599a73105b8SAntonio Quartulli spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); 1600a73105b8SAntonio Quartulli 1601a73105b8SAntonio Quartulli out: 1602a73105b8SAntonio Quartulli if (res_dst_orig_node) 16037d211efcSSven Eckelmann batadv_orig_node_free_ref(res_dst_orig_node); 1604a73105b8SAntonio Quartulli if (req_dst_orig_node) 16057d211efcSSven Eckelmann batadv_orig_node_free_ref(req_dst_orig_node); 1606a73105b8SAntonio Quartulli if (neigh_node) 16077d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1608a73105b8SAntonio Quartulli if (primary_if) 1609e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1610a73105b8SAntonio Quartulli if (!ret) 1611a73105b8SAntonio Quartulli kfree_skb(skb); 1612a73105b8SAntonio Quartulli return ret; 1613a73105b8SAntonio Quartulli 1614a73105b8SAntonio Quartulli } 1615a513088dSSven Eckelmann static bool batadv_send_my_tt_response(struct bat_priv *bat_priv, 1616a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1617a73105b8SAntonio Quartulli { 1618a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1619a73105b8SAntonio Quartulli struct neigh_node *neigh_node = NULL; 1620a73105b8SAntonio Quartulli struct hard_iface *primary_if = NULL; 1621a73105b8SAntonio Quartulli uint8_t my_ttvn, req_ttvn, ttvn; 1622a73105b8SAntonio Quartulli int ret = false; 1623a73105b8SAntonio Quartulli unsigned char *tt_buff; 1624a73105b8SAntonio Quartulli bool full_table; 1625a73105b8SAntonio Quartulli uint16_t tt_len, tt_tot; 1626a73105b8SAntonio Quartulli struct sk_buff *skb = NULL; 1627a73105b8SAntonio Quartulli struct tt_query_packet *tt_response; 1628a73105b8SAntonio Quartulli 16291eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 163086ceb360SSven Eckelmann "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", 163186ceb360SSven Eckelmann tt_request->src, tt_request->ttvn, 1632a73105b8SAntonio Quartulli (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); 1633a73105b8SAntonio Quartulli 1634a73105b8SAntonio Quartulli 1635a73105b8SAntonio Quartulli my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1636a73105b8SAntonio Quartulli req_ttvn = tt_request->ttvn; 1637a73105b8SAntonio Quartulli 1638da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); 1639a73105b8SAntonio Quartulli if (!orig_node) 1640a73105b8SAntonio Quartulli goto out; 1641a73105b8SAntonio Quartulli 16427d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(orig_node); 1643a73105b8SAntonio Quartulli if (!neigh_node) 1644a73105b8SAntonio Quartulli goto out; 1645a73105b8SAntonio Quartulli 1646e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 1647a73105b8SAntonio Quartulli if (!primary_if) 1648a73105b8SAntonio Quartulli goto out; 1649a73105b8SAntonio Quartulli 1650a73105b8SAntonio Quartulli /* If the full table has been explicitly requested or the gap 16519cfc7bd6SSven Eckelmann * is too big send the whole local translation table 16529cfc7bd6SSven Eckelmann */ 1653a73105b8SAntonio Quartulli if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn || 1654a73105b8SAntonio Quartulli !bat_priv->tt_buff) 1655a73105b8SAntonio Quartulli full_table = true; 1656a73105b8SAntonio Quartulli else 1657a73105b8SAntonio Quartulli full_table = false; 1658a73105b8SAntonio Quartulli 1659a73105b8SAntonio Quartulli /* In this version, fragmentation is not implemented, then 16609cfc7bd6SSven Eckelmann * I'll send only one packet with as much TT entries as I can 16619cfc7bd6SSven Eckelmann */ 1662a73105b8SAntonio Quartulli if (!full_table) { 1663a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_buff_lock); 1664a73105b8SAntonio Quartulli tt_len = bat_priv->tt_buff_len; 1665a73105b8SAntonio Quartulli tt_tot = tt_len / sizeof(struct tt_change); 1666a73105b8SAntonio Quartulli 1667a73105b8SAntonio Quartulli skb = dev_alloc_skb(sizeof(struct tt_query_packet) + 1668a73105b8SAntonio Quartulli tt_len + ETH_HLEN); 1669a73105b8SAntonio Quartulli if (!skb) 1670a73105b8SAntonio Quartulli goto unlock; 1671a73105b8SAntonio Quartulli 1672a73105b8SAntonio Quartulli skb_reserve(skb, ETH_HLEN); 1673a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb_put(skb, 1674a73105b8SAntonio Quartulli sizeof(struct tt_query_packet) + tt_len); 1675a73105b8SAntonio Quartulli tt_response->ttvn = req_ttvn; 1676a73105b8SAntonio Quartulli tt_response->tt_data = htons(tt_tot); 1677a73105b8SAntonio Quartulli 1678a73105b8SAntonio Quartulli tt_buff = skb->data + sizeof(struct tt_query_packet); 1679a73105b8SAntonio Quartulli memcpy(tt_buff, bat_priv->tt_buff, 1680a73105b8SAntonio Quartulli bat_priv->tt_buff_len); 1681a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1682a73105b8SAntonio Quartulli } else { 1683a73105b8SAntonio Quartulli tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) * 1684a73105b8SAntonio Quartulli sizeof(struct tt_change); 1685a73105b8SAntonio Quartulli ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1686a73105b8SAntonio Quartulli 1687a513088dSSven Eckelmann skb = batadv_tt_response_fill_table(tt_len, ttvn, 1688a73105b8SAntonio Quartulli bat_priv->tt_local_hash, 1689a513088dSSven Eckelmann primary_if, 1690a513088dSSven Eckelmann batadv_tt_local_valid_entry, 1691058d0e26SAntonio Quartulli NULL); 1692a73105b8SAntonio Quartulli if (!skb) 1693a73105b8SAntonio Quartulli goto out; 1694a73105b8SAntonio Quartulli 1695a73105b8SAntonio Quartulli tt_response = (struct tt_query_packet *)skb->data; 1696a73105b8SAntonio Quartulli } 1697a73105b8SAntonio Quartulli 169876543d14SSven Eckelmann tt_response->header.packet_type = BAT_TT_QUERY; 169976543d14SSven Eckelmann tt_response->header.version = COMPAT_VERSION; 170076543d14SSven Eckelmann tt_response->header.ttl = TTL; 1701a73105b8SAntonio Quartulli memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); 1702a73105b8SAntonio Quartulli memcpy(tt_response->dst, tt_request->src, ETH_ALEN); 1703a73105b8SAntonio Quartulli tt_response->flags = TT_RESPONSE; 1704a73105b8SAntonio Quartulli 1705a73105b8SAntonio Quartulli if (full_table) 1706a73105b8SAntonio Quartulli tt_response->flags |= TT_FULL_TABLE; 1707a73105b8SAntonio Quartulli 17081eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 1709a73105b8SAntonio Quartulli "Sending TT_RESPONSE to %pM via %pM [%c]\n", 1710a73105b8SAntonio Quartulli orig_node->orig, neigh_node->addr, 1711a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1712a73105b8SAntonio Quartulli 1713f8214865SMartin Hundebøll batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX); 1714f8214865SMartin Hundebøll 17159455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1716a73105b8SAntonio Quartulli ret = true; 1717a73105b8SAntonio Quartulli goto out; 1718a73105b8SAntonio Quartulli 1719a73105b8SAntonio Quartulli unlock: 1720a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_buff_lock); 1721a73105b8SAntonio Quartulli out: 1722a73105b8SAntonio Quartulli if (orig_node) 17237d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1724a73105b8SAntonio Quartulli if (neigh_node) 17257d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 1726a73105b8SAntonio Quartulli if (primary_if) 1727e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 1728a73105b8SAntonio Quartulli if (!ret) 1729a73105b8SAntonio Quartulli kfree_skb(skb); 1730a73105b8SAntonio Quartulli /* This packet was for me, so it doesn't need to be re-routed */ 1731a73105b8SAntonio Quartulli return true; 1732a73105b8SAntonio Quartulli } 1733a73105b8SAntonio Quartulli 173408c36d3eSSven Eckelmann bool batadv_send_tt_response(struct bat_priv *bat_priv, 1735a73105b8SAntonio Quartulli struct tt_query_packet *tt_request) 1736a73105b8SAntonio Quartulli { 17373193e8fdSSven Eckelmann if (batadv_is_my_mac(tt_request->dst)) { 173820ff9d59SSimon Wunderlich /* don't answer backbone gws! */ 173908adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src)) 174020ff9d59SSimon Wunderlich return true; 174120ff9d59SSimon Wunderlich 1742a513088dSSven Eckelmann return batadv_send_my_tt_response(bat_priv, tt_request); 174320ff9d59SSimon Wunderlich } else { 1744a513088dSSven Eckelmann return batadv_send_other_tt_response(bat_priv, tt_request); 1745a73105b8SAntonio Quartulli } 174620ff9d59SSimon Wunderlich } 1747a73105b8SAntonio Quartulli 1748a513088dSSven Eckelmann static void _batadv_tt_update_changes(struct bat_priv *bat_priv, 1749a73105b8SAntonio Quartulli struct orig_node *orig_node, 1750a73105b8SAntonio Quartulli struct tt_change *tt_change, 1751a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn) 1752a73105b8SAntonio Quartulli { 1753a73105b8SAntonio Quartulli int i; 1754a513088dSSven Eckelmann int roams; 1755a73105b8SAntonio Quartulli 1756a73105b8SAntonio Quartulli for (i = 0; i < tt_num_changes; i++) { 175708c36d3eSSven Eckelmann if ((tt_change + i)->flags & TT_CLIENT_DEL) { 1758a513088dSSven Eckelmann roams = (tt_change + i)->flags & TT_CLIENT_ROAM; 1759a513088dSSven Eckelmann batadv_tt_global_del(bat_priv, orig_node, 1760a73105b8SAntonio Quartulli (tt_change + i)->addr, 1761cc47f66eSAntonio Quartulli "tt removed by changes", 1762a513088dSSven Eckelmann roams); 176308c36d3eSSven Eckelmann } else { 176408c36d3eSSven Eckelmann if (!batadv_tt_global_add(bat_priv, orig_node, 1765d4f44692SAntonio Quartulli (tt_change + i)->addr, 1766d4f44692SAntonio Quartulli (tt_change + i)->flags, ttvn)) 1767a73105b8SAntonio Quartulli /* In case of problem while storing a 1768a73105b8SAntonio Quartulli * global_entry, we stop the updating 1769a73105b8SAntonio Quartulli * procedure without committing the 1770a73105b8SAntonio Quartulli * ttvn change. This will avoid to send 1771a73105b8SAntonio Quartulli * corrupted data on tt_request 1772a73105b8SAntonio Quartulli */ 1773a73105b8SAntonio Quartulli return; 1774a73105b8SAntonio Quartulli } 177508c36d3eSSven Eckelmann } 177617071578SAntonio Quartulli orig_node->tt_initialised = true; 1777a73105b8SAntonio Quartulli } 1778a73105b8SAntonio Quartulli 1779a513088dSSven Eckelmann static void batadv_tt_fill_gtable(struct bat_priv *bat_priv, 1780a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1781a73105b8SAntonio Quartulli { 1782a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1783a73105b8SAntonio Quartulli 1784da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); 1785a73105b8SAntonio Quartulli if (!orig_node) 1786a73105b8SAntonio Quartulli goto out; 1787a73105b8SAntonio Quartulli 1788a73105b8SAntonio Quartulli /* Purge the old table first.. */ 178908c36d3eSSven Eckelmann batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table"); 1790a73105b8SAntonio Quartulli 1791a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, 1792a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1), 1793a513088dSSven Eckelmann ntohs(tt_response->tt_data), 1794a513088dSSven Eckelmann tt_response->ttvn); 1795a73105b8SAntonio Quartulli 1796a73105b8SAntonio Quartulli spin_lock_bh(&orig_node->tt_buff_lock); 1797a73105b8SAntonio Quartulli kfree(orig_node->tt_buff); 1798a73105b8SAntonio Quartulli orig_node->tt_buff_len = 0; 1799a73105b8SAntonio Quartulli orig_node->tt_buff = NULL; 1800a73105b8SAntonio Quartulli spin_unlock_bh(&orig_node->tt_buff_lock); 1801a73105b8SAntonio Quartulli 1802a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, tt_response->ttvn); 1803a73105b8SAntonio Quartulli 1804a73105b8SAntonio Quartulli out: 1805a73105b8SAntonio Quartulli if (orig_node) 18067d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1807a73105b8SAntonio Quartulli } 1808a73105b8SAntonio Quartulli 1809a513088dSSven Eckelmann static void batadv_tt_update_changes(struct bat_priv *bat_priv, 1810a943cac1SMarek Lindner struct orig_node *orig_node, 1811a73105b8SAntonio Quartulli uint16_t tt_num_changes, uint8_t ttvn, 1812a73105b8SAntonio Quartulli struct tt_change *tt_change) 1813a73105b8SAntonio Quartulli { 1814a513088dSSven Eckelmann _batadv_tt_update_changes(bat_priv, orig_node, tt_change, 1815a513088dSSven Eckelmann tt_num_changes, ttvn); 1816a73105b8SAntonio Quartulli 1817a513088dSSven Eckelmann batadv_tt_save_orig_buffer(bat_priv, orig_node, 1818a513088dSSven Eckelmann (unsigned char *)tt_change, tt_num_changes); 1819a73105b8SAntonio Quartulli atomic_set(&orig_node->last_ttvn, ttvn); 1820a73105b8SAntonio Quartulli } 1821a73105b8SAntonio Quartulli 182208c36d3eSSven Eckelmann bool batadv_is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) 1823a73105b8SAntonio Quartulli { 18247683fdc1SAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 18257683fdc1SAntonio Quartulli bool ret = false; 1826a73105b8SAntonio Quartulli 1827a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); 18287683fdc1SAntonio Quartulli if (!tt_local_entry) 18297683fdc1SAntonio Quartulli goto out; 1830058d0e26SAntonio Quartulli /* Check if the client has been logically deleted (but is kept for 18319cfc7bd6SSven Eckelmann * consistency purpose) 18329cfc7bd6SSven Eckelmann */ 183348100bacSAntonio Quartulli if (tt_local_entry->common.flags & TT_CLIENT_PENDING) 1834058d0e26SAntonio Quartulli goto out; 18357683fdc1SAntonio Quartulli ret = true; 18367683fdc1SAntonio Quartulli out: 1837a73105b8SAntonio Quartulli if (tt_local_entry) 1838a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 18397683fdc1SAntonio Quartulli return ret; 1840a73105b8SAntonio Quartulli } 1841a73105b8SAntonio Quartulli 184208c36d3eSSven Eckelmann void batadv_handle_tt_response(struct bat_priv *bat_priv, 1843a73105b8SAntonio Quartulli struct tt_query_packet *tt_response) 1844a73105b8SAntonio Quartulli { 1845a73105b8SAntonio Quartulli struct tt_req_node *node, *safe; 1846a73105b8SAntonio Quartulli struct orig_node *orig_node = NULL; 1847a73105b8SAntonio Quartulli 18481eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 184986ceb360SSven Eckelmann "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", 1850f25bd58aSAl Viro tt_response->src, tt_response->ttvn, 1851f25bd58aSAl Viro ntohs(tt_response->tt_data), 1852a73105b8SAntonio Quartulli (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); 1853a73105b8SAntonio Quartulli 185420ff9d59SSimon Wunderlich /* we should have never asked a backbone gw */ 185508adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src)) 185620ff9d59SSimon Wunderlich goto out; 185720ff9d59SSimon Wunderlich 1858da641193SSven Eckelmann orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); 1859a73105b8SAntonio Quartulli if (!orig_node) 1860a73105b8SAntonio Quartulli goto out; 1861a73105b8SAntonio Quartulli 1862a73105b8SAntonio Quartulli if (tt_response->flags & TT_FULL_TABLE) 1863a513088dSSven Eckelmann batadv_tt_fill_gtable(bat_priv, tt_response); 1864a73105b8SAntonio Quartulli else 1865a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, 1866f25bd58aSAl Viro ntohs(tt_response->tt_data), 1867a73105b8SAntonio Quartulli tt_response->ttvn, 1868a73105b8SAntonio Quartulli (struct tt_change *)(tt_response + 1)); 1869a73105b8SAntonio Quartulli 1870a73105b8SAntonio Quartulli /* Delete the tt_req_node from pending tt_requests list */ 1871a73105b8SAntonio Quartulli spin_lock_bh(&bat_priv->tt_req_list_lock); 1872a73105b8SAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { 18731eda58bfSSven Eckelmann if (!batadv_compare_eth(node->addr, tt_response->src)) 1874a73105b8SAntonio Quartulli continue; 1875a73105b8SAntonio Quartulli list_del(&node->list); 1876a73105b8SAntonio Quartulli kfree(node); 1877a73105b8SAntonio Quartulli } 1878a73105b8SAntonio Quartulli spin_unlock_bh(&bat_priv->tt_req_list_lock); 1879a73105b8SAntonio Quartulli 1880a73105b8SAntonio Quartulli /* Recalculate the CRC for this orig_node and store it */ 1881a513088dSSven Eckelmann orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 1882cc47f66eSAntonio Quartulli /* Roaming phase is over: tables are in sync again. I can 18839cfc7bd6SSven Eckelmann * unset the flag 18849cfc7bd6SSven Eckelmann */ 1885cc47f66eSAntonio Quartulli orig_node->tt_poss_change = false; 1886a73105b8SAntonio Quartulli out: 1887a73105b8SAntonio Quartulli if (orig_node) 18887d211efcSSven Eckelmann batadv_orig_node_free_ref(orig_node); 1889a73105b8SAntonio Quartulli } 1890a73105b8SAntonio Quartulli 189108c36d3eSSven Eckelmann int batadv_tt_init(struct bat_priv *bat_priv) 1892a73105b8SAntonio Quartulli { 18935346c35eSSven Eckelmann int ret; 1894a73105b8SAntonio Quartulli 1895a513088dSSven Eckelmann ret = batadv_tt_local_init(bat_priv); 18965346c35eSSven Eckelmann if (ret < 0) 18975346c35eSSven Eckelmann return ret; 18985346c35eSSven Eckelmann 1899a513088dSSven Eckelmann ret = batadv_tt_global_init(bat_priv); 19005346c35eSSven Eckelmann if (ret < 0) 19015346c35eSSven Eckelmann return ret; 1902a73105b8SAntonio Quartulli 1903a513088dSSven Eckelmann batadv_tt_start_timer(bat_priv); 1904a73105b8SAntonio Quartulli 1905a73105b8SAntonio Quartulli return 1; 1906a73105b8SAntonio Quartulli } 1907a73105b8SAntonio Quartulli 1908a513088dSSven Eckelmann static void batadv_tt_roam_list_free(struct bat_priv *bat_priv) 1909a73105b8SAntonio Quartulli { 1910cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1911a73105b8SAntonio Quartulli 1912cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1913a73105b8SAntonio Quartulli 1914cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 1915cc47f66eSAntonio Quartulli list_del(&node->list); 1916cc47f66eSAntonio Quartulli kfree(node); 1917cc47f66eSAntonio Quartulli } 1918cc47f66eSAntonio Quartulli 1919cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1920cc47f66eSAntonio Quartulli } 1921cc47f66eSAntonio Quartulli 1922a513088dSSven Eckelmann static void batadv_tt_roam_purge(struct bat_priv *bat_priv) 1923cc47f66eSAntonio Quartulli { 1924cc47f66eSAntonio Quartulli struct tt_roam_node *node, *safe; 1925cc47f66eSAntonio Quartulli 1926cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1927cc47f66eSAntonio Quartulli list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { 19281eda58bfSSven Eckelmann if (!batadv_has_timed_out(node->first_time, ROAMING_MAX_TIME)) 1929cc47f66eSAntonio Quartulli continue; 1930cc47f66eSAntonio Quartulli 1931cc47f66eSAntonio Quartulli list_del(&node->list); 1932cc47f66eSAntonio Quartulli kfree(node); 1933cc47f66eSAntonio Quartulli } 1934cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1935cc47f66eSAntonio Quartulli } 1936cc47f66eSAntonio Quartulli 1937cc47f66eSAntonio Quartulli /* This function checks whether the client already reached the 1938cc47f66eSAntonio Quartulli * maximum number of possible roaming phases. In this case the ROAMING_ADV 1939cc47f66eSAntonio Quartulli * will not be sent. 1940cc47f66eSAntonio Quartulli * 19419cfc7bd6SSven Eckelmann * returns true if the ROAMING_ADV can be sent, false otherwise 19429cfc7bd6SSven Eckelmann */ 1943a513088dSSven Eckelmann static bool batadv_tt_check_roam_count(struct bat_priv *bat_priv, 1944cc47f66eSAntonio Quartulli uint8_t *client) 1945cc47f66eSAntonio Quartulli { 1946cc47f66eSAntonio Quartulli struct tt_roam_node *tt_roam_node; 1947cc47f66eSAntonio Quartulli bool ret = false; 1948cc47f66eSAntonio Quartulli 1949cc47f66eSAntonio Quartulli spin_lock_bh(&bat_priv->tt_roam_list_lock); 1950cc47f66eSAntonio Quartulli /* The new tt_req will be issued only if I'm not waiting for a 19519cfc7bd6SSven Eckelmann * reply from the same orig_node yet 19529cfc7bd6SSven Eckelmann */ 1953cc47f66eSAntonio Quartulli list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) { 19541eda58bfSSven Eckelmann if (!batadv_compare_eth(tt_roam_node->addr, client)) 1955cc47f66eSAntonio Quartulli continue; 1956cc47f66eSAntonio Quartulli 19571eda58bfSSven Eckelmann if (batadv_has_timed_out(tt_roam_node->first_time, 19581eda58bfSSven Eckelmann ROAMING_MAX_TIME)) 1959cc47f66eSAntonio Quartulli continue; 1960cc47f66eSAntonio Quartulli 19613e34819eSSven Eckelmann if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) 1962cc47f66eSAntonio Quartulli /* Sorry, you roamed too many times! */ 1963cc47f66eSAntonio Quartulli goto unlock; 1964cc47f66eSAntonio Quartulli ret = true; 1965cc47f66eSAntonio Quartulli break; 1966cc47f66eSAntonio Quartulli } 1967cc47f66eSAntonio Quartulli 1968cc47f66eSAntonio Quartulli if (!ret) { 1969cc47f66eSAntonio Quartulli tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); 1970cc47f66eSAntonio Quartulli if (!tt_roam_node) 1971cc47f66eSAntonio Quartulli goto unlock; 1972cc47f66eSAntonio Quartulli 1973cc47f66eSAntonio Quartulli tt_roam_node->first_time = jiffies; 1974cc47f66eSAntonio Quartulli atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1); 1975cc47f66eSAntonio Quartulli memcpy(tt_roam_node->addr, client, ETH_ALEN); 1976cc47f66eSAntonio Quartulli 1977cc47f66eSAntonio Quartulli list_add(&tt_roam_node->list, &bat_priv->tt_roam_list); 1978cc47f66eSAntonio Quartulli ret = true; 1979cc47f66eSAntonio Quartulli } 1980cc47f66eSAntonio Quartulli 1981cc47f66eSAntonio Quartulli unlock: 1982cc47f66eSAntonio Quartulli spin_unlock_bh(&bat_priv->tt_roam_list_lock); 1983cc47f66eSAntonio Quartulli return ret; 1984cc47f66eSAntonio Quartulli } 1985cc47f66eSAntonio Quartulli 1986a513088dSSven Eckelmann static void batadv_send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 1987cc47f66eSAntonio Quartulli struct orig_node *orig_node) 1988cc47f66eSAntonio Quartulli { 1989cc47f66eSAntonio Quartulli struct neigh_node *neigh_node = NULL; 1990cc47f66eSAntonio Quartulli struct sk_buff *skb = NULL; 1991cc47f66eSAntonio Quartulli struct roam_adv_packet *roam_adv_packet; 1992cc47f66eSAntonio Quartulli int ret = 1; 1993cc47f66eSAntonio Quartulli struct hard_iface *primary_if; 1994cc47f66eSAntonio Quartulli 1995cc47f66eSAntonio Quartulli /* before going on we have to check whether the client has 19969cfc7bd6SSven Eckelmann * already roamed to us too many times 19979cfc7bd6SSven Eckelmann */ 1998a513088dSSven Eckelmann if (!batadv_tt_check_roam_count(bat_priv, client)) 1999cc47f66eSAntonio Quartulli goto out; 2000cc47f66eSAntonio Quartulli 2001cc47f66eSAntonio Quartulli skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN); 2002cc47f66eSAntonio Quartulli if (!skb) 2003cc47f66eSAntonio Quartulli goto out; 2004cc47f66eSAntonio Quartulli 2005cc47f66eSAntonio Quartulli skb_reserve(skb, ETH_HLEN); 2006cc47f66eSAntonio Quartulli 2007cc47f66eSAntonio Quartulli roam_adv_packet = (struct roam_adv_packet *)skb_put(skb, 2008cc47f66eSAntonio Quartulli sizeof(struct roam_adv_packet)); 2009cc47f66eSAntonio Quartulli 201076543d14SSven Eckelmann roam_adv_packet->header.packet_type = BAT_ROAM_ADV; 201176543d14SSven Eckelmann roam_adv_packet->header.version = COMPAT_VERSION; 201276543d14SSven Eckelmann roam_adv_packet->header.ttl = TTL; 2013e5d89254SSven Eckelmann primary_if = batadv_primary_if_get_selected(bat_priv); 2014cc47f66eSAntonio Quartulli if (!primary_if) 2015cc47f66eSAntonio Quartulli goto out; 2016cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); 2017e5d89254SSven Eckelmann batadv_hardif_free_ref(primary_if); 2018cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); 2019cc47f66eSAntonio Quartulli memcpy(roam_adv_packet->client, client, ETH_ALEN); 2020cc47f66eSAntonio Quartulli 20217d211efcSSven Eckelmann neigh_node = batadv_orig_node_get_router(orig_node); 2022cc47f66eSAntonio Quartulli if (!neigh_node) 2023cc47f66eSAntonio Quartulli goto out; 2024cc47f66eSAntonio Quartulli 20251eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 2026cc47f66eSAntonio Quartulli "Sending ROAMING_ADV to %pM (client %pM) via %pM\n", 2027cc47f66eSAntonio Quartulli orig_node->orig, client, neigh_node->addr); 2028cc47f66eSAntonio Quartulli 2029f8214865SMartin Hundebøll batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_TX); 2030f8214865SMartin Hundebøll 20319455e34cSSven Eckelmann batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 2032cc47f66eSAntonio Quartulli ret = 0; 2033cc47f66eSAntonio Quartulli 2034cc47f66eSAntonio Quartulli out: 2035cc47f66eSAntonio Quartulli if (neigh_node) 20367d211efcSSven Eckelmann batadv_neigh_node_free_ref(neigh_node); 2037cc47f66eSAntonio Quartulli if (ret) 2038cc47f66eSAntonio Quartulli kfree_skb(skb); 2039cc47f66eSAntonio Quartulli return; 2040a73105b8SAntonio Quartulli } 2041a73105b8SAntonio Quartulli 2042a513088dSSven Eckelmann static void batadv_tt_purge(struct work_struct *work) 2043a73105b8SAntonio Quartulli { 2044a73105b8SAntonio Quartulli struct delayed_work *delayed_work = 2045a73105b8SAntonio Quartulli container_of(work, struct delayed_work, work); 2046a73105b8SAntonio Quartulli struct bat_priv *bat_priv = 2047a73105b8SAntonio Quartulli container_of(delayed_work, struct bat_priv, tt_work); 2048a73105b8SAntonio Quartulli 2049a513088dSSven Eckelmann batadv_tt_local_purge(bat_priv); 2050a513088dSSven Eckelmann batadv_tt_global_roam_purge(bat_priv); 2051a513088dSSven Eckelmann batadv_tt_req_purge(bat_priv); 2052a513088dSSven Eckelmann batadv_tt_roam_purge(bat_priv); 2053a73105b8SAntonio Quartulli 2054a513088dSSven Eckelmann batadv_tt_start_timer(bat_priv); 2055a73105b8SAntonio Quartulli } 2056cc47f66eSAntonio Quartulli 205708c36d3eSSven Eckelmann void batadv_tt_free(struct bat_priv *bat_priv) 2058cc47f66eSAntonio Quartulli { 2059cc47f66eSAntonio Quartulli cancel_delayed_work_sync(&bat_priv->tt_work); 2060cc47f66eSAntonio Quartulli 2061a513088dSSven Eckelmann batadv_tt_local_table_free(bat_priv); 2062a513088dSSven Eckelmann batadv_tt_global_table_free(bat_priv); 2063a513088dSSven Eckelmann batadv_tt_req_list_free(bat_priv); 2064a513088dSSven Eckelmann batadv_tt_changes_list_free(bat_priv); 2065a513088dSSven Eckelmann batadv_tt_roam_list_free(bat_priv); 2066cc47f66eSAntonio Quartulli 2067cc47f66eSAntonio Quartulli kfree(bat_priv->tt_buff); 2068cc47f66eSAntonio Quartulli } 2069058d0e26SAntonio Quartulli 2070697f2531SAntonio Quartulli /* This function will enable or disable the specified flags for all the entries 20719cfc7bd6SSven Eckelmann * in the given hash table and returns the number of modified entries 20729cfc7bd6SSven Eckelmann */ 2073a513088dSSven Eckelmann static uint16_t batadv_tt_set_flags(struct hashtable_t *hash, uint16_t flags, 2074697f2531SAntonio Quartulli bool enable) 2075058d0e26SAntonio Quartulli { 2076c90681b8SAntonio Quartulli uint32_t i; 2077697f2531SAntonio Quartulli uint16_t changed_num = 0; 2078058d0e26SAntonio Quartulli struct hlist_head *head; 2079058d0e26SAntonio Quartulli struct hlist_node *node; 208048100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 2081058d0e26SAntonio Quartulli 2082058d0e26SAntonio Quartulli if (!hash) 2083697f2531SAntonio Quartulli goto out; 2084058d0e26SAntonio Quartulli 2085058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2086058d0e26SAntonio Quartulli head = &hash->table[i]; 2087058d0e26SAntonio Quartulli 2088058d0e26SAntonio Quartulli rcu_read_lock(); 208948100bacSAntonio Quartulli hlist_for_each_entry_rcu(tt_common_entry, node, 2090058d0e26SAntonio Quartulli head, hash_entry) { 2091697f2531SAntonio Quartulli if (enable) { 2092697f2531SAntonio Quartulli if ((tt_common_entry->flags & flags) == flags) 2093697f2531SAntonio Quartulli continue; 2094697f2531SAntonio Quartulli tt_common_entry->flags |= flags; 2095697f2531SAntonio Quartulli } else { 209648100bacSAntonio Quartulli if (!(tt_common_entry->flags & flags)) 209731901264SAntonio Quartulli continue; 209848100bacSAntonio Quartulli tt_common_entry->flags &= ~flags; 2099697f2531SAntonio Quartulli } 2100697f2531SAntonio Quartulli changed_num++; 2101058d0e26SAntonio Quartulli } 2102058d0e26SAntonio Quartulli rcu_read_unlock(); 2103058d0e26SAntonio Quartulli } 2104697f2531SAntonio Quartulli out: 2105697f2531SAntonio Quartulli return changed_num; 2106058d0e26SAntonio Quartulli } 2107058d0e26SAntonio Quartulli 2108058d0e26SAntonio Quartulli /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ 2109a513088dSSven Eckelmann static void batadv_tt_local_purge_pending_clients(struct bat_priv *bat_priv) 2110058d0e26SAntonio Quartulli { 2111058d0e26SAntonio Quartulli struct hashtable_t *hash = bat_priv->tt_local_hash; 211248100bacSAntonio Quartulli struct tt_common_entry *tt_common_entry; 2113058d0e26SAntonio Quartulli struct tt_local_entry *tt_local_entry; 2114058d0e26SAntonio Quartulli struct hlist_node *node, *node_tmp; 2115058d0e26SAntonio Quartulli struct hlist_head *head; 2116058d0e26SAntonio Quartulli spinlock_t *list_lock; /* protects write access to the hash lists */ 2117c90681b8SAntonio Quartulli uint32_t i; 2118058d0e26SAntonio Quartulli 2119058d0e26SAntonio Quartulli if (!hash) 2120058d0e26SAntonio Quartulli return; 2121058d0e26SAntonio Quartulli 2122058d0e26SAntonio Quartulli for (i = 0; i < hash->size; i++) { 2123058d0e26SAntonio Quartulli head = &hash->table[i]; 2124058d0e26SAntonio Quartulli list_lock = &hash->list_locks[i]; 2125058d0e26SAntonio Quartulli 2126058d0e26SAntonio Quartulli spin_lock_bh(list_lock); 212748100bacSAntonio Quartulli hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, 2128058d0e26SAntonio Quartulli head, hash_entry) { 212948100bacSAntonio Quartulli if (!(tt_common_entry->flags & TT_CLIENT_PENDING)) 2130058d0e26SAntonio Quartulli continue; 2131058d0e26SAntonio Quartulli 21321eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 213386ceb360SSven Eckelmann "Deleting local tt entry (%pM): pending\n", 213486ceb360SSven Eckelmann tt_common_entry->addr); 2135058d0e26SAntonio Quartulli 2136058d0e26SAntonio Quartulli atomic_dec(&bat_priv->num_local_tt); 2137058d0e26SAntonio Quartulli hlist_del_rcu(node); 213848100bacSAntonio Quartulli tt_local_entry = container_of(tt_common_entry, 213948100bacSAntonio Quartulli struct tt_local_entry, 214048100bacSAntonio Quartulli common); 2141a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 2142058d0e26SAntonio Quartulli } 2143058d0e26SAntonio Quartulli spin_unlock_bh(list_lock); 2144058d0e26SAntonio Quartulli } 2145058d0e26SAntonio Quartulli 2146058d0e26SAntonio Quartulli } 2147058d0e26SAntonio Quartulli 2148a513088dSSven Eckelmann static int batadv_tt_commit_changes(struct bat_priv *bat_priv, 2149a513088dSSven Eckelmann unsigned char **packet_buff, 2150a513088dSSven Eckelmann int *packet_buff_len, int packet_min_len) 2151058d0e26SAntonio Quartulli { 2152be9aa4c1SMarek Lindner uint16_t changed_num = 0; 2153be9aa4c1SMarek Lindner 2154be9aa4c1SMarek Lindner if (atomic_read(&bat_priv->tt_local_changes) < 1) 2155be9aa4c1SMarek Lindner return -ENOENT; 2156be9aa4c1SMarek Lindner 2157a513088dSSven Eckelmann changed_num = batadv_tt_set_flags(bat_priv->tt_local_hash, 2158697f2531SAntonio Quartulli TT_CLIENT_NEW, false); 2159be9aa4c1SMarek Lindner 2160be9aa4c1SMarek Lindner /* all reset entries have to be counted as local entries */ 2161697f2531SAntonio Quartulli atomic_add(changed_num, &bat_priv->num_local_tt); 2162a513088dSSven Eckelmann batadv_tt_local_purge_pending_clients(bat_priv); 2163be9aa4c1SMarek Lindner bat_priv->tt_crc = batadv_tt_local_crc(bat_priv); 2164058d0e26SAntonio Quartulli 2165058d0e26SAntonio Quartulli /* Increment the TTVN only once per OGM interval */ 2166058d0e26SAntonio Quartulli atomic_inc(&bat_priv->ttvn); 21671eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 21681eda58bfSSven Eckelmann "Local changes committed, updating to ttvn %u\n", 2169db08e6e5SSimon Wunderlich (uint8_t)atomic_read(&bat_priv->ttvn)); 2170058d0e26SAntonio Quartulli bat_priv->tt_poss_change = false; 2171be9aa4c1SMarek Lindner 2172be9aa4c1SMarek Lindner /* reset the sending counter */ 2173be9aa4c1SMarek Lindner atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX); 2174be9aa4c1SMarek Lindner 2175a513088dSSven Eckelmann return batadv_tt_changes_fill_buff(bat_priv, packet_buff, 2176be9aa4c1SMarek Lindner packet_buff_len, packet_min_len); 2177be9aa4c1SMarek Lindner } 2178be9aa4c1SMarek Lindner 2179be9aa4c1SMarek Lindner /* when calling this function (hard_iface == primary_if) has to be true */ 2180be9aa4c1SMarek Lindner int batadv_tt_append_diff(struct bat_priv *bat_priv, 2181be9aa4c1SMarek Lindner unsigned char **packet_buff, int *packet_buff_len, 2182be9aa4c1SMarek Lindner int packet_min_len) 2183be9aa4c1SMarek Lindner { 2184be9aa4c1SMarek Lindner int tt_num_changes; 2185be9aa4c1SMarek Lindner 2186be9aa4c1SMarek Lindner /* if at least one change happened */ 2187a513088dSSven Eckelmann tt_num_changes = batadv_tt_commit_changes(bat_priv, packet_buff, 2188a513088dSSven Eckelmann packet_buff_len, 2189a513088dSSven Eckelmann packet_min_len); 2190be9aa4c1SMarek Lindner 2191be9aa4c1SMarek Lindner /* if the changes have been sent often enough */ 2192be9aa4c1SMarek Lindner if ((tt_num_changes < 0) && 21933e34819eSSven Eckelmann (!batadv_atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))) { 2194a513088dSSven Eckelmann batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, 2195be9aa4c1SMarek Lindner packet_min_len, packet_min_len); 2196be9aa4c1SMarek Lindner tt_num_changes = 0; 2197be9aa4c1SMarek Lindner } 2198be9aa4c1SMarek Lindner 2199be9aa4c1SMarek Lindner return tt_num_changes; 2200058d0e26SAntonio Quartulli } 220159b699cdSAntonio Quartulli 220208c36d3eSSven Eckelmann bool batadv_is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, 220308c36d3eSSven Eckelmann uint8_t *dst) 220459b699cdSAntonio Quartulli { 220559b699cdSAntonio Quartulli struct tt_local_entry *tt_local_entry = NULL; 220659b699cdSAntonio Quartulli struct tt_global_entry *tt_global_entry = NULL; 22075870adc6SMarek Lindner bool ret = false; 220859b699cdSAntonio Quartulli 220959b699cdSAntonio Quartulli if (!atomic_read(&bat_priv->ap_isolation)) 22105870adc6SMarek Lindner goto out; 221159b699cdSAntonio Quartulli 2212a513088dSSven Eckelmann tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst); 221359b699cdSAntonio Quartulli if (!tt_local_entry) 221459b699cdSAntonio Quartulli goto out; 221559b699cdSAntonio Quartulli 2216a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, src); 221759b699cdSAntonio Quartulli if (!tt_global_entry) 221859b699cdSAntonio Quartulli goto out; 221959b699cdSAntonio Quartulli 22201f129fefSAntonio Quartulli if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) 222159b699cdSAntonio Quartulli goto out; 222259b699cdSAntonio Quartulli 22235870adc6SMarek Lindner ret = true; 222459b699cdSAntonio Quartulli 222559b699cdSAntonio Quartulli out: 222659b699cdSAntonio Quartulli if (tt_global_entry) 2227a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 222859b699cdSAntonio Quartulli if (tt_local_entry) 2229a513088dSSven Eckelmann batadv_tt_local_entry_free_ref(tt_local_entry); 223059b699cdSAntonio Quartulli return ret; 223159b699cdSAntonio Quartulli } 2232a943cac1SMarek Lindner 223308c36d3eSSven Eckelmann void batadv_tt_update_orig(struct bat_priv *bat_priv, 223408c36d3eSSven Eckelmann struct orig_node *orig_node, 2235a943cac1SMarek Lindner const unsigned char *tt_buff, uint8_t tt_num_changes, 2236a943cac1SMarek Lindner uint8_t ttvn, uint16_t tt_crc) 2237a943cac1SMarek Lindner { 2238a943cac1SMarek Lindner uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); 2239a943cac1SMarek Lindner bool full_table = true; 2240a943cac1SMarek Lindner 224120ff9d59SSimon Wunderlich /* don't care about a backbone gateways updates. */ 224208adf151SSven Eckelmann if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) 224320ff9d59SSimon Wunderlich return; 224420ff9d59SSimon Wunderlich 224517071578SAntonio Quartulli /* orig table not initialised AND first diff is in the OGM OR the ttvn 22469cfc7bd6SSven Eckelmann * increased by one -> we can apply the attached changes 22479cfc7bd6SSven Eckelmann */ 224817071578SAntonio Quartulli if ((!orig_node->tt_initialised && ttvn == 1) || 224917071578SAntonio Quartulli ttvn - orig_ttvn == 1) { 2250a943cac1SMarek Lindner /* the OGM could not contain the changes due to their size or 2251a943cac1SMarek Lindner * because they have already been sent TT_OGM_APPEND_MAX times. 22529cfc7bd6SSven Eckelmann * In this case send a tt request 22539cfc7bd6SSven Eckelmann */ 2254a943cac1SMarek Lindner if (!tt_num_changes) { 2255a943cac1SMarek Lindner full_table = false; 2256a943cac1SMarek Lindner goto request_table; 2257a943cac1SMarek Lindner } 2258a943cac1SMarek Lindner 2259a513088dSSven Eckelmann batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 2260a513088dSSven Eckelmann ttvn, (struct tt_change *)tt_buff); 2261a943cac1SMarek Lindner 2262a943cac1SMarek Lindner /* Even if we received the precomputed crc with the OGM, we 2263a943cac1SMarek Lindner * prefer to recompute it to spot any possible inconsistency 22649cfc7bd6SSven Eckelmann * in the global table 22659cfc7bd6SSven Eckelmann */ 2266a513088dSSven Eckelmann orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 2267a943cac1SMarek Lindner 2268a943cac1SMarek Lindner /* The ttvn alone is not enough to guarantee consistency 2269a943cac1SMarek Lindner * because a single value could represent different states 2270a943cac1SMarek Lindner * (due to the wrap around). Thus a node has to check whether 2271a943cac1SMarek Lindner * the resulting table (after applying the changes) is still 2272a943cac1SMarek Lindner * consistent or not. E.g. a node could disconnect while its 2273a943cac1SMarek Lindner * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case 2274a943cac1SMarek Lindner * checking the CRC value is mandatory to detect the 22759cfc7bd6SSven Eckelmann * inconsistency 22769cfc7bd6SSven Eckelmann */ 2277a943cac1SMarek Lindner if (orig_node->tt_crc != tt_crc) 2278a943cac1SMarek Lindner goto request_table; 2279a943cac1SMarek Lindner 2280a943cac1SMarek Lindner /* Roaming phase is over: tables are in sync again. I can 22819cfc7bd6SSven Eckelmann * unset the flag 22829cfc7bd6SSven Eckelmann */ 2283a943cac1SMarek Lindner orig_node->tt_poss_change = false; 2284a943cac1SMarek Lindner } else { 2285a943cac1SMarek Lindner /* if we missed more than one change or our tables are not 22869cfc7bd6SSven Eckelmann * in sync anymore -> request fresh tt data 22879cfc7bd6SSven Eckelmann */ 228817071578SAntonio Quartulli if (!orig_node->tt_initialised || ttvn != orig_ttvn || 228917071578SAntonio Quartulli orig_node->tt_crc != tt_crc) { 2290a943cac1SMarek Lindner request_table: 22911eda58bfSSven Eckelmann batadv_dbg(DBG_TT, bat_priv, 229286ceb360SSven 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", 229386ceb360SSven Eckelmann orig_node->orig, ttvn, orig_ttvn, tt_crc, 229486ceb360SSven Eckelmann orig_node->tt_crc, tt_num_changes); 2295a513088dSSven Eckelmann batadv_send_tt_request(bat_priv, orig_node, ttvn, 2296a513088dSSven Eckelmann tt_crc, full_table); 2297a943cac1SMarek Lindner return; 2298a943cac1SMarek Lindner } 2299a943cac1SMarek Lindner } 2300a943cac1SMarek Lindner } 23013275e7ccSAntonio Quartulli 23023275e7ccSAntonio Quartulli /* returns true whether we know that the client has moved from its old 23033275e7ccSAntonio Quartulli * originator to another one. This entry is kept is still kept for consistency 23043275e7ccSAntonio Quartulli * purposes 23053275e7ccSAntonio Quartulli */ 230608c36d3eSSven Eckelmann bool batadv_tt_global_client_is_roaming(struct bat_priv *bat_priv, 230708c36d3eSSven Eckelmann uint8_t *addr) 23083275e7ccSAntonio Quartulli { 23093275e7ccSAntonio Quartulli struct tt_global_entry *tt_global_entry; 23103275e7ccSAntonio Quartulli bool ret = false; 23113275e7ccSAntonio Quartulli 2312a513088dSSven Eckelmann tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); 23133275e7ccSAntonio Quartulli if (!tt_global_entry) 23143275e7ccSAntonio Quartulli goto out; 23153275e7ccSAntonio Quartulli 23163275e7ccSAntonio Quartulli ret = tt_global_entry->common.flags & TT_CLIENT_ROAM; 2317a513088dSSven Eckelmann batadv_tt_global_entry_free_ref(tt_global_entry); 23183275e7ccSAntonio Quartulli out: 23193275e7ccSAntonio Quartulli return ret; 23203275e7ccSAntonio Quartulli } 2321