diff -Nur olsrd-0.5.1.orig/lib/quagga/src/olsrd_plugin.c olsrd-0.5.1/lib/quagga/src/olsrd_plugin.c
--- olsrd-0.5.1.orig/lib/quagga/src/olsrd_plugin.c	2007-04-28 17:31:40.000000000 +0200
+++ olsrd-0.5.1/lib/quagga/src/olsrd_plugin.c	2007-07-13 20:43:36.000000000 +0200
@@ -34,6 +34,22 @@
 static void __attribute__ ((destructor)) my_fini(void);
 static void redist_hna (void);
 
+static olsr_route_function orig_addroute_function;
+static olsr_route_function orig_delroute_function;
+
+int hook_addroute(struct rt_entry *entry)
+{
+	int ret = zebra_add_olsr_v4_route(entry);
+	if (NULL != orig_addroute_function) return orig_addroute_function(entry);
+	return ret;
+}
+
+int hook_delroute(struct rt_entry *entry)
+{
+	int ret = zebra_del_olsr_v4_route(entry);
+	if (NULL != orig_delroute_function) return orig_delroute_function(entry);
+	return ret;
+}
 
 int olsrd_plugin_interface_version() {
   return OLSRD_PLUGIN_INTERFACE_VERSION;
@@ -55,17 +71,17 @@
   }
   else if(!strcmp(key, "ExportRoutes")) {
     if (!strcmp(value, "only")) {
-      if (!olsr_addroute_remove_function(&olsr_ioctl_add_route, AF_INET))
-	puts ("AIII, could not remove the kernel route exporter");
-      if (!olsr_delroute_remove_function(&olsr_ioctl_del_route, AF_INET))
-	puts ("AIII, could not remove the kernel route deleter");
-      olsr_addroute_add_function(&zebra_add_olsr_v4_route, AF_INET);
-      olsr_delroute_add_function(&zebra_del_olsr_v4_route, AF_INET);
+      orig_addroute_function = NULL;
+      orig_delroute_function = NULL;
+      olsr_addroute_function = zebra_add_olsr_v4_route;
+      olsr_delroute_function = zebra_del_olsr_v4_route;
       return 1;
     }
     else if (!strcmp(value, "additional")) {
-      olsr_addroute_add_function(&zebra_add_olsr_v4_route, AF_INET);
-      olsr_delroute_add_function(&zebra_del_olsr_v4_route, AF_INET);
+      orig_addroute_function = olsr_addroute_function;
+      orig_delroute_function = olsr_delroute_function;
+      olsr_addroute_function = zebra_add_olsr_v4_route;
+      olsr_delroute_function = zebra_del_olsr_v4_route;
       return 1;
     }
   }
diff -Nur olsrd-0.5.1.orig/src/lq_route.c olsrd-0.5.1/src/lq_route.c
--- olsrd-0.5.1.orig/src/lq_route.c	2007-07-06 00:43:46.000000000 +0200
+++ olsrd-0.5.1/src/lq_route.c	2007-07-13 20:43:36.000000000 +0200
@@ -589,9 +589,9 @@
    */
   olsr_spf_run_full(&cand_tree, &path_tree);
 
-  // save the old routing table
+  // Start with an empty routing table
 
-  olsr_move_route_table(routingtable, old_routes);
+  olsr_free_routing_table(routingtable);
 
   OLSR_PRINTF(2, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- DIJKSTRA\n\n",
               nowtm->tm_hour,
@@ -671,9 +671,9 @@
     }
   }
 
-  // save the old HNA routing table
+  // Start with an empty HNA routing table
 
-  olsr_move_route_table(hna_routes, old_hna);
+  olsr_free_routing_table(hna_routes);
 
   // add HNA routes
 
@@ -758,13 +758,8 @@
 
   // move the route changes into the kernel
 
-  olsr_update_kernel_routes();
-  olsr_update_kernel_hna_routes();
-
-  // free the saved routing table
-
-  olsr_free_routing_table(old_routes);
-  olsr_free_routing_table(old_hna);
+  olsr_update_routes(routingtable);
+  olsr_update_hna(hna_routes);
 }
 
 /*
diff -Nur olsrd-0.5.1.orig/src/main.c olsrd-0.5.1/src/main.c
--- olsrd-0.5.1.orig/src/main.c	2007-05-09 01:35:22.000000000 +0200
+++ olsrd-0.5.1/src/main.c	2007-07-13 20:43:36.000000000 +0200
@@ -285,9 +285,6 @@
   /* Initialize parser */
   olsr_init_parser();
 
-  /* Initialize route-exporter */
-  olsr_init_export_route();
-
   /* Initialize message sequencnumber */
   init_msg_seqno();
 
@@ -467,7 +464,7 @@
   OLSR_PRINTF(1, "Scheduler stopped.\n");
 #endif
 
-  olsr_delete_all_kernel_routes();
+  olsr_exit_routes();
 
   OLSR_PRINTF(1, "Closing sockets...\n");
 
