Index: batman-adv-kernelland/vis.c
===================================================================
--- batman-adv-kernelland/vis.c	(revision 1489)
+++ batman-adv-kernelland/vis.c	(working copy)
@@ -26,6 +26,7 @@
 #include "soft-interface.h"
 #include "hard-interface.h"
 #include "hash.h"
+#include "originator.h"
 #include "compat.h"
 
 struct hashtable_t *vis_hash;
@@ -262,16 +263,16 @@
 
 /* Walk the originators and find the VIS server with the best tq. Set the packet
  * address to its address and return the best_tq.
- *
- * Must be called with the originator hash locked */
+ */
 static int find_best_vis_server(struct vis_info *info)
 {
 	struct hash_it_t *hashit = NULL;
-	struct orig_node *orig_node;
+	struct orig_node *orig_node = NULL;
 	int best_tq = -1;
 
-	while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
-		orig_node = hashit->bucket->data;
+	while (NULL != (orig_node = orig_hash_iterate(&hashit, orig_node))) {
+
+		spin_lock(&orig_node->lock);
 		if ((orig_node != NULL) &&
 		    (orig_node->router != NULL) &&
 		    (orig_node->flags & VIS_SERVER) &&
@@ -280,6 +281,7 @@
 			memcpy(info->packet.target_orig, orig_node->orig,
 			       ETH_ALEN);
 		}
+		spin_unlock(&orig_node->lock);
 	}
 	return best_tq;
 }
@@ -298,7 +300,7 @@
 static int generate_vis_packet(void)
 {
 	struct hash_it_t *hashit = NULL;
-	struct orig_node *orig_node;
+	struct orig_node *orig_node = NULL;
 	struct vis_info *info = (struct vis_info *)my_vis_info;
 	struct vis_info_entry *entry, *entry_array;
 	struct hna_local_entry *hna_local_entry;
@@ -307,7 +309,6 @@
 
 	info->first_seen = jiffies;
 
-	spin_lock(&orig_hash_lock);
 	memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
 	info->packet.ttl = TTL;
 	info->packet.seqno++;
@@ -316,17 +317,17 @@
 	if (!is_vis_server_locked()) {
 		best_tq = find_best_vis_server(info);
 		if (best_tq < 0) {
-			spin_unlock(&orig_hash_lock);
 			return -1;
 		}
 	}
-	hashit = NULL;
 
 	entry_array = (struct vis_info_entry *)
 		((char *)info + sizeof(struct vis_info));
 
-	while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
-		orig_node = hashit->bucket->data;
+	while (NULL != (orig_node = orig_hash_iterate(&hashit, orig_node))) {
+
+		spin_lock(&orig_node->lock);
+
 		if (orig_node->router != NULL
 			&& compare_orig(orig_node->router->addr, orig_node->orig)
 			&& orig_node->batman_if
@@ -340,15 +341,16 @@
 			entry->quality = orig_node->router->tq_avg;
 			info->packet.entries++;
 
+			/* TODO: this is is a possible memory leak, 
+			 * hashit should be freed somewhere. */
 			if (vis_packet_full(info)) {
-				spin_unlock(&orig_hash_lock);
+				spin_unlock(&orig_node->lock);
+				orig_unreference(orig_node);
 				return 0;
 			}
 		}
 	}
 
-	spin_unlock(&orig_hash_lock);
-
 	hashit = NULL;
 	spin_lock_irqsave(&hna_local_hash_lock, flags);
 	while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
@@ -388,14 +390,12 @@
 static void broadcast_vis_packet(struct vis_info *info, int packet_length)
 {
 	struct hash_it_t *hashit = NULL;
-	struct orig_node *orig_node;
+	struct orig_node *orig_node = NULL;
 
-	spin_lock(&orig_hash_lock);
-
 	/* send to all routers in range. */
-	while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
-		orig_node = hashit->bucket->data;
+	while (NULL != (orig_node = orig_hash_iterate(&hashit, orig_node))) {
 
+		spin_lock(&orig_node->lock);
 		/* if it's a vis server and reachable, send it. */
 		if (orig_node &&
 		    (orig_node->flags & VIS_SERVER) &&
@@ -415,27 +415,28 @@
 					orig_node->batman_if,
 					orig_node->router->addr);
 		}
+		spin_unlock(&orig_node->lock);
 	}
 	memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
-	spin_unlock(&orig_hash_lock);
 }
 
 static void unicast_vis_packet(struct vis_info *info, int packet_length)
 {
 	struct orig_node *orig_node;
 
-	spin_lock(&orig_hash_lock);
-	orig_node = ((struct orig_node *)
-		     hash_find(orig_hash, info->packet.target_orig));
+	orig_node = orig_find(info->packet.target_orig);
 
-	if ((orig_node != NULL) &&
-	    (orig_node->batman_if != NULL) &&
-	    (orig_node->router != NULL)) {
-		send_raw_packet((unsigned char *) &info->packet, packet_length,
+	if (orig_node) {
+		spin_lock(&orig_node->lock);
+	    if ((orig_node->batman_if != NULL) &&
+	    	(orig_node->router != NULL)) {
+			send_raw_packet((unsigned char *) &info->packet, packet_length,
 				orig_node->batman_if,
 				orig_node->router->addr);
+		}
+		spin_unlock(&orig_node->lock);
+		orig_unreference(orig_node);
 	}
-	spin_unlock(&orig_hash_lock);
 }
 
 /* only send one vis packet. called from send_vis_packets() */
Index: batman-adv-kernelland/Makefile.kbuild
===================================================================
--- batman-adv-kernelland/Makefile.kbuild	(revision 1489)
+++ batman-adv-kernelland/Makefile.kbuild	(working copy)
@@ -25,7 +25,7 @@
 -include $(TOPDIR)/Rules.make
 endif
 
-# EXTRA_CFLAGS += -DCONFIG_BATMAN_DEBUG
+EXTRA_CFLAGS += -DCONFIG_BATMAN_DEBUG
 
 ifneq ($(REVISION),)
 EXTRA_CFLAGS += -DREVISION_VERSION=\"r$(REVISION)\"
Index: batman-adv-kernelland/types.h
===================================================================
--- batman-adv-kernelland/types.h	(revision 1489)
+++ batman-adv-kernelland/types.h	(working copy)
@@ -62,6 +62,8 @@
 	int16_t  hna_buff_len;
 	uint16_t last_real_seqno;   /* last and best known squence number */
 	uint8_t last_ttl;         /* ttl of last received packet */
+	spinlock_t lock;
+	atomic_t refcnt;
 	TYPE_OF_WORD bcast_bits[NUM_WORDS];
 	uint16_t last_bcast_seqno;  /* last broadcast sequence number received by this host */
 	struct list_head neigh_list;
Index: batman-adv-kernelland/translation-table.c
===================================================================
--- batman-adv-kernelland/translation-table.c	(revision 1489)
+++ batman-adv-kernelland/translation-table.c	(working copy)
@@ -24,6 +24,7 @@
 #include "soft-interface.h"
 #include "types.h"
 #include "hash.h"
+#include "originator.h"
 #include "compat.h"
 
 struct hashtable_t *hna_local_hash;
@@ -257,6 +258,9 @@
 	return 1;
 }
 
+
+/* adds an HNA entry to the global address table.
+ * orig_node's spinlock should be hold from outside */
 void hna_global_add_orig(struct orig_node *orig_node,
 			 unsigned char *hna_buff, int hna_buff_len)
 {
@@ -299,7 +303,7 @@
 
 		}
 
-		hna_global_entry->orig_node = orig_node;
+		hna_global_entry->orig_node = orig_reference(orig_node);
 		spin_unlock_irqrestore(&hna_global_hash_lock, flags);
 
 		/* remove address from local hash if present */
@@ -391,6 +395,8 @@
 		hna_str, orig_str, message);
 
 	hash_remove(hna_global_hash, hna_global_entry->addr);
+	orig_unreference(hna_global_entry->orig_node);
+
 	kfree(hna_global_entry);
 }
 
@@ -452,5 +458,5 @@
 	if (hna_global_entry == NULL)
 		return NULL;
 
-	return hna_global_entry->orig_node;
+	return orig_reference(hna_global_entry->orig_node);
 }
Index: batman-adv-kernelland/send.c
===================================================================
--- batman-adv-kernelland/send.c	(revision 1489)
+++ batman-adv-kernelland/send.c	(working copy)
@@ -294,6 +294,7 @@
 	batman_packet->ttl--;
 	memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
 
+	spin_lock(&orig_node->lock);
 	/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
 	 * of our best tq value */
 	if ((orig_node->router) && (orig_node->router->tq_avg != 0)) {
@@ -308,6 +309,7 @@
 
 		tq_avg = orig_node->router->tq_avg;
 	}
+	spin_unlock(&orig_node->lock);
 
 	/* apply hop penalty */
 	batman_packet->tq = hop_penalty(batman_packet->tq);
Index: batman-adv-kernelland/device.c
===================================================================
--- batman-adv-kernelland/device.c	(revision 1489)
+++ batman-adv-kernelland/device.c	(working copy)
@@ -24,6 +24,7 @@
 #include "send.h"
 #include "types.h"
 #include "hash.h"
+#include "originator.h"
 
 #include "compat.h"
 
@@ -205,6 +206,7 @@
 	struct icmp_packet icmp_packet;
 	struct orig_node *orig_node;
 	struct batman_if *batman_if;
+	uint8_t router_addr[ETH_ALEN];
 
 	if (len < sizeof(struct icmp_packet)) {
 		printk(KERN_DEBUG "batman-adv:Error - can't send packet from char device: invalid packet size\n");
@@ -239,15 +241,20 @@
 	if (atomic_read(&module_state) != MODULE_ACTIVE)
 		goto dst_unreach;
 
-	spin_lock(&orig_hash_lock);
-	orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst));
+	orig_node = orig_find(icmp_packet.dst);
 
 	if (!orig_node)
-		goto unlock;
+		goto dst_unreach;
 
+	spin_lock(&orig_node->lock);
+
 	if (!orig_node->router)
 		goto unlock;
 
+	memcpy(router_addr,
+	       orig_node->router->addr,
+	       ETH_ALEN);
+
 	batman_if = orig_node->batman_if;
 
 	if (!batman_if)
@@ -257,15 +264,18 @@
 	       batman_if->net_dev->dev_addr,
 	       ETH_ALEN);
 
+	spin_unlock(&orig_node->lock);
+	orig_unreference(orig_node);
+
 	send_raw_packet((unsigned char *)&icmp_packet,
 			sizeof(struct icmp_packet),
-			batman_if, orig_node->router->addr);
+			batman_if, router_addr);
 
-	spin_unlock(&orig_hash_lock);
 	goto out;
 
 unlock:
-	spin_unlock(&orig_hash_lock);
+	spin_unlock(&orig_node->lock);
+	orig_unreference(orig_node);
 dst_unreach:
 	icmp_packet.msg_type = DESTINATION_UNREACHABLE;
 	bat_device_add_packet(device_client, &icmp_packet);
Index: batman-adv-kernelland/proc.c
===================================================================
--- batman-adv-kernelland/proc.c	(revision 1489)
+++ batman-adv-kernelland/proc.c	(working copy)
@@ -28,6 +28,7 @@
 #include "hash.h"
 #include "vis.h"
 #include "compat.h"
+#include "originator.h"
 
 static uint8_t vis_format = DOT_DRAW;
 
@@ -187,7 +188,7 @@
 static int proc_originators_read(struct seq_file *seq, void *offset)
 {
 	struct hash_it_t *hashit = NULL;
-	struct orig_node *orig_node;
+	struct orig_node *orig_node = NULL;
 	struct neigh_node *neigh_node;
 	int batman_count = 0;
 	char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
@@ -213,11 +214,10 @@
 		   ((struct batman_if *)if_list.next)->addr_str);
 
 	rcu_read_unlock();
-	spin_lock(&orig_hash_lock);
 
-	while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
+	while (NULL != (orig_node = orig_hash_iterate(&hashit, orig_node))) {
 
-		orig_node = hashit->bucket->data;
+		spin_lock(&orig_node->lock);
 
 		if (!orig_node->router)
 			continue;
@@ -241,11 +241,10 @@
 		}
 
 		seq_printf(seq, "\n");
+		spin_unlock(&orig_node->lock);
 
 	}
 
-	spin_unlock(&orig_hash_lock);
-
 	if (batman_count == 0)
 		seq_printf(seq, "No batman nodes in range ... \n");
 
Index: batman-adv-kernelland/soft-interface.c
===================================================================
--- batman-adv-kernelland/soft-interface.c	(revision 1489)
+++ batman-adv-kernelland/soft-interface.c	(working copy)
@@ -26,6 +26,7 @@
 #include "translation-table.h"
 #include "types.h"
 #include "hash.h"
+#include "originator.h"
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
 #include "compat.h"
@@ -34,7 +35,6 @@
 				  * broadcast storms */
 static int32_t skb_packets;
 static int32_t skb_bad_packets;
-static int32_t lock_dropped;
 
 unsigned char mainIfAddr[ETH_ALEN];
 static unsigned char mainIfAddr_default[ETH_ALEN];
@@ -205,60 +205,55 @@
 	/* unicast packet */
 	} else {
 
-		/* simply spin_lock()ing can deadlock when the lock is already
-		 * hold. */
-		/* TODO: defer the work in a working queue instead of
-		 * dropping */
-		if (!spin_trylock(&orig_hash_lock)) {
-			lock_dropped++;
-			printk(KERN_WARNING "batman-adv:%d packets dropped because lock was hold\n", lock_dropped);
-			goto dropped;
-		}
-
 		/* get routing information */
-		orig_node = ((struct orig_node *)hash_find(orig_hash,
-							   ethhdr->h_dest));
+		orig_node = orig_find(ethhdr->h_dest);
 
 		/* check for hna host */
 		if (!orig_node)
 			orig_node = transtable_search(ethhdr->h_dest);
 
-		if ((orig_node) &&
-		    (orig_node->batman_if) &&
-		    (orig_node->router)) {
-			if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
-				goto unlock;
+		if (!orig_node) 
+			goto dropped;
 
-			unicast_packet = (struct unicast_packet *)skb->data;
+		spin_lock(&orig_node->lock);
 
-			unicast_packet->version = COMPAT_VERSION;
-			/* batman packet type: unicast */
-			unicast_packet->packet_type = BAT_UNICAST;
-			/* set unicast ttl */
-			unicast_packet->ttl = TTL;
-			/* copy the destination for faster routing */
-			memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+	    if (!((orig_node->batman_if) &&
+		    (orig_node->router))) 
+			goto unlock;
 
-			/* net_dev won't be available when not active */
-			if (orig_node->batman_if->if_active != IF_ACTIVE)
-				goto unlock;
+		if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0) 
+			goto unlock;
 
-			send_raw_packet(skb->data, skb->len,
-					orig_node->batman_if,
-					orig_node->router->addr);
-		} else {
+		unicast_packet = (struct unicast_packet *)skb->data;
+
+		unicast_packet->version = COMPAT_VERSION;
+		/* batman packet type: unicast */
+		unicast_packet->packet_type = BAT_UNICAST;
+		/* set unicast ttl */
+		unicast_packet->ttl = TTL;
+		/* copy the destination for faster routing */
+		memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+
+		/* net_dev won't be available when not active */
+		if (orig_node->batman_if->if_active != IF_ACTIVE) 
 			goto unlock;
-		}
+		
+		send_raw_packet(skb->data, skb->len,
+			orig_node->batman_if,
+			orig_node->router->addr);
 
