aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
authorSimon Wunderlich <siwu@hrz.tu-chemnitz.de>2011-10-22 14:12:51 -0400
committerAntonio Quartulli <ordex@autistici.org>2012-04-11 08:28:59 -0400
commitdb08e6e557ebc8ffedf6530693937d0e51b8f6b9 (patch)
treef9f5eb55dd5258e5def03f4e39f2d10145afbaa1 /net/batman-adv
parent9bf8e4d4254397684250eae29a0dc12d54a00251 (diff)
batman-adv: allow multiple entries in tt_global_entries
as backbone gateways will all independently announce the same clients, also the tt global table must be able to hold multiple originators per client entry. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/translation-table.c395
-rw-r--r--net/batman-adv/types.h9
2 files changed, 311 insertions, 93 deletions
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 5f8c540b9f17..9648b0dc57ef 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -32,10 +32,8 @@
32 32
33static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, 33static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
34 struct orig_node *orig_node); 34 struct orig_node *orig_node);
35static void _tt_global_del(struct bat_priv *bat_priv,
36 struct tt_global_entry *tt_global_entry,
37 const char *message);
38static void tt_purge(struct work_struct *work); 35static void tt_purge(struct work_struct *work);
36static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry);
39 37
40/* returns 1 if they are the same mac addr */ 38/* returns 1 if they are the same mac addr */
41static int compare_tt(const struct hlist_node *node, const void *data2) 39static int compare_tt(const struct hlist_node *node, const void *data2)
@@ -125,17 +123,31 @@ static void tt_global_entry_free_rcu(struct rcu_head *rcu)
125 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, 123 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
126 common); 124 common);
127 125
128 if (tt_global_entry->orig_node)
129 orig_node_free_ref(tt_global_entry->orig_node);
130
131 kfree(tt_global_entry); 126 kfree(tt_global_entry);
132} 127}
133 128
134static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry) 129static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
135{ 130{
136 if (atomic_dec_and_test(&tt_global_entry->common.refcount)) 131 if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
132 tt_global_del_orig_list(tt_global_entry);
137 call_rcu(&tt_global_entry->common.rcu, 133 call_rcu(&tt_global_entry->common.rcu,
138 tt_global_entry_free_rcu); 134 tt_global_entry_free_rcu);
135 }
136}
137
138static void tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
139{
140 struct tt_orig_list_entry *orig_entry;
141
142 orig_entry = container_of(rcu, struct tt_orig_list_entry, rcu);
143 atomic_dec(&orig_entry->orig_node->tt_size);
144 orig_node_free_ref(orig_entry->orig_node);
145 kfree(orig_entry);
146}
147
148static void tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry)
149{
150 call_rcu(&orig_entry->rcu, tt_orig_list_entry_free_rcu);
139} 151}
140 152
141static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr, 153static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
@@ -184,6 +196,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
184 struct bat_priv *bat_priv = netdev_priv(soft_iface); 196 struct bat_priv *bat_priv = netdev_priv(soft_iface);
185 struct tt_local_entry *tt_local_entry = NULL; 197 struct tt_local_entry *tt_local_entry = NULL;
186 struct tt_global_entry *tt_global_entry = NULL; 198 struct tt_global_entry *tt_global_entry = NULL;
199 struct hlist_head *head;
200 struct hlist_node *node;
201 struct tt_orig_list_entry *orig_entry;
187 int hash_added; 202 int hash_added;
188 203
189 tt_local_entry = tt_local_hash_find(bat_priv, addr); 204 tt_local_entry = tt_local_hash_find(bat_priv, addr);
@@ -234,14 +249,21 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
234 249
235 /* Check whether it is a roaming! */ 250 /* Check whether it is a roaming! */
236 if (tt_global_entry) { 251 if (tt_global_entry) {
237 /* This node is probably going to update its tt table */ 252 /* These node are probably going to update their tt table */
238 tt_global_entry->orig_node->tt_poss_change = true; 253 head = &tt_global_entry->orig_list;
239 /* The global entry has to be marked as ROAMING and has to be 254 rcu_read_lock();
240 * kept for consistency purpose */ 255 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
256 orig_entry->orig_node->tt_poss_change = true;
257
258 send_roam_adv(bat_priv, tt_global_entry->common.addr,
259 orig_entry->orig_node);
260 }
261 rcu_read_unlock();
262 /* The global entry has to be marked as ROAMING and
263 * has to be kept for consistency purpose
264 */
241 tt_global_entry->common.flags |= TT_CLIENT_ROAM; 265 tt_global_entry->common.flags |= TT_CLIENT_ROAM;
242 tt_global_entry->roam_at = jiffies; 266 tt_global_entry->roam_at = jiffies;
243 send_roam_adv(bat_priv, tt_global_entry->common.addr,
244 tt_global_entry->orig_node);
245 } 267 }
246out: 268out:
247 if (tt_local_entry) 269 if (tt_local_entry)
@@ -492,33 +514,76 @@ static void tt_changes_list_free(struct bat_priv *bat_priv)
492 spin_unlock_bh(&bat_priv->tt_changes_list_lock); 514 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
493} 515}
494 516
517/* find out if an orig_node is already in the list of a tt_global_entry.
518 * returns 1 if found, 0 otherwise
519 */
520static bool tt_global_entry_has_orig(const struct tt_global_entry *entry,
521 const struct orig_node *orig_node)
522{
523 struct tt_orig_list_entry *tmp_orig_entry;
524 const struct hlist_head *head;
525 struct hlist_node *node;
526 bool found = false;
527
528 rcu_read_lock();
529 head = &entry->orig_list;
530 hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) {
531 if (tmp_orig_entry->orig_node == orig_node) {
532 found = true;
533 break;
534 }
535 }
536 rcu_read_unlock();
537 return found;
538}
539
540static void tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry,
541 struct orig_node *orig_node,
542 int ttvn)
543{
544 struct tt_orig_list_entry *orig_entry;
545
546 orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
547 if (!orig_entry)
548 return;
549
550 INIT_HLIST_NODE(&orig_entry->list);
551 atomic_inc(&orig_node->refcount);
552 atomic_inc(&orig_node->tt_size);
553 orig_entry->orig_node = orig_node;
554 orig_entry->ttvn = ttvn;
555
556 spin_lock_bh(&tt_global_entry->list_lock);
557 hlist_add_head_rcu(&orig_entry->list,
558 &tt_global_entry->orig_list);
559 spin_unlock_bh(&tt_global_entry->list_lock);
560}
561
495/* caller must hold orig_node refcount */ 562/* caller must hold orig_node refcount */
496int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, 563int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
497 const unsigned char *tt_addr, uint8_t ttvn, bool roaming, 564 const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
498 bool wifi) 565 bool wifi)
499{ 566{
500 struct tt_global_entry *tt_global_entry; 567 struct tt_global_entry *tt_global_entry = NULL;
501 struct orig_node *orig_node_tmp;
502 int ret = 0; 568 int ret = 0;
503 int hash_added; 569 int hash_added;
504 570
505 tt_global_entry = tt_global_hash_find(bat_priv, tt_addr); 571 tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
506 572
507 if (!tt_global_entry) { 573 if (!tt_global_entry) {
508 tt_global_entry = 574 tt_global_entry = kzalloc(sizeof(*tt_global_entry),
509 kmalloc(sizeof(*tt_global_entry), 575 GFP_ATOMIC);
510 GFP_ATOMIC);
511 if (!tt_global_entry) 576 if (!tt_global_entry)
512 goto out; 577 goto out;
513 578
514 memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN); 579 memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
580
515 tt_global_entry->common.flags = NO_FLAGS; 581 tt_global_entry->common.flags = NO_FLAGS;
516 atomic_set(&tt_global_entry->common.refcount, 2);
517 /* Assign the new orig_node */
518 atomic_inc(&orig_node->refcount);
519 tt_global_entry->orig_node = orig_node;
520 tt_global_entry->ttvn = ttvn;
521 tt_global_entry->roam_at = 0; 582 tt_global_entry->roam_at = 0;
583 atomic_set(&tt_global_entry->common.refcount, 2);
584
585 INIT_HLIST_HEAD(&tt_global_entry->orig_list);
586 spin_lock_init(&tt_global_entry->list_lock);
522 587
523 hash_added = hash_add(bat_priv->tt_global_hash, compare_tt, 588 hash_added = hash_add(bat_priv->tt_global_hash, compare_tt,
524 choose_orig, &tt_global_entry->common, 589 choose_orig, &tt_global_entry->common,
@@ -529,19 +594,27 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
529 tt_global_entry_free_ref(tt_global_entry); 594 tt_global_entry_free_ref(tt_global_entry);
530 goto out_remove; 595 goto out_remove;
531 } 596 }
532 atomic_inc(&orig_node->tt_size); 597
598 tt_global_add_orig_entry(tt_global_entry, orig_node, ttvn);
533 } else { 599 } else {
534 if (tt_global_entry->orig_node != orig_node) { 600 /* there is already a global entry, use this one. */
535 atomic_dec(&tt_global_entry->orig_node->tt_size); 601
536 orig_node_tmp = tt_global_entry->orig_node; 602 /* If there is the TT_CLIENT_ROAM flag set, there is only one
537 atomic_inc(&orig_node->refcount); 603 * originator left in the list and we previously received a
538 tt_global_entry->orig_node = orig_node; 604 * delete + roaming change for this originator.
539 orig_node_free_ref(orig_node_tmp); 605 *
540 atomic_inc(&orig_node->tt_size); 606 * We should first delete the old originator before adding the
607 * new one.
608 */
609 if (tt_global_entry->common.flags & TT_CLIENT_ROAM) {
610 tt_global_del_orig_list(tt_global_entry);
611 tt_global_entry->common.flags &= ~TT_CLIENT_ROAM;
612 tt_global_entry->roam_at = 0;
541 } 613 }
542 tt_global_entry->common.flags = NO_FLAGS; 614
543 tt_global_entry->ttvn = ttvn; 615 if (!tt_global_entry_has_orig(tt_global_entry, orig_node))
544 tt_global_entry->roam_at = 0; 616 tt_global_add_orig_entry(tt_global_entry, orig_node,
617 ttvn);
545 } 618 }
546 619
547 if (wifi) 620 if (wifi)
@@ -562,6 +635,34 @@ out:
562 return ret; 635 return ret;
563} 636}
564 637
638/* print all orig nodes who announce the address for this global entry.
639 * it is assumed that the caller holds rcu_read_lock();
640 */
641static void tt_global_print_entry(struct tt_global_entry *tt_global_entry,
642 struct seq_file *seq)
643{
644 struct hlist_head *head;
645 struct hlist_node *node;
646 struct tt_orig_list_entry *orig_entry;
647 struct tt_common_entry *tt_common_entry;
648 uint16_t flags;
649 uint8_t last_ttvn;
650
651 tt_common_entry = &tt_global_entry->common;
652
653 head = &tt_global_entry->orig_list;
654
655 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
656 flags = tt_common_entry->flags;
657 last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
658 seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n",
659 tt_global_entry->common.addr, orig_entry->ttvn,
660 orig_entry->orig_node->orig, last_ttvn,
661 (flags & TT_CLIENT_ROAM ? 'R' : '.'),
662 (flags & TT_CLIENT_WIFI ? 'W' : '.'));
663 }
664}
665
565int tt_global_seq_print_text(struct seq_file *seq, void *offset) 666int tt_global_seq_print_text(struct seq_file *seq, void *offset)
566{ 667{
567 struct net_device *net_dev = (struct net_device *)seq->private; 668 struct net_device *net_dev = (struct net_device *)seq->private;
@@ -605,18 +706,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
605 tt_global_entry = container_of(tt_common_entry, 706 tt_global_entry = container_of(tt_common_entry,
606 struct tt_global_entry, 707 struct tt_global_entry,
607 common); 708 common);
608 seq_printf(seq, 709 tt_global_print_entry(tt_global_entry, seq);
609 " * %pM (%3u) via %pM (%3u) [%c%c]\n",
610 tt_global_entry->common.addr,
611 tt_global_entry->ttvn,
612 tt_global_entry->orig_node->orig,
613 (uint8_t) atomic_read(
614 &tt_global_entry->orig_node->
615 last_ttvn),
616 (tt_global_entry->common.flags &
617 TT_CLIENT_ROAM ? 'R' : '.'),
618 (tt_global_entry->common.flags &
619 TT_CLIENT_WIFI ? 'W' : '.'));
620 } 710 }
621 rcu_read_unlock(); 711 rcu_read_unlock();
622 } 712 }
@@ -626,27 +716,103 @@ out:
626 return ret; 716 return ret;
627} 717}
628 718
629static void _tt_global_del(struct bat_priv *bat_priv, 719/* deletes the orig list of a tt_global_entry */
630 struct tt_global_entry *tt_global_entry, 720static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry)
631 const char *message)
632{ 721{
633 if (!tt_global_entry) 722 struct hlist_head *head;
634 goto out; 723 struct hlist_node *node, *safe;
724 struct tt_orig_list_entry *orig_entry;
635 725
636 bat_dbg(DBG_TT, bat_priv, 726 spin_lock_bh(&tt_global_entry->list_lock);
637 "Deleting global tt entry %pM (via %pM): %s\n", 727 head = &tt_global_entry->orig_list;
638 tt_global_entry->common.addr, tt_global_entry->orig_node->orig, 728 hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
639 message); 729 hlist_del_rcu(node);
730 tt_orig_list_entry_free_ref(orig_entry);
731 }
732 spin_unlock_bh(&tt_global_entry->list_lock);
640 733
641 atomic_dec(&tt_global_entry->orig_node->tt_size); 734}
735
736static void tt_global_del_orig_entry(struct bat_priv *bat_priv,
737 struct tt_global_entry *tt_global_entry,
738 struct orig_node *orig_node,
739 const char *message)
740{
741 struct hlist_head *head;
742 struct hlist_node *node, *safe;
743 struct tt_orig_list_entry *orig_entry;
744
745 spin_lock_bh(&tt_global_entry->list_lock);
746 head = &tt_global_entry->orig_list;
747 hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
748 if (orig_entry->orig_node == orig_node) {
749 bat_dbg(DBG_TT, bat_priv,
750 "Deleting %pM from global tt entry %pM: %s\n",
751 orig_node->orig, tt_global_entry->common.addr,
752 message);
753 hlist_del_rcu(node);
754 tt_orig_list_entry_free_ref(orig_entry);
755 }
756 }
757 spin_unlock_bh(&tt_global_entry->list_lock);
758}
759
760static void tt_global_del_struct(struct bat_priv *bat_priv,
761 struct tt_global_entry *tt_global_entry,
762 const char *message)
763{
764 bat_dbg(DBG_TT, bat_priv,
765 "Deleting global tt entry %pM: %s\n",
766 tt_global_entry->common.addr, message);
642 767
643 hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig, 768 hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
644 tt_global_entry->common.addr); 769 tt_global_entry->common.addr);
645out: 770 tt_global_entry_free_ref(tt_global_entry);
646 if (tt_global_entry) 771
647 tt_global_entry_free_ref(tt_global_entry);
648} 772}
649 773
774/* If the client is to be deleted, we check if it is the last origantor entry
775 * within tt_global entry. If yes, we set the TT_CLIENT_ROAM flag and the timer,
776 * otherwise we simply remove the originator scheduled for deletion.
777 */
778static void tt_global_del_roaming(struct bat_priv *bat_priv,
779 struct tt_global_entry *tt_global_entry,
780 struct orig_node *orig_node,
781 const char *message)
782{
783 bool last_entry = true;
784 struct hlist_head *head;
785 struct hlist_node *node;
786 struct tt_orig_list_entry *orig_entry;
787
788 /* no local entry exists, case 1:
789 * Check if this is the last one or if other entries exist.
790 */
791
792 rcu_read_lock();
793 head = &tt_global_entry->orig_list;
794 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
795 if (orig_entry->orig_node != orig_node) {
796 last_entry = false;
797 break;
798 }
799 }
800 rcu_read_unlock();
801
802 if (last_entry) {
803 /* its the last one, mark for roaming. */
804 tt_global_entry->common.flags |= TT_CLIENT_ROAM;
805 tt_global_entry->roam_at = jiffies;
806 } else
807 /* there is another entry, we can simply delete this
808 * one and can still use the other one.
809 */
810 tt_global_del_orig_entry(bat_priv, tt_global_entry,
811 orig_node, message);
812}
813
814
815
650static void tt_global_del(struct bat_priv *bat_priv, 816static void tt_global_del(struct bat_priv *bat_priv,
651 struct orig_node *orig_node, 817 struct orig_node *orig_node,
652 const unsigned char *addr, 818 const unsigned char *addr,
@@ -656,30 +822,44 @@ static void tt_global_del(struct bat_priv *bat_priv,
656 struct tt_local_entry *tt_local_entry = NULL; 822 struct tt_local_entry *tt_local_entry = NULL;
657 823
658 tt_global_entry = tt_global_hash_find(bat_priv, addr); 824 tt_global_entry = tt_global_hash_find(bat_priv, addr);
659 if (!tt_global_entry || tt_global_entry->orig_node != orig_node) 825 if (!tt_global_entry)
660 goto out; 826 goto out;
661 827
662 if (!roaming) 828 if (!roaming) {
663 goto out_del; 829 tt_global_del_orig_entry(bat_priv, tt_global_entry, orig_node,
830 message);
831
832 if (hlist_empty(&tt_global_entry->orig_list))
833 tt_global_del_struct(bat_priv, tt_global_entry,
834 message);
835
836 goto out;
837 }
664 838
665 /* if we are deleting a global entry due to a roam 839 /* if we are deleting a global entry due to a roam
666 * event, there are two possibilities: 840 * event, there are two possibilities:
667 * 1) the client roamed from node A to node B => we mark 841 * 1) the client roamed from node A to node B => if there
842 * is only one originator left for this client, we mark
668 * it with TT_CLIENT_ROAM, we start a timer and we 843 * it with TT_CLIENT_ROAM, we start a timer and we
669 * wait for node B to claim it. In case of timeout 844 * wait for node B to claim it. In case of timeout
670 * the entry is purged. 845 * the entry is purged.
846 *
847 * If there are other originators left, we directly delete
848 * the originator.
671 * 2) the client roamed to us => we can directly delete 849 * 2) the client roamed to us => we can directly delete
672 * the global entry, since it is useless now. */ 850 * the global entry, since it is useless now. */
851
673 tt_local_entry = tt_local_hash_find(bat_priv, 852 tt_local_entry = tt_local_hash_find(bat_priv,
674 tt_global_entry->common.addr); 853 tt_global_entry->common.addr);
675 if (!tt_local_entry) { 854 if (tt_local_entry) {
676 tt_global_entry->common.flags |= TT_CLIENT_ROAM; 855 /* local entry exists, case 2: client roamed to us. */
677 tt_global_entry->roam_at = jiffies; 856 tt_global_del_orig_list(tt_global_entry);
678 goto out; 857 tt_global_del_struct(bat_priv, tt_global_entry, message);
679 } 858 } else
859 /* no local entry exists, case 1: check for roaming */
860 tt_global_del_roaming(bat_priv, tt_global_entry, orig_node,
861 message);
680 862
681out_del:
682 _tt_global_del(bat_priv, tt_global_entry, message);
683 863
684out: 864out:
685 if (tt_global_entry) 865 if (tt_global_entry)
@@ -712,11 +892,14 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
712 tt_global_entry = container_of(tt_common_entry, 892 tt_global_entry = container_of(tt_common_entry,
713 struct tt_global_entry, 893 struct tt_global_entry,
714 common); 894 common);
715 if (tt_global_entry->orig_node == orig_node) { 895
896 tt_global_del_orig_entry(bat_priv, tt_global_entry,
897 orig_node, message);
898
899 if (hlist_empty(&tt_global_entry->orig_list)) {
716 bat_dbg(DBG_TT, bat_priv, 900 bat_dbg(DBG_TT, bat_priv,
717 "Deleting global tt entry %pM (via %pM): %s\n", 901 "Deleting global tt entry %pM: %s\n",
718 tt_global_entry->common.addr, 902 tt_global_entry->common.addr,
719 tt_global_entry->orig_node->orig,
720 message); 903 message);
721 hlist_del_rcu(node); 904 hlist_del_rcu(node);
722 tt_global_entry_free_ref(tt_global_entry); 905 tt_global_entry_free_ref(tt_global_entry);
@@ -757,7 +940,7 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv)
757 bat_dbg(DBG_TT, bat_priv, 940 bat_dbg(DBG_TT, bat_priv,
758 "Deleting global tt entry (%pM): Roaming timeout\n", 941 "Deleting global tt entry (%pM): Roaming timeout\n",
759 tt_global_entry->common.addr); 942 tt_global_entry->common.addr);
760 atomic_dec(&tt_global_entry->orig_node->tt_size); 943
761 hlist_del_rcu(node); 944 hlist_del_rcu(node);
762 tt_global_entry_free_ref(tt_global_entry); 945 tt_global_entry_free_ref(tt_global_entry);
763 } 946 }
@@ -820,6 +1003,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
820 struct tt_local_entry *tt_local_entry = NULL; 1003 struct tt_local_entry *tt_local_entry = NULL;
821 struct tt_global_entry *tt_global_entry = NULL; 1004 struct tt_global_entry *tt_global_entry = NULL;
822 struct orig_node *orig_node = NULL; 1005 struct orig_node *orig_node = NULL;
1006 struct neigh_node *router = NULL;
1007 struct hlist_head *head;
1008 struct hlist_node *node;
1009 struct tt_orig_list_entry *orig_entry;
1010 int best_tq;
823 1011
824 if (src && atomic_read(&bat_priv->ap_isolation)) { 1012 if (src && atomic_read(&bat_priv->ap_isolation)) {
825 tt_local_entry = tt_local_hash_find(bat_priv, src); 1013 tt_local_entry = tt_local_hash_find(bat_priv, src);
@@ -836,11 +1024,25 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
836 if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry)) 1024 if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
837 goto out; 1025 goto out;
838 1026
839 if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) 1027 best_tq = 0;
840 goto out;
841 1028
842 orig_node = tt_global_entry->orig_node; 1029 rcu_read_lock();
1030 head = &tt_global_entry->orig_list;
1031 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
1032 router = orig_node_get_router(orig_entry->orig_node);
1033 if (!router)
1034 continue;
843 1035
1036 if (router->tq_avg > best_tq) {
1037 orig_node = orig_entry->orig_node;
1038 best_tq = router->tq_avg;
1039 }
1040 neigh_node_free_ref(router);
1041 }
1042 /* found anything? */
1043 if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
1044 orig_node = NULL;
1045 rcu_read_unlock();
844out: 1046out:
845 if (tt_global_entry) 1047 if (tt_global_entry)
846 tt_global_entry_free_ref(tt_global_entry); 1048 tt_global_entry_free_ref(tt_global_entry);
@@ -872,20 +1074,26 @@ static uint16_t tt_global_crc(struct bat_priv *bat_priv,
872 tt_global_entry = container_of(tt_common_entry, 1074 tt_global_entry = container_of(tt_common_entry,
873 struct tt_global_entry, 1075 struct tt_global_entry,
874 common); 1076 common);
875 if (compare_eth(tt_global_entry->orig_node, 1077 /* Roaming clients are in the global table for
876 orig_node)) { 1078 * consistency only. They don't have to be
877 /* Roaming clients are in the global table for 1079 * taken into account while computing the
878 * consistency only. They don't have to be 1080 * global crc
879 * taken into account while computing the 1081 */
880 * global crc */ 1082 if (tt_global_entry->common.flags & TT_CLIENT_ROAM)
881 if (tt_common_entry->flags & TT_CLIENT_ROAM) 1083 continue;
882 continue; 1084
883 total_one = 0; 1085 /* find out if this global entry is announced by this
884 for (j = 0; j < ETH_ALEN; j++) 1086 * originator
885 total_one = crc16_byte(total_one, 1087 */
886 tt_common_entry->addr[j]); 1088 if (!tt_global_entry_has_orig(tt_global_entry,
887 total ^= total_one; 1089 orig_node))
888 } 1090 continue;
1091
1092 total_one = 0;
1093 for (j = 0; j < ETH_ALEN; j++)
1094 total_one = crc16_byte(total_one,
1095 tt_global_entry->common.addr[j]);
1096 total ^= total_one;
889 } 1097 }
890 rcu_read_unlock(); 1098 rcu_read_unlock();
891 } 1099 }
@@ -1026,7 +1234,7 @@ static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
1026 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, 1234 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
1027 common); 1235 common);
1028 1236
1029 return (tt_global_entry->orig_node == orig_node); 1237 return tt_global_entry_has_orig(tt_global_entry, orig_node);
1030} 1238}
1031 1239
1032static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, 1240static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
@@ -1802,6 +2010,8 @@ void tt_commit_changes(struct bat_priv *bat_priv)
1802 2010
1803 /* Increment the TTVN only once per OGM interval */ 2011 /* Increment the TTVN only once per OGM interval */
1804 atomic_inc(&bat_priv->ttvn); 2012 atomic_inc(&bat_priv->ttvn);
2013 bat_dbg(DBG_TT, bat_priv, "Local changes committed, updating to ttvn %u\n",
2014 (uint8_t)atomic_read(&bat_priv->ttvn));
1805 bat_priv->tt_poss_change = false; 2015 bat_priv->tt_poss_change = false;
1806} 2016}
1807 2017
@@ -1879,6 +2089,7 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
1879 } else { 2089 } else {
1880 /* if we missed more than one change or our tables are not 2090 /* if we missed more than one change or our tables are not
1881 * in sync anymore -> request fresh tt data */ 2091 * in sync anymore -> request fresh tt data */
2092
1882 if (!orig_node->tt_initialised || ttvn != orig_ttvn || 2093 if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
1883 orig_node->tt_crc != tt_crc) { 2094 orig_node->tt_crc != tt_crc) {
1884request_table: 2095request_table:
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 089dd44a29b1..35cd831508a9 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -241,9 +241,16 @@ struct tt_local_entry {
241 241
242struct tt_global_entry { 242struct tt_global_entry {
243 struct tt_common_entry common; 243 struct tt_common_entry common;
244 struct hlist_head orig_list;
245 spinlock_t list_lock; /* protects the list */
246 unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
247};
248
249struct tt_orig_list_entry {
244 struct orig_node *orig_node; 250 struct orig_node *orig_node;
245 uint8_t ttvn; 251 uint8_t ttvn;
246 unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */ 252 struct rcu_head rcu;
253 struct hlist_node list;
247}; 254};
248 255
249struct backbone_gw { 256struct backbone_gw {