diff -Nur olsrd-0.5.1.orig/src/olsr.c olsrd-0.5.1/src/olsr.c
--- olsrd-0.5.1.orig/src/olsr.c	2007-07-06 00:43:47.000000000 +0200
+++ olsrd-0.5.1/src/olsr.c	2007-07-13 20:43:36.000000000 +0200
@@ -283,8 +283,8 @@
   /* Initialize two hop table */
   olsr_init_two_hop_table();
 
-  /* Initialize old route table */
-  olsr_init_old_table();
+  /* Initialize the routing module */
+  olsr_init_routes();
 
   /* Initialize topology */
   olsr_init_tc();
diff -Nur olsrd-0.5.1.orig/src/process_routes.c olsrd-0.5.1/src/process_routes.c
--- olsrd-0.5.1.orig/src/process_routes.c	2007-05-14 00:24:10.000000000 +0200
+++ olsrd-0.5.1/src/process_routes.c	2007-07-13 20:43:47.000000000 +0200
@@ -1,11 +1,9 @@
 /*
  * The olsr.org Optimized Link-State Routing daemon(olsrd)
  * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
+ * Copyright (c) 2007, sven-ola for the complete rewrite
  * All rights reserved.
  *
- * export_route_entry interface added by Immo 'FaUl Wehrenberg 
- * <immo@chaostreff-dortmund.de>
- *
  * Redistribution and use in source and binary forms, with or without 
  * modification, are permitted provided that the following conditions 
  * are met:
@@ -53,571 +51,342 @@
 #define strerror(x) StrError(x)
 #endif
 
-struct export_route_entry
-{
-  olsr_u8_t type;       /* AF_INET/AF_INET6 */
-  int (*function)(struct rt_entry*);
-  struct export_route_entry *next;
-};
-
+olsr_route_function olsr_addroute_function;
+olsr_route_function olsr_addroute6_function;
+olsr_route_function olsr_delroute_function;
+olsr_route_function olsr_delroute6_function;
 
-static struct export_route_entry *add_routes;
-static struct export_route_entry *del_routes;
+static struct rt_entry current_hna[HASHSIZE];
+static struct rt_entry current_routes[HASHSIZE];
 
+#undef DEBUG
+#define DEBUG_DEFGW
 
-struct rt_entry old_routes[HASHSIZE];
-struct rt_entry old_hna[HASHSIZE];
-
-void 
-olsr_addroute_add_function(int (*function)(struct rt_entry*), olsr_u8_t type) 
-{
-  struct export_route_entry *tmp;
-  tmp = olsr_malloc(sizeof *tmp, "olsr_addroute_add_function");
-  tmp->type = type;
-  tmp->function = function;
-  tmp->next = add_routes;
-  add_routes = tmp;
-}
-
-void 
-olsr_delroute_add_function(int (*function) (struct rt_entry*), olsr_u8_t type)
-{
-  struct export_route_entry *tmp;
-  tmp = olsr_malloc(sizeof *tmp, "olsr_delroute_add_function");
-  tmp->type = type;
-  tmp->function = function;
-  tmp->next = del_routes;
-  del_routes = tmp;
-}
-
-
-int 
-olsr_addroute_remove_function(int (*function) (struct rt_entry*), olsr_u8_t type)
+/*
+ * Init this modules (resets current_routes and current_hna
+ */
+void olsr_init_routes(void)
 {
-  struct export_route_entry *tmp, *prev = NULL /* Make compiler happy */; 
-  tmp = add_routes;
-  while (tmp) 
-    {
-      if (function == tmp->function && type == tmp->type) 
-	{
-	  if (tmp == add_routes) 
-	    {
-	      add_routes = add_routes->next;
-	      free (tmp);
-	      return 1;
-	    }
-	  else 
-	    {
-	      prev->next = tmp->next;
-	      free (tmp);
-	      return 1;
-	    }
-	}
-      prev = tmp;
-      tmp = tmp->next;
-    }
-  return 0;
-}
+	int index;
 