-		spin_unlock(&orig_hash_lock);
+		spin_unlock(&orig_node->lock);
+		orig_unreference(orig_node);
 	}
 
 	priv->stats.tx_packets++;
 	priv->stats.tx_bytes += data_len;
 	goto end;
 
+
 unlock:
-	spin_unlock(&orig_hash_lock);
+	spin_unlock(&orig_node->lock);
+	orig_unreference(orig_node);
 dropped:
 	priv->stats.tx_dropped++;
 end:
Index: batman-adv-kernelland/hard-interface.c
===================================================================
--- batman-adv-kernelland/hard-interface.c	(revision 1489)
+++ batman-adv-kernelland/hard-interface.c	(working copy)
@@ -26,6 +26,7 @@
 #include "translation-table.h"
 #include "routing.h"
 #include "hash.h"
+#include "originator.h"
 #include "compat.h"
 
 #define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -317,8 +318,9 @@
 {
 	struct batman_if *batman_if;
 	struct batman_packet *batman_packet;
-	struct orig_node *orig_node;
+	struct orig_node *orig_node = NULL;
 	struct hash_it_t *hashit = NULL;
+	int ret;
 
 	batman_if = kmalloc(sizeof(struct batman_if), GFP_KERNEL);
 
@@ -375,18 +377,18 @@
 
 	/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
 	 * if_num */
-	spin_lock(&orig_hash_lock);
 
-	while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
-		orig_node = hashit->bucket->data;
-		if (resize_orig(orig_node, if_num) == -1) {
-			spin_unlock(&orig_hash_lock);
-			goto out;
-		}
+	ret = 0;
+	while (NULL != (orig_node = orig_hash_iterate(&hashit, orig_node))) {
+		ret |= resize_orig(orig_node, if_num);
 	}
 
-	spin_unlock(&orig_hash_lock);
+	if (ret) {
+		printk(KERN_ERR "batman-adv:Resizing originators for %s failed.\n", batman_if->dev);
+		goto out;
+	}
 
+
 	if (!hardif_is_interface_up(batman_if->dev))
 		printk(KERN_ERR "batman-adv:Not using interface %s (retrying later): interface not active\n", batman_if->dev);
 	else
Index: batman-adv-kernelland/originator.c
===================================================================
--- batman-adv-kernelland/originator.c	(revision 1489)
+++ batman-adv-kernelland/originator.c	(working copy)
@@ -19,17 +19,86 @@
  *
  */
 
-/* increase the reference counter for this originator */
-
 #include "main.h"
+#include "hash.h"
 #include "originator.h"
-#include "hash.h"
 #include "translation-table.h"
 #include "routing.h"
 
 
+DEFINE_SPINLOCK(orig_hash_lock);
 static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
 
+/* increase the reference counter for this originator */
+
+struct orig_node *orig_reference(struct orig_node *orig_node)
+{
+	if (orig_node == NULL) {
+		printk(KERN_ERR "batman-adv: tried to reference a NULL orig\n");
+		dump_stack();
+		return NULL;
+	} else if (atomic_read(&orig_node->refcnt) < 1) {
+		printk(KERN_DEBUG "batman-adv: trying to access a vanished node with refcnt %d\n", atomic_read(&orig_node->refcnt));
+		return NULL;
+	} else {
+		atomic_inc(&orig_node->refcnt);
+
+		return orig_node;
+	}
+}
+
+static void __free_orig_node(void *data)
+{
+	struct orig_node *orig_node = (struct orig_node *)data;
+
+	hna_global_del_orig(orig_node, "__free_orig_node");
+
+	kfree(orig_node->bcast_own);
+	kfree(orig_node->bcast_own_sum);
+	kfree(orig_node);
+}
+
+
+/* decrease the reference counter for this originator */
+struct orig_node *orig_unreference(struct orig_node *orig_node)
+{
+	char orig_str[ETH_STR_LEN];
+
+	if (orig_node == NULL) {
+		printk(KERN_ERR "batman-adv: tried to reference a NULL orig\n");
+		dump_stack();
+		return NULL;
+	} else if (atomic_read(&orig_node->refcnt) < 1) {
+		printk(KERN_DEBUG "batman-adv: trying to access a vanished node with refcnt %d\n", atomic_read(&orig_node->refcnt));
+		return NULL;
+	} else {
+
+		if (atomic_dec_and_test(&orig_node->refcnt)) {
+			addr_to_string(orig_str, orig_node->orig);
+			bat_dbg(DBG_BATMAN,"%s:decreasing refcnt of orig %s to %d, time to free\n", __func__, orig_str, atomic_read(&orig_node->refcnt));
+			__free_orig_node(orig_node);
+		}
+		return orig_node;
+	}
+}
+
+
+/* find an orig node and increase the reference counter */
+
+struct orig_node *orig_find(char *mac)
+{
+	struct orig_node *orig_node;
+
+	spin_lock(&orig_hash_lock);
+	orig_node = ((struct orig_node *)hash_find(orig_hash, mac));
+	spin_unlock(&orig_hash_lock);
+
+	if (orig_node)
+		orig_node = orig_reference(orig_node);
+
+	return orig_node;
+}
+
 static void start_purge_timer(void)
 {
 	queue_delayed_work(bat_event_workqueue, &purge_orig_wq, 1 * HZ);
@@ -64,6 +133,7 @@
 
 	spin_lock(&orig_hash_lock);
 	hash_delete(orig_hash, free_orig_node);
+
 	orig_hash = NULL;
 	spin_unlock(&orig_hash_lock);
 }
@@ -81,7 +151,7 @@
 	INIT_LIST_HEAD(&neigh_node->list);
 
 	memcpy(neigh_node->addr, neigh, ETH_ALEN);
-	neigh_node->orig_node = orig_neigh_node;
+	neigh_node->orig_node = orig_reference(orig_neigh_node);
 	neigh_node->if_incoming = if_incoming;
 
 	list_add_tail(&neigh_node->list, &orig_node->neigh_list);
@@ -90,39 +160,35 @@
 
 void free_orig_node(void *data)
 {
+	struct orig_node *orig_node = (struct orig_node *) data;
 	struct list_head *list_pos, *list_pos_tmp;
 	struct neigh_node *neigh_node;
-	struct orig_node *orig_node = (struct orig_node *)data;
 
+	hna_global_del_orig(orig_node, "originator timeout");
+
+	spin_lock(&orig_node->lock);
 	/* 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);
 
+		orig_unreference(neigh_node->orig_node);
+
 		list_del(list_pos);
 		kfree(neigh_node);
 	}
+	orig_node->router = NULL;
+	spin_unlock(&orig_node->lock);
 
-	hna_global_del_orig(orig_node, "originator timed out");
-
-	kfree(orig_node->bcast_own);
-	kfree(orig_node->bcast_own_sum);
-	kfree(orig_node);
+	orig_unreference(orig_node);
 }
 
-/* this function finds or creates an originator entry for the given
- * address if it does not exits */
-struct orig_node *get_orig_node(uint8_t *addr)
+struct orig_node *orig_node_create(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));
-
-	if (orig_node != NULL)
-		return orig_node;
-
 	addr_to_string(orig_str, addr);
 	bat_dbg(DBG_BATMAN, "Creating new originator: %s \n", orig_str);
 
@@ -131,9 +197,12 @@
 	INIT_LIST_HEAD(&orig_node->neigh_list);
 
 	memcpy(orig_node->orig, addr, ETH_ALEN);
+
+	orig_node->lock = __SPIN_LOCK_UNLOCKED(device_client->lock);
 	orig_node->router = NULL;
 	orig_node->batman_if = NULL;
 	orig_node->hna_buff = NULL;
+	atomic_set(&orig_node->refcnt, 1);
 
 	size = num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS;
 
@@ -155,7 +224,24 @@
 		else
 			orig_hash = swaphash;
 	}
