OSDN Git Service

Staging: batman-adv: Refactor routing.c
authorAndrew Lunn <andrew@lunn.ch>
Sat, 12 Dec 2009 22:39:42 +0000 (23:39 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 4 Mar 2010 00:42:29 +0000 (16:42 -0800)
Break up a lot of the big functions up into many smaller ones. This
helps with readability and there is now a lot less code squashed
against the right hand margin.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Acked-by: Marek Lindner <lindner_marek@yahoo.de>
Acked-by: Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/batman-adv/routing.c

index 1f42d41..1ff2a7a 100644 (file)
  *
  */
 
-
-
-
-
 #include "main.h"
 #include "routing.h"
 #include "send.h"
@@ -37,8 +33,6 @@
 #include "aggregation.h"
 #include "compat.h"
 
-
-
 DECLARE_WAIT_QUEUE_HEAD(thread_wait);
 static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
 
@@ -83,7 +77,9 @@ void originator_free(void)
        spin_unlock(&orig_hash_lock);
 }
 
-static struct neigh_node *create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, struct batman_if *if_incoming)
+static struct neigh_node *
+create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
+               uint8_t *neigh, struct batman_if *if_incoming)
 {
        struct neigh_node *neigh_node;
 
@@ -122,12 +118,14 @@ void free_orig_node(void *data)
        kfree(orig_node);
 }
 
-/* this function finds or creates an originator entry for the given address if it does not exits */
+/* this function finds or creates an originator entry for the given
+ * address if it does not exits */
 static struct orig_node *get_orig_node(uint8_t *addr)
 {
        struct orig_node *orig_node;
        struct hashtable_t *swaphash;
        char orig_str[ETH_STR_LEN];
+       int size;
 
        orig_node = ((struct orig_node *)hash_find(orig_hash, addr));
 
@@ -146,11 +144,14 @@ static struct orig_node *get_orig_node(uint8_t *addr)
        orig_node->batman_if = NULL;
        orig_node->hna_buff = NULL;
 
-       orig_node->bcast_own = kmalloc(num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS, GFP_ATOMIC);
-       memset(orig_node->bcast_own, 0, num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS);
+       size = num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS;
+
+       orig_node->bcast_own = kmalloc(size, GFP_ATOMIC);
+       memset(orig_node->bcast_own, 0, size);
 
-       orig_node->bcast_own_sum = kmalloc(num_ifs * sizeof(uint8_t), GFP_ATOMIC);
-       memset(orig_node->bcast_own_sum, 0, num_ifs * sizeof(uint8_t));
+       size = num_ifs * sizeof(uint8_t);
+       orig_node->bcast_own_sum = kmalloc(size, GFP_ATOMIC);
+       memset(orig_node->bcast_own_sum, 0, size);
 
        hash_add(orig_hash, orig_node);
 
@@ -158,7 +159,8 @@ static struct orig_node *get_orig_node(uint8_t *addr)
                swaphash = hash_resize(orig_hash, orig_hash->size * 2);
 
                if (swaphash == NULL)
-                       printk(KERN_ERR "batman-adv:Couldn't resize orig hash table \n");
+                       printk(KERN_ERR
+                              "batman-adv:Couldn't resize orig hash table \n");
                else
                        orig_hash = swaphash;
        }
@@ -170,75 +172,99 @@ void slide_own_bcast_window(struct batman_if *batman_if)
 {
        struct hash_it_t *hashit = NULL;
        struct orig_node *orig_node;
+       TYPE_OF_WORD *word;
 
        spin_lock(&orig_hash_lock);
 
        while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
                orig_node = hashit->bucket->data;
+               word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]);
 
-               bit_get_packet((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]), 1, 0);
-               orig_node->bcast_own_sum[batman_if->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]));
+               bit_get_packet(word, 1, 0);
+               orig_node->bcast_own_sum[batman_if->if_num] =
+                       bit_packet_count(word);
        }
 
        spin_unlock(&orig_hash_lock);
 }
 
-static void update_routes(struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len)
+static void update_HNA(struct orig_node *orig_node,
+                      unsigned char *hna_buff, int hna_buff_len)
 {
-       char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
+       if ((hna_buff_len != orig_node->hna_buff_len) ||
+           ((hna_buff_len > 0) &&
+            (orig_node->hna_buff_len > 0) &&
+            (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) {
 
-       if (orig_node == NULL)
-               return;
-
-       if (orig_node->router != neigh_node) {
-               addr_to_string(orig_str, orig_node->orig);
-
-               /* route deleted */
-               if ((orig_node->router != NULL) && (neigh_node == NULL)) {
-                       bat_dbg(DBG_ROUTES, "Deleting route towards: %s\n",
-                               orig_str);
-                       hna_global_del_orig(orig_node, "originator timed out");
+               if (orig_node->hna_buff_len > 0)
+                       hna_global_del_orig(orig_node,
+                                           "originator changed hna");
 
-               /* route added */
-               } else if ((orig_node->router == NULL) && (neigh_node != NULL)) {
-
-                       addr_to_string(neigh_str, neigh_node->addr);
-                       bat_dbg(DBG_ROUTES, "Adding route towards: %s (via %s)\n", orig_str, neigh_str);
+               if ((hna_buff_len > 0) && (hna_buff != NULL))
                        hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
+       }
+}
 
-               /* route changed */
-               } else {
+static void update_route(struct orig_node *orig_node,
+                        struct neigh_node *neigh_node,
+                        unsigned char *hna_buff, int hna_buff_len)
+{
+       char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN];
+       char router_str[ETH_STR_LEN];
 
-                       addr_to_string(neigh_str, neigh_node->addr);
-                       addr_to_string(router_str, orig_node->router->addr);
-                       bat_dbg(DBG_ROUTES, "Changing route towards: %s (now via %s - was via %s)\n", orig_str, neigh_str, router_str);
+       addr_to_string(orig_str, orig_node->orig);
 
-               }
+       /* route deleted */
+       if ((orig_node->router != NULL) && (neigh_node == NULL)) {
 
-               if (neigh_node != NULL)
-                       orig_node->batman_if = neigh_node->if_incoming;
-               else
-                       orig_node->batman_if = NULL;
+               bat_dbg(DBG_ROUTES, "Deleting route towards: %s\n",
+                       orig_str);
+               hna_global_del_orig(orig_node, "originator timed out");
 
-               orig_node->router = neigh_node;
+               /* route added */
+       } else if ((orig_node->router == NULL) && (neigh_node != NULL)) {
 
-       /* may be just HNA changed */
+               addr_to_string(neigh_str, neigh_node->addr);
+               bat_dbg(DBG_ROUTES,
+                       "Adding route towards: %s (via %s)\n",
+                       orig_str, neigh_str);
+               hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
+
+               /* route changed */
        } else {
+               addr_to_string(neigh_str, neigh_node->addr);
+               addr_to_string(router_str, orig_node->router->addr);
+               bat_dbg(DBG_ROUTES, "Changing route towards: %s (now via %s - was via %s)\n", orig_str, neigh_str, router_str);
+       }
 
-               if ((hna_buff_len != orig_node->hna_buff_len) || ((hna_buff_len > 0) && (orig_node->hna_buff_len > 0) && (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) {
+       if (neigh_node != NULL)
+               orig_node->batman_if = neigh_node->if_incoming;
+       else
+               orig_node->batman_if = NULL;
 
-                       if (orig_node->hna_buff_len > 0)
-                               hna_global_del_orig(orig_node, "originator changed hna");
+       orig_node->router = neigh_node;
+}
 
-                       if ((hna_buff_len > 0) && (hna_buff != NULL))
-                               hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
 
-               }
+static void update_routes(struct orig_node *orig_node,
+                         struct neigh_node *neigh_node,
+                         unsigned char *hna_buff, int hna_buff_len)
+{
 
-       }
+       if (orig_node == NULL)
+               return;
+
+       if (orig_node->router != neigh_node)
+               update_route(orig_node, neigh_node, hna_buff, hna_buff_len);
+       /* may be just HNA changed */
+       else
+               update_HNA(orig_node, hna_buff, hna_buff_len);
 }
 
-static int isBidirectionalNeigh(struct orig_node *orig_node, struct orig_node *orig_neigh_node, struct batman_packet *batman_packet, struct batman_if *if_incoming)
+static int isBidirectionalNeigh(struct orig_node *orig_node,
+                               struct orig_node *orig_neigh_node,
+                               struct batman_packet *batman_packet,
+                               struct batman_if *if_incoming)
 {
        struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
        char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN];
@@ -248,66 +274,100 @@ static int isBidirectionalNeigh(struct orig_node *orig_node, struct orig_node *o
        addr_to_string(neigh_str, orig_neigh_node->orig);
 
        if (orig_node == orig_neigh_node) {
-               list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+               list_for_each_entry(tmp_neigh_node,
+                                   &orig_node->neigh_list,
+                                   list) {
 
-                       if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming))
+                       if (compare_orig(tmp_neigh_node->addr,
+                                        orig_neigh_node->orig) &&
+                           (tmp_neigh_node->if_incoming == if_incoming))
                                neigh_node = tmp_neigh_node;
                }
 
                if (neigh_node == NULL)
-                       neigh_node = create_neighbor(orig_node, orig_neigh_node, orig_neigh_node->orig, if_incoming);
+                       neigh_node = create_neighbor(orig_node,
+                                                    orig_neigh_node,
+                                                    orig_neigh_node->orig,
+                                                    if_incoming);
 
                neigh_node->last_valid = jiffies;
        } else {
                /* find packet count of corresponding one hop neighbor */
-               list_for_each_entry(tmp_neigh_node, &orig_neigh_node->neigh_list, list) {
+               list_for_each_entry(tmp_neigh_node,
+                                   &orig_neigh_node->neigh_list, list) {
 
-                       if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming))
+                       if (compare_orig(tmp_neigh_node->addr,
+                                        orig_neigh_node->orig) &&
+                           (tmp_neigh_node->if_incoming == if_incoming))
                                neigh_node = tmp_neigh_node;
                }
 
                if (neigh_node == NULL)
-                       neigh_node = create_neighbor(orig_neigh_node, orig_neigh_node, orig_neigh_node->orig, if_incoming);
+                       neigh_node = create_neighbor(orig_neigh_node,
+                                                    orig_neigh_node,
+                                                    orig_neigh_node->orig,
+                                                    if_incoming);
        }
 
        orig_node->last_valid = jiffies;
 
        /* pay attention to not get a value bigger than 100 % */
-       total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > neigh_node->real_packet_count ? neigh_node->real_packet_count : orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
+       total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] >
+                      neigh_node->real_packet_count ?
+                      neigh_node->real_packet_count :
+                      orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
 
        /* if we have too few packets (too less data) we set tq_own to zero */
        /* if we receive too few packets it is not considered bidirectional */