-int
-olsr_delroute_remove_function(int (*function) (struct rt_entry*), olsr_u8_t type)
-{
-  struct export_route_entry *tmp, *prev = NULL /* Make compiler happy */;
-  tmp = del_routes;
-  while (tmp) 
-    {
-      if (function == tmp->function && type == tmp->type) 
+	for(index=0; index<HASHSIZE; index++)
 	{
-	  if (tmp == del_routes) 
-	    {
-	      del_routes = del_routes->next;
-	      free (tmp);
-	      return 1;
-	    }
-	  else 
-	    {
-	      prev->next = tmp->next;
-	      free (tmp);
-	      return 1; 
-	    }
+		current_hna[index].next = &current_hna[index];
+		current_hna[index].prev = &current_hna[index];
+		current_routes[index].next = &current_routes[index];
+		current_routes[index].prev = &current_routes[index];
 	}
-      prev = tmp;
-      tmp = tmp->next;
-    }
-  return 0;
-}
-
-void 
-olsr_init_export_route(void)
-{
-  olsr_addroute_add_function(&olsr_ioctl_add_route, AF_INET);
-  olsr_addroute_add_function(&olsr_ioctl_add_route6, AF_INET6);
-  olsr_delroute_add_function(&olsr_ioctl_del_route, AF_INET);
-  olsr_delroute_add_function(&olsr_ioctl_del_route6, AF_INET6);
-}
-
-int
-olsr_export_add_route (struct rt_entry *e) 
-{
-  int retval = 0;
-  struct export_route_entry *tmp;
-  for (tmp = add_routes; tmp; tmp = tmp->next)
-    {
-      if (tmp->type == AF_INET)
-	retval = tmp->function(e);
-    }
-  return retval;
-}
-
-int
-olsr_export_add_route6 (struct rt_entry *e) 
-{
-  int retval = 0;
-  struct export_route_entry *tmp;
-  for (tmp = add_routes; tmp; tmp = tmp->next)
-    {
-      if (tmp->type == AF_INET6)
-	retval = tmp->function(e);
-    }
-  return retval;
-}
-
-int
-olsr_export_del_route (struct rt_entry *e) 
-{
-  int retval = 0;
-  struct export_route_entry *tmp;
-  for (tmp = del_routes; tmp; tmp = tmp->next)
-    {
-      if (tmp->type == AF_INET)
-	retval = tmp->function(e);
-    }
-  return retval;
-}
-
-int
-olsr_export_del_route6 (struct rt_entry *e) 
-{
-  int retval = 0;
-  struct export_route_entry *tmp;
-  for (tmp = del_routes; tmp; tmp = tmp->next)
-    {
-      if (tmp->type == AF_INET6)
-	retval = tmp->function(e);
-    }
-  return retval;
+	olsr_addroute_function = olsr_ioctl_add_route;
+	olsr_addroute6_function = olsr_ioctl_add_route6;
+	olsr_delroute_function = olsr_ioctl_del_route;
+	olsr_delroute6_function = olsr_ioctl_del_route6;
 }
 
+#ifdef DEBUG
+#define ROUTE_ERRORLEVEL 0
+#else
+#define ROUTE_ERRORLEVEL 1
+#endif
 
+#define GET_MASK(mask) (AF_INET == olsr_cnf->ip_version ? mask.v4 : mask.v6)
 
-int
-olsr_init_old_table(void)
+static char mask_buf[16];
+static char* olsr_netmask_to_string(union hna_netmask *mask)
 {
-  int index;
-
-  for(index=0;index<HASHSIZE;index++)
-    {
-      old_routes[index].next = &old_routes[index];
-      old_routes[index].prev = &old_routes[index];
-      old_hna[index].next = &old_hna[index];
-      old_hna[index].prev = &old_hna[index];
-    }
-
-  return 1;
-}
-
-/**
- *Checks if there exists a route to a given host
- *in a given hash table.
- *
- *@param dst the host to check for
- *@param table the table to check
- *
- *@return 1 if the host exists in the table, 0 if not
- */
-int
-olsr_find_up_route(struct rt_entry *dst, struct rt_entry *table)
-{ 
-  struct rt_entry  *destination;
-  const olsr_u32_t  hash = olsr_hashing(&dst->rt_dst);
-
-  for(destination = table[hash].next; destination != &table[hash]; destination = destination->next)
-    {
-      //printf("Checking %s hc: %d ", olsr_ip_to_string(&dst->rt_dst), dst->rt_metric);
-      //printf("vs %s hc: %d ... ", olsr_ip_to_string(&destination->rt_dst), destination->rt_metric);      
-      if (COMP_IP(&destination->rt_dst, &dst->rt_dst) &&
-	  COMP_IP(&destination->rt_router, &dst->rt_router) &&
-	  (destination->rt_if->if_index == dst->rt_if->if_index))
+	if (AF_INET == olsr_cnf->ip_version)
 	{
-	  if(destination->rt_metric == dst->rt_metric)
-	    {
-	      return 1;
-	    }
-	  else
-	    {
-	      return 0;
-	    }
+		inet_ntop(AF_INET, &mask->v4, mask_buf, sizeof(mask_buf));
 	}
-    }
-  return 0;
-}
-
-
-/**
- *Create a list containing the entries in from_table
- *that do not exist in in_table
- *
- *@param from_table the table to use
- *@param in_table the routes already added
- *
- *@return a poiter to a linked list of routes to add
- */
-struct destination_n *
-olsr_build_update_list(struct rt_entry *from_table,struct rt_entry *in_table)
-{
-  struct destination_n *kernel_route_list = NULL;
-  struct rt_entry      *destination;
-  olsr_u8_t            index;
-  
-  for(index=0;index<HASHSIZE;index++)
-    {
-      for(destination = from_table[index].next;
-	  destination != &from_table[index];
-	  destination = destination->next)
+	else
 	{
-	  if (!olsr_find_up_route(destination, in_table))
-	    {
-	      struct destination_n *route_list;
-	      route_list = olsr_malloc(sizeof(struct destination_n), "create route tmp list");
-	      
-	      route_list->destination = destination;
-	      
-	      route_list->next = kernel_route_list;
-	      kernel_route_list = route_list;
-	    }
-	}   
-    }
-  
-  return (kernel_route_list);
-}
-
-
-
-
-
-/**
- *Deletes all OLSR routes
- *
- *
- *@return 1
- */
-int
-olsr_delete_all_kernel_routes(void)
-{ 
-  struct destination_n *delete_kernel_list;
-  struct destination_n *tmp;
-
-  OLSR_PRINTF(1, "Deleting all routes...\n");
-
-  delete_kernel_list = olsr_build_update_list(hna_routes, old_hna);
-
-  OLSR_PRINTF(1, "HNA list:\n");
-  for(tmp = delete_kernel_list;tmp;tmp = tmp->next)
-    {
-      union olsr_ip_addr *tmp_addr = &tmp->destination->rt_dst;
-      OLSR_PRINTF(1, "Dest: %s\n", olsr_ip_to_string(tmp_addr));
-    }
-
-  olsr_delete_routes_from_kernel(delete_kernel_list);
-
-  delete_kernel_list = olsr_build_update_list(routingtable,old_routes);
-
-  OLSR_PRINTF(1, "Route list:\n");
-  for(tmp = delete_kernel_list;tmp;tmp = tmp->next)
-    {
-      union olsr_ip_addr *tmp_addr = &tmp->destination->rt_dst;
-      OLSR_PRINTF(1, "Dest: %s\n", olsr_ip_to_string(tmp_addr));
-    }
-  olsr_delete_routes_from_kernel(delete_kernel_list);
-  return 1;
+		sprintf(mask_buf, "%d", mask->v6);
+	}
+	return mask_buf;
 }
 