+	return orig_node;
+}
 
+/* this function finds or creates an originator entry for the given
+ * address if it does not exits */
+struct orig_node *get_orig_node(uint8_t *addr)
+{
+	struct orig_node *orig_node;
+
+	orig_node = orig_find(addr);
+
+	if (orig_node)
+		return orig_node;
+
+	orig_node = orig_node_create(addr);
+	if (orig_node)
+		orig_node = orig_reference(orig_node_create(addr));
+
 	return orig_node;
 }
 
@@ -164,6 +250,7 @@
 {
 	struct list_head *list_pos, *list_pos_tmp;
 	char neigh_str[ETH_STR_LEN];
+	char orig_str[ETH_STR_LEN];
 	struct neigh_node *neigh_node;
 	bool neigh_purged = false;
 
@@ -178,10 +265,14 @@
 			       (neigh_node->last_valid +
 				((PURGE_TIMEOUT * HZ) / 1000)))) {
 
+			addr_to_string(orig_str, orig_node->orig);
 			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;
+			if (neigh_node == orig_node->router)
+				orig_node->router = NULL;
 
-			neigh_purged = true;
+			orig_unreference(neigh_node->orig_node);
 			list_del(list_pos);
 			kfree(neigh_node);
 		} else {
@@ -201,10 +292,10 @@
 
 	addr_to_string(orig_str, orig_node->orig);
 
+	spin_lock(&orig_node->lock);
 	if (time_after(jiffies,
 		       (orig_node->last_valid +
 			((2 * PURGE_TIMEOUT * HZ) / 1000)))) {
-
 		bat_dbg(DBG_BATMAN,
 			"Originator timeout: originator %s, last_valid %lu\n",
 			orig_str, (orig_node->last_valid / HZ));
@@ -215,28 +306,48 @@
 				      orig_node->hna_buff,
 				      orig_node->hna_buff_len);
 	}