-       if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
+       if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
+           (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
                orig_neigh_node->tq_own = 0;
        else
-               /* neigh_node->real_packet_count is never zero as we only purge old information when getting new information */
-               orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / neigh_node->real_packet_count;
+               /* neigh_node->real_packet_count is never zero as we
+                * only purge old information when getting new
+                * information */
+               orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) /
+                       neigh_node->real_packet_count;
 
        /*
-        * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE
-        * this does affect the nearly-symmetric links only a little,
-        * but punishes asymmetric links more.
-        * this will give a value between 0 and TQ_MAX_VALUE
+        * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
+        * affect the nearly-symmetric links only a little, but
+        * punishes asymmetric links more.  This will give a value
+        * between 0 and TQ_MAX_VALUE
         */
-       orig_neigh_node->tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
-                       (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
-                       (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
-                       (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) /
-                       (TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE);
-
-       batman_packet->tq = ((batman_packet->tq * orig_neigh_node->tq_own * orig_neigh_node->tq_asym_penalty) / (TQ_MAX_VALUE *  TQ_MAX_VALUE));
+       orig_neigh_node->tq_asym_penalty =
+               TQ_MAX_VALUE -
+               (TQ_MAX_VALUE *
+                (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
+                (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
+                (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) /
+               (TQ_LOCAL_WINDOW_SIZE *
+                TQ_LOCAL_WINDOW_SIZE *
+                TQ_LOCAL_WINDOW_SIZE);
+
+       batman_packet->tq = ((batman_packet->tq *
+                             orig_neigh_node->tq_own *
+                             orig_neigh_node->tq_asym_penalty) /
+                            (TQ_MAX_VALUE *     TQ_MAX_VALUE));
 
        bat_dbg(DBG_BATMAN, "bidirectional: orig = %-15s neigh = %-15s => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n",
-                 orig_str, neigh_str, total_count, neigh_node->real_packet_count, orig_neigh_node->tq_own, orig_neigh_node->tq_asym_penalty, batman_packet->tq);
+               orig_str, neigh_str, total_count,
+               neigh_node->real_packet_count, orig_neigh_node->tq_own,
+               orig_neigh_node->tq_asym_penalty, batman_packet->tq);
 
-       /* if link has the minimum required transmission quality consider it bidirectional */
+       /* if link has the minimum required transmission quality
+        * consider it bidirectional */
        if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
                return 1;
 
        return 0;
 }
 
-static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming, unsigned char *hna_buff, int hna_buff_len, char is_duplicate)
+static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr,
+                       struct batman_packet *batman_packet,
+                       struct batman_if *if_incoming,
+                       unsigned char *hna_buff, int hna_buff_len,
+                       char is_duplicate)
 {
        struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
        int tmp_hna_buff_len;
@@ -315,7 +375,8 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru
        bat_dbg(DBG_BATMAN, "update_originator(): Searching and updating originator entry of received packet \n");
 
        list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
-               if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming)) {
+               if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
+                   (tmp_neigh_node->if_incoming == if_incoming)) {
                        neigh_node = tmp_neigh_node;
                        continue;
                }
@@ -323,19 +384,26 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru
                if (is_duplicate)
                        continue;
 
-               ring_buffer_set(tmp_neigh_node->tq_recv, &tmp_neigh_node->tq_index, 0);
-               tmp_neigh_node->tq_avg = ring_buffer_avg(tmp_neigh_node->tq_recv);
+               ring_buffer_set(tmp_neigh_node->tq_recv,
+                               &tmp_neigh_node->tq_index, 0);
+               tmp_neigh_node->tq_avg =
+                       ring_buffer_avg(tmp_neigh_node->tq_recv);
        }
 
        if (neigh_node == NULL)
-               neigh_node = create_neighbor(orig_node, get_orig_node(ethhdr->h_source), ethhdr->h_source, if_incoming);
+               neigh_node = create_neighbor(orig_node,
+                                            get_orig_node(ethhdr->h_source),
+                                            ethhdr->h_source, if_incoming);
        else
-               bat_dbg(DBG_BATMAN, "Updating existing last-hop neighbour of originator\n");
+               bat_dbg(DBG_BATMAN,
+                       "Updating existing last-hop neighbour of originator\n");
 
        orig_node->flags = batman_packet->flags;
        neigh_node->last_valid = jiffies;
 
-       ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, batman_packet->tq);
+       ring_buffer_set(neigh_node->tq_recv,
+                       &neigh_node->tq_index,
+                       batman_packet->tq);
        neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
 
        if (!is_duplicate) {
@@ -343,9 +411,11 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru
                neigh_node->last_ttl = batman_packet->ttl;
        }
 
-       tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? batman_packet->num_hna * ETH_ALEN : hna_buff_len);
+       tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ?
+                           batman_packet->num_hna * ETH_ALEN : hna_buff_len);
 
-       /* if this neighbor already is our next hop there is nothing to change */
+       /* if this neighbor already is our next hop there is nothing
+        * to change */
        if (orig_node->router == neigh_node)
                goto update_hna;
 
@@ -354,11 +424,12 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru
            (orig_node->router->tq_avg > neigh_node->tq_avg))
                goto update_hna;
 
-       /* if the TQ is the same and the link not more symetric we won't consider it either */
+       /* if the TQ is the same and the link not more symetric we
+        * won't consider it either */
        if ((orig_node->router) &&
             ((neigh_node->tq_avg == orig_node->router->tq_avg) &&
-            (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] >=
-             neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
+            (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num]
+             >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
                goto update_hna;
 
        update_routes(orig_node, neigh_node, hna_buff, tmp_hna_buff_len);
@@ -369,29 +440,35 @@ update_hna:
        return;
 }
 
-static char count_real_packets(struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming)
+static char count_real_packets(struct ethhdr *ethhdr,
+                              struct batman_packet *batman_packet,
+                              struct batman_if *if_incoming)
 {
        struct orig_node *orig_node;
        struct neigh_node *tmp_neigh_node;
        char is_duplicate = 0;
-
+       uint16_t seq_diff;
 
        orig_node = get_orig_node(batman_packet->orig);
        if (orig_node == NULL)
                return 0;
 
-
        list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
 
                if (!is_duplicate)
-                       is_duplicate = get_bit_status(tmp_neigh_node->real_bits, orig_node->last_real_seqno, batman_packet->seqno);
-
-               if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming))
-                       bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 1);
+                       is_duplicate =
+                               get_bit_status(tmp_neigh_node->real_bits,
+                                              orig_node->last_real_seqno,
+                                              batman_packet->seqno);
+               seq_diff = batman_packet->seqno - orig_node->last_real_seqno;
+               if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
+                   (tmp_neigh_node->if_incoming == if_incoming))
+                       bit_get_packet(tmp_neigh_node->real_bits, seq_diff, 1);
                else
-                       bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 0);
+                       bit_get_packet(tmp_neigh_node->real_bits, seq_diff, 0);
 
-               tmp_neigh_node->real_packet_count = bit_packet_count(tmp_neigh_node->real_bits);
+               tmp_neigh_node->real_packet_count =
+                       bit_packet_count(tmp_neigh_node->real_bits);
        }
 
        if (!is_duplicate) {
@@ -403,24 +480,33 @@ static char count_real_packets(struct ethhdr *ethhdr, struct batman_packet *batm
        return is_duplicate;
 }
 
-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)
+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)
 {
        struct batman_if *batman_if;
        struct orig_node *orig_neigh_node, *orig_node;
-       char orig_str[ETH_STR_LEN], prev_sender_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN];
+       char orig_str[ETH_STR_LEN], prev_sender_str[ETH_STR_LEN];
+       char neigh_str[ETH_STR_LEN];
        char has_directlink_flag;
-       char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0, is_broadcast = 0, is_bidirectional, is_single_hop_neigh, is_duplicate;
+       char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
+       char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
+       char is_duplicate;
        unsigned short if_incoming_seqno;
 
-       /* Silently drop when the batman packet is actually not a correct packet.
+       /* Silently drop when the batman packet is actually not a
+        * correct packet.
         *
         * This might happen if a packet is padded (e.g. Ethernet has a
         * minimum frame length of 64 byte) and the aggregation interprets
         * it as an additional length.
         *
-        * TODO: A more sane solution would be to have a bit in the batman_packet
-        * to detect whether the packet is the last packet in an aggregation.
-        * Here we expect that the padding is always zero (or not 0x01)
+        * TODO: A more sane solution would be to have a bit in the
+        * batman_packet to detect whether the packet is the last
+        * packet in an aggregation.  Here we expect that the padding
+        * is always zero (or not 0x01)
         */
        if (batman_packet->packet_type != BAT_PACKET)
                return;
@@ -434,21 +520,29 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
 
        has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0);
 
-       is_single_hop_neigh = (compare_orig(ethhdr->h_source, batman_packet->orig) ? 1 : 0);
+       is_single_hop_neigh = (compare_orig(ethhdr->h_source,
+                                           batman_packet->orig) ? 1 : 0);
 
-       bat_dbg(DBG_BATMAN, "Received BATMAN packet via NB: %s, IF: %s [%s] (from OG: %s, via prev OG: %s, seqno %d, tq %d, TTL %d, V %d, IDF %d) \n", neigh_str, if_incoming->dev, if_incoming->addr_str, orig_str, prev_sender_str, batman_packet->seqno, batman_packet->tq, batman_packet->ttl, batman_packet->version, has_directlink_flag);
+       bat_dbg(DBG_BATMAN, "Received BATMAN packet via NB: %s, IF: %s [%s] (from OG: %s, via prev OG: %s, seqno %d, tq %d, TTL %d, V %d, IDF %d) \n",
+               neigh_str, if_incoming->dev, if_incoming->addr_str,
+               orig_str, prev_sender_str, batman_packet->seqno,
+               batman_packet->tq, batman_packet->ttl, batman_packet->version,
+               has_directlink_flag);
 
        list_for_each_entry_rcu(batman_if, &if_list, list) {
                if (batman_if->if_active != IF_ACTIVE)
                        continue;
 
-               if (compare_orig(ethhdr->h_source, batman_if->net_dev->dev_addr))
+               if (compare_orig(ethhdr->h_source,
+                                batman_if->net_dev->dev_addr))
                        is_my_addr = 1;
 
-               if (compare_orig(batman_packet->orig, batman_if->net_dev->dev_addr))
+               if (compare_orig(batman_packet->orig,
+                                batman_if->net_dev->dev_addr))
                        is_my_orig = 1;
 
-               if (compare_orig(batman_packet->prev_sender, batman_if->net_dev->dev_addr))
+               if (compare_orig(batman_packet->prev_sender,
+                                batman_if->net_dev->dev_addr))
                        is_my_oldorig = 1;
 
                if (compare_orig(ethhdr->h_source, broadcastAddr))
@@ -456,12 +550,16 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
        }
 
        if (batman_packet->version != COMPAT_VERSION) {
-               bat_dbg(DBG_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version);
+               bat_dbg(DBG_BATMAN,
+                       "Drop packet: incompatible batman version (%i)\n",
+                       batman_packet->version);
                return;
        }
 
        if (is_my_addr) {
-               bat_dbg(DBG_BATMAN, "Drop packet: received my own broadcast (sender: %s) \n", neigh_str);
+               bat_dbg(DBG_BATMAN,
+                       "Drop packet: received my own broadcast (sender: %s)\n",
+                       neigh_str);
                return;
        }
 