-
-/**
- *Perform all neccessary actions for an update of the 
- *routes in the kernel.
- *
- *@return nada
+/*
+ * Cleans entries from old_table not available in new_table
  */
-void
-olsr_update_kernel_routes(void)
+static void olsr_clean_the_routes(struct rt_entry *old_table, const struct rt_entry *new_table)
 {
-  struct destination_n *delete_kernel_list;
-  struct destination_n *add_kernel_list;
-
-  OLSR_PRINTF(3, "Updating kernel routes...\n");
-  delete_kernel_list = olsr_build_update_list(old_routes, routingtable);
-  add_kernel_list = olsr_build_update_list(routingtable, old_routes);
-
-  olsr_delete_routes_from_kernel(delete_kernel_list);
-  olsr_add_routes_in_kernel(add_kernel_list);
+	olsr_u8_t index;
+	for(index=0; index<HASHSIZE; index++)
+	{
+		struct rt_entry *old;
+		for(old = old_table[index].next; old != &old_table[index]; old = old->next)
+		{
+			struct rt_entry *new;
+			olsr_bool del_entry = OLSR_TRUE;
+			const olsr_u32_t hash = olsr_hashing(&old->rt_dst);
+			for(new = new_table[hash].next; new != &new_table[hash]; new = new->next)
+			{
+				if(COMP_IP(&old->rt_dst, &new->rt_dst) && GET_MASK(old->rt_mask) == GET_MASK(new->rt_mask))
+				{
+					del_entry = OLSR_FALSE;
+					break;
+				}
+			} /* for new */
+			if (del_entry)
+			{
+				struct rt_entry *tmp = old;
+#ifdef DEBUG
+#ifdef DEBUG_DEFGW
+				if (0 == GET_MASK(old->rt_mask))
+#endif
+				OLSR_PRINTF(0, "Deleting route to %s/%s via %s dev %s hops %d etx %f\n",
+					olsr_ip_to_string(&old->rt_dst),
+					olsr_netmask_to_string(&old->rt_mask),
+					olsr_ip_to_string(&old->rt_router),
+					old->rt_if->int_name,
+					old->rt_metric,
+					old->rt_etx);
+#endif
+				if(!olsr_cnf->host_emul)
+				{
+					if(0 > (AF_INET == olsr_cnf->ip_version ?
+						olsr_delroute_function(old) :
+						olsr_delroute6_function(old)))
+					{
+						const char * const err_msg = strerror(errno);
+						OLSR_PRINTF(ROUTE_ERRORLEVEL, "Del route to %s/%s via %s dev %s hops %d: %s\n",
+							olsr_ip_to_string(&old->rt_dst),
+							olsr_netmask_to_string(&old->rt_mask),
+							olsr_ip_to_string(&old->rt_router),
+							old->rt_if->int_name,
+							old->rt_metric,
+							err_msg);
+						olsr_syslog(OLSR_LOG_ERR, "Del route to %s/%s via %s dev %s hops %d: %s\n",
+							olsr_ip_to_string(&old->rt_dst),
+							olsr_netmask_to_string(&old->rt_mask),
+							olsr_ip_to_string(&old->rt_router),
+							old->rt_if->int_name,
+							old->rt_metric,
+							err_msg);
+					}
+				}
+				old = old->prev;
+				DEQUEUE_ELEM(tmp);
+				free(tmp);
+			}
+		} /* for old */
+	}
 }
 
-
-
-/**
- *Perform all neccessary actions for an update of the 
- *HNA routes in the kernel.
- *
- *@return nada
- */
-void
-olsr_update_kernel_hna_routes(void)
+static int add_rt(struct rt_entry *new, olsr_bool preadd)
 {
-  struct destination_n *delete_kernel_list;
-  struct destination_n *add_kernel_list;
-
-  OLSR_PRINTF(3, "Updating kernel HNA routes...\n");
-
-  delete_kernel_list = olsr_build_update_list(old_hna, hna_routes);
-  add_kernel_list = olsr_build_update_list(hna_routes, old_hna);
-
-  olsr_delete_routes_from_kernel(delete_kernel_list);
-  olsr_add_routes_in_kernel(add_kernel_list);
+	int ret = 0;
+#ifdef DEBUG
+#ifdef DEBUG_DEFGW
+	if (0 == GET_MASK(new->rt_mask))
+#endif
+	OLSR_PRINTF(0, "%sAdd route to %s/%s via %s dev %s hops %d etx %f\n",
+		(preadd ? "Pre-" : ""),
+		olsr_ip_to_string(&new->rt_dst),
+		olsr_netmask_to_string(&new->rt_mask),
+		olsr_ip_to_string(&new->rt_router),
+		new->rt_if->int_name,
+		new->rt_metric,
+		new->rt_etx);
+#endif
+	if(!olsr_cnf->host_emul)
+	{
+		if(0 > (ret = (olsr_cnf->ip_version == AF_INET ?
+			olsr_addroute_function(new) :
+			olsr_addroute6_function(new))))
+		{
+			const char* err_msg;
+#ifndef DEBUG
+			if (preadd) return ret;
+#endif			
+			err_msg = strerror(errno);
+			OLSR_PRINTF(ROUTE_ERRORLEVEL, "Add route to %s/%s via %s dev %s hops %d: %s\n",
+				olsr_ip_to_string(&new->rt_dst),
+				olsr_netmask_to_string(&new->rt_mask),
+				olsr_ip_to_string(&new->rt_router),
+				new->rt_if->int_name,
+				new->rt_metric,
+				err_msg);
+			olsr_syslog(OLSR_LOG_ERR, "Add route to %s/%s via %s dev %s hops %d: %s\n",
+				olsr_ip_to_string(&new->rt_dst),
+				olsr_netmask_to_string(&new->rt_mask),
+				olsr_ip_to_string(&new->rt_router),
+				new->rt_if->int_name,
+				new->rt_metric,
+				err_msg);
+		}
+	}
+	return ret;
 }
 
-
-/**
- *Create a copy of the routing table and
- *clear the current table
- *
- *@param original the table to move from
- *@param the table to move to
- *
- *@return nada
- */
-void
-olsr_move_route_table(struct rt_entry *original, struct rt_entry *new)
+static int del_rt(struct rt_entry *old)
 {
-  olsr_16_t index;
-
-  for(index=0;index<HASHSIZE;index++)
-    {
-      if(original[index].next == &original[index])
-	{
-	  new[index].next = &new[index];
-	  new[index].prev = &new[index];
-	}
-      else
+	int ret = 0;
+#ifdef DEBUG
+#ifdef DEBUG_DEFGW
+	if (0 == GET_MASK(old->rt_mask))
+#endif
+	OLSR_PRINTF(0, "Del route to %s via %s/%s dev %s hops %d etx %f\n",
+		olsr_ip_to_string(&old->rt_dst),
+		olsr_netmask_to_string(&old->rt_mask),
+		olsr_ip_to_string(&old->rt_router),
+		old->rt_if->int_name,
+		old->rt_metric,
+		old->rt_etx);
+#endif
+	if(!olsr_cnf->host_emul)
 	{
-	  /* Copy to old */
-	  new[index].next = original[index].next;
-	  new[index].next->prev = &new[index];
-	  new[index].prev = original[index].prev;
-	  new[index].prev->next = &new[index];
-
-	  /* Clear original */
-	  original[index].next = &original[index];
-	  original[index].prev = &original[index];
+		if(0 > (ret = (AF_INET == olsr_cnf->ip_version ?
+			olsr_delroute_function(old) :
+			olsr_delroute6_function(old))))
+		{
+			const char * const err_msg = strerror(errno);
+			OLSR_PRINTF(ROUTE_ERRORLEVEL, "Del route to %s/%s via %s dev %s hops %d: %s\n",
+				olsr_ip_to_string(&old->rt_dst),
+				olsr_netmask_to_string(&old->rt_mask),
+				olsr_ip_to_string(&old->rt_router),
+				old->rt_if->int_name,
+				old->rt_metric,
+				err_msg);
+			olsr_syslog(OLSR_LOG_ERR, "Del route to %s/%s via %s dev %s hops %d: %s\n",
+				olsr_ip_to_string(&old->rt_dst),
+				olsr_netmask_to_string(&old->rt_mask),
+				olsr_ip_to_string(&old->rt_router),
+				old->rt_if->int_name,
+				old->rt_metric,
+				err_msg);
+			}
 	}
-    }
+	return ret;
 }
 
