aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
authorMarek Lindner <lindner_marek@yahoo.de>2011-01-19 15:01:42 -0500
committerMarek Lindner <lindner_marek@yahoo.de>2011-03-05 06:49:59 -0500
commit16b1aba849eeb45d51a5de731cf103143439ffe1 (patch)
tree2bbda8638bd925014e8d6025d704cb2860d28606 /net/batman-adv
parentfb778ea173fcd58b8fc3d75c674f07fab187b55f (diff)
batman-adv: protect originator nodes with reference counters
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/originator.c61
-rw-r--r--net/batman-adv/originator.h1
-rw-r--r--net/batman-adv/routing.c33
-rw-r--r--net/batman-adv/types.h2
4 files changed, 78 insertions, 19 deletions
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 5c32314f8279..fcdb0b7fe586 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -103,12 +103,13 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
103 return neigh_node; 103 return neigh_node;
104} 104}
105 105
106static void free_orig_node(void *data, void *arg) 106void orig_node_free_ref(struct kref *refcount)
107{ 107{
108 struct hlist_node *node, *node_tmp; 108 struct hlist_node *node, *node_tmp;
109 struct neigh_node *neigh_node; 109 struct neigh_node *neigh_node;
110 struct orig_node *orig_node = (struct orig_node *)data; 110 struct orig_node *orig_node;
111 struct bat_priv *bat_priv = (struct bat_priv *)arg; 111
112 orig_node = container_of(refcount, struct orig_node, refcount);
112 113
113 spin_lock_bh(&orig_node->neigh_list_lock); 114 spin_lock_bh(&orig_node->neigh_list_lock);
114 115
@@ -122,7 +123,8 @@ static void free_orig_node(void *data, void *arg)
122 spin_unlock_bh(&orig_node->neigh_list_lock); 123 spin_unlock_bh(&orig_node->neigh_list_lock);
123 124
124 frag_list_free(&orig_node->frag_list); 125 frag_list_free(&orig_node->frag_list);
125 hna_global_del_orig(bat_priv, orig_node, "originator timed out"); 126 hna_global_del_orig(orig_node->bat_priv, orig_node,
127 "originator timed out");
126 128
127 kfree(orig_node->bcast_own); 129 kfree(orig_node->bcast_own);
128 kfree(orig_node->bcast_own_sum); 130 kfree(orig_node->bcast_own_sum);
@@ -131,17 +133,53 @@ static void free_orig_node(void *data, void *arg)
131 133
132void originator_free(struct bat_priv *bat_priv) 134void originator_free(struct bat_priv *bat_priv)
133{ 135{
134 if (!bat_priv->orig_hash) 136 struct hashtable_t *hash = bat_priv->orig_hash;
137 struct hlist_node *walk, *safe;
138 struct hlist_head *head;
139 struct element_t *bucket;
140 spinlock_t *list_lock; /* spinlock to protect write access */
141 struct orig_node *orig_node;
142 int i;
143
144 if (!hash)
135 return; 145 return;
136 146
137 cancel_delayed_work_sync(&bat_priv->orig_work); 147 cancel_delayed_work_sync(&bat_priv->orig_work);
138 148
139 spin_lock_bh(&bat_priv->orig_hash_lock); 149 spin_lock_bh(&bat_priv->orig_hash_lock);
140 hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv);
141 bat_priv->orig_hash = NULL; 150 bat_priv->orig_hash = NULL;
151
152 for (i = 0; i < hash->size; i++) {
153 head = &hash->table[i];
154 list_lock = &hash->list_locks[i];
155
156 spin_lock_bh(list_lock);
157 hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
158 orig_node = bucket->data;
159
160 hlist_del_rcu(walk);
161 call_rcu(&bucket->rcu, bucket_free_rcu);
162 kref_put(&orig_node->refcount, orig_node_free_ref);
163 }
164 spin_unlock_bh(list_lock);
165 }
166
167 hash_destroy(hash);
142 spin_unlock_bh(&bat_priv->orig_hash_lock); 168 spin_unlock_bh(&bat_priv->orig_hash_lock);
143} 169}
144 170
171static void bucket_free_orig_rcu(struct rcu_head *rcu)
172{
173 struct element_t *bucket;
174 struct orig_node *orig_node;
175
176 bucket = container_of(rcu, struct element_t, rcu);
177 orig_node = bucket->data;
178
179 kref_put(&orig_node->refcount, orig_node_free_ref);
180 kfree(bucket);
181}
182
145/* this function finds or creates an originator entry for the given 183/* this function finds or creates an originator entry for the given
146 * address if it does not exits */ 184 * address if it does not exits */
147struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) 185struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
@@ -156,8 +194,10 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
156 addr)); 194 addr));
157 rcu_read_unlock(); 195 rcu_read_unlock();
158 196
159 if (orig_node) 197 if (orig_node) {
198 kref_get(&orig_node->refcount);
160 return orig_node; 199 return orig_node;
200 }
161 201
162 bat_dbg(DBG_BATMAN, bat_priv, 202 bat_dbg(DBG_BATMAN, bat_priv,
163 "Creating new originator: %pM\n", addr); 203 "Creating new originator: %pM\n", addr);
@@ -168,7 +208,9 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
168 208
169 INIT_HLIST_HEAD(&orig_node->neigh_list); 209 INIT_HLIST_HEAD(&orig_node->neigh_list);
170 spin_lock_init(&orig_node->neigh_list_lock); 210 spin_lock_init(&orig_node->neigh_list_lock);
211 kref_init(&orig_node->refcount);
171 212
213 orig_node->bat_priv = bat_priv;
172 memcpy(orig_node->orig, addr, ETH_ALEN); 214 memcpy(orig_node->orig, addr, ETH_ALEN);
173 orig_node->router = NULL; 215 orig_node->router = NULL;
174 orig_node->hna_buff = NULL; 216 orig_node->hna_buff = NULL;
@@ -197,6 +239,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
197 if (hash_added < 0) 239 if (hash_added < 0)
198 goto free_bcast_own_sum; 240 goto free_bcast_own_sum;
199 241
242 /* extra reference for return */
243 kref_get(&orig_node->refcount);
200 return orig_node; 244 return orig_node;
201free_bcast_own_sum: 245free_bcast_own_sum:
202 kfree(orig_node->bcast_own_sum); 246 kfree(orig_node->bcast_own_sum);
@@ -318,8 +362,7 @@ static void _purge_orig(struct bat_priv *bat_priv)
318 if (orig_node->gw_flags) 362 if (orig_node->gw_flags)
319 gw_node_delete(bat_priv, orig_node); 363 gw_node_delete(bat_priv, orig_node);
320 hlist_del_rcu(walk); 364 hlist_del_rcu(walk);
321 call_rcu(&bucket->rcu, bucket_free_rcu); 365 call_rcu(&bucket->rcu, bucket_free_orig_rcu);
322 free_orig_node(orig_node, bat_priv);
323 continue; 366 continue;
324 } 367 }
325 368
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 88e5c6049243..edc64dc33b12 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -25,6 +25,7 @@
25int originator_init(struct bat_priv *bat_priv); 25int originator_init(struct bat_priv *bat_priv);
26void originator_free(struct bat_priv *bat_priv); 26void originator_free(struct bat_priv *bat_priv);
27void purge_orig_ref(struct bat_priv *bat_priv); 27void purge_orig_ref(struct bat_priv *bat_priv);
28void orig_node_free_ref(struct kref *refcount);
28struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); 29struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
29struct neigh_node *create_neighbor(struct orig_node *orig_node, 30struct neigh_node *create_neighbor(struct orig_node *orig_node,
30 struct orig_node *orig_neigh_node, 31 struct orig_node *orig_neigh_node,
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 32ae04e26a05..1c31a0e9f90a 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -311,6 +311,8 @@ static void update_orig(struct bat_priv *bat_priv,
311 311
312 neigh_node = create_neighbor(orig_node, orig_tmp, 312 neigh_node = create_neighbor(orig_node, orig_tmp,
313 ethhdr->h_source, if_incoming); 313 ethhdr->h_source, if_incoming);
314
315 kref_put(&orig_tmp->refcount, orig_node_free_ref);
314 if (!neigh_node) 316 if (!neigh_node)
315 goto unlock; 317 goto unlock;
316 } else 318 } else
@@ -438,7 +440,7 @@ static char count_real_packets(struct ethhdr *ethhdr,
438 /* signalize caller that the packet is to be dropped. */ 440 /* signalize caller that the packet is to be dropped. */
439 if (window_protected(bat_priv, seq_diff, 441 if (window_protected(bat_priv, seq_diff,
440 &orig_node->batman_seqno_reset)) 442 &orig_node->batman_seqno_reset))
441 return -1; 443 goto err;
442 444
443 rcu_read_lock(); 445 rcu_read_lock();
444 hlist_for_each_entry_rcu(tmp_neigh_node, node, 446 hlist_for_each_entry_rcu(tmp_neigh_node, node,
@@ -471,7 +473,12 @@ static char count_real_packets(struct ethhdr *ethhdr,
471 orig_node->last_real_seqno = batman_packet->seqno; 473 orig_node->last_real_seqno = batman_packet->seqno;
472 } 474 }
473 475
476 kref_put(&orig_node->refcount, orig_node_free_ref);
474 return is_duplicate; 477 return is_duplicate;
478
479err:
480 kref_put(&orig_node->refcount, orig_node_free_ref);
481 return -1;
475} 482}
476 483
477/* copy primary address for bonding */ 484/* copy primary address for bonding */
@@ -686,7 +693,6 @@ void receive_bat_packet(struct ethhdr *ethhdr,
686 int offset; 693 int offset;
687 694
688 orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source); 695 orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
689
690 if (!orig_neigh_node) 696 if (!orig_neigh_node)
691 return; 697 return;
692 698
@@ -707,6 +713,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
707 713
708 bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " 714 bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
709 "originator packet from myself (via neighbor)\n"); 715 "originator packet from myself (via neighbor)\n");
716 kref_put(&orig_neigh_node->refcount, orig_node_free_ref);
710 return; 717 return;
711 } 718 }
712 719
@@ -727,13 +734,13 @@ void receive_bat_packet(struct ethhdr *ethhdr,
727 bat_dbg(DBG_BATMAN, bat_priv, 734 bat_dbg(DBG_BATMAN, bat_priv,
728 "Drop packet: packet within seqno protection time " 735 "Drop packet: packet within seqno protection time "
729 "(sender: %pM)\n", ethhdr->h_source); 736 "(sender: %pM)\n", ethhdr->h_source);
730 return; 737 goto out;
731 } 738 }
732 739
733 if (batman_packet->tq == 0) { 740 if (batman_packet->tq == 0) {
734 bat_dbg(DBG_BATMAN, bat_priv, 741 bat_dbg(DBG_BATMAN, bat_priv,
735 "Drop packet: originator packet with tq equal 0\n"); 742 "Drop packet: originator packet with tq equal 0\n");
736 return; 743 goto out;
737 } 744 }
738 745
739 /* avoid temporary routing loops */ 746 /* avoid temporary routing loops */
@@ -747,7 +754,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
747 bat_dbg(DBG_BATMAN, bat_priv, 754 bat_dbg(DBG_BATMAN, bat_priv,
748 "Drop packet: ignoring all rebroadcast packets that " 755 "Drop packet: ignoring all rebroadcast packets that "
749 "may make me loop (sender: %pM)\n", ethhdr->h_source); 756 "may make me loop (sender: %pM)\n", ethhdr->h_source);
750 return; 757 goto out;
751 } 758 }
752 759
753 /* if sender is a direct neighbor the sender mac equals 760 /* if sender is a direct neighbor the sender mac equals
@@ -756,14 +763,14 @@ void receive_bat_packet(struct ethhdr *ethhdr,
756 orig_node : 763 orig_node :
757 get_orig_node(bat_priv, ethhdr->h_source)); 764 get_orig_node(bat_priv, ethhdr->h_source));
758 if (!orig_neigh_node) 765 if (!orig_neigh_node)
759 return; 766 goto out_neigh;
760 767
761 /* drop packet if sender is not a direct neighbor and if we 768 /* drop packet if sender is not a direct neighbor and if we
762 * don't route towards it */ 769 * don't route towards it */
763 if (!is_single_hop_neigh && (!orig_neigh_node->router)) { 770 if (!is_single_hop_neigh && (!orig_neigh_node->router)) {
764 bat_dbg(DBG_BATMAN, bat_priv, 771 bat_dbg(DBG_BATMAN, bat_priv,
765 "Drop packet: OGM via unknown neighbor!\n"); 772 "Drop packet: OGM via unknown neighbor!\n");
766 return; 773 goto out_neigh;
767 } 774 }
768 775
769 is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node, 776 is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
@@ -790,26 +797,32 @@ void receive_bat_packet(struct ethhdr *ethhdr,
790 797
791 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " 798 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
792 "rebroadcast neighbor packet with direct link flag\n"); 799 "rebroadcast neighbor packet with direct link flag\n");
793 return; 800 goto out_neigh;
794 } 801 }
795 802
796 /* multihop originator */ 803 /* multihop originator */
797 if (!is_bidirectional) { 804 if (!is_bidirectional) {
798 bat_dbg(DBG_BATMAN, bat_priv, 805 bat_dbg(DBG_BATMAN, bat_priv,
799 "Drop packet: not received via bidirectional link\n"); 806 "Drop packet: not received via bidirectional link\n");
800 return; 807 goto out_neigh;
801 } 808 }
802 809
803 if (is_duplicate) { 810 if (is_duplicate) {
804 bat_dbg(DBG_BATMAN, bat_priv, 811 bat_dbg(DBG_BATMAN, bat_priv,
805 "Drop packet: duplicate packet received\n"); 812 "Drop packet: duplicate packet received\n");
806 return; 813 goto out_neigh;
807 } 814 }
808 815
809 bat_dbg(DBG_BATMAN, bat_priv, 816 bat_dbg(DBG_BATMAN, bat_priv,
810 "Forwarding packet: rebroadcast originator packet\n"); 817 "Forwarding packet: rebroadcast originator packet\n");
811 schedule_forward_packet(orig_node, ethhdr, batman_packet, 818 schedule_forward_packet(orig_node, ethhdr, batman_packet,
812 0, hna_buff_len, if_incoming); 819 0, hna_buff_len, if_incoming);
820
821out_neigh:
822 if (!is_single_hop_neigh)
823 kref_put(&orig_neigh_node->refcount, orig_node_free_ref);
824out:
825 kref_put(&orig_node->refcount, orig_node_free_ref);
813} 826}
814 827
815int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) 828int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index d4fa727aece3..ca4d42d05912 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -86,6 +86,8 @@ struct orig_node {
86 struct hlist_head neigh_list; 86 struct hlist_head neigh_list;
87 struct list_head frag_list; 87 struct list_head frag_list;
88 spinlock_t neigh_list_lock; /* protects neighbor list */ 88 spinlock_t neigh_list_lock; /* protects neighbor list */
89 struct kref refcount;
90 struct bat_priv *bat_priv;
89 unsigned long last_frag_packet; 91 unsigned long last_frag_packet;
90 struct { 92 struct {
91 uint8_t candidates; 93 uint8_t candidates;