]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/batman-adv/vis.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / net / batman-adv / vis.c
similarity index 68%
rename from drivers/staging/batman-adv/vis.c
rename to net/batman-adv/vis.c
index 3d2c1bccf2e6a46ce28828a01c9cb0dc4a0a504f..de1022cacaf7ee570a08b2d584862b7e11d5bd19 100644 (file)
@@ -26,6 +26,7 @@
 #include "soft-interface.h"
 #include "hard-interface.h"
 #include "hash.h"
+#include "originator.h"
 
 #define MAX_VIS_PACKET_SIZE 1000
 
@@ -53,17 +54,17 @@ static void free_info(struct kref *ref)
        struct vis_info *info = container_of(ref, struct vis_info, refcount);
        struct bat_priv *bat_priv = info->bat_priv;
        struct recvlist_node *entry, *tmp;
-       unsigned long flags;
 
        list_del_init(&info->send_list);
-       spin_lock_irqsave(&bat_priv->vis_list_lock, flags);
+       spin_lock_bh(&bat_priv->vis_list_lock);
        list_for_each_entry_safe(entry, tmp, &info->recv_list, list) {
                list_del(&entry->list);
                kfree(entry);
        }
 
-       spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_list_lock);
        kfree_skb(info->skb_packet);
+       kfree(info);
 }
 
 /* Compare two vis packets, used by the hashing algorithm */
@@ -135,9 +136,8 @@ static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list)
        hlist_for_each_entry(entry, pos, if_list, list) {
                if (entry->primary)
                        len += sprintf(buff + len, "PRIMARY, ");
-               else {
+               else
                        len += sprintf(buff + len,  "SEC %pM, ", entry->addr);
-               }
        }
 
        return len;
@@ -175,21 +175,23 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
 
 int vis_seq_print_text(struct seq_file *seq, void *offset)
 {
-       HASHIT(hashit);
-       HASHIT(hashit_count);
+       struct hlist_node *walk;
+       struct hlist_head *head;
+       struct element_t *bucket;
        struct vis_info *info;
        struct vis_packet *packet;
        struct vis_info_entry *entries;
        struct net_device *net_dev = (struct net_device *)seq->private;
        struct bat_priv *bat_priv = netdev_priv(net_dev);
+       struct hashtable_t *hash = bat_priv->vis_hash;
        HLIST_HEAD(vis_if_list);
        struct if_list_entry *entry;
        struct hlist_node *pos, *n;
-       int i;
-       unsigned long flags;
+       int i, j;
        int vis_server = atomic_read(&bat_priv->vis_mode);
        size_t buff_pos, buf_size;
        char *buff;
+       int compare;
 
        if ((!bat_priv->primary_if) ||
            (vis_server == VIS_TYPE_CLIENT_UPDATE))
@@ -197,84 +199,101 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
 
        buf_size = 1;
        /* Estimate length */
-       spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
-       while (hash_iterate(bat_priv->vis_hash, &hashit_count)) {
-               info = hashit_count.bucket->data;
-               packet = (struct vis_packet *)info->skb_packet->data;
-               entries = (struct vis_info_entry *)
-                         ((char *)packet + sizeof(struct vis_packet));
-
-               for (i = 0; i < packet->entries; i++) {
-                       if (entries[i].quality == 0)
-                               continue;
-                       vis_data_insert_interface(entries[i].src, &vis_if_list,
-                               compare_orig(entries[i].src, packet->vis_orig));
-               }
+       spin_lock_bh(&bat_priv->vis_hash_lock);
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+
+               hlist_for_each_entry(bucket, walk, head, hlist) {
+                       info = bucket->data;
+                       packet = (struct vis_packet *)info->skb_packet->data;
+                       entries = (struct vis_info_entry *)
+                               ((char *)packet + sizeof(struct vis_packet));
+
+                       for (j = 0; j < packet->entries; j++) {
+                               if (entries[j].quality == 0)
+                                       continue;
+                               compare =
+                                compare_orig(entries[j].src, packet->vis_orig);
+                               vis_data_insert_interface(entries[j].src,
+                                                         &vis_if_list,
+                                                         compare);
+                       }
 
-               hlist_for_each_entry(entry, pos, &vis_if_list, list) {
-                       buf_size += 18 + 26 * packet->entries;
+                       hlist_for_each_entry(entry, pos, &vis_if_list, list) {
+                               buf_size += 18 + 26 * packet->entries;
 
-                       /* add primary/secondary records */
-                       if (compare_orig(entry->addr, packet->vis_orig))
-                               buf_size +=
-                                       vis_data_count_prim_sec(&vis_if_list);
+                               /* add primary/secondary records */
+                               if (compare_orig(entry->addr, packet->vis_orig))
+                                       buf_size +=
+                                         vis_data_count_prim_sec(&vis_if_list);
 
-                       buf_size += 1;
-               }
+                               buf_size += 1;
+                       }
 
-               hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
-                       hlist_del(&entry->list);
-                       kfree(entry);
+                       hlist_for_each_entry_safe(entry, pos, n, &vis_if_list,
+                                                 list) {
+                               hlist_del(&entry->list);
+                               kfree(entry);
+                       }
                }
        }
 
        buff = kmalloc(buf_size, GFP_ATOMIC);
        if (!buff) {
-               spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+               spin_unlock_bh(&bat_priv->vis_hash_lock);
                return -ENOMEM;
        }
        buff[0] = '\0';
        buff_pos = 0;
 
-       while (hash_iterate(bat_priv->vis_hash, &hashit)) {
-               info = hashit.bucket->data;
-               packet = (struct vis_packet *)info->skb_packet->data;
-               entries = (struct vis_info_entry *)
-                         ((char *)packet + sizeof(struct vis_packet));
-
-               for (i = 0; i < packet->entries; i++) {
-                       if (entries[i].quality == 0)
-                               continue;
-                       vis_data_insert_interface(entries[i].src, &vis_if_list,
-                               compare_orig(entries[i].src, packet->vis_orig));
-               }
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+
+               hlist_for_each_entry(bucket, walk, head, hlist) {
+                       info = bucket->data;
+                       packet = (struct vis_packet *)info->skb_packet->data;
+                       entries = (struct vis_info_entry *)
+                               ((char *)packet + sizeof(struct vis_packet));
+
+                       for (j = 0; j < packet->entries; j++) {
+                               if (entries[j].quality == 0)
+                                       continue;
+                               compare =
+                                compare_orig(entries[j].src, packet->vis_orig);
+                               vis_data_insert_interface(entries[j].src,
+                                                         &vis_if_list,
+                                                         compare);
+                       }
 
-               hlist_for_each_entry(entry, pos, &vis_if_list, list) {
-                       buff_pos += sprintf(buff + buff_pos, "%pM,",
-                                           entry->addr);
+                       hlist_for_each_entry(entry, pos, &vis_if_list, list) {
+                               buff_pos += sprintf(buff + buff_pos, "%pM,",
+                                               entry->addr);
 
-                       for (i = 0; i < packet->entries; i++)
-                               buff_pos += vis_data_read_entry(buff + buff_pos,
-                                                               &entries[i],
-                                                               entry->addr,
-                                                               entry->primary);
+                               for (j = 0; j < packet->entries; j++)
+                                       buff_pos += vis_data_read_entry(
+                                                       buff + buff_pos,
+                                                       &entries[j],
+                                                       entry->addr,
+                                                       entry->primary);
 
-                       /* add primary/secondary records */
-                       if (compare_orig(entry->addr, packet->vis_orig))
-                               buff_pos +=
-                                       vis_data_read_prim_sec(buff + buff_pos,
-                                                              &vis_if_list);
+                               /* add primary/secondary records */
+                               if (compare_orig(entry->addr, packet->vis_orig))
+                                       buff_pos +=
+                                        vis_data_read_prim_sec(buff + buff_pos,
+                                                               &vis_if_list);
 
-                       buff_pos += sprintf(buff + buff_pos, "\n");
-               }
+                               buff_pos += sprintf(buff + buff_pos, "\n");
+                       }
 
-               hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
-                       hlist_del(&entry->list);
-                       kfree(entry);
+                       hlist_for_each_entry_safe(entry, pos, n, &vis_if_list,
+                                                 list) {
+                               hlist_del(&entry->list);
+                               kfree(entry);
+                       }
                }
        }
 
-       spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_hash_lock);
 
        seq_printf(seq, "%s", buff);
        kfree(buff);
@@ -307,16 +326,15 @@ static void recv_list_add(struct bat_priv *bat_priv,
                          struct list_head *recv_list, char *mac)
 {
        struct recvlist_node *entry;
-       unsigned long flags;
 
        entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC);
        if (!entry)
                return;
 
        memcpy(entry->mac, mac, ETH_ALEN);
-       spin_lock_irqsave(&bat_priv->vis_list_lock, flags);
+       spin_lock_bh(&bat_priv->vis_list_lock);
        list_add_tail(&entry->list, recv_list);
-       spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_list_lock);
 }
 
 /* returns 1 if this mac is in the recv_list */
@@ -324,17 +342,15 @@ static int recv_list_is_in(struct bat_priv *bat_priv,
                           struct list_head *recv_list, char *mac)
 {
        struct recvlist_node *entry;
-       unsigned long flags;
 
-       spin_lock_irqsave(&bat_priv->vis_list_lock, flags);
+       spin_lock_bh(&bat_priv->vis_list_lock);
        list_for_each_entry(entry, recv_list, list) {
                if (memcmp(entry->mac, mac, ETH_ALEN) == 0) {
-                       spin_unlock_irqrestore(&bat_priv->vis_list_lock,
-                                              flags);
+                       spin_unlock_bh(&bat_priv->vis_list_lock);
                        return 1;
                }
        }
-       spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_list_lock);
        return 0;
 }
 
@@ -350,6 +366,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
        struct vis_packet *search_packet, *old_packet;
        struct vis_info search_elem;
        struct vis_packet *packet;
+       int hash_added;
 
        *is_new = 0;
        /* sanity check */
@@ -364,10 +381,11 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
                                                     sizeof(struct vis_packet));
 
        memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
-       old_info = hash_find(bat_priv->vis_hash, &search_elem);
+       old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
+                            &search_elem);
        kfree_skb(search_elem.skb_packet);
 
-       if (old_info != NULL) {
+       if (old_info) {
                old_packet = (struct vis_packet *)old_info->skb_packet->data;
                if (!seq_after(ntohl(vis_packet->seqno),
                               ntohl(old_packet->seqno))) {
@@ -381,7 +399,8 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
                        }
                }
                /* remove old entry */
-               hash_remove(bat_priv->vis_hash, old_info);
+               hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
+                           old_info);
                send_list_del(old_info);
                kref_put(&old_info->refcount, free_info);
        }
@@ -422,9 +441,11 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
        recv_list_add(bat_priv, &info->recv_list, packet->sender_orig);
 
        /* try to add it */
-       if (hash_add(bat_priv->vis_hash, info) < 0) {
+       hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
+                             info);
+       if (hash_added < 0) {
                /* did not work (for some reason) */
-               kref_put(&old_info->refcount, free_info);
+               kref_put(&info->refcount, free_info);
                info = NULL;
        }
 
@@ -438,12 +459,11 @@ void receive_server_sync_packet(struct bat_priv *bat_priv,
 {
        struct vis_info *info;
        int is_new, make_broadcast;
-       unsigned long flags;
        int vis_server = atomic_read(&bat_priv->vis_mode);
 
        make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC);
 
-       spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
+       spin_lock_bh(&bat_priv->vis_hash_lock);
        info = add_packet(bat_priv, vis_packet, vis_info_len,
                          &is_new, make_broadcast);
        if (!info)
@@ -454,7 +474,7 @@ void receive_server_sync_packet(struct bat_priv *bat_priv,
        if (vis_server == VIS_TYPE_SERVER_SYNC && is_new)
                send_list_add(bat_priv, info);
 end:
-       spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_hash_lock);
 }
 
 /* handle an incoming client update packet and schedule forward if needed. */
@@ -465,12 +485,11 @@ void receive_client_update_packet(struct bat_priv *bat_priv,
        struct vis_info *info;
        struct vis_packet *packet;
        int is_new;
-       unsigned long flags;
        int vis_server = atomic_read(&bat_priv->vis_mode);
        int are_target = 0;
 
        /* clients shall not broadcast. */
-       if (is_bcast(vis_packet->target_orig))
+       if (is_broadcast_ether_addr(vis_packet->target_orig))
                return;
 
        /* Are we the target for this VIS packet? */
@@ -478,7 +497,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv,
            is_my_mac(vis_packet->target_orig))
                are_target = 1;
 
-       spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
+       spin_lock_bh(&bat_priv->vis_hash_lock);
        info = add_packet(bat_priv, vis_packet, vis_info_len,
                          &is_new, are_target);
 
@@ -499,7 +518,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv,
        }
 
 end:
-       spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_hash_lock);
 }
 
 /* Walk the originators and find the VIS server with the best tq. Set the packet
@@ -509,22 +528,31 @@ end:
 static int find_best_vis_server(struct bat_priv *bat_priv,
                                struct vis_info *info)
 {
-       HASHIT(hashit);
+       struct hashtable_t *hash = bat_priv->orig_hash;
+       struct hlist_node *walk;
+       struct hlist_head *head;
+       struct element_t *bucket;
        struct orig_node *orig_node;
        struct vis_packet *packet;
-       int best_tq = -1;
+       int best_tq = -1, i;
 
        packet = (struct vis_packet *)info->skb_packet->data;
 
-       while (hash_iterate(bat_priv->orig_hash, &hashit)) {
-               orig_node = hashit.bucket->data;
-               if ((orig_node) && (orig_node->router) &&
-                   (orig_node->flags & VIS_SERVER) &&
-                   (orig_node->router->tq_avg > best_tq)) {
-                       best_tq = orig_node->router->tq_avg;
-                       memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+
+               hlist_for_each_entry(bucket, walk, head, hlist) {
+                       orig_node = bucket->data;
+                       if ((orig_node) && (orig_node->router) &&
+                       (orig_node->flags & VIS_SERVER) &&
+                       (orig_node->router->tq_avg > best_tq)) {
+                               best_tq = orig_node->router->tq_avg;
+                               memcpy(packet->target_orig, orig_node->orig,
+                                      ETH_ALEN);
+                       }
                }
        }
+
        return best_tq;
 }
 
@@ -544,20 +572,22 @@ static bool vis_packet_full(struct vis_info *info)
  * returns 0 on success, -1 if no packet could be generated */
 static int generate_vis_packet(struct bat_priv *bat_priv)
 {
-       HASHIT(hashit_local);
-       HASHIT(hashit_global);
+       struct hashtable_t *hash = bat_priv->orig_hash;
+       struct hlist_node *walk;
+       struct hlist_head *head;
+       struct element_t *bucket;
        struct orig_node *orig_node;
+       struct neigh_node *neigh_node;
        struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
        struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
        struct vis_info_entry *entry;
        struct hna_local_entry *hna_local_entry;
-       int best_tq = -1;
-       unsigned long flags;
+       int best_tq = -1, i;
 
        info->first_seen = jiffies;
        packet->vis_type = atomic_read(&bat_priv->vis_mode);
 
-       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
+       spin_lock_bh(&bat_priv->orig_hash_lock);
        memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
        packet->ttl = TTL;
        packet->seqno = htonl(ntohl(packet->seqno) + 1);
@@ -568,64 +598,73 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
                best_tq = find_best_vis_server(bat_priv, info);
 
                if (best_tq < 0) {
-                       spin_unlock_irqrestore(&bat_priv->orig_hash_lock,
-                                              flags);
+                       spin_unlock_bh(&bat_priv->orig_hash_lock);
                        return -1;
                }
        }
 