-
-/**
- *Delete a linked list of routes from the kernel.
- *
- *@param delete_kernel_list the list to delete
- *
- *@return nada
+/*
+ * Updates the kernel routing (either hna or standard table)
+ * Moves entries from new_table to old_table to reflect kernel status
  */
-void 
-olsr_delete_routes_from_kernel(struct destination_n *delete_kernel_list)
+static void olsr_update_the_routes(struct rt_entry *old_table, const struct rt_entry *new_table)
 {
-  struct destination_n *destination_ptr;
-  int metric_counter = 1;
-  olsr_bool last_run = OLSR_FALSE;
-
-
-  /* Find highest metric */
-  for(destination_ptr = delete_kernel_list;
-      destination_ptr != NULL;
-      destination_ptr = destination_ptr->next)
-    {
-      if(destination_ptr->destination->rt_metric > metric_counter)
-	metric_counter = destination_ptr->destination->rt_metric;
-    }
-
-#ifdef DEBUG
-  OLSR_PRINTF(3, "%s highest metric %d\n",
-	      __func__, metric_counter);
-#endif
- 
-  while(delete_kernel_list!=NULL)
-    {
-      struct destination_n *previous_node = delete_kernel_list;
-
-      assert(metric_counter);
-
-      /* searching for all the items with metric equal to n */
-      for(destination_ptr = delete_kernel_list; destination_ptr != NULL; )
+	olsr_u8_t index;
+	for(index=0; index<HASHSIZE; index++)
 	{
-
-	  if(destination_ptr->destination->rt_metric == metric_counter)
-	    {
-	      /* Make sure one-hop direct neighbors are deleted last */
-	      if(metric_counter == 1 &&
-		 (!last_run && 
-		  COMP_IP(&destination_ptr->destination->rt_dst, 
-			  &destination_ptr->destination->rt_router)))
-		{
-		  previous_node = destination_ptr;
-		  destination_ptr = destination_ptr->next;
-		}
-	      else
+		struct rt_entry *new;
+		for(new = new_table[index].next; new != &new_table[index]; new = new->next)
 		{
-		  olsr_16_t error;		  
+			struct rt_entry *old, *tmp;
+			olsr_bool add_entry = OLSR_TRUE;
+			const olsr_u32_t hash = olsr_hashing(&new->rt_dst);
+			for(old = old_table[hash].next; old != &old_table[hash]; old = old->next)
+			{
+				if(COMP_IP(&old->rt_dst, &new->rt_dst) && GET_MASK(old->rt_mask) == GET_MASK(new->rt_mask))
+				{
 #ifdef DEBUG
-		  OLSR_PRINTF(3, "Deleting route to %s hopcount %d\n",
-			      olsr_ip_to_string(&destination_ptr->destination->rt_dst),
-			      destination_ptr->destination->rt_metric);
-#endif
-		    if(!olsr_cnf->host_emul)
-		      {
-			if(olsr_cnf->ip_version == AF_INET)
-			  error = olsr_export_del_route(destination_ptr->destination);
-			else
-			  error = olsr_export_del_route6(destination_ptr->destination);
+#ifdef DEBUG_DEFGW
+					if (0 == GET_MASK(old->rt_mask))
+#endif
+					OLSR_PRINTF(0, "Compare route to %s/%s via %s dev %s hops %d etx %f\n",
+						olsr_ip_to_string(&new->rt_dst),
+						olsr_netmask_to_string(&new->rt_mask),
+						olsr_ip_to_string(&new->rt_router),
+						new->rt_if->int_name,
+						new->rt_metric,
+						new->rt_etx);
+#endif
+					if(!COMP_IP(&old->rt_router, &new->rt_router) ||
+					   GET_MASK(old->rt_mask) != GET_MASK(new->rt_mask) ||
+					   old->rt_if->if_index != new->rt_if->if_index ||
+					   old->rt_metric != new->rt_metric)
+					{
+						/*
+						 * Special for the default route. Because NAT ist often
+						 * used, switching the gateway leads to aborted connections.
+						 * We are a bit sticky here now. Sven-Ola
+						 */
+						if (0 == GET_MASK(new->rt_mask))
+						{
+							if (new->rt_etx / old->rt_etx > 0.95 &&
+							    new->rt_etx / old->rt_etx < 1.05)
+							{
+#ifdef DEBUG
+								OLSR_PRINTF(0, "Not switching default gw, diff only %f\n", new->rt_etx / old->rt_etx);
+#endif
+								add_entry = OLSR_FALSE;
+								break;
+							}
+						}
+						/* 
+						 * ioctl offers no change route CMD. We try to
+						 * add the new route before deleting the old one.
+						 * Does not work for switching ifaces.
+						 */
+						if (old->rt_metric != new->rt_metric &&
+						    0 <= add_rt(new, OLSR_TRUE))
+						{
+							tmp = new;
+							new = new->prev;
+							DEQUEUE_ELEM(tmp);
+							QUEUE_ELEM(old_table[hash], tmp);
+							add_entry = OLSR_FALSE;
+						}
+						tmp = old;
+						del_rt(old);
+						old = old->prev;
+						DEQUEUE_ELEM(tmp);
+						free(tmp);
+					}
+					else
+					{
+						/* Entry already exists: update etx only */
+						old->rt_etx = new->rt_etx;
+						add_entry = OLSR_FALSE;
+					}
+					break;
+				}
+			} /* for old */
 			
-			if(error < 0)
-			  {
-                            const char * const err_msg = strerror(errno);
-			    OLSR_PRINTF(1, "Delete route(%s):%s\n", olsr_ip_to_string(&destination_ptr->destination->rt_dst), err_msg);
-                            olsr_syslog(OLSR_LOG_ERR, "Delete route:%s", err_msg);
-			  }
-		    }
-		  
-		  /* Getting rid of this node and hooking up the broken point */
-		  if(destination_ptr == delete_kernel_list) 
-		    {
-		      destination_ptr = delete_kernel_list->next;
-		      free(delete_kernel_list);
-		      delete_kernel_list = destination_ptr;
-		      previous_node = delete_kernel_list;
-		    }
-		  else 
-		    {
-		      previous_node->next = destination_ptr->next;
-		      free(destination_ptr);
-		      destination_ptr = previous_node->next;
-		    }
-		}
-	    }
-	  else 
-	    {
-	      previous_node = destination_ptr;
-	      destination_ptr = destination_ptr->next;
-	    }
-		
+			if (add_entry)
+			{
+				add_rt(new, OLSR_FALSE);
+				/* Move the routing entry from new to old */
+				tmp = new;
+				new = new->prev;
+				DEQUEUE_ELEM(tmp);
+				QUEUE_ELEM(old_table[hash], tmp);
+			}
+		} /* for new */
 	}
-      if((metric_counter == 1) && !last_run)
-        {
-	  last_run = OLSR_TRUE;
-        }
-      else
-        {
-	  metric_counter--;
-        }
-    }
+}
  