+	spin_unlock(&orig_node->lock);
 	return false;
 }
 
 void purge_orig(struct work_struct *work)
 {
 	struct hash_it_t *hashit = NULL;
-	struct orig_node *orig_node;
+	struct orig_node *orig_node = NULL;
 
-	spin_lock(&orig_hash_lock);
 
 	/* for all origins... */
-	while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
-		orig_node = hashit->bucket->data;
+	while (NULL != (orig_node = orig_hash_iterate(&hashit, orig_node))) {
+
 		if (purge_orig_node(orig_node)) {
 			hash_remove_bucket(orig_hash, hashit);
 			free_orig_node(orig_node);
 		}
 	}
 
-	spin_unlock(&orig_hash_lock);
-
 	start_purge_timer();
 }
 
 
+/* iterates over the originator hash, automatically referencing acquired orig_nodes.
+ * It also unreferences the last node if it is given.
+ *
+ * The calling function does not have to handle the orig_hash locks as this function
+ * does it. */
+struct orig_node *orig_hash_iterate(struct hash_it_t **hashit, struct orig_node *orig_node)
+{
+	if (orig_node)
+		orig_unreference(orig_node);
+
+	spin_lock(&orig_hash_lock);
+
+	*hashit = hash_iterate(orig_hash, *hashit);
+	if (*hashit)
+		orig_node = orig_reference((*hashit)->bucket->data);
+	else 
+		orig_node = NULL;
+
+	spin_unlock(&orig_hash_lock);
+
+	return orig_node;
+}
Index: batman-adv-kernelland/originator.h
===================================================================
--- batman-adv-kernelland/originator.h	(revision 1489)
+++ batman-adv-kernelland/originator.h	(working copy)
@@ -19,6 +19,8 @@
  *
  */
 
+extern spinlock_t orig_hash_lock;
+
 int originator_init(void);
 void free_orig_node(void *data);
 void originator_free(void);
@@ -28,4 +30,8 @@
 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 orig_node *orig_reference(struct orig_node *orig);
+struct orig_node *orig_unreference(struct orig_node *orig);
+struct orig_node *orig_find(char *mac);
+struct orig_node *orig_hash_iterate(struct hash_it_t **hashit, struct orig_node *orig_node);
 
Index: batman-adv-kernelland/main.c
===================================================================
--- batman-adv-kernelland/main.c	(revision 1489)
+++ batman-adv-kernelland/main.c	(working copy)
@@ -23,7 +23,6 @@
 #include "proc.h"
 #include "routing.h"
 #include "send.h"
-#include "originator.h"
 #include "soft-interface.h"
 #include "device.h"
 #include "translation-table.h"
@@ -31,6 +30,7 @@
 #include "types.h"
 #include "vis.h"
 #include "hash.h"
+#include "originator.h"
 #include "compat.h"
 
 struct list_head if_list;
@@ -38,7 +38,6 @@
 struct hlist_head forw_bcast_list;
 struct hashtable_t *orig_hash;
 
-DEFINE_SPINLOCK(orig_hash_lock);
 DEFINE_SPINLOCK(forw_bat_list_lock);
 DEFINE_SPINLOCK(forw_bcast_list_lock);
 
Index: batman-adv-kernelland/routing.c
===================================================================
--- batman-adv-kernelland/routing.c	(revision 1489)
+++ batman-adv-kernelland/routing.c	(working copy)
@@ -38,24 +38,21 @@
 
 static atomic_t data_ready_cond;
 atomic_t exit_cond;
+
 void slide_own_bcast_window(struct batman_if *batman_if)
 {
 	struct hash_it_t *hashit = NULL;
-	struct orig_node *orig_node;
+	struct orig_node *orig_node = NULL;
 	TYPE_OF_WORD *word;
 
-	spin_lock(&orig_hash_lock);
+	while (NULL != (orig_node = orig_hash_iterate(&hashit, orig_node))) {
 
-	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(word, 1, 0);
 		orig_node->bcast_own_sum[batman_if->if_num] =
 			bit_packet_count(word);
 	}
-
-	spin_unlock(&orig_hash_lock);
 }
 
 static void update_HNA(struct orig_node *orig_node,
@@ -131,6 +128,8 @@
 		update_HNA(orig_node, hna_buff, hna_buff_len);
 }
 