@@ -471,14 +569,24 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
        }
 
        if (is_my_orig) {
+               TYPE_OF_WORD *word;
+               int offset;
+
                orig_neigh_node = get_orig_node(ethhdr->h_source);
 
-               /* neighbour has to indicate direct link and it has to come via the corresponding interface */
-               /* if received seqno equals last send seqno save new seqno for bidirectional check */
-               if (has_directlink_flag && compare_orig(if_incoming->net_dev->dev_addr, batman_packet->orig) &&
-                                 (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
-                       bit_mark((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS]), 0);
-                       orig_neigh_node->bcast_own_sum[if_incoming->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS]));
+               /* neighbour has to indicate direct link and it has to
+                * come via the corresponding interface */
+               /* if received seqno equals last send seqno save new
+                * seqno for bidirectional check */
+               if (has_directlink_flag &&
+                   compare_orig(if_incoming->net_dev->dev_addr,
+                                batman_packet->orig) &&
+                   (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
+                       offset = if_incoming->if_num * NUM_WORDS;
+                       word = &(orig_neigh_node->bcast_own[offset]);
+                       bit_mark(word, 0);
+                       orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
+                               bit_packet_count(word);
                }
 
                bat_dbg(DBG_BATMAN, "Drop packet: originator packet from myself (via neighbour) \n");
@@ -504,38 +612,50 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
                return;
 
        /* avoid temporary routing loops */
-       if ((orig_node->router) && (orig_node->router->orig_node->router) &&
-           (compare_orig(orig_node->router->addr, batman_packet->prev_sender)) &&
+       if ((orig_node->router) &&
+           (orig_node->router->orig_node->router) &&
+           (compare_orig(orig_node->router->addr,
+                         batman_packet->prev_sender)) &&
            !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) &&
-           (compare_orig(orig_node->router->addr, orig_node->router->orig_node->router->addr))) {
+           (compare_orig(orig_node->router->addr,
+                         orig_node->router->orig_node->router->addr))) {
                bat_dbg(DBG_BATMAN, "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %s) \n", neigh_str);
                return;
        }
 
-       /* if sender is a direct neighbor the sender mac equals originator mac */
-       orig_neigh_node = (is_single_hop_neigh ? orig_node : get_orig_node(ethhdr->h_source));
+       /* if sender is a direct neighbor the sender mac equals
+        * originator mac */
+       orig_neigh_node = (is_single_hop_neigh ?
+                          orig_node : get_orig_node(ethhdr->h_source));
        if (orig_neigh_node == NULL)
                return;
 
-       /* drop packet if sender is not a direct neighbor and if we don't route towards it */
-       if (!is_single_hop_neigh && (orig_neigh_node->router == NULL)) {
+       /* drop packet if sender is not a direct neighbor and if we
+        * don't route towards it */
+       if (!is_single_hop_neigh &&
+           (orig_neigh_node->router == NULL)) {
                bat_dbg(DBG_BATMAN, "Drop packet: OGM via unknown neighbor!\n");
                return;
        }
 
-       is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node, batman_packet, if_incoming);
+       is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node,
+                                               batman_packet, if_incoming);
 
-       /* update ranking if it is not a duplicate or has the same seqno and similar ttl as the non-duplicate */
-       if (is_bidirectional && (!is_duplicate ||
-               ((orig_node->last_real_seqno == batman_packet->seqno) &&
-                       (orig_node->last_ttl - 3 <= batman_packet->ttl))))
-               update_orig(orig_node, ethhdr, batman_packet, if_incoming, hna_buff, hna_buff_len, is_duplicate);
+       /* update ranking if it is not a duplicate or has the same
+        * seqno and similar ttl as the non-duplicate */
+       if (is_bidirectional &&
+           (!is_duplicate ||
+            ((orig_node->last_real_seqno == batman_packet->seqno) &&
+             (orig_node->last_ttl - 3 <= batman_packet->ttl))))
+               update_orig(orig_node, ethhdr, batman_packet,
+                           if_incoming, hna_buff, hna_buff_len, is_duplicate);
 
        /* is single hop (direct) neighbour */
        if (is_single_hop_neigh) {
 
                /* mark direct link on incoming interface */
-               schedule_forward_packet(orig_node, ethhdr, batman_packet, 1, hna_buff_len, if_incoming);
+               schedule_forward_packet(orig_node, ethhdr, batman_packet,
+                                       1, hna_buff_len, if_incoming);
 
                bat_dbg(DBG_BATMAN, "Forwarding packet: rebroadcast neighbour packet with direct link flag\n");
                return;
@@ -543,7 +663,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
 
        /* multihop originator */
        if (!is_bidirectional) {
-               bat_dbg(DBG_BATMAN, "Drop packet: not received via bidirectional link\n");
+               bat_dbg(DBG_BATMAN,
+                       "Drop packet: not received via bidirectional link\n");
                return;
        }
 
@@ -552,65 +673,85 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
                return;
        }
 
-       bat_dbg(DBG_BATMAN, "Forwarding packet: rebroadcast originator packet\n");
-       schedule_forward_packet(orig_node, ethhdr, batman_packet, 0, hna_buff_len, if_incoming);
+       bat_dbg(DBG_BATMAN,
+               "Forwarding packet: rebroadcast originator packet\n");
+       schedule_forward_packet(orig_node, ethhdr, batman_packet,
+                               0, hna_buff_len, if_incoming);
 }
 
-void purge_orig(struct work_struct *work)
+static bool purge_orig_neigbours(struct orig_node *orig_node,
+                                struct neigh_node **best_neigh_node)
 {
        struct list_head *list_pos, *list_pos_tmp;
-       struct hash_it_t *hashit = NULL;
-       struct orig_node *orig_node;
-       struct neigh_node *neigh_node, *best_neigh_node;
-       char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], neigh_purged;
-
-       spin_lock(&orig_hash_lock);
+       char neigh_str[ETH_STR_LEN], orig_str[ETH_STR_LEN];
+       struct neigh_node *neigh_node;
+       bool neigh_purged = false;
 
-       /* for all origins... */
-       while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
+       *best_neigh_node = NULL;
 
-               orig_node = hashit->bucket->data;
-               addr_to_string(orig_str, orig_node->orig);
 
-               if (time_after(jiffies, orig_node->last_valid + ((2 * PURGE_TIMEOUT * HZ) / 1000))) {
+       /* for all neighbours towards this originator ... */
+       list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
+               neigh_node = list_entry(list_pos, struct neigh_node, list);
 
-                       bat_dbg(DBG_BATMAN, "Originator timeout: originator %s, last_valid %lu\n", orig_str, (orig_node->last_valid / HZ));
+               if (time_after(jiffies,
+                              (neigh_node->last_valid +
+                               ((PURGE_TIMEOUT * HZ) / 1000)))) {
 
-                       hash_remove_bucket(orig_hash, hashit);
-                       free_orig_node(orig_node);
+                       addr_to_string(neigh_str, neigh_node->addr);
+                       bat_dbg(DBG_BATMAN, "Neighbour timeout: originator %s, neighbour: %s, last_valid %lu\n", orig_str, neigh_str, (neigh_node->last_valid / HZ));
 
+                       neigh_purged = true;
+                       list_del(list_pos);
+                       kfree(neigh_node);
                } else {
+                       if ((*best_neigh_node == NULL) ||
+                           (neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
+                               *best_neigh_node = neigh_node;
+               }
+       }
+       return neigh_purged;
+}
 
-                       best_neigh_node = NULL;
-                       neigh_purged = 0;
-
-                       /* for all neighbours towards this originator ... */
-                       list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
-                               neigh_node = list_entry(list_pos, struct neigh_node, list);
-
-                               if (time_after(jiffies, neigh_node->last_valid + ((PURGE_TIMEOUT * HZ) / 1000))) {
-
-                                       addr_to_string(neigh_str, neigh_node->addr);
-                                       bat_dbg(DBG_BATMAN, "Neighbour timeout: originator %s, neighbour: %s, last_valid %lu\n", orig_str, neigh_str, (neigh_node->last_valid / HZ));
+static bool purge_orig_node(struct orig_node *orig_node)
+{
+       struct neigh_node *best_neigh_node;
+       char orig_str[ETH_STR_LEN];
 
-                                       neigh_purged = 1;
-                                       list_del(list_pos);
-                                       kfree(neigh_node);
+       addr_to_string(orig_str, orig_node->orig);
 
-                               } else {
+       if (time_after(jiffies,
+                      (orig_node->last_valid +
+                       ((2 * PURGE_TIMEOUT * HZ) / 1000)))) {
 
-                                       if ((best_neigh_node == NULL) || (neigh_node->tq_avg > best_neigh_node->tq_avg))
-                                               best_neigh_node = neigh_node;
+               bat_dbg(DBG_BATMAN,
+                       "Originator timeout: originator %s, last_valid %lu\n",
+                       orig_str, (orig_node->last_valid / HZ));
+               return true;
+       } else {
+               if (purge_orig_neigbours(orig_node, &best_neigh_node))
+                       update_routes(orig_node, best_neigh_node,
+                                     orig_node->hna_buff,
+                                     orig_node->hna_buff_len);
+       }
+       return false;
+}
 
-                               }
 
-                       }
+void purge_orig(struct work_struct *work)
+{
+       struct hash_it_t *hashit = NULL;
+       struct orig_node *orig_node;
 
-                       if (neigh_purged)
-                               update_routes(orig_node, best_neigh_node, orig_node->hna_buff, orig_node->hna_buff_len);
+       spin_lock(&orig_hash_lock);
 
+       /* for all origins... */
+       while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
+               orig_node = hashit->bucket->data;
+               if (purge_orig_node(orig_node)) {
+                       hash_remove_bucket(orig_hash, hashit);
+                       free_orig_node(orig_node);
                }
-
        }
 
        spin_unlock(&orig_hash_lock);