-       while (hash_iterate(bat_priv->orig_hash, &hashit_global)) {
-               orig_node = hashit_global.bucket->data;
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
 
-               if (!orig_node->router)
-                       continue;
+               hlist_for_each_entry(bucket, walk, head, hlist) {
+                       orig_node = bucket->data;
+                       neigh_node = orig_node->router;
 
-               if (!compare_orig(orig_node->router->addr, orig_node->orig))
-                       continue;
+                       if (!neigh_node)
+                               continue;
 
-               if (orig_node->router->if_incoming->if_status != IF_ACTIVE)
-                       continue;
+                       if (!compare_orig(neigh_node->addr, orig_node->orig))
+                               continue;
 
-               if (orig_node->router->tq_avg < 1)
-                       continue;
+                       if (neigh_node->if_incoming->if_status != IF_ACTIVE)
+                               continue;
 
-               /* fill one entry into buffer. */
-               entry = (struct vis_info_entry *)
-                               skb_put(info->skb_packet, sizeof(*entry));
-               memcpy(entry->src,
-                      orig_node->router->if_incoming->net_dev->dev_addr,
-                      ETH_ALEN);
-               memcpy(entry->dest, orig_node->orig, ETH_ALEN);
-               entry->quality = orig_node->router->tq_avg;
-               packet->entries++;
+                       if (neigh_node->tq_avg < 1)
+                               continue;
 
-               if (vis_packet_full(info)) {
-                       spin_unlock_irqrestore(
-                                       &bat_priv->orig_hash_lock, flags);
-                       return 0;
+                       /* fill one entry into buffer. */
+                       entry = (struct vis_info_entry *)
+                                     skb_put(info->skb_packet, sizeof(*entry));
+                       memcpy(entry->src,
+                              neigh_node->if_incoming->net_dev->dev_addr,
+                              ETH_ALEN);
+                       memcpy(entry->dest, orig_node->orig, ETH_ALEN);
+                       entry->quality = neigh_node->tq_avg;
+                       packet->entries++;
+
+                       if (vis_packet_full(info)) {
+                               spin_unlock_bh(&bat_priv->orig_hash_lock);
+                               return 0;
+                       }
                }
        }
 
-       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
-       spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
-       while (hash_iterate(bat_priv->hna_local_hash, &hashit_local)) {
-               hna_local_entry = hashit_local.bucket->data;
-               entry = (struct vis_info_entry *)skb_put(info->skb_packet,
-                                                        sizeof(*entry));
-               memset(entry->src, 0, ETH_ALEN);
-               memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN);
-               entry->quality = 0; /* 0 means HNA */
-               packet->entries++;
-
-               if (vis_packet_full(info)) {
-                       spin_unlock_irqrestore(&bat_priv->hna_lhash_lock,
-                                              flags);
-                       return 0;
+       spin_unlock_bh(&bat_priv->orig_hash_lock);
+
+       hash = bat_priv->hna_local_hash;
+
+       spin_lock_bh(&bat_priv->hna_lhash_lock);
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+
+               hlist_for_each_entry(bucket, walk, head, hlist) {
+                       hna_local_entry = bucket->data;
+                       entry = (struct vis_info_entry *)
+                                       skb_put(info->skb_packet,
+                                               sizeof(*entry));
+                       memset(entry->src, 0, ETH_ALEN);
+                       memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN);
+                       entry->quality = 0; /* 0 means HNA */
+                       packet->entries++;
+
+                       if (vis_packet_full(info)) {
+                               spin_unlock_bh(&bat_priv->hna_lhash_lock);
+                               return 0;
+                       }
                }
        }
 
-       spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
+       spin_unlock_bh(&bat_priv->hna_lhash_lock);
        return 0;
 }
 
@@ -633,21 +672,30 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
  * held */
 static void purge_vis_packets(struct bat_priv *bat_priv)
 {
-       HASHIT(hashit);
+       int i;
+       struct hashtable_t *hash = bat_priv->vis_hash;
+       struct hlist_node *walk, *safe;
+       struct hlist_head *head;
+       struct element_t *bucket;
        struct vis_info *info;
 
-       while (hash_iterate(bat_priv->vis_hash, &hashit)) {
-               info = hashit.bucket->data;
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+
+               hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
+                       info = bucket->data;
 
-               /* never purge own data. */
-               if (info == bat_priv->my_vis_info)
-                       continue;
+                       /* never purge own data. */
+                       if (info == bat_priv->my_vis_info)
+                               continue;
 
-               if (time_after(jiffies,
-                              info->first_seen + VIS_TIMEOUT * HZ)) {
-                       hash_remove_bucket(bat_priv->vis_hash, &hashit);
-                       send_list_del(info);
-                       kref_put(&info->refcount, free_info);
+                       if (time_after(jiffies,
+                                      info->first_seen + VIS_TIMEOUT * HZ)) {
+                               hlist_del(walk);
+                               kfree(bucket);
+                               send_list_del(info);
+                               kref_put(&info->refcount, free_info);
+                       }
                }
        }
 }