+/* TODO: rename and comment this function */
+/* TODO: review referencing here */
 static int isBidirectionalNeigh(struct orig_node *orig_node,
 				struct orig_node *orig_neigh_node,
 				struct batman_packet *batman_packet,
@@ -144,25 +143,29 @@
 	addr_to_string(neigh_str, orig_neigh_node->orig);
 
 	if (orig_node == orig_neigh_node) {
+		spin_lock(&orig_node->lock);
 		list_for_each_entry(tmp_neigh_node,
 				    &orig_node->neigh_list,
 				    list) {
 
 			if (compare_orig(tmp_neigh_node->addr,
-					 orig_neigh_node->orig) &&
+					 orig_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,
+						     orig_node,
+						     orig_node->orig,
 						     if_incoming);
 
 		neigh_node->last_valid = jiffies;
+		spin_unlock(&orig_node->lock);
 	} else {
 		/* find packet count of corresponding one hop neighbor */
+		spin_lock(&orig_neigh_node->lock);
+
 		list_for_each_entry(tmp_neigh_node,
 				    &orig_neigh_node->neigh_list, list) {
 
@@ -177,6 +180,7 @@
 						     orig_neigh_node,
 						     orig_neigh_node->orig,
 						     if_incoming);
+		spin_unlock(&orig_neigh_node->lock);
 	}
 
 	orig_node->last_valid = jiffies;
@@ -239,6 +243,7 @@
 			unsigned char *hna_buff, int hna_buff_len,
 			char is_duplicate)
 {
+	struct orig_node *source_orig_node;
 	struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
 	int tmp_hna_buff_len;
 
@@ -260,11 +265,13 @@
 			ring_buffer_avg(tmp_neigh_node->tq_recv);
 	}
 
-	if (neigh_node == NULL)
+	if (neigh_node == NULL) {
+		source_orig_node = get_orig_node(ethhdr->h_source);
 		neigh_node = create_neighbor(orig_node,
-					     get_orig_node(ethhdr->h_source),
+					     source_orig_node,
 					     ethhdr->h_source, if_incoming);
-	else
+		orig_unreference(source_orig_node);
+	} else
 		bat_dbg(DBG_BATMAN,
 			"Updating existing last-hop neighbour of originator\n");
 
@@ -323,6 +330,7 @@
 	if (orig_node == NULL)
 		return 0;
 
+	spin_lock(&orig_node->lock);
 	list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
 
 		if (!is_duplicate)
@@ -346,10 +354,13 @@
 			orig_node->last_real_seqno, batman_packet->seqno);
 		orig_node->last_real_seqno = batman_packet->seqno;
 	}
+	spin_unlock(&orig_node->lock);
+	orig_unreference(orig_node);
 
 	return is_duplicate;
 }
 
+/* receive and handle one batman packet */
 void receive_bat_packet(struct ethhdr *ethhdr,
 			struct batman_packet *batman_packet,
 			unsigned char *hna_buff,
@@ -448,10 +459,13 @@
 		 * come via the corresponding interface */
 		/* if received seqno equals last send seqno save new
 		 * seqno for bidirectional check */
+
+		spin_lock(&orig_neigh_node->lock);
 		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);
@@ -459,6 +473,9 @@
 				bit_packet_count(word);
 		}
 
+		spin_unlock(&orig_neigh_node->lock);
+		orig_unreference(orig_neigh_node);
+
 		bat_dbg(DBG_BATMAN, "Drop packet: originator packet from myself (via neighbour) \n");
 		return;
 	}
@@ -481,6 +498,8 @@
 	if (orig_node == NULL)
 		return;
 
+	spin_lock(&orig_node->lock);
+
 	/* avoid temporary routing loops */
 	if ((orig_node->router) &&
 	    (orig_node->router->orig_node->router) &&
@@ -489,36 +508,49 @@
 	    !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) &&
 	    (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);
+
+		spin_unlock(&orig_node->lock);
+		orig_unreference(orig_node);
 		return;
 	}
+	spin_unlock(&orig_node->lock);
 
 	/* 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)
+			   orig_reference(orig_node) : get_orig_node(ethhdr->h_source));
+	if (orig_neigh_node == NULL) {
+		orig_unreference(orig_node);
 		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)) {
 		bat_dbg(DBG_BATMAN, "Drop packet: OGM via unknown neighbor!\n");
+
+		orig_unreference(orig_node);
+		orig_unreference(orig_neigh_node);
 		return;
 	}
 
 	is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node,
 						batman_packet, if_incoming);
+	orig_unreference(orig_neigh_node);
 
 	/* update ranking if it is not a duplicate or has the same
 	 * seqno and similar ttl as the non-duplicate */
+	spin_lock(&orig_node->lock);
 	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);
+	spin_unlock(&orig_node->lock);
 
 	/* is single hop (direct) neighbour */
 	if (is_single_hop_neigh) {
@@ -528,6 +560,7 @@
 					1, hna_buff_len, if_incoming);
 
 		bat_dbg(DBG_BATMAN, "Forwarding packet: rebroadcast neighbour packet with direct link flag\n");
+		orig_unreference(orig_node);
 		return;
 	}
 
@@ -535,11 +568,13 @@
 	if (!is_bidirectional) {
 		bat_dbg(DBG_BATMAN,
 			"Drop packet: not received via bidirectional link\n");
+		orig_unreference(orig_node);
 		return;
 	}
 
 	if (is_duplicate) {
 		bat_dbg(DBG_BATMAN, "Drop packet: duplicate packet received\n");
+		orig_unreference(orig_node);
 		return;
 	}
 
@@ -547,6 +582,7 @@
 		"Forwarding packet: rebroadcast originator packet\n");
 	schedule_forward_packet(orig_node, ethhdr, batman_packet,
 				0, hna_buff_len, if_incoming);
+	orig_unreference(orig_node);
 }
 
 
@@ -585,12 +621,10 @@
 	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,
@@ -608,25 +642,28 @@
 
 	/* answer echo request (ping) */
 	/* get routing information */