@@ -618,7 +759,8 @@ void purge_orig(struct work_struct *work)
        start_purge_timer();
 }
 
-static int receive_raw_packet(struct socket *raw_sock, unsigned char *packet_buff, int packet_buff_len)
+static int receive_raw_packet(struct socket *raw_sock,
+                             unsigned char *packet_buff, int packet_buff_len)
 {
        struct kvec iov;
        struct msghdr msg;
@@ -631,367 +773,495 @@ static int receive_raw_packet(struct socket *raw_sock, unsigned char *packet_buf
        msg.msg_namelen = 0;
        msg.msg_control = NULL;
 
-       return kernel_recvmsg(raw_sock, &msg, &iov, 1, packet_buff_len, MSG_DONTWAIT);
+       return kernel_recvmsg(raw_sock, &msg, &iov, 1, packet_buff_len,
+                             MSG_DONTWAIT);
 }
 
-int packet_recv_thread(void *data)
+static void recv_bat_packet(struct ethhdr *ethhdr,
+                           unsigned char *packet_buff,
+                           int result,
+                           struct batman_if *batman_if)
+{
+       /* packet with broadcast indication but unicast recipient */
+       if (!is_bcast(ethhdr->h_dest))
+               return;
+
+       /* packet with broadcast sender address */
+       if (is_bcast(ethhdr->h_source))
+               return;
+
+       /* drop packet if it has not at least one batman packet as payload */
+       if (result < sizeof(struct ethhdr) + sizeof(struct batman_packet))
+               return;
+
+       spin_lock(&orig_hash_lock);
+       receive_aggr_bat_packet(ethhdr,
+                               packet_buff + sizeof(struct ethhdr),
+                               result - sizeof(struct ethhdr),
+                               batman_if);
+       spin_unlock(&orig_hash_lock);
+}
+
+static void recv_my_icmp_packet(struct ethhdr *ethhdr,
+                               struct icmp_packet *icmp_packet,
+                               unsigned char *packet_buff,
+                               int result)
 {
-       struct batman_if *batman_if;
-       struct ethhdr *ethhdr;
-       struct batman_packet *batman_packet;
-       struct unicast_packet *unicast_packet;
-       struct bcast_packet *bcast_packet;
-       struct icmp_packet *icmp_packet;
-       struct vis_packet *vis_packet;
        struct orig_node *orig_node;
-       unsigned char *packet_buff, src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN];
-       int vis_info_len;
-       int result;
 
-       atomic_set(&data_ready_cond, 0);
-       atomic_set(&exit_cond, 0);
-       packet_buff = kmalloc(PACKBUFF_SIZE, GFP_KERNEL);
-       if (!packet_buff) {
-               printk(KERN_ERR "batman-adv:Could allocate memory for the packet buffer. :(\n");
-               return -1;
+       /* add data to device queue */
+       if (icmp_packet->msg_type != ECHO_REQUEST) {
+               bat_device_receive_packet(icmp_packet);
+               return;
        }
 
-       while ((!kthread_should_stop()) && (!atomic_read(&exit_cond))) {
-
-               wait_event_interruptible(thread_wait, (atomic_read(&data_ready_cond) || atomic_read(&exit_cond)));
+       /* answer echo request (ping) */
+       /* get routing information */
+       spin_lock(&orig_hash_lock);
+       orig_node = ((struct orig_node *)hash_find(orig_hash,
+                                                  icmp_packet->orig));
+
+       if ((orig_node != NULL) &&
+           (orig_node->batman_if != NULL) &&
+           (orig_node->router != NULL)) {
+               memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
+               memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
+               icmp_packet->msg_type = ECHO_REPLY;
+               icmp_packet->ttl = TTL;
+
+               send_raw_packet(packet_buff + sizeof(struct ethhdr),
+                               result - sizeof(struct ethhdr),
+                               orig_node->batman_if,
+                               orig_node->router->addr);
+       }
 
-               atomic_set(&data_ready_cond, 0);
+       spin_unlock(&orig_hash_lock);
+       return;
+}
 
-               if (kthread_should_stop() || atomic_read(&exit_cond))
-                       break;
+static void recv_icmp_ttl_exceeded(struct icmp_packet *icmp_packet,
+                                  struct ethhdr *ethhdr,
+                                  unsigned char *packet_buff,
+                                  int result,
+                                  struct batman_if *batman_if)
+{
+       unsigned char src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN];
+       struct orig_node *orig_node;
 
-               /* we only want to safely traverse the list, hard-interfaces
-                * won't be deleted anyway as long as this thread runs. */
+       addr_to_string(src_str, icmp_packet->orig);
+       addr_to_string(dst_str, icmp_packet->dst);
 
-               rcu_read_lock();
-               list_for_each_entry_rcu(batman_if, &if_list, list) {
-                       rcu_read_unlock();
-
-                       result = -1;
-
-                       while (1) {
-                               if (batman_if->if_active != IF_ACTIVE) {
-                                       if (batman_if->if_active != IF_TO_BE_ACTIVATED)
-                                               printk(KERN_WARNING
-                                                      "batman-adv:Could not read from deactivated interface %s!\n",
-                                                      batman_if->dev);
-
-                                       if (batman_if->raw_sock)
-                                               receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE);
-                                       result = 0;
-                                       break;
-                               }
+       printk(KERN_WARNING "batman-adv:Warning - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
 
-                               result = receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE);
-                               if (result <= 0)
-                                       break;
+       /* send TTL exceeded if packet is an echo request (traceroute) */
+       if (icmp_packet->msg_type != ECHO_REQUEST)
+               return;
 
-                               if (result < sizeof(struct ethhdr) + 2)
-                                       continue;
+       /* get routing information */
+       spin_lock(&orig_hash_lock);
+       orig_node = ((struct orig_node *)
+                    hash_find(orig_hash, icmp_packet->orig));
+
+       if ((orig_node != NULL) &&
+           (orig_node->batman_if != NULL) &&
+           (orig_node->router != NULL)) {
+               memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
+               memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
+               icmp_packet->msg_type = TTL_EXCEEDED;
+               icmp_packet->ttl = TTL;
+
+               send_raw_packet(packet_buff + sizeof(struct ethhdr),
+                               result - sizeof(struct ethhdr),
+                               orig_node->batman_if,
+                               orig_node->router->addr);
 
-                               ethhdr = (struct ethhdr *)packet_buff;
-                               batman_packet = (struct batman_packet *)(packet_buff + sizeof(struct ethhdr));
+       }
 
-                               if (batman_packet->version != COMPAT_VERSION) {
-                                       bat_dbg(DBG_BATMAN, "Drop packet: incompatible batman version (%i)\n", batman_packet->version);
-                                       continue;
-                               }
+       spin_unlock(&orig_hash_lock);
+}
 
-                               switch (batman_packet->packet_type) {
-                               /* batman originator packet */
-                               case BAT_PACKET:
-                                       /* packet with broadcast indication but unicast recipient */
-                                       if (!is_bcast(ethhdr->h_dest))
-                                               continue;
 
-                                       /* packet with broadcast sender address */
-                                       if (is_bcast(ethhdr->h_source))
-                                               continue;
 
-                                       /* drop packet if it has not at least one batman packet as payload */
-                                       if (result < sizeof(struct ethhdr) + sizeof(struct batman_packet))
-                                               continue;
+static void recv_icmp_packet(struct ethhdr *ethhdr,
+                            unsigned char *packet_buff,
+                            int result,
+                            struct batman_if *batman_if)
+{
+       struct icmp_packet *icmp_packet;
+       struct orig_node *orig_node;
 
-                                       spin_lock(&orig_hash_lock);
-                                       receive_aggr_bat_packet(ethhdr,
-                                                               packet_buff + sizeof(struct ethhdr),
-                                                               result - sizeof(struct ethhdr),
-                                                               batman_if);
-                                       spin_unlock(&orig_hash_lock);
+       /* packet with unicast indication but broadcast recipient */
+       if (is_bcast(ethhdr->h_dest))
+               return;
 
-                                       break;
+       /* packet with broadcast sender address */
+       if (is_bcast(ethhdr->h_source))
+               return;
 
-                               /* batman icmp packet */
-                               case BAT_ICMP:
-                                       /* packet with unicast indication but broadcast recipient */
-                                       if (is_bcast(ethhdr->h_dest))
-                                               continue;
+       /* not for me */
+       if (!is_my_mac(ethhdr->h_dest))
+               return;
 
-                                       /* packet with broadcast sender address */
-                                       if (is_bcast(ethhdr->h_source))
-                                               continue;
+       /* drop packet if it has not necessary minimum size */
+       if (result < sizeof(struct ethhdr) + sizeof(struct icmp_packet))
+               return;
 
-                                       /* not for me */
-                                       if (!is_my_mac(ethhdr->h_dest))
-                                               continue;
+       icmp_packet = (struct icmp_packet *)
+               (packet_buff + sizeof(struct ethhdr));
 
-                                       /* drop packet if it has not necessary minimum size */
-                                       if (result < sizeof(struct ethhdr) + sizeof(struct icmp_packet))
-                                               continue;
+       /* packet for me */
+       if (is_my_mac(icmp_packet->dst))
+               recv_my_icmp_packet(ethhdr, icmp_packet, packet_buff, result);
 
-                                       icmp_packet = (struct icmp_packet *)(packet_buff + sizeof(struct ethhdr));
+       /* TTL exceeded */
+       if (icmp_packet->ttl < 2) {
+               recv_icmp_ttl_exceeded(icmp_packet, ethhdr, packet_buff, result,
+                                      batman_if);
+               return;
 
-                                       /* packet for me */
-                                       if (is_my_mac(icmp_packet->dst)) {
+       }
 
-                                               /* add data to device queue */
-                                               if (icmp_packet->msg_type != ECHO_REQUEST) {
-                                                       bat_device_receive_packet(icmp_packet);
-                                                       continue;
-                                               }
+       /* get routing information */
+       spin_lock(&orig_hash_lock);
+       orig_node = ((struct orig_node *)
+                    hash_find(orig_hash, icmp_packet->dst));
 
-                                               /* answer echo request (ping) */
-                                               /* get routing information */
-                                               spin_lock(&orig_hash_lock);
-                                               orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig));
+       if ((orig_node != NULL) &&
+           (orig_node->batman_if != NULL) &&
+           (orig_node->router != NULL)) {
 
-                                               if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
+               /* decrement ttl */
+               icmp_packet->ttl--;
 
-                                                       memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
-                                                       memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
-                                                       icmp_packet->msg_type = ECHO_REPLY;
-                                                       icmp_packet->ttl = TTL;
+               /* route it */
+               send_raw_packet(packet_buff + sizeof(struct ethhdr),
+                               result - sizeof(struct ethhdr),
+                               orig_node->batman_if,
+                               orig_node->router->addr);
+       }
+       spin_unlock(&orig_hash_lock);
+}
 
-                                                       send_raw_packet(packet_buff + sizeof(struct ethhdr),
-                                                                       result - sizeof(struct ethhdr),
-                                                                       orig_node->batman_if,
-                                                                       orig_node->router->addr);
+static void recv_unicast_packet(struct ethhdr *ethhdr,
+                               unsigned char *packet_buff,
+                               int result,
+                               struct batman_if *batman_if)
+{
+       struct unicast_packet *unicast_packet;
+       unsigned char src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN];
+       struct orig_node *orig_node;
+       int hdr_size = sizeof(struct ethhdr) + sizeof(struct unicast_packet);
 
-                                               }
+       /* packet with unicast indication but broadcast recipient */
+       if (is_bcast(ethhdr->h_dest))
+               return;
 
-                                               spin_unlock(&orig_hash_lock);
-                                               continue;
+       /* packet with broadcast sender address */
+       if (is_bcast(ethhdr->h_source))
+               return;
 
-                                       }
+       /* not for me */
+       if (!is_my_mac(ethhdr->h_dest))
+               return;
 
