diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2011-01-19 15:01:42 -0500 |
---|---|---|
committer | Marek Lindner <lindner_marek@yahoo.de> | 2011-03-05 06:49:59 -0500 |
commit | 16b1aba849eeb45d51a5de731cf103143439ffe1 (patch) | |
tree | 2bbda8638bd925014e8d6025d704cb2860d28606 /net/batman-adv | |
parent | fb778ea173fcd58b8fc3d75c674f07fab187b55f (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.c | 61 | ||||
-rw-r--r-- | net/batman-adv/originator.h | 1 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 33 | ||||
-rw-r--r-- | net/batman-adv/types.h | 2 |
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 | ||
106 | static void free_orig_node(void *data, void *arg) | 106 | void 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 | ||
132 | void originator_free(struct bat_priv *bat_priv) | 134 | void 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 | ||
171 | static 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 */ |
147 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) | 185 | struct 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; |
201 | free_bcast_own_sum: | 245 | free_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 @@ | |||
25 | int originator_init(struct bat_priv *bat_priv); | 25 | int originator_init(struct bat_priv *bat_priv); |
26 | void originator_free(struct bat_priv *bat_priv); | 26 | void originator_free(struct bat_priv *bat_priv); |
27 | void purge_orig_ref(struct bat_priv *bat_priv); | 27 | void purge_orig_ref(struct bat_priv *bat_priv); |
28 | void orig_node_free_ref(struct kref *refcount); | ||
28 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); | 29 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); |
29 | struct neigh_node *create_neighbor(struct orig_node *orig_node, | 30 | struct 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 | |||
479 | err: | ||
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 | |||
821 | out_neigh: | ||
822 | if (!is_single_hop_neigh) | ||
823 | kref_put(&orig_neigh_node->refcount, orig_node_free_ref); | ||
824 | out: | ||
825 | kref_put(&orig_node->refcount, orig_node_free_ref); | ||
813 | } | 826 | } |
814 | 827 | ||
815 | int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) | 828 | int 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; |