aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/vis.c
diff options
context:
space:
mode:
authorLinus Lüssing <linus.luessing@web.de>2011-03-14 18:43:37 -0400
committerSven Eckelmann <sven@narfation.org>2011-04-17 15:11:01 -0400
commite1a5382f978b67b5cc36eec65e6046730ce07714 (patch)
treef7ca07cde3a49858d0cfa33e0189a659a1fcc95d /net/batman-adv/vis.c
parent57f0c07c4d0da8bcc23e21c330fe9c7c5cf776b5 (diff)
batman-adv: Make orig_node->router an rcu protected pointer
The rcu protected macros rcu_dereference() and rcu_assign_pointer() for the orig_node->router need to be used, as well as spin/rcu locking. Otherwise we might end up using a router pointer pointing to already freed memory. Therefore this commit introduces the safe getter method orig_node_get_router(). Signed-off-by: Linus Lüssing <linus.luessing@web.de> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net/batman-adv/vis.c')
-rw-r--r--net/batman-adv/vis.c91
1 files changed, 45 insertions, 46 deletions
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index f90212f42082..d4cc4f5399f4 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -558,6 +558,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
558 struct vis_info *info) 558 struct vis_info *info)
559{ 559{
560 struct hashtable_t *hash = bat_priv->orig_hash; 560 struct hashtable_t *hash = bat_priv->orig_hash;
561 struct neigh_node *router;
561 struct hlist_node *node; 562 struct hlist_node *node;
562 struct hlist_head *head; 563 struct hlist_head *head;
563 struct orig_node *orig_node; 564 struct orig_node *orig_node;
@@ -571,13 +572,17 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
571 572
572 rcu_read_lock(); 573 rcu_read_lock();
573 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { 574 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
574 if ((orig_node) && (orig_node->router) && 575 router = orig_node_get_router(orig_node);
575 (orig_node->flags & VIS_SERVER) && 576 if (!router)
576 (orig_node->router->tq_avg > best_tq)) { 577 continue;
577 best_tq = orig_node->router->tq_avg; 578
579 if ((orig_node->flags & VIS_SERVER) &&
580 (router->tq_avg > best_tq)) {
581 best_tq = router->tq_avg;
578 memcpy(packet->target_orig, orig_node->orig, 582 memcpy(packet->target_orig, orig_node->orig,
579 ETH_ALEN); 583 ETH_ALEN);
580 } 584 }
585 neigh_node_free_ref(router);
581 } 586 }
582 rcu_read_unlock(); 587 rcu_read_unlock();
583 } 588 }
@@ -605,7 +610,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
605 struct hlist_node *node; 610 struct hlist_node *node;
606 struct hlist_head *head; 611 struct hlist_head *head;
607 struct orig_node *orig_node; 612 struct orig_node *orig_node;
608 struct neigh_node *neigh_node; 613 struct neigh_node *router;
609 struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; 614 struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
610 struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; 615 struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
611 struct vis_info_entry *entry; 616 struct vis_info_entry *entry;
@@ -633,30 +638,32 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
633 638
634 rcu_read_lock(); 639 rcu_read_lock();
635 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { 640 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
636 neigh_node = orig_node->router; 641 router = orig_node_get_router(orig_node);
637 642 if (!router)
638 if (!neigh_node)
639 continue; 643 continue;
640 644
641 if (!compare_eth(neigh_node->addr, orig_node->orig)) 645 if (!compare_eth(router->addr, orig_node->orig))
642 continue; 646 goto next;
643 647
644 if (neigh_node->if_incoming->if_status != IF_ACTIVE) 648 if (router->if_incoming->if_status != IF_ACTIVE)
645 continue; 649 goto next;
646 650
647 if (neigh_node->tq_avg < 1) 651 if (router->tq_avg < 1)
648 continue; 652 goto next;
649 653
650 /* fill one entry into buffer. */ 654 /* fill one entry into buffer. */
651 entry = (struct vis_info_entry *) 655 entry = (struct vis_info_entry *)
652 skb_put(info->skb_packet, sizeof(*entry)); 656 skb_put(info->skb_packet, sizeof(*entry));
653 memcpy(entry->src, 657 memcpy(entry->src,
654 neigh_node->if_incoming->net_dev->dev_addr, 658 router->if_incoming->net_dev->dev_addr,
655 ETH_ALEN); 659 ETH_ALEN);
656 memcpy(entry->dest, orig_node->orig, ETH_ALEN); 660 memcpy(entry->dest, orig_node->orig, ETH_ALEN);
657 entry->quality = neigh_node->tq_avg; 661 entry->quality = router->tq_avg;
658 packet->entries++; 662 packet->entries++;
659 663
664next:
665 neigh_node_free_ref(router);
666
660 if (vis_packet_full(info)) 667 if (vis_packet_full(info))
661 goto unlock; 668 goto unlock;
662 } 669 }
@@ -725,6 +732,7 @@ static void purge_vis_packets(struct bat_priv *bat_priv)
725static void broadcast_vis_packet(struct bat_priv *bat_priv, 732static void broadcast_vis_packet(struct bat_priv *bat_priv,
726 struct vis_info *info) 733 struct vis_info *info)
727{ 734{
735 struct neigh_node *router;
728 struct hashtable_t *hash = bat_priv->orig_hash; 736 struct hashtable_t *hash = bat_priv->orig_hash;
729 struct hlist_node *node; 737 struct hlist_node *node;
730 struct hlist_head *head; 738 struct hlist_head *head;
@@ -745,19 +753,26 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
745 rcu_read_lock(); 753 rcu_read_lock();
746 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { 754 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
747 /* if it's a vis server and reachable, send it. */ 755 /* if it's a vis server and reachable, send it. */
748 if ((!orig_node) || (!orig_node->router))
749 continue;
750 if (!(orig_node->flags & VIS_SERVER)) 756 if (!(orig_node->flags & VIS_SERVER))
751 continue; 757 continue;
758
759 router = orig_node_get_router(orig_node);
760 if (!router)
761 continue;
762
752 /* don't send it if we already received the packet from 763 /* don't send it if we already received the packet from
753 * this node. */ 764 * this node. */
754 if (recv_list_is_in(bat_priv, &info->recv_list, 765 if (recv_list_is_in(bat_priv, &info->recv_list,
755 orig_node->orig)) 766 orig_node->orig)) {
767 neigh_node_free_ref(router);
756 continue; 768 continue;
769 }
757 770
758 memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); 771 memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
759 hard_iface = orig_node->router->if_incoming; 772 hard_iface = router->if_incoming;
760 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); 773 memcpy(dstaddr, router->addr, ETH_ALEN);
774
775 neigh_node_free_ref(router);
761 776
762 skb = skb_clone(info->skb_packet, GFP_ATOMIC); 777 skb = skb_clone(info->skb_packet, GFP_ATOMIC);
763 if (skb) 778 if (skb)
@@ -772,45 +787,29 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
772 struct vis_info *info) 787 struct vis_info *info)
773{ 788{
774 struct orig_node *orig_node; 789 struct orig_node *orig_node;
775 struct neigh_node *neigh_node = NULL; 790 struct neigh_node *router = NULL;
776 struct sk_buff *skb; 791 struct sk_buff *skb;
777 struct vis_packet *packet; 792 struct vis_packet *packet;
778 793
779 packet = (struct vis_packet *)info->skb_packet->data; 794 packet = (struct vis_packet *)info->skb_packet->data;
780 795
781 rcu_read_lock();
782 orig_node = orig_hash_find(bat_priv, packet->target_orig); 796 orig_node = orig_hash_find(bat_priv, packet->target_orig);
783
784 if (!orig_node) 797 if (!orig_node)
785 goto unlock; 798 goto out;
786 799
787 neigh_node = orig_node->router; 800 router = orig_node_get_router(orig_node);
788 801 if (!router)
789 if (!neigh_node) 802 goto out;
790 goto unlock;
791
792 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
793 neigh_node = NULL;
794 goto unlock;
795 }
796
797 rcu_read_unlock();
798 803
799 skb = skb_clone(info->skb_packet, GFP_ATOMIC); 804 skb = skb_clone(info->skb_packet, GFP_ATOMIC);
800 if (skb) 805 if (skb)
801 send_skb_packet(skb, neigh_node->if_incoming, 806 send_skb_packet(skb, router->if_incoming, router->addr);
802 neigh_node->addr);
803
804 goto out;
805 807
806unlock:
807 rcu_read_unlock();
808out: 808out:
809 if (neigh_node) 809 if (router)
810 neigh_node_free_ref(neigh_node); 810 neigh_node_free_ref(router);
811 if (orig_node) 811 if (orig_node)
812 orig_node_free_ref(orig_node); 812 orig_node_free_ref(orig_node);
813 return;
814} 813}
815 814
816/* only send one vis packet. called from send_vis_packets() */ 815/* only send one vis packet. called from send_vis_packets() */