-	spin_lock(&orig_hash_lock);
-	orig_node = ((struct orig_node *)hash_find(orig_hash,
-						   icmp_packet->orig));
+	orig_node = orig_find(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;
+	if (orig_node) {
+		spin_lock(&orig_node->lock);
 
-		send_raw_packet(packet_buff + sizeof(struct ethhdr),
-				result - sizeof(struct ethhdr),
-				orig_node->batman_if,
-				orig_node->router->addr);
+		if ((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);
+		}
+
+		spin_unlock(&orig_node->lock);
+		orig_unreference(orig_node);
 	}
 
-	spin_unlock(&orig_hash_lock);
 	return;
 }
 
@@ -642,33 +679,32 @@
 	addr_to_string(src_str, icmp_packet->orig);
 	addr_to_string(dst_str, icmp_packet->dst);
 
-	printk(KERN_WARNING "batman-adv:Warning - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
-
 	/* send TTL exceeded if packet is an echo request (traceroute) */
 	if (icmp_packet->msg_type != ECHO_REQUEST)
 		return;
 
 	/* get routing information */
-	spin_lock(&orig_hash_lock);
-	orig_node = ((struct orig_node *)
-		     hash_find(orig_hash, icmp_packet->orig));
+	orig_node = orig_find(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;
+	if (orig_node) {
+		spin_lock(&orig_node->lock);
 
-		send_raw_packet(packet_buff + sizeof(struct ethhdr),
-				result - sizeof(struct ethhdr),
-				orig_node->batman_if,
-				orig_node->router->addr);
+		if ((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);
+		}
+
+		spin_unlock(&orig_node->lock);
+		orig_unreference(orig_node);
 	}
-
-	spin_unlock(&orig_hash_lock);
 }
 
 
@@ -713,24 +749,27 @@
 	}
 
 	/* get routing information */
-	spin_lock(&orig_hash_lock);
-	orig_node = ((struct orig_node *)
-		     hash_find(orig_hash, icmp_packet->dst));
+	orig_node = orig_find(icmp_packet->dst);
 
-	if ((orig_node != NULL) &&
-	    (orig_node->batman_if != NULL) &&
-	    (orig_node->router != NULL)) {
+	if (orig_node) {
+		spin_lock(&orig_node->lock);
 
-		/* decrement ttl */
-		icmp_packet->ttl--;
+	    if ((orig_node->batman_if != NULL) &&
+		    (orig_node->router != NULL)) {
 
-		/* route it */
-		send_raw_packet(packet_buff + sizeof(struct ethhdr),
-				result - sizeof(struct ethhdr),
-				orig_node->batman_if,
-				orig_node->router->addr);
+			/* decrement ttl */
+			icmp_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_node->lock);
+		orig_unreference(orig_node);
+
 	}
-	spin_unlock(&orig_hash_lock);
 }
 
 static void recv_unicast_packet(struct ethhdr *ethhdr,
@@ -781,23 +820,26 @@
 	}
 
 	/* get routing information */
-	spin_lock(&orig_hash_lock);
-	orig_node = ((struct orig_node *)
-		     hash_find(orig_hash, unicast_packet->dest));
+	orig_node = orig_find(unicast_packet->dest);
 
-	if ((orig_node != NULL) &&
-	    (orig_node->batman_if != NULL) &&
-	    (orig_node->router != NULL)) {
-		/* decrement ttl */
-		unicast_packet->ttl--;
+	if (orig_node) {
+		spin_lock(&orig_node->lock);
 
-		/* route it */
-		send_raw_packet(packet_buff + sizeof(struct ethhdr),
-				result - sizeof(struct ethhdr),
-				orig_node->batman_if,
-				orig_node->router->addr);
+	    if ((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_node->lock);
+		orig_unreference(orig_node);
 	}
-	spin_unlock(&orig_hash_lock);
 }
 
 
@@ -833,20 +875,19 @@
 	if (is_my_mac(bcast_packet->orig))
 		return;
 
-	spin_lock(&orig_hash_lock);
-	orig_node = ((struct orig_node *)
-		     hash_find(orig_hash, bcast_packet->orig));
+	orig_node = orig_find(bcast_packet->orig);
 
-	if (orig_node == NULL) {
-		spin_unlock(&orig_hash_lock);
+	if (!orig_node)
 		return;
-	}
 
+	spin_lock(&orig_node->lock);
+
 	/* 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);
+		spin_unlock(&orig_node->lock);
+		orig_unreference(orig_node);
 		return;
 	}
 
@@ -856,7 +897,8 @@
 			   orig_node->last_bcast_seqno, 1))
 		orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno);
 
-	spin_unlock(&orig_hash_lock);
+	spin_unlock(&orig_node->lock);
+	orig_unreference(orig_node);
 
 	/* broadcast for me */
 	interface_rx(soft_device, packet_buff + hdr_size, result - hdr_size);
Index: batman-adv-kernelland/main.h
===================================================================
--- batman-adv-kernelland/main.h	(revision 1489)
+++ batman-adv-kernelland/main.h	(working copy)
@@ -124,7 +124,6 @@
 extern struct hlist_head forw_bcast_list;
 extern struct hashtable_t *orig_hash;
 
-extern spinlock_t orig_hash_lock;
 extern spinlock_t forw_bat_list_lock;
 extern spinlock_t forw_bcast_list_lock;
 
