[PATCH 2/7] Staging: batman-adv: Refactor routing.c

Andrew Lunn andrew at lunn.ch
Sat Dec 12 22:39:42 UTC 2009


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 at lunn.ch>
Acked-by: Marek Lindner <lindner_marek at yahoo.de>
Acked-by: Simon Wunderlich <simon.wunderlich at s2003.tu-chemnitz.de>
---
 drivers/staging/batman-adv/routing.c | 1148 +++++++++++++++++++++-------------
 1 files changed, 709 insertions(+), 439 deletions(-)

diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c
index 1f42d41..1ff2a7a 100644
--- a/drivers/staging/batman-adv/routing.c
+++ b/drivers/staging/batman-adv/routing.c
@@ -19,10 +19,6 @@
  *
  */
 
-
-
-
-
 #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();
 
-- 
1.6.5.4




More information about the devel mailing list