diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 19:29:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 19:29:25 -0400 |
commit | 7a6362800cb7d1d618a697a650c7aaed3eb39320 (patch) | |
tree | 087f9bc6c13ef1fad4b392c5cf9325cd28fa8523 /net/batman-adv/vis.c | |
parent | 6445ced8670f37cfc2c5e24a9de9b413dbfc788d (diff) | |
parent | ceda86a108671294052cbf51660097b6534672f5 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1480 commits)
bonding: enable netpoll without checking link status
xfrm: Refcount destination entry on xfrm_lookup
net: introduce rx_handler results and logic around that
bonding: get rid of IFF_SLAVE_INACTIVE netdev->priv_flag
bonding: wrap slave state work
net: get rid of multiple bond-related netdevice->priv_flags
bonding: register slave pointer for rx_handler
be2net: Bump up the version number
be2net: Copyright notice change. Update to Emulex instead of ServerEngines
e1000e: fix kconfig for crc32 dependency
netfilter ebtables: fix xt_AUDIT to work with ebtables
xen network backend driver
bonding: Improve syslog message at device creation time
bonding: Call netif_carrier_off after register_netdevice
bonding: Incorrect TX queue offset
net_sched: fix ip_tos2prio
xfrm: fix __xfrm_route_forward()
be2net: Fix UDP packet detected status in RX compl
Phonet: fix aligned-mode pipe socket buffer header reserve
netxen: support for GbE port settings
...
Fix up conflicts in drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
with the staging updates.
Diffstat (limited to 'net/batman-adv/vis.c')
-rw-r--r-- | net/batman-adv/vis.c | 194 |
1 files changed, 111 insertions, 83 deletions
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index de1022cacaf7..f90212f42082 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors: | 2 | * Copyright (C) 2008-2011 B.A.T.M.A.N. contributors: |
3 | * | 3 | * |
4 | * Simon Wunderlich | 4 | * Simon Wunderlich |
5 | * | 5 | * |
@@ -68,15 +68,16 @@ static void free_info(struct kref *ref) | |||
68 | } | 68 | } |
69 | 69 | ||
70 | /* Compare two vis packets, used by the hashing algorithm */ | 70 | /* Compare two vis packets, used by the hashing algorithm */ |
71 | static int vis_info_cmp(void *data1, void *data2) | 71 | static int vis_info_cmp(struct hlist_node *node, void *data2) |
72 | { | 72 | { |
73 | struct vis_info *d1, *d2; | 73 | struct vis_info *d1, *d2; |
74 | struct vis_packet *p1, *p2; | 74 | struct vis_packet *p1, *p2; |
75 | d1 = data1; | 75 | |
76 | d1 = container_of(node, struct vis_info, hash_entry); | ||
76 | d2 = data2; | 77 | d2 = data2; |
77 | p1 = (struct vis_packet *)d1->skb_packet->data; | 78 | p1 = (struct vis_packet *)d1->skb_packet->data; |
78 | p2 = (struct vis_packet *)d2->skb_packet->data; | 79 | p2 = (struct vis_packet *)d2->skb_packet->data; |
79 | return compare_orig(p1->vis_orig, p2->vis_orig); | 80 | return compare_eth(p1->vis_orig, p2->vis_orig); |
80 | } | 81 | } |
81 | 82 | ||
82 | /* hash function to choose an entry in a hash table of given size */ | 83 | /* hash function to choose an entry in a hash table of given size */ |
@@ -104,6 +105,34 @@ static int vis_info_choose(void *data, int size) | |||
104 | return hash % size; | 105 | return hash % size; |
105 | } | 106 | } |
106 | 107 | ||
108 | static struct vis_info *vis_hash_find(struct bat_priv *bat_priv, | ||
109 | void *data) | ||
110 | { | ||
111 | struct hashtable_t *hash = bat_priv->vis_hash; | ||
112 | struct hlist_head *head; | ||
113 | struct hlist_node *node; | ||
114 | struct vis_info *vis_info, *vis_info_tmp = NULL; | ||
115 | int index; | ||
116 | |||
117 | if (!hash) | ||
118 | return NULL; | ||
119 | |||
120 | index = vis_info_choose(data, hash->size); | ||
121 | head = &hash->table[index]; | ||
122 | |||
123 | rcu_read_lock(); | ||
124 | hlist_for_each_entry_rcu(vis_info, node, head, hash_entry) { | ||
125 | if (!vis_info_cmp(node, data)) | ||
126 | continue; | ||
127 | |||
128 | vis_info_tmp = vis_info; | ||
129 | break; | ||
130 | } | ||
131 | rcu_read_unlock(); | ||
132 | |||
133 | return vis_info_tmp; | ||
134 | } | ||
135 | |||
107 | /* insert interface to the list of interfaces of one originator, if it | 136 | /* insert interface to the list of interfaces of one originator, if it |
108 | * does not already exist in the list */ | 137 | * does not already exist in the list */ |
109 | static void vis_data_insert_interface(const uint8_t *interface, | 138 | static void vis_data_insert_interface(const uint8_t *interface, |
@@ -114,7 +143,7 @@ static void vis_data_insert_interface(const uint8_t *interface, | |||
114 | struct hlist_node *pos; | 143 | struct hlist_node *pos; |
115 | 144 | ||
116 | hlist_for_each_entry(entry, pos, if_list, list) { | 145 | hlist_for_each_entry(entry, pos, if_list, list) { |
117 | if (compare_orig(entry->addr, (void *)interface)) | 146 | if (compare_eth(entry->addr, (void *)interface)) |
118 | return; | 147 | return; |
119 | } | 148 | } |
120 | 149 | ||
@@ -166,7 +195,7 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, | |||
166 | /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ | 195 | /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ |
167 | if (primary && entry->quality == 0) | 196 | if (primary && entry->quality == 0) |
168 | return sprintf(buff, "HNA %pM, ", entry->dest); | 197 | return sprintf(buff, "HNA %pM, ", entry->dest); |
169 | else if (compare_orig(entry->src, src)) | 198 | else if (compare_eth(entry->src, src)) |
170 | return sprintf(buff, "TQ %pM %d, ", entry->dest, | 199 | return sprintf(buff, "TQ %pM %d, ", entry->dest, |
171 | entry->quality); | 200 | entry->quality); |
172 | 201 | ||
@@ -175,9 +204,8 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, | |||
175 | 204 | ||
176 | int vis_seq_print_text(struct seq_file *seq, void *offset) | 205 | int vis_seq_print_text(struct seq_file *seq, void *offset) |
177 | { | 206 | { |
178 | struct hlist_node *walk; | 207 | struct hlist_node *node; |
179 | struct hlist_head *head; | 208 | struct hlist_head *head; |
180 | struct element_t *bucket; | ||
181 | struct vis_info *info; | 209 | struct vis_info *info; |
182 | struct vis_packet *packet; | 210 | struct vis_packet *packet; |
183 | struct vis_info_entry *entries; | 211 | struct vis_info_entry *entries; |
@@ -203,8 +231,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
203 | for (i = 0; i < hash->size; i++) { | 231 | for (i = 0; i < hash->size; i++) { |
204 | head = &hash->table[i]; | 232 | head = &hash->table[i]; |
205 | 233 | ||
206 | hlist_for_each_entry(bucket, walk, head, hlist) { | 234 | rcu_read_lock(); |
207 | info = bucket->data; | 235 | hlist_for_each_entry_rcu(info, node, head, hash_entry) { |
208 | packet = (struct vis_packet *)info->skb_packet->data; | 236 | packet = (struct vis_packet *)info->skb_packet->data; |
209 | entries = (struct vis_info_entry *) | 237 | entries = (struct vis_info_entry *) |
210 | ((char *)packet + sizeof(struct vis_packet)); | 238 | ((char *)packet + sizeof(struct vis_packet)); |
@@ -213,7 +241,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
213 | if (entries[j].quality == 0) | 241 | if (entries[j].quality == 0) |
214 | continue; | 242 | continue; |
215 | compare = | 243 | compare = |
216 | compare_orig(entries[j].src, packet->vis_orig); | 244 | compare_eth(entries[j].src, packet->vis_orig); |
217 | vis_data_insert_interface(entries[j].src, | 245 | vis_data_insert_interface(entries[j].src, |
218 | &vis_if_list, | 246 | &vis_if_list, |
219 | compare); | 247 | compare); |
@@ -223,7 +251,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
223 | buf_size += 18 + 26 * packet->entries; | 251 | buf_size += 18 + 26 * packet->entries; |
224 | 252 | ||
225 | /* add primary/secondary records */ | 253 | /* add primary/secondary records */ |
226 | if (compare_orig(entry->addr, packet->vis_orig)) | 254 | if (compare_eth(entry->addr, packet->vis_orig)) |
227 | buf_size += | 255 | buf_size += |
228 | vis_data_count_prim_sec(&vis_if_list); | 256 | vis_data_count_prim_sec(&vis_if_list); |
229 | 257 | ||
@@ -236,6 +264,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
236 | kfree(entry); | 264 | kfree(entry); |
237 | } | 265 | } |
238 | } | 266 | } |
267 | rcu_read_unlock(); | ||
239 | } | 268 | } |
240 | 269 | ||
241 | buff = kmalloc(buf_size, GFP_ATOMIC); | 270 | buff = kmalloc(buf_size, GFP_ATOMIC); |
@@ -249,8 +278,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
249 | for (i = 0; i < hash->size; i++) { | 278 | for (i = 0; i < hash->size; i++) { |
250 | head = &hash->table[i]; | 279 | head = &hash->table[i]; |
251 | 280 | ||
252 | hlist_for_each_entry(bucket, walk, head, hlist) { | 281 | rcu_read_lock(); |
253 | info = bucket->data; | 282 | hlist_for_each_entry_rcu(info, node, head, hash_entry) { |
254 | packet = (struct vis_packet *)info->skb_packet->data; | 283 | packet = (struct vis_packet *)info->skb_packet->data; |
255 | entries = (struct vis_info_entry *) | 284 | entries = (struct vis_info_entry *) |
256 | ((char *)packet + sizeof(struct vis_packet)); | 285 | ((char *)packet + sizeof(struct vis_packet)); |
@@ -259,7 +288,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
259 | if (entries[j].quality == 0) | 288 | if (entries[j].quality == 0) |
260 | continue; | 289 | continue; |
261 | compare = | 290 | compare = |
262 | compare_orig(entries[j].src, packet->vis_orig); | 291 | compare_eth(entries[j].src, packet->vis_orig); |
263 | vis_data_insert_interface(entries[j].src, | 292 | vis_data_insert_interface(entries[j].src, |
264 | &vis_if_list, | 293 | &vis_if_list, |
265 | compare); | 294 | compare); |
@@ -277,7 +306,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
277 | entry->primary); | 306 | entry->primary); |
278 | 307 | ||
279 | /* add primary/secondary records */ | 308 | /* add primary/secondary records */ |
280 | if (compare_orig(entry->addr, packet->vis_orig)) | 309 | if (compare_eth(entry->addr, packet->vis_orig)) |
281 | buff_pos += | 310 | buff_pos += |
282 | vis_data_read_prim_sec(buff + buff_pos, | 311 | vis_data_read_prim_sec(buff + buff_pos, |
283 | &vis_if_list); | 312 | &vis_if_list); |
@@ -291,6 +320,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
291 | kfree(entry); | 320 | kfree(entry); |
292 | } | 321 | } |
293 | } | 322 | } |
323 | rcu_read_unlock(); | ||
294 | } | 324 | } |
295 | 325 | ||
296 | spin_unlock_bh(&bat_priv->vis_hash_lock); | 326 | spin_unlock_bh(&bat_priv->vis_hash_lock); |
@@ -345,7 +375,7 @@ static int recv_list_is_in(struct bat_priv *bat_priv, | |||
345 | 375 | ||
346 | spin_lock_bh(&bat_priv->vis_list_lock); | 376 | spin_lock_bh(&bat_priv->vis_list_lock); |
347 | list_for_each_entry(entry, recv_list, list) { | 377 | list_for_each_entry(entry, recv_list, list) { |
348 | if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { | 378 | if (compare_eth(entry->mac, mac)) { |
349 | spin_unlock_bh(&bat_priv->vis_list_lock); | 379 | spin_unlock_bh(&bat_priv->vis_list_lock); |
350 | return 1; | 380 | return 1; |
351 | } | 381 | } |
@@ -381,8 +411,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, | |||
381 | sizeof(struct vis_packet)); | 411 | sizeof(struct vis_packet)); |
382 | 412 | ||
383 | memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); | 413 | memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); |
384 | old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | 414 | old_info = vis_hash_find(bat_priv, &search_elem); |
385 | &search_elem); | ||
386 | kfree_skb(search_elem.skb_packet); | 415 | kfree_skb(search_elem.skb_packet); |
387 | 416 | ||
388 | if (old_info) { | 417 | if (old_info) { |
@@ -442,7 +471,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, | |||
442 | 471 | ||
443 | /* try to add it */ | 472 | /* try to add it */ |
444 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | 473 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, |
445 | info); | 474 | info, &info->hash_entry); |
446 | if (hash_added < 0) { | 475 | if (hash_added < 0) { |
447 | /* did not work (for some reason) */ | 476 | /* did not work (for some reason) */ |
448 | kref_put(&info->refcount, free_info); | 477 | kref_put(&info->refcount, free_info); |
@@ -529,9 +558,8 @@ static int find_best_vis_server(struct bat_priv *bat_priv, | |||
529 | struct vis_info *info) | 558 | struct vis_info *info) |
530 | { | 559 | { |
531 | struct hashtable_t *hash = bat_priv->orig_hash; | 560 | struct hashtable_t *hash = bat_priv->orig_hash; |
532 | struct hlist_node *walk; | 561 | struct hlist_node *node; |
533 | struct hlist_head *head; | 562 | struct hlist_head *head; |
534 | struct element_t *bucket; | ||
535 | struct orig_node *orig_node; | 563 | struct orig_node *orig_node; |
536 | struct vis_packet *packet; | 564 | struct vis_packet *packet; |
537 | int best_tq = -1, i; | 565 | int best_tq = -1, i; |
@@ -541,16 +569,17 @@ static int find_best_vis_server(struct bat_priv *bat_priv, | |||
541 | for (i = 0; i < hash->size; i++) { | 569 | for (i = 0; i < hash->size; i++) { |
542 | head = &hash->table[i]; | 570 | head = &hash->table[i]; |
543 | 571 | ||
544 | hlist_for_each_entry(bucket, walk, head, hlist) { | 572 | rcu_read_lock(); |
545 | orig_node = bucket->data; | 573 | hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { |
546 | if ((orig_node) && (orig_node->router) && | 574 | if ((orig_node) && (orig_node->router) && |
547 | (orig_node->flags & VIS_SERVER) && | 575 | (orig_node->flags & VIS_SERVER) && |
548 | (orig_node->router->tq_avg > best_tq)) { | 576 | (orig_node->router->tq_avg > best_tq)) { |
549 | best_tq = orig_node->router->tq_avg; | 577 | best_tq = orig_node->router->tq_avg; |
550 | memcpy(packet->target_orig, orig_node->orig, | 578 | memcpy(packet->target_orig, orig_node->orig, |
551 | ETH_ALEN); | 579 | ETH_ALEN); |
552 | } | 580 | } |
553 | } | 581 | } |
582 | rcu_read_unlock(); | ||
554 | } | 583 | } |
555 | 584 | ||
556 | return best_tq; | 585 | return best_tq; |
@@ -573,9 +602,8 @@ static bool vis_packet_full(struct vis_info *info) | |||
573 | static int generate_vis_packet(struct bat_priv *bat_priv) | 602 | static int generate_vis_packet(struct bat_priv *bat_priv) |
574 | { | 603 | { |
575 | struct hashtable_t *hash = bat_priv->orig_hash; | 604 | struct hashtable_t *hash = bat_priv->orig_hash; |
576 | struct hlist_node *walk; | 605 | struct hlist_node *node; |
577 | struct hlist_head *head; | 606 | struct hlist_head *head; |
578 | struct element_t *bucket; | ||
579 | struct orig_node *orig_node; | 607 | struct orig_node *orig_node; |
580 | struct neigh_node *neigh_node; | 608 | struct neigh_node *neigh_node; |
581 | struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; | 609 | struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; |
@@ -587,7 +615,6 @@ static int generate_vis_packet(struct bat_priv *bat_priv) | |||
587 | info->first_seen = jiffies; | 615 | info->first_seen = jiffies; |
588 | packet->vis_type = atomic_read(&bat_priv->vis_mode); | 616 | packet->vis_type = atomic_read(&bat_priv->vis_mode); |
589 | 617 | ||
590 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
591 | memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); | 618 | memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); |
592 | packet->ttl = TTL; | 619 | packet->ttl = TTL; |
593 | packet->seqno = htonl(ntohl(packet->seqno) + 1); | 620 | packet->seqno = htonl(ntohl(packet->seqno) + 1); |
@@ -597,23 +624,21 @@ static int generate_vis_packet(struct bat_priv *bat_priv) | |||
597 | if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) { | 624 | if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) { |
598 | best_tq = find_best_vis_server(bat_priv, info); | 625 | best_tq = find_best_vis_server(bat_priv, info); |
599 | 626 | ||
600 | if (best_tq < 0) { | 627 | if (best_tq < 0) |
601 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
602 | return -1; | 628 | return -1; |
603 | } | ||
604 | } | 629 | } |
605 | 630 | ||
606 | for (i = 0; i < hash->size; i++) { | 631 | for (i = 0; i < hash->size; i++) { |
607 | head = &hash->table[i]; | 632 | head = &hash->table[i]; |
608 | 633 | ||
609 | hlist_for_each_entry(bucket, walk, head, hlist) { | 634 | rcu_read_lock(); |
610 | orig_node = bucket->data; | 635 | hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { |
611 | neigh_node = orig_node->router; | 636 | neigh_node = orig_node->router; |
612 | 637 | ||
613 | if (!neigh_node) | 638 | if (!neigh_node) |
614 | continue; | 639 | continue; |
615 | 640 | ||
616 | if (!compare_orig(neigh_node->addr, orig_node->orig)) | 641 | if (!compare_eth(neigh_node->addr, orig_node->orig)) |
617 | continue; | 642 | continue; |
618 | 643 | ||
619 | if (neigh_node->if_incoming->if_status != IF_ACTIVE) | 644 | if (neigh_node->if_incoming->if_status != IF_ACTIVE) |
@@ -632,23 +657,19 @@ static int generate_vis_packet(struct bat_priv *bat_priv) | |||
632 | entry->quality = neigh_node->tq_avg; | 657 | entry->quality = neigh_node->tq_avg; |
633 | packet->entries++; | 658 | packet->entries++; |
634 | 659 | ||
635 | if (vis_packet_full(info)) { | 660 | if (vis_packet_full(info)) |
636 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 661 | goto unlock; |
637 | return 0; | ||
638 | } | ||
639 | } | 662 | } |
663 | rcu_read_unlock(); | ||
640 | } | 664 | } |
641 | 665 | ||
642 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
643 | |||
644 | hash = bat_priv->hna_local_hash; | 666 | hash = bat_priv->hna_local_hash; |
645 | 667 | ||
646 | spin_lock_bh(&bat_priv->hna_lhash_lock); | 668 | spin_lock_bh(&bat_priv->hna_lhash_lock); |
647 | for (i = 0; i < hash->size; i++) { | 669 | for (i = 0; i < hash->size; i++) { |
648 | head = &hash->table[i]; | 670 | head = &hash->table[i]; |
649 | 671 | ||
650 | hlist_for_each_entry(bucket, walk, head, hlist) { | 672 | hlist_for_each_entry(hna_local_entry, node, head, hash_entry) { |
651 | hna_local_entry = bucket->data; | ||
652 | entry = (struct vis_info_entry *) | 673 | entry = (struct vis_info_entry *) |
653 | skb_put(info->skb_packet, | 674 | skb_put(info->skb_packet, |
654 | sizeof(*entry)); | 675 | sizeof(*entry)); |
@@ -666,6 +687,10 @@ static int generate_vis_packet(struct bat_priv *bat_priv) | |||
666 | 687 | ||
667 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | 688 | spin_unlock_bh(&bat_priv->hna_lhash_lock); |
668 | return 0; | 689 | return 0; |
690 | |||
691 | unlock: | ||
692 | rcu_read_unlock(); | ||
693 | return 0; | ||
669 | } | 694 | } |
670 | 695 | ||
671 | /* free old vis packets. Must be called with this vis_hash_lock | 696 | /* free old vis packets. Must be called with this vis_hash_lock |
@@ -674,25 +699,22 @@ static void purge_vis_packets(struct bat_priv *bat_priv) | |||
674 | { | 699 | { |
675 | int i; | 700 | int i; |
676 | struct hashtable_t *hash = bat_priv->vis_hash; | 701 | struct hashtable_t *hash = bat_priv->vis_hash; |
677 | struct hlist_node *walk, *safe; | 702 | struct hlist_node *node, *node_tmp; |
678 | struct hlist_head *head; | 703 | struct hlist_head *head; |
679 | struct element_t *bucket; | ||
680 | struct vis_info *info; | 704 | struct vis_info *info; |
681 | 705 | ||
682 | for (i = 0; i < hash->size; i++) { | 706 | for (i = 0; i < hash->size; i++) { |
683 | head = &hash->table[i]; | 707 | head = &hash->table[i]; |
684 | 708 | ||
685 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | 709 | hlist_for_each_entry_safe(info, node, node_tmp, |
686 | info = bucket->data; | 710 | head, hash_entry) { |
687 | |||
688 | /* never purge own data. */ | 711 | /* never purge own data. */ |
689 | if (info == bat_priv->my_vis_info) | 712 | if (info == bat_priv->my_vis_info) |
690 | continue; | 713 | continue; |
691 | 714 | ||
692 | if (time_after(jiffies, | 715 | if (time_after(jiffies, |
693 | info->first_seen + VIS_TIMEOUT * HZ)) { | 716 | info->first_seen + VIS_TIMEOUT * HZ)) { |
694 | hlist_del(walk); | 717 | hlist_del(node); |
695 | kfree(bucket); | ||
696 | send_list_del(info); | 718 | send_list_del(info); |
697 | kref_put(&info->refcount, free_info); | 719 | kref_put(&info->refcount, free_info); |
698 | } | 720 | } |
@@ -704,27 +726,24 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, | |||
704 | struct vis_info *info) | 726 | struct vis_info *info) |
705 | { | 727 | { |
706 | struct hashtable_t *hash = bat_priv->orig_hash; | 728 | struct hashtable_t *hash = bat_priv->orig_hash; |
707 | struct hlist_node *walk; | 729 | struct hlist_node *node; |
708 | struct hlist_head *head; | 730 | struct hlist_head *head; |
709 | struct element_t *bucket; | ||
710 | struct orig_node *orig_node; | 731 | struct orig_node *orig_node; |
711 | struct vis_packet *packet; | 732 | struct vis_packet *packet; |
712 | struct sk_buff *skb; | 733 | struct sk_buff *skb; |
713 | struct batman_if *batman_if; | 734 | struct hard_iface *hard_iface; |
714 | uint8_t dstaddr[ETH_ALEN]; | 735 | uint8_t dstaddr[ETH_ALEN]; |
715 | int i; | 736 | int i; |
716 | 737 | ||
717 | 738 | ||
718 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
719 | packet = (struct vis_packet *)info->skb_packet->data; | 739 | packet = (struct vis_packet *)info->skb_packet->data; |
720 | 740 | ||
721 | /* send to all routers in range. */ | 741 | /* send to all routers in range. */ |
722 | for (i = 0; i < hash->size; i++) { | 742 | for (i = 0; i < hash->size; i++) { |
723 | head = &hash->table[i]; | 743 | head = &hash->table[i]; |
724 | 744 | ||
725 | hlist_for_each_entry(bucket, walk, head, hlist) { | 745 | rcu_read_lock(); |
726 | orig_node = bucket->data; | 746 | hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { |
727 | |||
728 | /* if it's a vis server and reachable, send it. */ | 747 | /* if it's a vis server and reachable, send it. */ |
729 | if ((!orig_node) || (!orig_node->router)) | 748 | if ((!orig_node) || (!orig_node->router)) |
730 | continue; | 749 | continue; |
@@ -737,54 +756,61 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, | |||
737 | continue; | 756 | continue; |
738 | 757 | ||
739 | memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); | 758 | memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); |
740 | batman_if = orig_node->router->if_incoming; | 759 | hard_iface = orig_node->router->if_incoming; |
741 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | 760 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); |
742 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
743 | 761 | ||
744 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | 762 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); |
745 | if (skb) | 763 | if (skb) |
746 | send_skb_packet(skb, batman_if, dstaddr); | 764 | send_skb_packet(skb, hard_iface, dstaddr); |
747 | 765 | ||
748 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
749 | } | 766 | } |
750 | 767 | rcu_read_unlock(); | |
751 | } | 768 | } |
752 | |||
753 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
754 | } | 769 | } |
755 | 770 | ||
756 | static void unicast_vis_packet(struct bat_priv *bat_priv, | 771 | static void unicast_vis_packet(struct bat_priv *bat_priv, |
757 | struct vis_info *info) | 772 | struct vis_info *info) |
758 | { | 773 | { |
759 | struct orig_node *orig_node; | 774 | struct orig_node *orig_node; |
775 | struct neigh_node *neigh_node = NULL; | ||
760 | struct sk_buff *skb; | 776 | struct sk_buff *skb; |
761 | struct vis_packet *packet; | 777 | struct vis_packet *packet; |
762 | struct batman_if *batman_if; | ||
763 | uint8_t dstaddr[ETH_ALEN]; | ||
764 | 778 | ||
765 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
766 | packet = (struct vis_packet *)info->skb_packet->data; | 779 | packet = (struct vis_packet *)info->skb_packet->data; |
767 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
768 | compare_orig, choose_orig, | ||
769 | packet->target_orig)); | ||
770 | 780 | ||
771 | if ((!orig_node) || (!orig_node->router)) | 781 | rcu_read_lock(); |
772 | goto out; | 782 | orig_node = orig_hash_find(bat_priv, packet->target_orig); |
773 | 783 | ||
774 | /* don't lock while sending the packets ... we therefore | 784 | if (!orig_node) |
775 | * copy the required data before sending */ | 785 | goto unlock; |
776 | batman_if = orig_node->router->if_incoming; | 786 | |
777 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | 787 | neigh_node = orig_node->router; |
778 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 788 | |
789 | if (!neigh_node) | ||
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(); | ||
779 | 798 | ||
780 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | 799 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); |
781 | if (skb) | 800 | if (skb) |
782 | send_skb_packet(skb, batman_if, dstaddr); | 801 | send_skb_packet(skb, neigh_node->if_incoming, |
802 | neigh_node->addr); | ||
783 | 803 | ||
784 | return; | 804 | goto out; |
785 | 805 | ||
806 | unlock: | ||
807 | rcu_read_unlock(); | ||
786 | out: | 808 | out: |
787 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 809 | if (neigh_node) |
810 | neigh_node_free_ref(neigh_node); | ||
811 | if (orig_node) | ||
812 | orig_node_free_ref(orig_node); | ||
813 | return; | ||
788 | } | 814 | } |
789 | 815 | ||
790 | /* only send one vis packet. called from send_vis_packets() */ | 816 | /* only send one vis packet. called from send_vis_packets() */ |
@@ -896,7 +922,8 @@ int vis_init(struct bat_priv *bat_priv) | |||
896 | INIT_LIST_HEAD(&bat_priv->vis_send_list); | 922 | INIT_LIST_HEAD(&bat_priv->vis_send_list); |
897 | 923 | ||
898 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | 924 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, |
899 | bat_priv->my_vis_info); | 925 | bat_priv->my_vis_info, |
926 | &bat_priv->my_vis_info->hash_entry); | ||
900 | if (hash_added < 0) { | 927 | if (hash_added < 0) { |
901 | pr_err("Can't add own vis packet into hash\n"); | 928 | pr_err("Can't add own vis packet into hash\n"); |
902 | /* not in hash, need to remove it manually. */ | 929 | /* not in hash, need to remove it manually. */ |
@@ -918,10 +945,11 @@ err: | |||
918 | } | 945 | } |
919 | 946 | ||
920 | /* Decrease the reference count on a hash item info */ | 947 | /* Decrease the reference count on a hash item info */ |
921 | static void free_info_ref(void *data, void *arg) | 948 | static void free_info_ref(struct hlist_node *node, void *arg) |
922 | { | 949 | { |
923 | struct vis_info *info = data; | 950 | struct vis_info *info; |
924 | 951 | ||
952 | info = container_of(node, struct vis_info, hash_entry); | ||
925 | send_list_del(info); | 953 | send_list_del(info); |
926 | kref_put(&info->refcount, free_info); | 954 | kref_put(&info->refcount, free_info); |
927 | } | 955 | } |