-                                       /* TTL exceeded */
-                                       if (icmp_packet->ttl < 2) {
+       /* drop packet if it has not necessary minimum size */
+       if (result < hdr_size)
+               return;
 
-                                               addr_to_string(src_str, icmp_packet->orig);
-                                               addr_to_string(dst_str, icmp_packet->dst);
+       unicast_packet = (struct unicast_packet *)
+               (packet_buff + sizeof(struct ethhdr));
 
-                                               printk(KERN_WARNING "batman-adv:Warning - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
+       /* packet for me */
+       if (is_my_mac(unicast_packet->dest)) {
+               interface_rx(soft_device, packet_buff + hdr_size,
+                            result - hdr_size);
+               return;
 
-                                               /* send TTL exceeded if packet is an echo request (traceroute) */
-                                               if (icmp_packet->msg_type != ECHO_REQUEST)
-                                                       continue;
+       }
 
-                                               /* get routing information */
-                                               spin_lock(&orig_hash_lock);
-                                               orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig));
+       /* TTL exceeded */
+       if (unicast_packet->ttl < 2) {
+               addr_to_string(src_str, ((struct ethhdr *)
+                                        (unicast_packet + 1))->h_source);
+               addr_to_string(dst_str, unicast_packet->dest);
 
-                                               if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
+               printk(KERN_WARNING "batman-adv:Warning - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
+               return;
+       }
 
-                                                       memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
-                                                       memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
-                                                       icmp_packet->msg_type = TTL_EXCEEDED;
-                                                       icmp_packet->ttl = TTL;
+       /* get routing information */
+       spin_lock(&orig_hash_lock);
+       orig_node = ((struct orig_node *)
+                    hash_find(orig_hash, unicast_packet->dest));
+
+       if ((orig_node != NULL) &&
+           (orig_node->batman_if != NULL) &&
+           (orig_node->router != NULL)) {
+               /* decrement ttl */
+               unicast_packet->ttl--;
+
+               /* route it */
+               send_raw_packet(packet_buff + sizeof(struct ethhdr),
+                               result - sizeof(struct ethhdr),
+                               orig_node->batman_if,
+                               orig_node->router->addr);
+       }
+       spin_unlock(&orig_hash_lock);
+}
 
-                                                       send_raw_packet(packet_buff + sizeof(struct ethhdr),
-                                                                       result - sizeof(struct ethhdr),
-                                                                       orig_node->batman_if,
-                                                                       orig_node->router->addr);
 
-                                               }
+static void recv_bcast_packet(struct ethhdr *ethhdr,
+                             unsigned char *packet_buff,
+                             int result,
+                             struct batman_if *batman_if)
+{
+       struct orig_node *orig_node;
+       struct bcast_packet *bcast_packet;
+       int hdr_size = sizeof(struct ethhdr) + sizeof(struct bcast_packet);
 
-                                               spin_unlock(&orig_hash_lock);
-                                               continue;
+       /* packet with broadcast indication but unicast recipient */
+       if (!is_bcast(ethhdr->h_dest))
+               return;
 
-                                       }
+       /* packet with broadcast sender address */
+       if (is_bcast(ethhdr->h_source))
+               return;
 
-                                       /* get routing information */
-                                       spin_lock(&orig_hash_lock);
-                                       orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->dst));
+       /* drop packet if it has not necessary minimum size */
+       if (result < hdr_size)
+               return;
 
-                                       if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
+       /* ignore broadcasts sent by myself */
+       if (is_my_mac(ethhdr->h_source))
+               return;
 
-                                               /* decrement ttl */
-                                               icmp_packet->ttl--;
+       bcast_packet = (struct bcast_packet *)
+               (packet_buff + sizeof(struct ethhdr));
 
-                                               /* route it */
-                                               send_raw_packet(packet_buff + sizeof(struct ethhdr),
-                                                               result - sizeof(struct ethhdr),
-                                                               orig_node->batman_if,
-                                                               orig_node->router->addr);
-                                       }
+       /* ignore broadcasts originated by myself */
+       if (is_my_mac(bcast_packet->orig))
+               return;
 
-                                       spin_unlock(&orig_hash_lock);
-                                       break;
+       spin_lock(&orig_hash_lock);
+       orig_node = ((struct orig_node *)
+                    hash_find(orig_hash, bcast_packet->orig));
 
-                               /* unicast packet */
-                               case BAT_UNICAST:
-                                       /* packet with unicast indication but broadcast recipient */
-                                       if (is_bcast(ethhdr->h_dest))
-                                               continue;
+       if (orig_node == NULL) {
+               spin_unlock(&orig_hash_lock);
+               return;
+       }
 
-                                       /* packet with broadcast sender address */
-                                       if (is_bcast(ethhdr->h_source))
-                                               continue;
+       /* check flood history */
+       if (get_bit_status(orig_node->bcast_bits,
+                          orig_node->last_bcast_seqno,
+                          ntohs(bcast_packet->seqno))) {
+               spin_unlock(&orig_hash_lock);
+               return;
+       }
 
-                                       /* not for me */
-                                       if (!is_my_mac(ethhdr->h_dest))
-                                               continue;
+       /* mark broadcast in flood history */
+       if (bit_get_packet(orig_node->bcast_bits,
+                          ntohs(bcast_packet->seqno) -
+                          orig_node->last_bcast_seqno, 1))
+               orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno);
 
-                                       /* drop packet if it has not necessary minimum size */
-                                       if (result < sizeof(struct ethhdr) + sizeof(struct unicast_packet))
-                                               continue;
+       spin_unlock(&orig_hash_lock);
 
-                                       unicast_packet = (struct unicast_packet *)(packet_buff + sizeof(struct ethhdr));
+       /* broadcast for me */
+       interface_rx(soft_device, packet_buff + hdr_size, result - hdr_size);
 
-                                       /* packet for me */
-                                       if (is_my_mac(unicast_packet->dest)) {
+       /* rebroadcast packet */
+       add_bcast_packet_to_list(packet_buff + sizeof(struct ethhdr),
+                                result - sizeof(struct ethhdr));
+}
 
-                                               interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct unicast_packet), result - sizeof(struct ethhdr) - sizeof(struct unicast_packet));
-                                               continue;
+static void recv_vis_packet(struct ethhdr *ethhdr,
+                           unsigned char *packet_buff,
+                           int result)
+{
+       struct vis_packet *vis_packet;
+       int hdr_size = sizeof(struct ethhdr) + sizeof(struct vis_packet);
+       int vis_info_len;
 
-                                       }
+       /* drop if too short. */
+       if (result < hdr_size)
+               return;
 
-                                       /* TTL exceeded */
-                                       if (unicast_packet->ttl < 2) {
-                                               addr_to_string(src_str, ((struct ethhdr *)(unicast_packet + 1))->h_source);
-                                               addr_to_string(dst_str, unicast_packet->dest);
+       /* not for me */
+       if (!is_my_mac(ethhdr->h_dest))
+               return;
 
-                                               printk(KERN_WARNING "batman-adv:Warning - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
-                                               continue;
-                                       }
+       vis_packet = (struct vis_packet *)(packet_buff + sizeof(struct ethhdr));
+       vis_info_len = result  - hdr_size;
 
-                                       /* get routing information */
-                                       spin_lock(&orig_hash_lock);
-                                       orig_node = ((struct orig_node *)hash_find(orig_hash, unicast_packet->dest));
+       /* ignore own packets */
+       if (is_my_mac(vis_packet->vis_orig))
+               return;
 
-                                       if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
-                                               /* decrement ttl */
-                                               unicast_packet->ttl--;
+       if (is_my_mac(vis_packet->sender_orig))
+               return;
 
-                                               /* route it */
-                                               send_raw_packet(packet_buff + sizeof(struct ethhdr),
-                                                               result - sizeof(struct ethhdr),
-                                                               orig_node->batman_if,
-                                                               orig_node->router->addr);
-                                       }
+       switch (vis_packet->vis_type) {
+       case VIS_TYPE_SERVER_SYNC:
+               receive_server_sync_packet(vis_packet, vis_info_len);
+               break;
 
-                                       spin_unlock(&orig_hash_lock);
-                                       break;
+       case VIS_TYPE_CLIENT_UPDATE:
+               receive_client_update_packet(vis_packet, vis_info_len);
+               break;
 
-                               /* broadcast packet */
-                               case BAT_BCAST:
-                                       /* packet with broadcast indication but unicast recipient */
-                                       if (!is_bcast(ethhdr->h_dest))
-                                               continue;
+       default:        /* ignore unknown packet */
+               break;
+       }
+}
 