+/*
+ * Updates the kernel hna routing table with a new hna table
+ */
+void olsr_update_hna(const struct rt_entry *new_hna)
+{
+	olsr_clean_the_routes(current_hna, new_hna);
+	olsr_update_the_routes(current_hna, new_hna);
 }
 
-/**
- *Add a list of routes to the kernel. Adding
- *is done by hopcount to be sure a route
- *to the nexthop is added.
- *
- *@param add_kernel_list the linked list of routes to add
- *
- *@return nada
+/* 
+ * Updates the kernel routing table with a new table
  */
-void 
-olsr_add_routes_in_kernel(struct destination_n *add_kernel_list)
+void olsr_update_routes(const struct rt_entry *new_routes)
 {
-  int metric_counter = 1;
-  olsr_bool first_run = OLSR_TRUE;
-  
-  while(add_kernel_list != NULL)
-    {
-      struct destination_n *destination_kernel = NULL;
-      struct destination_n *previous_node = add_kernel_list;
+	olsr_clean_the_routes(current_routes, new_routes);
+	olsr_update_the_routes(current_routes, new_routes);
+}
 
-      /* searching for all the items with metric equal to n */
-      for(destination_kernel = add_kernel_list; destination_kernel != NULL; )
-	{
-	  if((destination_kernel->destination->rt_metric == metric_counter) &&
-	     (!first_run || 
-              COMP_IP(&destination_kernel->destination->rt_dst,
-                      &destination_kernel->destination->rt_router)))
-	    {
-	      olsr_16_t error;
-	      /* First add all 1-hop routes that has themselves as GW */
+/* 
+ * Exits from this modules (removes all routes from kernel)
+ */
+void olsr_exit_routes(void)
+{
+	int index;
+	struct rt_entry null_table[HASHSIZE];
 
-#ifdef DEBUG
-	      OLSR_PRINTF(3, "Adding route to %s hopcount %d\n",
-			  olsr_ip_to_string(&destination_kernel->destination->rt_dst),
-			  destination_kernel->destination->rt_metric);
-#endif
-			  
-		if(!olsr_cnf->host_emul)
-		  {
-		    if(olsr_cnf->ip_version == AF_INET)
-		      error=olsr_export_add_route(destination_kernel->destination);
-		    else
-		      error=olsr_export_add_route6(destination_kernel->destination);
-		    
-		    if(error < 0)
-		      {
-                        const char * const err_msg = strerror(errno);
-			OLSR_PRINTF(1, "Add route(%s): %s\n", olsr_ip_to_string(&destination_kernel->destination->rt_dst), err_msg);
-                        olsr_syslog(OLSR_LOG_ERR, "Add route:%s", err_msg);
-		      }
-		  }
-
-	      
-	      /* Getting rid of this node and hooking up the broken point */
-	      if(destination_kernel == add_kernel_list) 
-		{
-		  destination_kernel = add_kernel_list->next;
-		  free(add_kernel_list);
-		  add_kernel_list = destination_kernel;
-		  previous_node=add_kernel_list;
-		}
-	      else 
-		{
-		  previous_node->next = destination_kernel->next;
-		  free(destination_kernel);
-		  destination_kernel = previous_node->next;
-		}
-	    }
-	  else 
-	    {
-	      previous_node = destination_kernel;
-	      destination_kernel = destination_kernel->next;
-	    }
-		
+	for(index=0; index<HASHSIZE; index++)
+	{
+		null_table[index].next = &null_table[index];
+		null_table[index].prev = &null_table[index];
 	}
-      if(first_run)
-        {
-	  first_run = OLSR_FALSE;
-        }
-      else
-        {
-	  metric_counter++;
-        }
-    }
 	
+	olsr_clean_the_routes(current_routes, null_table);
+	olsr_clean_the_routes(current_hna, null_table);
 }
-
-
-
diff -Nur olsrd-0.5.1.orig/src/process_routes.h olsrd-0.5.1/src/process_routes.h
--- olsrd-0.5.1.orig/src/process_routes.h	2007-04-28 17:31:43.000000000 +0200
+++ olsrd-0.5.1/src/process_routes.h	2007-07-13 20:43:36.000000000 +0200
@@ -1,6 +1,7 @@
 /*
  * The olsr.org Optimized Link-State Routing daemon(olsrd)
  * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
+ * Copyright (c) 2007, sven-ola for the complete rewrite
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without 
@@ -47,62 +48,16 @@
 
 #include <sys/ioctl.h>
 
-extern struct rt_entry old_routes[HASHSIZE];
-extern struct rt_entry old_hna[HASHSIZE];
+typedef int (*olsr_route_function)(struct rt_entry*);
 
-void
-olsr_init_export_route(void);
-
-void
-olsr_addroute_add_function(int (*)(struct rt_entry*), olsr_u8_t);
-
-int
-olsr_addroute_remove_function(int (*)(struct rt_entry*), olsr_u8_t);
-
-void
-olsr_delroute_add_function(int (*)(struct rt_entry*), olsr_u8_t);
-
-int
-olsr_delroute_remove_function(int (*)(struct rt_entry*), olsr_u8_t);
-
-int
-olsr_export_add_route (struct rt_entry*); 
-
-int
-olsr_export_del_route (struct rt_entry*); 
-
-int
-olsr_export_add_route6 (struct rt_entry*); 
-
-int
-olsr_export_del_route6 (struct rt_entry*); 
-
-
-int
-olsr_init_old_table(void);
-
-int
-olsr_find_up_route(struct rt_entry *dst,struct rt_entry *table);
-
-struct destination_n *
-olsr_build_update_list(struct rt_entry *from_table, struct rt_entry *in_table);
-
-void
-olsr_update_kernel_routes(void);
-
-void
-olsr_update_kernel_hna_routes(void);
-
-void
-olsr_move_route_table(struct rt_entry *, struct rt_entry *);
-
-void
-olsr_delete_routes_from_kernel(struct destination_n *delete_kernel_list);
-
-void
-olsr_add_routes_in_kernel(struct destination_n *add_kernel_list);
-
-int
-olsr_delete_all_kernel_routes(void);
+extern olsr_route_function olsr_addroute_function;
+extern olsr_route_function olsr_addroute6_function;
+extern olsr_route_function olsr_delroute_function;
+extern olsr_route_function olsr_delroute6_function;
+
+void olsr_init_routes(void);
+void olsr_update_hna(const struct rt_entry *new_hna);
+void olsr_update_routes(const struct rt_entry *new_routes);
+void olsr_exit_routes(void);
 
 #endif
diff -Nur olsrd-0.5.1.orig/src/routing_table.c olsrd-0.5.1/src/routing_table.c
--- olsrd-0.5.1.orig/src/routing_table.c	2007-04-28 17:31:43.000000000 +0200
+++ olsrd-0.5.1/src/routing_table.c	2007-07-13 20:43:36.000000000 +0200
@@ -430,7 +430,7 @@
 {
   struct destination_n *list_destination_n_1;
 
-  olsr_move_route_table(routingtable, old_routes);
+  olsr_free_routing_table(routingtable);
 
   /* Add neighbors */
   olsr_fill_routing_table_with_neighbors();
@@ -522,16 +522,12 @@
       printf("************** TABLES ****************\n");
       printf("Routing table:\n");
       olsr_print_routing_table(routingtable);
-      printf("Old table:\n");
-      olsr_print_routing_table(old_routes);
       printf("**************************************\n");
     }
 
   
   /* Update routes */
-  olsr_update_kernel_routes();
-
-  olsr_free_routing_table(old_routes);
+  olsr_update_routes(routingtable);
 }
 
 
@@ -633,7 +629,7 @@
   OLSR_PRINTF(3, "Calculating HNA routes\n");
 #endif
 
-  olsr_move_route_table(hna_routes, old_hna);
+  olsr_free_routing_table(hna_routes);
 
   for(index=0;index<HASHSIZE;index++)
     {
@@ -712,15 +708,13 @@
     }
 
   /* Update kernel */
-  olsr_update_kernel_hna_routes();
+  olsr_update_hna(hna_routes);
 
   if(olsr_cnf->debug_level > 2)
     {
       OLSR_PRINTF(3, "HNA table:\n");
       olsr_print_routing_table(hna_routes);
     }
-
-  olsr_free_routing_table(old_hna);
 }
 
 
