aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/packet.h4
-rw-r--r--net/batman-adv/send.c4
-rw-r--r--net/batman-adv/translation-table.c146
-rw-r--r--net/batman-adv/translation-table.h1
4 files changed, 125 insertions, 30 deletions
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index 590e4a66089f..b76b4be10b92 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -84,7 +84,9 @@ enum tt_query_flags {
84enum tt_client_flags { 84enum tt_client_flags {
85 TT_CLIENT_DEL = 1 << 0, 85 TT_CLIENT_DEL = 1 << 0,
86 TT_CLIENT_ROAM = 1 << 1, 86 TT_CLIENT_ROAM = 1 << 1,
87 TT_CLIENT_NOPURGE = 1 << 8 87 TT_CLIENT_NOPURGE = 1 << 8,
88 TT_CLIENT_NEW = 1 << 9,
89 TT_CLIENT_PENDING = 1 << 10
88}; 90};
89 91
90struct batman_packet { 92struct batman_packet {
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 4b8e11bc14fa..58d14472068c 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -309,10 +309,8 @@ void schedule_own_packet(struct hard_iface *hard_iface)
309 if (hard_iface == primary_if) { 309 if (hard_iface == primary_if) {
310 /* if at least one change happened */ 310 /* if at least one change happened */
311 if (atomic_read(&bat_priv->tt_local_changes) > 0) { 311 if (atomic_read(&bat_priv->tt_local_changes) > 0) {
312 tt_commit_changes(bat_priv);
312 prepare_packet_buffer(bat_priv, hard_iface); 313 prepare_packet_buffer(bat_priv, hard_iface);
313 /* Increment the TTVN only once per OGM interval */
314 atomic_inc(&bat_priv->ttvn);
315 bat_priv->tt_poss_change = false;
316 } 314 }
317 315
318 /* if the changes have been sent enough times */ 316 /* if the changes have been sent enough times */
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 06d361d4ac4b..7cc67c0f4915 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -215,11 +215,14 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
215 215
216 tt_local_event(bat_priv, addr, tt_local_entry->flags); 216 tt_local_event(bat_priv, addr, tt_local_entry->flags);
217 217
218 /* The local entry has to be marked as NEW to avoid to send it in
219 * a full table response going out before the next ttvn increment
220 * (consistency check) */
221 tt_local_entry->flags |= TT_CLIENT_NEW;
222
218 hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, 223 hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
219 tt_local_entry, &tt_local_entry->hash_entry); 224 tt_local_entry, &tt_local_entry->hash_entry);
220 225
221 atomic_inc(&bat_priv->num_local_tt);
222
223 /* remove address from global hash if present */ 226 /* remove address from global hash if present */
224 tt_global_entry = tt_global_hash_find(bat_priv, addr); 227 tt_global_entry = tt_global_hash_find(bat_priv, addr);
225 228
@@ -358,19 +361,17 @@ out:
358 return ret; 361 return ret;
359} 362}
360 363
361static void tt_local_del(struct bat_priv *bat_priv, 364static void tt_local_set_pending(struct bat_priv *bat_priv,
362 struct tt_local_entry *tt_local_entry, 365 struct tt_local_entry *tt_local_entry,
363 const char *message) 366 uint16_t flags)
364{ 367{
365 bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n", 368 tt_local_event(bat_priv, tt_local_entry->addr,
366 tt_local_entry->addr, message); 369 tt_local_entry->flags | flags);
367
368 atomic_dec(&bat_priv->num_local_tt);
369
370 hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
371 tt_local_entry->addr);
372 370
373 tt_local_entry_free_ref(tt_local_entry); 371 /* The local client has to be merked as "pending to be removed" but has
372 * to be kept in the table in order to send it in an full tables
373 * response issued before the net ttvn increment (consistency check) */
374 tt_local_entry->flags |= TT_CLIENT_PENDING;
374} 375}
375 376
376void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, 377void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
@@ -379,14 +380,14 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
379 struct tt_local_entry *tt_local_entry = NULL; 380 struct tt_local_entry *tt_local_entry = NULL;
380 381
381 tt_local_entry = tt_local_hash_find(bat_priv, addr); 382 tt_local_entry = tt_local_hash_find(bat_priv, addr);
382
383 if (!tt_local_entry) 383 if (!tt_local_entry)
384 goto out; 384 goto out;
385 385
386 tt_local_event(bat_priv, tt_local_entry->addr, 386 tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
387 tt_local_entry->flags | TT_CLIENT_DEL | 387 (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
388 (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); 388
389 tt_local_del(bat_priv, tt_local_entry, message); 389 bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
390 "%s\n", tt_local_entry->addr, message);
390out: 391out:
391 if (tt_local_entry) 392 if (tt_local_entry)
392 tt_local_entry_free_ref(tt_local_entry); 393 tt_local_entry_free_ref(tt_local_entry);
@@ -411,18 +412,19 @@ static void tt_local_purge(struct bat_priv *bat_priv)
411 if (tt_local_entry->flags & TT_CLIENT_NOPURGE) 412 if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
412 continue; 413 continue;
413 414
415 /* entry already marked for deletion */
416 if (tt_local_entry->flags & TT_CLIENT_PENDING)
417 continue;
418
414 if (!is_out_of_time(tt_local_entry->last_seen, 419 if (!is_out_of_time(tt_local_entry->last_seen,
415 TT_LOCAL_TIMEOUT * 1000)) 420 TT_LOCAL_TIMEOUT * 1000))
416 continue; 421 continue;
417 422
418 tt_local_event(bat_priv, tt_local_entry->addr, 423 tt_local_set_pending(bat_priv, tt_local_entry,
419 tt_local_entry->flags | TT_CLIENT_DEL); 424 TT_CLIENT_DEL);
420 atomic_dec(&bat_priv->num_local_tt); 425 bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
421 bat_dbg(DBG_TT, bat_priv, "Deleting local " 426 "pending to be removed: timed out\n",
422 "tt entry (%pM): timed out\n",
423 tt_local_entry->addr); 427 tt_local_entry->addr);
424 hlist_del_rcu(node);
425 tt_local_entry_free_ref(tt_local_entry);
426 } 428 }
427 spin_unlock_bh(list_lock); 429 spin_unlock_bh(list_lock);
428 } 430 }
@@ -846,6 +848,10 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv)
846 rcu_read_lock(); 848 rcu_read_lock();
847 hlist_for_each_entry_rcu(tt_local_entry, node, 849 hlist_for_each_entry_rcu(tt_local_entry, node,
848 head, hash_entry) { 850 head, hash_entry) {
851 /* not yet committed clients have not to be taken into
852 * account while computing the CRC */
853 if (tt_local_entry->flags & TT_CLIENT_NEW)
854 continue;
849 total_one = 0; 855 total_one = 0;
850 for (j = 0; j < ETH_ALEN; j++) 856 for (j = 0; j < ETH_ALEN; j++)
851 total_one = crc16_byte(total_one, 857 total_one = crc16_byte(total_one,
@@ -935,6 +941,16 @@ unlock:
935 return tt_req_node; 941 return tt_req_node;
936} 942}
937 943
944/* data_ptr is useless here, but has to be kept to respect the prototype */
945static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
946{
947 const struct tt_local_entry *tt_local_entry = entry_ptr;
948
949 if (tt_local_entry->flags & TT_CLIENT_NEW)
950 return 0;
951 return 1;
952}
953
938static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) 954static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
939{ 955{
940 const struct tt_global_entry *tt_global_entry = entry_ptr; 956 const struct tt_global_entry *tt_global_entry = entry_ptr;
@@ -1275,7 +1291,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,
1275 1291
1276 skb = tt_response_fill_table(tt_len, ttvn, 1292 skb = tt_response_fill_table(tt_len, ttvn,
1277 bat_priv->tt_local_hash, 1293 bat_priv->tt_local_hash,
1278 primary_if, NULL, NULL); 1294 primary_if, tt_local_valid_entry,
1295 NULL);
1279 if (!skb) 1296 if (!skb)
1280 goto out; 1297 goto out;
1281 1298
@@ -1400,6 +1417,10 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
1400 tt_local_entry = tt_local_hash_find(bat_priv, addr); 1417 tt_local_entry = tt_local_hash_find(bat_priv, addr);
1401 if (!tt_local_entry) 1418 if (!tt_local_entry)
1402 goto out; 1419 goto out;
1420 /* Check if the client has been logically deleted (but is kept for
1421 * consistency purpose) */
1422 if (tt_local_entry->flags & TT_CLIENT_PENDING)
1423 goto out;
1403 ret = true; 1424 ret = true;
1404out: 1425out:
1405 if (tt_local_entry) 1426 if (tt_local_entry)
@@ -1620,3 +1641,76 @@ void tt_free(struct bat_priv *bat_priv)
1620 1641
1621 kfree(bat_priv->tt_buff); 1642 kfree(bat_priv->tt_buff);
1622} 1643}
1644
1645/* This function will reset the specified flags from all the entries in
1646 * the given hash table and will increment num_local_tt for each involved
1647 * entry */
1648static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
1649{
1650 int i;
1651 struct hashtable_t *hash = bat_priv->tt_local_hash;
1652 struct hlist_head *head;
1653 struct hlist_node *node;
1654 struct tt_local_entry *tt_local_entry;
1655
1656 if (!hash)
1657 return;
1658
1659 for (i = 0; i < hash->size; i++) {
1660 head = &hash->table[i];
1661
1662 rcu_read_lock();
1663 hlist_for_each_entry_rcu(tt_local_entry, node,
1664 head, hash_entry) {
1665 tt_local_entry->flags &= ~flags;
1666 atomic_inc(&bat_priv->num_local_tt);
1667 }
1668 rcu_read_unlock();
1669 }
1670
1671}
1672
1673/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
1674static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
1675{
1676 struct hashtable_t *hash = bat_priv->tt_local_hash;
1677 struct tt_local_entry *tt_local_entry;
1678 struct hlist_node *node, *node_tmp;
1679 struct hlist_head *head;
1680 spinlock_t *list_lock; /* protects write access to the hash lists */
1681 int i;
1682
1683 if (!hash)
1684 return;
1685
1686 for (i = 0; i < hash->size; i++) {
1687 head = &hash->table[i];
1688 list_lock = &hash->list_locks[i];
1689
1690 spin_lock_bh(list_lock);
1691 hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
1692 head, hash_entry) {
1693 if (!(tt_local_entry->flags & TT_CLIENT_PENDING))
1694 continue;
1695
1696 bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
1697 "(%pM): pending\n", tt_local_entry->addr);
1698
1699 atomic_dec(&bat_priv->num_local_tt);
1700 hlist_del_rcu(node);
1701 tt_local_entry_free_ref(tt_local_entry);
1702 }
1703 spin_unlock_bh(list_lock);
1704 }
1705
1706}
1707
1708void tt_commit_changes(struct bat_priv *bat_priv)
1709{
1710 tt_local_reset_flags(bat_priv, TT_CLIENT_NEW);
1711 tt_local_purge_pending_clients(bat_priv);
1712
1713 /* Increment the TTVN only once per OGM interval */
1714 atomic_inc(&bat_priv->ttvn);
1715 bat_priv->tt_poss_change = false;
1716}
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index 460e5839cdd6..d4122cba53b8 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -61,5 +61,6 @@ void handle_tt_response(struct bat_priv *bat_priv,
61 struct tt_query_packet *tt_response); 61 struct tt_query_packet *tt_response);
62void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 62void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
63 struct orig_node *orig_node); 63 struct orig_node *orig_node);
64void tt_commit_changes(struct bat_priv *bat_priv);
64 65
65#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ 66#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */