return count;
 }
 
+static ssize_t show_bond(struct kobject *kobj, struct attribute *attr,
+                            char *buff)
+{
+       struct device *dev = to_dev(kobj->parent);
+       struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
+       int bond_status = atomic_read(&bat_priv->bonding_enabled);
+
+       return sprintf(buff, "%s\n",
+                      bond_status == 0 ? "disabled" : "enabled");
+}
+
+static ssize_t store_bond(struct kobject *kobj, struct attribute *attr,
+                         char *buff, size_t count)
+{
+       struct device *dev = to_dev(kobj->parent);
+       struct net_device *net_dev = to_net_dev(dev);
+       struct bat_priv *bat_priv = netdev_priv(net_dev);
+       int bonding_enabled_tmp = -1;
+
+       if (((count == 2) && (buff[0] == '1')) ||
+           (strncmp(buff, "enable", 6) == 0))
+               bonding_enabled_tmp = 1;
+
+       if (((count == 2) && (buff[0] == '0')) ||
+           (strncmp(buff, "disable", 7) == 0))
+               bonding_enabled_tmp = 0;
+
+       if (bonding_enabled_tmp < 0) {
+               if (buff[count - 1] == '\n')
+                       buff[count - 1] = '\0';
+
+               printk(KERN_ERR "batman-adv:Invalid parameter for 'bonding' setting on mesh %s received: %s\n",
+                      net_dev->name, buff);
+               return -EINVAL;
+       }
+
+       if (atomic_read(&bat_priv->bonding_enabled) == bonding_enabled_tmp)
+               return count;
+
+       printk(KERN_INFO "batman-adv:Changing bonding from: %s to: %s on mesh: %s\n",
+              atomic_read(&bat_priv->bonding_enabled) == 1 ?
+              "enabled" : "disabled",
+              bonding_enabled_tmp == 1 ? "enabled" : "disabled",
+              net_dev->name);
+
+       atomic_set(&bat_priv->bonding_enabled, (unsigned)bonding_enabled_tmp);
+       return count;
+}
+
 static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
                             char *buff)
 {
 
 static BAT_ATTR(aggregated_ogms, S_IRUGO | S_IWUSR,
                show_aggr_ogms, store_aggr_ogms);
+static BAT_ATTR(bonding, S_IRUGO | S_IWUSR, show_bond, store_bond);
 static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
 static BAT_ATTR(orig_interval, S_IRUGO | S_IWUSR,
                show_orig_interval, store_orig_interval);
 
 static struct bat_attribute *mesh_attrs[] = {
        &bat_attr_aggregated_ogms,
+       &bat_attr_bonding,
        &bat_attr_vis_mode,
        &bat_attr_orig_interval,
        NULL,
        /* FIXME: should be done in the general mesh setup
                  routine as soon as we have it */
        atomic_set(&bat_priv->aggregation_enabled, 1);
+       atomic_set(&bat_priv->bonding_enabled, 0);
        atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
        atomic_set(&bat_priv->orig_interval, 1000);
        bat_priv->primary_if = NULL;
 
        return is_duplicate;
 }
 
+/* copy primary address for bonding */
+static void mark_bonding_address(struct bat_priv *bat_priv,
+                                struct orig_node *orig_node,
+                                struct orig_node *orig_neigh_node,
+                                struct batman_packet *batman_packet)
+
+{
+       /* don't care if bonding is not enabled */
+       if (!atomic_read(&bat_priv->bonding_enabled)) {
+               orig_node->bond.candidates = 0;
+               return;
+       }
+
+       if (batman_packet->flags & PRIMARIES_FIRST_HOP)
+               memcpy(orig_neigh_node->primary_addr,
+                      orig_node->orig, ETH_ALEN);
+
+       return;
+}
+
+/* mark possible bond.candidates in the neighbor list */
+void update_bonding_candidates(struct bat_priv *bat_priv,
+                              struct orig_node *orig_node)
+{
+       int candidates;
+       int interference_candidate;
+       int best_tq;
+       struct neigh_node *tmp_neigh_node, *tmp_neigh_node2;
+       struct neigh_node *first_candidate, *last_candidate;
+
+       /* don't care if bonding is not enabled */
+       if (!atomic_read(&bat_priv->bonding_enabled)) {
+               orig_node->bond.candidates = 0;
+               return;
+       }
+
+       /* update the candidates for this originator */
+       if (!orig_node->router) {
+               orig_node->bond.candidates = 0;
+               return;
+       }
+
+       best_tq = orig_node->router->tq_avg;
+
+       /* update bond.candidates */
+
+       candidates = 0;
+
+       /* mark other nodes which also received "PRIMARIES FIRST HOP" packets
+        * as "bonding partner" */
+
+       /* first, zero the list */
+       list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+               tmp_neigh_node->next_bond_candidate = NULL;
+       }
+
+       first_candidate = NULL;
+       last_candidate = NULL;
+       list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+
+               /* only consider if it has the same primary address ...  */
+               if (memcmp(orig_node->orig,
+                               tmp_neigh_node->orig_node->primary_addr,
+                               ETH_ALEN) != 0)
+                       continue;
+
+               /* ... and is good enough to be considered */
+               if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD)
+                       continue;
+
+               /* check if we have another candidate with the same
+                * mac address or interface. If we do, we won't
+                * select this candidate because of possible interference. */
+
+               interference_candidate = 0;
+               list_for_each_entry(tmp_neigh_node2,
+                               &orig_node->neigh_list, list) {
+
+                       if (tmp_neigh_node2 == tmp_neigh_node)
+                               continue;
+
+                       /* we only care if the other candidate is even
+                        * considered as candidate. */
+                       if (tmp_neigh_node2->next_bond_candidate == NULL)
+                               continue;
+
+
+                       if ((tmp_neigh_node->if_incoming ==
+                               tmp_neigh_node2->if_incoming)
+                               || (memcmp(tmp_neigh_node->addr,
+                               tmp_neigh_node2->addr, ETH_ALEN) == 0)) {
+
+                               interference_candidate = 1;
+                               break;
+                       }
+               }
+               /* don't care further if it is an interference candidate */
+               if (interference_candidate)
+                       continue;
+
+               if (first_candidate == NULL) {
+                       first_candidate = tmp_neigh_node;
+                       tmp_neigh_node->next_bond_candidate = first_candidate;
+               } else
+                       tmp_neigh_node->next_bond_candidate = last_candidate;
+
+               last_candidate = tmp_neigh_node;
+
+               candidates++;
+       }
+
+       if (candidates > 0) {
+               first_candidate->next_bond_candidate = last_candidate;
+               orig_node->bond.selected = first_candidate;
+       }
+
+       orig_node->bond.candidates = candidates;
+}
+
 void receive_bat_packet(struct ethhdr *ethhdr,
                                struct batman_packet *batman_packet,
                                unsigned char *hna_buff, int hna_buff_len,
                                struct batman_if *if_incoming)
 {
+       /* FIXME: each orig_node->batman_if will be attached to a softif */
+       struct bat_priv *bat_priv = netdev_priv(soft_device);
        struct batman_if *batman_if;
        struct orig_node *orig_neigh_node, *orig_node;
        char has_directlink_flag;
                update_orig(orig_node, ethhdr, batman_packet,
                            if_incoming, hna_buff, hna_buff_len, is_duplicate);
 
+       mark_bonding_address(bat_priv, orig_node,
+                            orig_neigh_node, batman_packet);
+       update_bonding_candidates(bat_priv, orig_node);
+
        /* is single hop (direct) neighbor */
        if (is_single_hop_neigh) {
 
        return ret;
 }
 
+/* find a suitable router for this originator, and use
+ * bonding if possible. */
+struct neigh_node *find_router(struct orig_node *orig_node)
+{
+       /* FIXME: each orig_node->batman_if will be attached to a softif */
+       struct bat_priv *bat_priv = netdev_priv(soft_device);
+       struct orig_node *primary_orig_node;
+       struct orig_node *router_orig;
+       struct neigh_node *router;
+       static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+
+       if (!orig_node)
+               return NULL;
+
+       if (!orig_node->router)
+               return NULL;
+
+       /* don't care if bonding is not enabled */
+       if (!atomic_read(&bat_priv->bonding_enabled))
+               return orig_node->router;
+
+       router_orig = orig_node->router->orig_node;
+
+       /* if we have something in the primary_addr, we can search
+        * for a potential bonding candidate. */
+       if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0)
+               return orig_node->router;
+
+       /* find the orig_node which has the primary interface. might
+        * even be the same as our router_orig in many cases */
+
+       if (memcmp(router_orig->primary_addr,
+                               router_orig->orig, ETH_ALEN) == 0) {
+               primary_orig_node = router_orig;
+       } else {
+               primary_orig_node = hash_find(orig_hash,
+                                               router_orig->primary_addr);
+               if (!primary_orig_node)
+                       return orig_node->router;
+       }
+
+       /* with less than 2 candidates, we can't do any
+        * bonding and prefer the original router. */
+
+       if (primary_orig_node->bond.candidates < 2)
+               return orig_node->router;
+
+       router = primary_orig_node->bond.selected;
+
+       /* sanity check - this should never happen. */
+       if (!router)
+               return orig_node->router;
+
+       /* select the next bonding partner ... */
+       primary_orig_node->bond.selected = router->next_bond_candidate;
+
+       return router;
+}
+
 int recv_unicast_packet(struct sk_buff *skb)
 {
        struct unicast_packet *unicast_packet;
        struct orig_node *orig_node;
+       struct neigh_node *router;
        struct ethhdr *ethhdr;
        struct batman_if *batman_if;
        struct sk_buff *skb_old;
        uint8_t dstaddr[ETH_ALEN];
        int hdr_size = sizeof(struct unicast_packet);
-       int ret;
        unsigned long flags;
 
        /* drop packet if it has not necessary minimum size */
                return NET_RX_DROP;
        }
 
-       ret = NET_RX_DROP;
        /* get routing information */
        spin_lock_irqsave(&orig_hash_lock, flags);
        orig_node = ((struct orig_node *)
                     hash_find(orig_hash, unicast_packet->dest));
 
-       if ((orig_node != NULL) &&
-           (orig_node->router != NULL)) {
+       router = find_router(orig_node);
 
-               /* don't lock while sending the packets ... we therefore
-                * copy the required data before sending */
-               batman_if = orig_node->router->if_incoming;
-               memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+       if (!router) {
                spin_unlock_irqrestore(&orig_hash_lock, flags);
+               return NET_RX_DROP;
+       }
 
-               /* create a copy of the skb, if needed, to modify it. */
-               if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) {
-                       skb_old = skb;
-                       skb = skb_copy(skb, GFP_ATOMIC);
-                       if (!skb)
-                               return NET_RX_DROP;
-                       unicast_packet = (struct unicast_packet *)skb->data;
-                       ethhdr = (struct ethhdr *)skb_mac_header(skb);
-                       kfree_skb(skb_old);
-               }
-               /* decrement ttl */
-               unicast_packet->ttl--;
+       /* don't lock while sending the packets ... we therefore
+        * copy the required data before sending */
 
-               /* route it */
-               send_skb_packet(skb, batman_if, dstaddr);
-               ret = NET_RX_SUCCESS;
+       batman_if = router->if_incoming;
+       memcpy(dstaddr, router->addr, ETH_ALEN);
 
-       } else
-               spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_unlock_irqrestore(&orig_hash_lock, flags);
 
-       return ret;
+       /* create a copy of the skb, if needed, to modify it. */
+       if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) {
+               skb_old = skb;
+               skb = skb_copy(skb, GFP_ATOMIC);
+               if (!skb)
+                       return NET_RX_DROP;
+               unicast_packet = (struct unicast_packet *) skb->data;
+               ethhdr = (struct ethhdr *)skb_mac_header(skb);
+               kfree_skb(skb_old);
+       }
+
+       /* decrement ttl */
+       unicast_packet->ttl--;
+
+       /* route it */
+       send_skb_packet(skb, batman_if, dstaddr);
+
+       return NET_RX_SUCCESS;
 }
 
 int recv_bcast_packet(struct sk_buff *skb)
 
 #include "main.h"
 #include "soft-interface.h"
 #include "hard-interface.h"
+#include "routing.h"
 #include "send.h"
 #include "translation-table.h"
 #include "types.h"
        struct unicast_packet *unicast_packet;
        struct bcast_packet *bcast_packet;
        struct orig_node *orig_node;
+       struct neigh_node *router;
        struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
        struct bat_priv *priv = netdev_priv(dev);
        struct batman_if *batman_if;
                if (!orig_node)
                        orig_node = transtable_search(ethhdr->h_dest);
 
-               if ((orig_node) &&
-                   (orig_node->router)) {
-                       struct neigh_node *router = orig_node->router;
+               router = find_router(orig_node);
 
-                       if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
-                               goto unlock;
+               if (!router)
+                       goto unlock;
+
+               /* don't lock while sending the packets ... we therefore
+                * copy the required data before sending */
+
+               batman_if = router->if_incoming;
+               memcpy(dstaddr, router->addr, ETH_ALEN);
 
-                       unicast_packet = (struct unicast_packet *)skb->data;
+               spin_unlock_irqrestore(&orig_hash_lock, flags);
 
-                       unicast_packet->version = COMPAT_VERSION;
-                       /* batman packet type: unicast */
-                       unicast_packet->packet_type = BAT_UNICAST;
-                       /* set unicast ttl */
-                       unicast_packet->ttl = TTL;
-                       /* copy the destination for faster routing */
-                       memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+               if (batman_if->if_status != IF_ACTIVE)
+                       goto dropped;
 
-                       /* net_dev won't be available when not active */
-                       if (router->if_incoming->if_status != IF_ACTIVE)
-                               goto unlock;
+               if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
+                       goto dropped;
 
-                       /* don't lock while sending the packets ... we therefore
-                        * copy the required data before sending */
+               unicast_packet = (struct unicast_packet *)skb->data;
 
-                       batman_if = router->if_incoming;
-                       memcpy(dstaddr, router->addr, ETH_ALEN);
-                       spin_unlock_irqrestore(&orig_hash_lock, flags);
+               unicast_packet->version = COMPAT_VERSION;
+               /* batman packet type: unicast */
+               unicast_packet->packet_type = BAT_UNICAST;
+               /* set unicast ttl */
+               unicast_packet->ttl = TTL;
+               /* copy the destination for faster routing */
+               memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
 
-                       send_skb_packet(skb, batman_if, dstaddr);
-               } else {
-                       goto unlock;
-               }
+               send_skb_packet(skb, batman_if, dstaddr);
        }
 
        priv->stats.tx_packets++;