@@ -655,47 +703,54 @@ static void purge_vis_packets(struct bat_priv *bat_priv)
 static void broadcast_vis_packet(struct bat_priv *bat_priv,
                                 struct vis_info *info)
 {
-       HASHIT(hashit);
+       struct hashtable_t *hash = bat_priv->orig_hash;
+       struct hlist_node *walk;
+       struct hlist_head *head;
+       struct element_t *bucket;
        struct orig_node *orig_node;
        struct vis_packet *packet;
        struct sk_buff *skb;
-       unsigned long flags;
        struct batman_if *batman_if;
        uint8_t dstaddr[ETH_ALEN];
+       int i;
 
 
-       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
+       spin_lock_bh(&bat_priv->orig_hash_lock);
        packet = (struct vis_packet *)info->skb_packet->data;
 
        /* send to all routers in range. */
-       while (hash_iterate(bat_priv->orig_hash, &hashit)) {
-               orig_node = hashit.bucket->data;
-
-               /* if it's a vis server and reachable, send it. */
-               if ((!orig_node) || (!orig_node->router))
-                       continue;
-               if (!(orig_node->flags & VIS_SERVER))
-                       continue;
-               /* don't send it if we already received the packet from
-                * this node. */
-               if (recv_list_is_in(bat_priv, &info->recv_list,
-                                                       orig_node->orig))
-                       continue;
-
-               memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
-               batman_if = orig_node->router->if_incoming;
-               memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
-               spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
-               skb = skb_clone(info->skb_packet, GFP_ATOMIC);
-               if (skb)
-                       send_skb_packet(skb, batman_if, dstaddr);
-
-               spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+
+               hlist_for_each_entry(bucket, walk, head, hlist) {
+                       orig_node = bucket->data;
+
+                       /* if it's a vis server and reachable, send it. */
+                       if ((!orig_node) || (!orig_node->router))
+                               continue;
+                       if (!(orig_node->flags & VIS_SERVER))
+                               continue;
+                       /* don't send it if we already received the packet from
+                       * this node. */
+                       if (recv_list_is_in(bat_priv, &info->recv_list,
+                                           orig_node->orig))
+                               continue;
+
+                       memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
+                       batman_if = orig_node->router->if_incoming;
+                       memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+                       spin_unlock_bh(&bat_priv->orig_hash_lock);
+
+                       skb = skb_clone(info->skb_packet, GFP_ATOMIC);
+                       if (skb)
+                               send_skb_packet(skb, batman_if, dstaddr);
+
+                       spin_lock_bh(&bat_priv->orig_hash_lock);
+               }
 
        }
 
-       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->orig_hash_lock);
 }
 
 static void unicast_vis_packet(struct bat_priv *bat_priv,
@@ -704,13 +759,13 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
        struct orig_node *orig_node;
        struct sk_buff *skb;
        struct vis_packet *packet;
-       unsigned long flags;
        struct batman_if *batman_if;
        uint8_t dstaddr[ETH_ALEN];
 
-       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
+       spin_lock_bh(&bat_priv->orig_hash_lock);
        packet = (struct vis_packet *)info->skb_packet->data;
        orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
+                                                  compare_orig, choose_orig,
                                                   packet->target_orig));
 
        if ((!orig_node) || (!orig_node->router))
@@ -720,7 +775,7 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
         * copy the required data before sending */
        batman_if = orig_node->router->if_incoming;
        memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
-       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->orig_hash_lock);
 
        skb = skb_clone(info->skb_packet, GFP_ATOMIC);
        if (skb)
@@ -729,7 +784,7 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
        return;
 
 out:
-       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->orig_hash_lock);
 }
 
 /* only send one vis packet. called from send_vis_packets() */
@@ -747,7 +802,7 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
               ETH_ALEN);
        packet->ttl--;
 
-       if (is_bcast(packet->target_orig))
+       if (is_broadcast_ether_addr(packet->target_orig))
                broadcast_vis_packet(bat_priv, info);
        else
                unicast_vis_packet(bat_priv, info);
@@ -761,10 +816,9 @@ static void send_vis_packets(struct work_struct *work)
                container_of(work, struct delayed_work, work);
        struct bat_priv *bat_priv =
                container_of(delayed_work, struct bat_priv, vis_work);
-       struct vis_info *info, *temp;
-       unsigned long flags;
+       struct vis_info *info;
 
-       spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
+       spin_lock_bh(&bat_priv->vis_hash_lock);
        purge_vis_packets(bat_priv);
 
        if (generate_vis_packet(bat_priv) == 0) {
@@ -772,20 +826,21 @@ static void send_vis_packets(struct work_struct *work)
                send_list_add(bat_priv, bat_priv->my_vis_info);
        }
 
-       list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list,
-                                send_list) {
+       while (!list_empty(&bat_priv->vis_send_list)) {
+               info = list_first_entry(&bat_priv->vis_send_list,
+                                       typeof(*info), send_list);
 
                kref_get(&info->refcount);
-               spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+               spin_unlock_bh(&bat_priv->vis_hash_lock);
 
                if (bat_priv->primary_if)
                        send_vis_packet(bat_priv, info);
 
-               spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
+               spin_lock_bh(&bat_priv->vis_hash_lock);
                send_list_del(info);
                kref_put(&info->refcount, free_info);
        }
-       spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_hash_lock);
        start_vis_timer(bat_priv);
 }
 
@@ -794,14 +849,14 @@ static void send_vis_packets(struct work_struct *work)
 int vis_init(struct bat_priv *bat_priv)
 {
        struct vis_packet *packet;
-       unsigned long flags;
+       int hash_added;
 
        if (bat_priv->vis_hash)
                return 1;
 
-       spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
+       spin_lock_bh(&bat_priv->vis_hash_lock);
 
-       bat_priv->vis_hash = hash_new(256, vis_info_cmp, vis_info_choose);
+       bat_priv->vis_hash = hash_new(256);
        if (!bat_priv->vis_hash) {
                pr_err("Can't initialize vis_hash\n");
                goto err;
@@ -840,14 +895,16 @@ int vis_init(struct bat_priv *bat_priv)
 
        INIT_LIST_HEAD(&bat_priv->vis_send_list);
 
-       if (hash_add(bat_priv->vis_hash, bat_priv->my_vis_info) < 0) {
+       hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
+                             bat_priv->my_vis_info);
+       if (hash_added < 0) {
                pr_err("Can't add own vis packet into hash\n");
                /* not in hash, need to remove it manually. */
                kref_put(&bat_priv->my_vis_info->refcount, free_info);
                goto err;
        }
 
-       spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_hash_lock);
        start_vis_timer(bat_priv);
        return 1;
 
@@ -855,7 +912,7 @@ free_info:
        kfree(bat_priv->my_vis_info);
        bat_priv->my_vis_info = NULL;
 err:
-       spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_hash_lock);
        vis_quit(bat_priv);
        return 0;
 }
@@ -872,18 +929,17 @@ static void free_info_ref(void *data, void *arg)
 /* shutdown vis-server */
 void vis_quit(struct bat_priv *bat_priv)
 {
-       unsigned long flags;
        if (!bat_priv->vis_hash)
                return;
 
        cancel_delayed_work_sync(&bat_priv->vis_work);
 
-       spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
+       spin_lock_bh(&bat_priv->vis_hash_lock);
        /* properly remove, kill timers ... */
        hash_delete(bat_priv->vis_hash, free_info_ref, NULL);
        bat_priv->vis_hash = NULL;
        bat_priv->my_vis_info = NULL;
-       spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
+       spin_unlock_bh(&bat_priv->vis_hash_lock);
 }
 
 /* schedule packets for (re)transmission */