-                                       /* packet with broadcast sender address */
-                                       if (is_bcast(ethhdr->h_source))
-                                               continue;
+static int recv_one_packet(struct batman_if *batman_if,
+                          unsigned char *packet_buff)
+{
+       int result;
+       struct ethhdr *ethhdr;
+       struct batman_packet *batman_packet;
 
-                                       /* drop packet if it has not necessary minimum size */
-                                       if (result < sizeof(struct ethhdr) + sizeof(struct bcast_packet))
-                                               continue;
+       result = receive_raw_packet(batman_if->raw_sock, packet_buff,
+                                   PACKBUFF_SIZE);
+       if (result <= 0)
+               return result;
 
-                                       /* ignore broadcasts sent by myself */
-                                       if (is_my_mac(ethhdr->h_source))
-                                               continue;
+       if (result < sizeof(struct ethhdr) + 2)
+               return 0;
 
-                                       bcast_packet = (struct bcast_packet *)(packet_buff + sizeof(struct ethhdr));
+       ethhdr = (struct ethhdr *)packet_buff;
+       batman_packet = (struct batman_packet *)
+               (packet_buff + sizeof(struct ethhdr));
 
-                                       /* ignore broadcasts originated by myself */
-                                       if (is_my_mac(bcast_packet->orig))
-                                               continue;
+       if (batman_packet->version != COMPAT_VERSION) {
+               bat_dbg(DBG_BATMAN,
+                       "Drop packet: incompatible batman version (%i)\n",
+                       batman_packet->version);
+               return 0;
+       }
 
-                                       spin_lock(&orig_hash_lock);
-                                       orig_node = ((struct orig_node *)hash_find(orig_hash, bcast_packet->orig));
+       switch (batman_packet->packet_type) {
+               /* batman originator packet */
+       case BAT_PACKET:
+               recv_bat_packet(ethhdr, packet_buff, result, batman_if);
+               break;
+
+               /* batman icmp packet */
+       case BAT_ICMP:
+               recv_icmp_packet(ethhdr, packet_buff, result, batman_if);
+               break;
+
+               /* unicast packet */
+       case BAT_UNICAST:
+               recv_unicast_packet(ethhdr, packet_buff, result, batman_if);
+               break;
+
+               /* broadcast packet */
+       case BAT_BCAST:
+               recv_bcast_packet(ethhdr,
+                                 packet_buff, result, batman_if);
+               break;
+
+               /* vis packet */
+       case BAT_VIS:
+               recv_vis_packet(ethhdr, packet_buff, result);
+               break;
+       }
+       return 0;
+}
 
-                                       if (orig_node == NULL) {
-                                               spin_unlock(&orig_hash_lock);
-                                               continue;
-                                       }
 
-                                       /* check flood history */
-                                       if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, ntohs(bcast_packet->seqno))) {
-                                               spin_unlock(&orig_hash_lock);
-                                               continue;
-                                       }
+static int discard_one_packet(struct batman_if *batman_if,
+                             unsigned char *packet_buff)
+{
+       int result = -EAGAIN;
 
-                                       /* mark broadcast in flood history */
-                                       if (bit_get_packet(orig_node->bcast_bits, ntohs(bcast_packet->seqno) - orig_node->last_bcast_seqno, 1))
-                                               orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno);
+       if (batman_if->if_active != IF_TO_BE_ACTIVATED) {
+               printk(KERN_WARNING
+                      "batman-adv:Could not read from deactivated interface %s!\n",
+                      batman_if->dev);
+       } else {
+               if (batman_if->raw_sock)
+                       result = receive_raw_packet(batman_if->raw_sock,
+                                                   packet_buff,
+                                                   PACKBUFF_SIZE);
+       }
+       return result;
+}
 
-                                       spin_unlock(&orig_hash_lock);
 
-                                       /* broadcast for me */
-                                       interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct bcast_packet), result - sizeof(struct ethhdr) - sizeof(struct bcast_packet));
+static bool is_interface_active(struct batman_if *batman_if)
+{
+       if (batman_if->if_active != IF_ACTIVE)
+               return false;
 
-                                       /* rebroadcast packet */
-                                       add_bcast_packet_to_list(packet_buff + sizeof(struct ethhdr),
-                                                                       result - sizeof(struct ethhdr));
+       return true;
+}
 
-                                       break;
+static void service_interface(struct batman_if *batman_if,
+                             unsigned char *packet_buff)
 
-                               /* vis packet */
-                               case BAT_VIS:
-                                       /* drop if too short. */
-                                       if (result < sizeof(struct ethhdr) + sizeof(struct vis_packet))
-                                               continue;
+{
+       int result;
 
-                                       /* not for me */
-                                       if (!is_my_mac(ethhdr->h_dest))
-                                               continue;
+       do {
+               if (is_interface_active(batman_if))
+                       result = recv_one_packet(batman_if, packet_buff);
+               else
+                       result = discard_one_packet(batman_if, packet_buff);
+       } while (result >= 0);
 
-                                       vis_packet = (struct vis_packet *)(packet_buff + sizeof(struct ethhdr));
-                                       vis_info_len = result  - sizeof(struct ethhdr) - sizeof(struct vis_packet);
+       /* we perform none blocking reads, so EAGAIN indicates there
+          are no more packets to read. Anything else is a real
+          error.*/
 
-                                       /* ignore own packets */
-                                       if (is_my_mac(vis_packet->vis_orig))
-                                               continue;
+       if ((result < 0) && (result != -EAGAIN))
+               printk(KERN_ERR "batman-adv:Could not receive packet from interface %s: %i\n", batman_if->dev, result);
+}
 
-                                       if (is_my_mac(vis_packet->sender_orig))
-                                               continue;
+static void service_interfaces(unsigned char *packet_buffer)
+{
+       struct batman_if *batman_if;
+       rcu_read_lock();
+       list_for_each_entry_rcu(batman_if, &if_list, list) {
+               rcu_read_unlock();
+               service_interface(batman_if, packet_buffer);
+               rcu_read_lock();
+       }
+       rcu_read_unlock();
+}
 
-                                       switch (vis_packet->vis_type) {
-                                       case VIS_TYPE_SERVER_SYNC:
-                                               receive_server_sync_packet(vis_packet, vis_info_len);
-                                               break;
 
-                                       case VIS_TYPE_CLIENT_UPDATE:
-                                               receive_client_update_packet(vis_packet, vis_info_len);
-                                               break;
+int packet_recv_thread(void *data)
+{
+       unsigned char *packet_buff;
 
-                                       default:        /* ignore unknown packet */
-                                               break;
-                                       }
+       atomic_set(&data_ready_cond, 0);
+       atomic_set(&exit_cond, 0);
+       packet_buff = kmalloc(PACKBUFF_SIZE, GFP_KERNEL);
+       if (!packet_buff) {
+               printk(KERN_ERR"batman-adv:Could allocate memory for the packet buffer. :(\n");
+               return -1;
+       }
 
-                                       break;
-                               }
+       while ((!kthread_should_stop()) && (!atomic_read(&exit_cond))) {
 
-                       }
+               wait_event_interruptible(thread_wait,
+                                        (atomic_read(&data_ready_cond) ||
+                                         atomic_read(&exit_cond)));
 
-                       if ((result < 0) && (result != -EAGAIN))
-                               printk(KERN_ERR "batman-adv:Could not receive packet from interface %s: %i\n", batman_if->dev, result);
+               atomic_set(&data_ready_cond, 0);
 
-                       /* lock for the next iteration */
-                       rcu_read_lock();
-               }
-               rcu_read_unlock();
+               if (kthread_should_stop() || atomic_read(&exit_cond))
+                       break;
 
+               service_interfaces(packet_buff);
        }
        kfree(packet_buff);
 
-       /* do not exit until kthread_stop() is actually called, otherwise it will wait for us
-        * forever. */
+       /* do not exit until kthread_stop() is actually called,
+        * otherwise it will wait for us forever. */
        while (!kthread_should_stop())
                schedule();