call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu);
 }
 
-static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv)
+static void softif_neigh_vid_free_rcu(struct rcu_head *rcu)
 {
-       struct softif_neigh *neigh;
-
-       rcu_read_lock();
-       neigh = rcu_dereference(bat_priv->softif_neigh);
-
-       if (neigh && !atomic_inc_not_zero(&neigh->refcount))
-               neigh = NULL;
-
-       rcu_read_unlock();
-       return neigh;
-}
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct softif_neigh *softif_neigh;
+       struct hlist_node *node, *node_tmp;
+       struct bat_priv *bat_priv;
 
-static void softif_neigh_select(struct bat_priv *bat_priv,
-                               struct softif_neigh *new_neigh)
-{
-       struct softif_neigh *curr_neigh;
+       softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu);
+       bat_priv = softif_neigh_vid->bat_priv;
 
        spin_lock_bh(&bat_priv->softif_neigh_lock);
-
-       if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
-               new_neigh = NULL;
-
-       curr_neigh = bat_priv->softif_neigh;
-       rcu_assign_pointer(bat_priv->softif_neigh, new_neigh);
-
-       if (curr_neigh)
-               softif_neigh_free_ref(curr_neigh);
-
+       hlist_for_each_entry_safe(softif_neigh, node, node_tmp,
+                                 &softif_neigh_vid->softif_neigh_list, list) {
+               hlist_del_rcu(&softif_neigh->list);
+               softif_neigh_free_ref(softif_neigh);
+       }
        spin_unlock_bh(&bat_priv->softif_neigh_lock);
+
+       kfree(softif_neigh_vid);
 }
 
-static void softif_neigh_deselect(struct bat_priv *bat_priv)
+static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid)
 {
-       softif_neigh_select(bat_priv, NULL);
+       if (atomic_dec_and_test(&softif_neigh_vid->refcount))
+               call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu);
 }
 
-void softif_neigh_purge(struct bat_priv *bat_priv)
+static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv,
+                                                    short vid)
 {
-       struct softif_neigh *softif_neigh, *curr_softif_neigh;
-       struct hlist_node *node, *node_tmp;
-       char do_deselect = 0;
-
-       curr_softif_neigh = softif_neigh_get_selected(bat_priv);
-
-       spin_lock_bh(&bat_priv->softif_neigh_lock);
-
-       hlist_for_each_entry_safe(softif_neigh, node, node_tmp,
-                                 &bat_priv->softif_neigh_list, list) {
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct hlist_node *node;
 
-               if ((!time_after(jiffies, softif_neigh->last_seen +
-                               msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) &&
-                   (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(softif_neigh_vid, node,
+                                &bat_priv->softif_neigh_vids, list) {
+               if (softif_neigh_vid->vid != vid)
                        continue;
 
-               if (curr_softif_neigh == softif_neigh) {
-                       bat_dbg(DBG_ROUTES, bat_priv,
-                                "Current mesh exit point '%pM' vanished "
-                                "(vid: %d).\n",
-                                softif_neigh->addr, softif_neigh->vid);
-                       do_deselect = 1;
-               }
+               if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
+                       continue;
 
-               hlist_del_rcu(&softif_neigh->list);
-               softif_neigh_free_ref(softif_neigh);
+               goto out;
        }
 
-       spin_unlock_bh(&bat_priv->softif_neigh_lock);
+       softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid),
+                                  GFP_ATOMIC);
+       if (!softif_neigh_vid)
+               goto out;
 
-       /* soft_neigh_deselect() needs to acquire the softif_neigh_lock */
-       if (do_deselect)
-               softif_neigh_deselect(bat_priv);
+       softif_neigh_vid->vid = vid;
+       softif_neigh_vid->bat_priv = bat_priv;
 
-       if (curr_softif_neigh)
-               softif_neigh_free_ref(curr_softif_neigh);
+       /* initialize with 2 - caller decrements counter by one */
+       atomic_set(&softif_neigh_vid->refcount, 2);
+       INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list);
+       INIT_HLIST_NODE(&softif_neigh_vid->list);
+       spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
+       hlist_add_head_rcu(&softif_neigh_vid->list,
+                          &bat_priv->softif_neigh_vids);
+       spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
+
+out:
+       rcu_read_unlock();
+       return softif_neigh_vid;
 }
 
 static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
                                             uint8_t *addr, short vid)
 {
-       struct softif_neigh *softif_neigh;
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct softif_neigh *softif_neigh = NULL;
        struct hlist_node *node;
 
+       softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+       if (!softif_neigh_vid)
+               goto out;
+
        rcu_read_lock();
        hlist_for_each_entry_rcu(softif_neigh, node,
-                                &bat_priv->softif_neigh_list, list) {
+                                &softif_neigh_vid->softif_neigh_list,
+                                list) {
                if (!compare_eth(softif_neigh->addr, addr))
                        continue;
 
-               if (softif_neigh->vid != vid)
-                       continue;
-
                if (!atomic_inc_not_zero(&softif_neigh->refcount))
                        continue;
 
                softif_neigh->last_seen = jiffies;
-               goto out;
+               goto unlock;
        }
 
        softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC);
        if (!softif_neigh)
-               goto out;
+               goto unlock;
 
        memcpy(softif_neigh->addr, addr, ETH_ALEN);
-       softif_neigh->vid = vid;
        softif_neigh->last_seen = jiffies;
        /* initialize with 2 - caller decrements counter by one */
        atomic_set(&softif_neigh->refcount, 2);
 
        INIT_HLIST_NODE(&softif_neigh->list);
        spin_lock_bh(&bat_priv->softif_neigh_lock);
-       hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list);
+       hlist_add_head_rcu(&softif_neigh->list,
+                          &softif_neigh_vid->softif_neigh_list);
        spin_unlock_bh(&bat_priv->softif_neigh_lock);
 
+unlock:
+       rcu_read_unlock();
 out:
+       if (softif_neigh_vid)
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+       return softif_neigh;
+}
+
+static struct softif_neigh *softif_neigh_get_selected(
+                               struct softif_neigh_vid *softif_neigh_vid)
+{
+       struct softif_neigh *softif_neigh;
+
+       rcu_read_lock();
+       softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
+
+       if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount))
+               softif_neigh = NULL;
+
        rcu_read_unlock();
        return softif_neigh;
 }
 
+static struct softif_neigh *softif_neigh_vid_get_selected(
+                                               struct bat_priv *bat_priv,
+                                               short vid)
+{
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct softif_neigh *softif_neigh = NULL;
+
+       softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+       if (!softif_neigh_vid)
+               goto out;
+
+       softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+out:
+       if (softif_neigh_vid)
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+       return softif_neigh;
+}
+
+static void softif_neigh_vid_select(struct bat_priv *bat_priv,
+                                   struct softif_neigh *new_neigh,
+                                   short vid)
+{
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct softif_neigh *curr_neigh;
+
+       softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+       if (!softif_neigh_vid)
+               goto out;
+
+       spin_lock_bh(&bat_priv->softif_neigh_lock);
+
+       if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
+               new_neigh = NULL;
+
+       curr_neigh = softif_neigh_vid->softif_neigh;
+       rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh);
+
+       if ((curr_neigh) && (!new_neigh))
+               bat_dbg(DBG_ROUTES, bat_priv,
+                       "Removing mesh exit point on vid: %d (prev: %pM).\n",
+                       vid, curr_neigh->addr);
+       else if ((curr_neigh) && (new_neigh))
+               bat_dbg(DBG_ROUTES, bat_priv,
+                       "Changing mesh exit point on vid: %d from %pM "
+                       "to %pM.\n", vid, curr_neigh->addr, new_neigh->addr);
+       else if ((!curr_neigh) && (new_neigh))
+               bat_dbg(DBG_ROUTES, bat_priv,
+                       "Setting mesh exit point on vid: %d to %pM.\n",
+                       vid, new_neigh->addr);
+
+       if (curr_neigh)
+               softif_neigh_free_ref(curr_neigh);
+
+       spin_unlock_bh(&bat_priv->softif_neigh_lock);
+
+out:
+       if (softif_neigh_vid)
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+}
+
+static void softif_neigh_vid_deselect(struct bat_priv *bat_priv,
+                                     struct softif_neigh_vid *softif_neigh_vid)
+{
+       struct softif_neigh *curr_neigh;
+       struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp;
+       struct hard_iface *primary_if = NULL;
+       struct hlist_node *node;
+
+       primary_if = primary_if_get_selected(bat_priv);
+       if (!primary_if)
+               goto out;
+
+       /* find new softif_neigh immediately to avoid temporary loops */
+       rcu_read_lock();
+       curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
+
+       hlist_for_each_entry_rcu(softif_neigh_tmp, node,
+                                &softif_neigh_vid->softif_neigh_list,
+                                list) {
+               if (softif_neigh_tmp == curr_neigh)
+                       continue;
+
+               /* we got a neighbor but its mac is 'bigger' than ours  */
+               if (memcmp(primary_if->net_dev->dev_addr,
+                          softif_neigh_tmp->addr, ETH_ALEN) < 0)
+                       continue;
+
+               if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount))
+                       continue;
+
+               softif_neigh = softif_neigh_tmp;
+               goto unlock;
+       }
+
+unlock:
+       rcu_read_unlock();
+out:
+       softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid);
+
+       if (primary_if)
+               hardif_free_ref(primary_if);
+       if (softif_neigh)
+               softif_neigh_free_ref(softif_neigh);
+}
+
 int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
 {
        struct net_device *net_dev = (struct net_device *)seq->private;
        struct bat_priv *bat_priv = netdev_priv(net_dev);
+       struct softif_neigh_vid *softif_neigh_vid;
        struct softif_neigh *softif_neigh;
        struct hard_iface *primary_if;
-       struct hlist_node *node;
+       struct hlist_node *node, *node_tmp;
        struct softif_neigh *curr_softif_neigh;
-       int ret = 0;
+       int ret = 0, last_seen_secs, last_seen_msecs;
 
        primary_if = primary_if_get_selected(bat_priv);
        if (!primary_if) {
 
        seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
 
-       curr_softif_neigh = softif_neigh_get_selected(bat_priv);
        rcu_read_lock();
-       hlist_for_each_entry_rcu(softif_neigh, node,
-                                &bat_priv->softif_neigh_list, list)
-               seq_printf(seq, "%s %pM (vid: %d)\n",
-                               curr_softif_neigh == softif_neigh
-                               ? "=>" : "  ", softif_neigh->addr,
-                               softif_neigh->vid);
+       hlist_for_each_entry_rcu(softif_neigh_vid, node,
+                                &bat_priv->softif_neigh_vids, list) {
+               seq_printf(seq, "     %-15s %s on vid: %d\n",
+                          "Originator", "last-seen", softif_neigh_vid->vid);
+
+               curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+
+               hlist_for_each_entry_rcu(softif_neigh, node_tmp,
+                                        &softif_neigh_vid->softif_neigh_list,
+                                        list) {
+                       last_seen_secs = jiffies_to_msecs(jiffies -
+                                               softif_neigh->last_seen) / 1000;
+                       last_seen_msecs = jiffies_to_msecs(jiffies -
+                                               softif_neigh->last_seen) % 1000;
+                       seq_printf(seq, "%s %pM  %3i.%03is\n",
+                                  curr_softif_neigh == softif_neigh
+                                  ? "=>" : "  ", softif_neigh->addr,
+                                  last_seen_secs, last_seen_msecs);
+               }
+
+               if (curr_softif_neigh)
+                       softif_neigh_free_ref(curr_softif_neigh);
+
+               seq_printf(seq, "\n");
+       }
        rcu_read_unlock();
-       if (curr_softif_neigh)
-               softif_neigh_free_ref(curr_softif_neigh);
 
 out:
        if (primary_if)
        return ret;
 }
 
+void softif_neigh_purge(struct bat_priv *bat_priv)
+{
+       struct softif_neigh *softif_neigh, *curr_softif_neigh;
+       struct softif_neigh_vid *softif_neigh_vid;
+       struct hlist_node *node, *node_tmp, *node_tmp2;
+       char do_deselect;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(softif_neigh_vid, node,
+                                &bat_priv->softif_neigh_vids, list) {
+               if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
+                       continue;
+
+               curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+               do_deselect = 0;
+
+               spin_lock_bh(&bat_priv->softif_neigh_lock);
+               hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2,
+                                         &softif_neigh_vid->softif_neigh_list,
+                                         list) {
+                       if ((!time_after(jiffies, softif_neigh->last_seen +
+                               msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) &&
+                           (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
+                               continue;
+
+                       if (curr_softif_neigh == softif_neigh) {
+                               bat_dbg(DBG_ROUTES, bat_priv,
+                                       "Current mesh exit point on vid: %d "
+                                       "'%pM' vanished.\n",
+                                       softif_neigh_vid->vid,
+                                       softif_neigh->addr);
+                               do_deselect = 1;
+                       }
+
+                       hlist_del_rcu(&softif_neigh->list);
+                       softif_neigh_free_ref(softif_neigh);
+               }
+               spin_unlock_bh(&bat_priv->softif_neigh_lock);
+
+               /* soft_neigh_vid_deselect() needs to acquire the
+                * softif_neigh_lock */
+               if (do_deselect)
+                       softif_neigh_vid_deselect(bat_priv, softif_neigh_vid);
+
+               if (curr_softif_neigh)
+                       softif_neigh_free_ref(curr_softif_neigh);
+
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+       }
+       rcu_read_unlock();
+
+       spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
+       hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp,
+                                 &bat_priv->softif_neigh_vids, list) {
+               if (!hlist_empty(&softif_neigh_vid->softif_neigh_list))
+                       continue;
+
+               hlist_del_rcu(&softif_neigh_vid->list);
+               softif_neigh_vid_free_ref(softif_neigh_vid);
+       }
+       spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
+
+}
+
 static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
                               short vid)
 {
        if (!softif_neigh)
                goto out;
 
-       curr_softif_neigh = softif_neigh_get_selected(bat_priv);
-       if (!curr_softif_neigh)
-               goto out;
-
+       curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
        if (curr_softif_neigh == softif_neigh)
                goto out;
 
                   softif_neigh->addr, ETH_ALEN) < 0)
                goto out;
 
-       /* switch to new 'smallest neighbor' */
-       if ((curr_softif_neigh) &&
-           (memcmp(softif_neigh->addr, curr_softif_neigh->addr,
-                                                       ETH_ALEN) < 0)) {
-               bat_dbg(DBG_ROUTES, bat_priv,
-                       "Changing mesh exit point from %pM (vid: %d) "
-                       "to %pM (vid: %d).\n",
-                        curr_softif_neigh->addr,
-                        curr_softif_neigh->vid,
-                        softif_neigh->addr, softif_neigh->vid);
-
-               softif_neigh_select(bat_priv, softif_neigh);
-               goto out;
-       }
-
        /* close own batX device and use softif_neigh as exit node */
-       if ((!curr_softif_neigh) &&
-           (memcmp(softif_neigh->addr,
-                   primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) {
-               bat_dbg(DBG_ROUTES, bat_priv,
-                       "Setting mesh exit point to %pM (vid: %d).\n",
-                       softif_neigh->addr, softif_neigh->vid);
-
-               softif_neigh_select(bat_priv, softif_neigh);
+       if (!curr_softif_neigh) {
+               softif_neigh_vid_select(bat_priv, softif_neigh, vid);
                goto out;
        }
 
+       /* switch to new 'smallest neighbor' */
+       if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0)
+               softif_neigh_vid_select(bat_priv, softif_neigh, vid);
+
 out:
        kfree_skb(skb);
        if (softif_neigh)
         * if we have a another chosen mesh exit node in range
         * it will transport the packets to the mesh
         */
-       curr_softif_neigh = softif_neigh_get_selected(bat_priv);
-       if ((curr_softif_neigh) && (curr_softif_neigh->vid == vid))
+       curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
+       if (curr_softif_neigh)
                goto dropped;
 
        /* TODO: check this for locks */
         * if we have a another chosen mesh exit node in range
         * it will transport the packets to the non-mesh network
         */
-       curr_softif_neigh = softif_neigh_get_selected(bat_priv);
-       if (curr_softif_neigh && (curr_softif_neigh->vid == vid)) {
+       curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
+       if (curr_softif_neigh) {
                skb_push(skb, hdr_size);
                unicast_packet = (struct unicast_packet *)skb->data;
 
 
        bat_priv->primary_if = NULL;
        bat_priv->num_ifaces = 0;
-       bat_priv->softif_neigh = NULL;
 
        ret = sysfs_add_meshif(soft_iface);
        if (ret < 0)