Add rp_filter handling for linux 2.6.31+
[olsrd.git] / src / hna_set.c
index f035411..a4a44b8 100644 (file)
 
 /*
- * OLSR ad-hoc routing table management protocol
- * Copyright (C) 2003 Andreas T√łnnesen (andreto@ifi.uio.no)
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
+ * All rights reserved.
  *
- * This file is part of the olsr.org OLSR daemon.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
  *
- * olsr.org is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
  *
- * olsr.org is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  *
- * You should have received a copy of the GNU General Public License
- * along with olsr.org; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
- * 
- * $Id: hna_set.c,v 1.7 2004/11/03 09:22:59 kattemat Exp $
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
  *
  */
 
+#include "ipcalc.h"
 #include "defs.h"
 #include "olsr.h"
 #include "scheduler.h"
+#include "net_olsr.h"
+#include "tc_set.h"
+#include "parser.h"
+#include "gateway.h"
+#include "duplicate_handler.h"
+
+struct hna_entry hna_set[HASHSIZE];
+struct olsr_cookie_info *hna_net_timer_cookie = NULL;
+struct olsr_cookie_info *hna_entry_mem_cookie = NULL;
+struct olsr_cookie_info *hna_net_mem_cookie = NULL;
 
+static bool olsr_delete_hna_net_entry(struct hna_net *net_to_delete);
 
 /**
- *Initialize the HNA set
+ * Initialize the HNA set
  */
 int
-olsr_init_hna_set()
+olsr_init_hna_set(void)
 {
+  int idx;
 
-  int index;
+  for (idx = 0; idx < HASHSIZE; idx++) {
+    hna_set[idx].next = &hna_set[idx];
+    hna_set[idx].prev = &hna_set[idx];
+  }
 
-  if(olsr_cnf->ip_version == AF_INET)
-    {
-      netmask_size = sizeof(olsr_u32_t);
-    }
-  else
-    {
-      netmask_size = sizeof(olsr_u16_t);
-    }
+  hna_net_timer_cookie = olsr_alloc_cookie("HNA Network", OLSR_COOKIE_TYPE_TIMER);
 
-  /* Since the holdingtime is assumed to be rather large for 
-   * HNA entries, the timeoutfunction is only ran once every second
-   */
-  olsr_register_scheduler_event(&olsr_time_out_hna_set, NULL, 1, 0, NULL);
+  hna_net_mem_cookie = olsr_alloc_cookie("hna_net", OLSR_COOKIE_TYPE_MEMORY);
+  olsr_cookie_set_memory_size(hna_net_mem_cookie, sizeof(struct hna_net));
 
-  for(index=0;index<HASHSIZE;index++)
-    {
-      hna_set[index].next = &hna_set[index];
-      hna_set[index].prev = &hna_set[index];
-    }
+  hna_entry_mem_cookie = olsr_alloc_cookie("hna_entry", OLSR_COOKIE_TYPE_MEMORY);
+  olsr_cookie_set_memory_size(hna_entry_mem_cookie, sizeof(struct hna_entry));
 
   return 1;
 }
 
+void
+olsr_cleanup_hna(union olsr_ip_addr *orig) {
+  struct hna_entry *hna;
 
-
+  OLSR_FOR_ALL_HNA_ENTRIES(hna) {
+    if (hna->networks.next != &hna->networks && ipequal(&hna->A_gateway_addr, orig)) {
+      while (!olsr_delete_hna_net_entry(hna->networks.next));
+    }
+  } OLSR_FOR_ALL_HNA_ENTRIES_END(hna)
+}
 
 /**
- *Lookup a network entry in a networkentry list
+ * Lookup a network entry in a networkentry list.
  *
- *@param nets the network list to look in
- *@param net the network to look for
- *@param mask the netmask to look for
+ * @param nets the network list to look in
+ * @param net the network to look for
+ * @param mask the netmask to look for
  *
- *@return the localted entry or NULL of not found
+ * @return the localized entry or NULL of not found
  */
 struct hna_net *
-olsr_lookup_hna_net(struct hna_net *nets, union olsr_ip_addr *net, union hna_netmask *mask)
+olsr_lookup_hna_net(const struct hna_net *nets, const union olsr_ip_addr *net, uint8_t prefixlen)
 {
-  struct hna_net *tmp_net;
-
+  struct hna_net *tmp;
 
   /* Loop trough entrys */
-  for(tmp_net = nets->next;
-      tmp_net != nets;
-      tmp_net = tmp_net->next)
-    { 
-      if(COMP_IP(&tmp_net->A_network_addr, net) &&
-        (memcmp(&tmp_net->A_netmask, mask, netmask_size) == 0))
-       return tmp_net;
+  for (tmp = nets->next; tmp != nets; tmp = tmp->next) {
+    if (tmp->hna_prefix.prefix_len == prefixlen && ipequal(&tmp->hna_prefix.prefix, net)) {
+      return tmp;
     }
-  
+  }
+
   /* Not found */
   return NULL;
 }
 
-
-
-
 /**
- *Lookup a gateway entry
+ * Lookup a gateway entry
  *
- *@param gw the address of the gateway
- *
- *@return the located entry or NULL if not found
+ * @param gw the address of the gateway
+ * @return the located entry or NULL if not found
  */
 struct hna_entry *
-olsr_lookup_hna_gw(union olsr_ip_addr *gw)
+olsr_lookup_hna_gw(const union olsr_ip_addr *gw)
 {
   struct hna_entry *tmp_hna;
-  olsr_u32_t hash;
-
-  //olsr_printf(5, "TC: lookup entry\n");
+  uint32_t hash = olsr_ip_hashing(gw);
 
-  hash = olsr_hashing(gw);
-  
+#if 0
+  OLSR_PRINTF(5, "HNA: lookup entry\n");
+#endif
   /* Check for registered entry */
-  for(tmp_hna = hna_set[hash].next;
-      tmp_hna != &hna_set[hash];
-      tmp_hna = tmp_hna->next)
-    {
-      if(COMP_IP(&tmp_hna->A_gateway_addr, gw))
-       return tmp_hna;
+
+  for (tmp_hna = hna_set[hash].next; tmp_hna != &hna_set[hash]; tmp_hna = tmp_hna->next) {
+    if (ipequal(&tmp_hna->A_gateway_addr, gw)) {
+      return tmp_hna;
     }
-  
+  }
+
   /* Not found */
   return NULL;
 }
 
-
-
 /**
  *Add a gatewayentry to the HNA set
  *
@@ -136,56 +151,53 @@ olsr_lookup_hna_gw(union olsr_ip_addr *gw)
  *@return the created entry
  */
 struct hna_entry *
-olsr_add_hna_entry(union olsr_ip_addr *addr)
+olsr_add_hna_entry(const union olsr_ip_addr *addr)
 {
   struct hna_entry *new_entry;
-  olsr_u32_t hash;
+  uint32_t hash;
 
-  new_entry = olsr_malloc(sizeof(struct hna_entry), "New HNA entry");
+  new_entry = olsr_cookie_malloc(hna_entry_mem_cookie);
 
   /* Fill struct */
-  COPY_IP(&new_entry->A_gateway_addr, addr);
+  new_entry->A_gateway_addr = *addr;
 
   /* Link nets */
   new_entry->networks.next = &new_entry->networks;
   new_entry->networks.prev = &new_entry->networks;
 
   /* queue */
-  hash = olsr_hashing(addr);
-  
+  hash = olsr_ip_hashing(addr);
+
   hna_set[hash].next->prev = new_entry;
   new_entry->next = hna_set[hash].next;
   hna_set[hash].next = new_entry;
   new_entry->prev = &hna_set[hash];
 
   return new_entry;
-
 }
 
-
-
 /**
- *Adds a ntework entry to a HNA gateway
+ * Adds a network entry to a HNA gateway.
  *
- *@param hna_gw the gateway entry to add the
- *network to
- *@param net the networkaddress to add
- *@param mask the netmask
+ * @param hna_gw the gateway entry to add the network to
+ * @param net the networkaddress to add
+ * @param mask the netmask
  *
- *@return the newly created entry
+ * @return the newly created entry
  */
 struct hna_net *
-olsr_add_hna_net(struct hna_entry *hna_gw, union olsr_ip_addr *net, union hna_netmask *mask)
+olsr_add_hna_net(struct hna_entry *hna_gw, const union olsr_ip_addr *net, uint8_t prefixlen)
 {
-  struct hna_net *new_net;
-
-
   /* Add the net */
-  new_net = olsr_malloc(sizeof(struct hna_net), "Add HNA net");
-  
+  struct hna_net *new_net = olsr_cookie_malloc(hna_net_mem_cookie);
+
   /* Fill struct */
-  COPY_IP(&new_net->A_network_addr, net);
-  memcpy(&new_net->A_netmask, mask, netmask_size);
+  memset(new_net, 0, sizeof(struct hna_net));
+  new_net->hna_prefix.prefix = *net;
+  new_net->hna_prefix.prefix_len= prefixlen;
+
+  /* Set backpointer */
+  new_net->hna_gw = hna_gw;
 
   /* Queue */
   hna_gw->networks.next->prev = new_net;
@@ -196,13 +208,63 @@ olsr_add_hna_net(struct hna_entry *hna_gw, union olsr_ip_addr *net, union hna_ne
   return new_net;
 }
 
+static bool
+olsr_delete_hna_net_entry(struct hna_net *net_to_delete) {
+#ifdef DEBUG
+  struct ipaddr_str buf1, buf2;
+#endif
+  struct hna_entry *hna_gw;
+  bool removed_entry = false;
+
+#ifndef WIN32
+  if (is_prefix_inetgw(&net_to_delete->hna_prefix)) {
+    /* modify smart gateway entry if necessary */
+    olsr_delete_gateway_entry(&net_to_delete->hna_gw->A_gateway_addr, net_to_delete->hna_prefix.prefix_len);
+  }
+#endif
+
+  olsr_stop_timer(net_to_delete->hna_net_timer);
+  net_to_delete->hna_net_timer = NULL;  /* be pedandic */
+  hna_gw = net_to_delete->hna_gw;
+
+#ifdef DEBUG
+  OLSR_PRINTF(5, "HNA: timeout %s via hna-gw %s\n",
+      olsr_ip_prefix_to_string(&net_to_delete->hna_prefix),
+              olsr_ip_to_string(&buf2, &hna_gw->A_gateway_addr));
+#endif
+
+  /*
+   * Delete the rt_path for the entry.
+   */
+  olsr_delete_routing_table(&net_to_delete->hna_prefix.prefix,
+      net_to_delete->hna_prefix.prefix_len, &hna_gw->A_gateway_addr);
+
+  DEQUEUE_ELEM(net_to_delete);
 
+  /* Delete hna_gw if empty */
+  if (hna_gw->networks.next == &hna_gw->networks) {
+    DEQUEUE_ELEM(hna_gw);
+    olsr_cookie_free(hna_entry_mem_cookie, hna_gw);
+    removed_entry = true;
+  }
 
+  olsr_cookie_free(hna_net_mem_cookie, net_to_delete);
+  return removed_entry;
+}
+
+/**
+ * Callback for the hna_net timer.
+ */
+static void
+olsr_expire_hna_net_entry(void *context)
+{
+  olsr_delete_hna_net_entry(context);
+}
 
 /**
  * Update a HNA entry. If it does not exist it
  * is created.
- * This is the only function that should be called 
+ * This is the only function that should be called
  * from outside concerning creation of HNA entries.
  *
  *@param gw address of the gateway
@@ -213,125 +275,221 @@ olsr_add_hna_net(struct hna_entry *hna_gw, union olsr_ip_addr *net, union hna_ne
  *@return nada
  */
 void
-olsr_update_hna_entry(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask, float vtime)
+olsr_update_hna_entry(const union olsr_ip_addr *gw, const union olsr_ip_addr *net, uint8_t prefixlen, olsr_reltime vtime)
 {
   struct hna_entry *gw_entry;
   struct hna_net *net_entry;
 
-  if((gw_entry = olsr_lookup_hna_gw(gw)) == NULL)
+  gw_entry = olsr_lookup_hna_gw(gw);
+  if (!gw_entry) {
+
     /* Need to add the entry */
     gw_entry = olsr_add_hna_entry(gw);
-  
-  if((net_entry = olsr_lookup_hna_net(&gw_entry->networks, net, mask)) == NULL)
-    {
-      /* Need to add the net */
-      net_entry = olsr_add_hna_net(gw_entry, net, mask);
-      changes_hna = TRUE;
-    }
-
-  /* Update holdingtime */
-  olsr_get_timestamp((olsr_u32_t) vtime*1000, &net_entry->A_time);
-
-}
-
+  }
 
+  net_entry = olsr_lookup_hna_net(&gw_entry->networks, net, prefixlen);
+  if (net_entry == NULL) {
 
+    /* Need to add the net */
+    net_entry = olsr_add_hna_net(gw_entry, net, prefixlen);
+    changes_hna = true;
+  }
 
+  /*
+   * Add the rt_path for the entry.
+   */
+  olsr_insert_routing_table(&net_entry->hna_prefix.prefix,
+      net_entry->hna_prefix.prefix_len, &gw_entry->A_gateway_addr, OLSR_RT_ORIGIN_HNA);
 
+  /*
+   * Start, or refresh the timer, whatever is appropriate.
+   */
+  olsr_set_timer(&net_entry->hna_net_timer, vtime, OLSR_HNA_NET_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_hna_net_entry, net_entry,
+                 hna_net_timer_cookie);
+}
 
 /**
- *Function that times out all entrys in the hna set and
- *deletes the timed out ones.
+ * Print all HNA entries.
  *
  *@return nada
  */
 void
-olsr_time_out_hna_set(void *foo)
+olsr_print_hna_set(void)
 {
-  int index;
-  struct hna_entry *tmp_hna, *hna_to_delete;
-  struct hna_net *tmp_net, *net_to_delete;
-
-  for(index=0;index<HASHSIZE;index++)
-    {
-      tmp_hna = hna_set[index].next;
-      /* Check all entrys */
-      while(tmp_hna != &hna_set[index])
-       {
-         /* Check all networks */
-         tmp_net = tmp_hna->networks.next;
-
-         while(tmp_net != &tmp_hna->networks)
-           {
-             if(TIMED_OUT(&tmp_net->A_time))
-               {
-                 net_to_delete = tmp_net;
-                 tmp_net = tmp_net->next;
-                 delete_hna_net(net_to_delete);
-                 changes_hna = TRUE;
-               }
-             else
-               tmp_net = tmp_net->next;
-           }
-
-         /* Delete gw entry if empty */
-         if(tmp_hna->networks.next == &tmp_hna->networks)
-           {
-             hna_to_delete = tmp_hna;
-             tmp_hna = tmp_hna->next;
-             delete_hna_entry(hna_to_delete);
-           }
-         else
-           tmp_hna = tmp_hna->next;
-       }
-    }
-
-}
-
-
-
+#ifdef NODEBUG
+  /* The whole function doesn't do anything else. */
+  int idx;
 
+  OLSR_PRINTF(1, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- HNA SET\n\n", nowtm->tm_hour,
+              nowtm->tm_min, nowtm->tm_sec, (int)now.tv_usec / 10000);
 
+  if (olsr_cnf->ip_version == AF_INET)
+    OLSR_PRINTF(1, "IP net          netmask         GW IP\n");
+  else
+    OLSR_PRINTF(1, "IP net/prefixlen               GW IP\n");
+
+  for (idx = 0; idx < HASHSIZE; idx++) {
+    struct hna_entry *tmp_hna = hna_set[idx].next;
+    /* Check all entrys */
+    while (tmp_hna != &hna_set[idx]) {
+      /* Check all networks */
+      struct hna_net *tmp_net = tmp_hna->networks.next;
+
+      while (tmp_net != &tmp_hna->networks) {
+        if (olsr_cnf->ip_version == AF_INET) {
+          struct ipaddr_str buf;
+          OLSR_PRINTF(1, "%-15s ", olsr_ip_to_string(&buf, &tmp_net->A_network_addr));
+          OLSR_PRINTF(1, "%-15d ", tmp_net->prefix_len);
+          OLSR_PRINTF(1, "%-15s\n", olsr_ip_to_string(&buf, &tmp_hna->A_gateway_addr));
+        } else {
+          struct ipaddr_str buf;
+          OLSR_PRINTF(1, "%-27s/%d", olsr_ip_to_string(&buf, &tmp_net->A_network_addr), tmp_net->A_netmask.v6);
+          OLSR_PRINTF(1, "%s\n", olsr_ip_to_string(&buf, &tmp_hna->A_gateway_addr));
+        }
+
+        tmp_net = tmp_net->next;
+      }
+      tmp_hna = tmp_hna->next;
+    }
+  }
+#endif
+}
 
 /**
- *Deletes and dequeues a HNA network entry
+ *Process incoming HNA message.
+ *Forwards the message if that is to be done.
  *
- *@param net the entry to delete
+ *@param m the incoming OLSR message
+ *the OLSR message.
+ *@return 1 on success
  */
-void
-delete_hna_net(struct hna_net *net)
-{
 
-  /* Dequeue */
-  net->prev->next = net->next;
-  net->next->prev = net->prev;
+bool
+olsr_input_hna(union olsr_message *m, struct interface *in_if __attribute__ ((unused)), union olsr_ip_addr *from_addr)
+{
 
-  /* Delete */
-  free(net);
+  uint8_t olsr_msgtype;
+  olsr_reltime vtime;
+  uint16_t olsr_msgsize;
+  union olsr_ip_addr originator;
+  uint8_t hop_count;
+  uint16_t msg_seq_number;
+
+  int hnasize;
+  const uint8_t *curr, *curr_end;
+
+  struct ipaddr_str buf;
+#ifdef DEBUG
+  OLSR_PRINTF(5, "Processing HNA\n");
+#endif
+
+  /* Check if everyting is ok */
+  if (!m) {
+    return false;
+  }
+  curr = (const uint8_t *)m;
+
+  /* olsr_msgtype */
+  pkt_get_u8(&curr, &olsr_msgtype);
+  if (olsr_msgtype != HNA_MESSAGE) {
+    OLSR_PRINTF(1, "not a HNA message!\n");
+    return false;
+  }
+  /* Get vtime */
+  pkt_get_reltime(&curr, &vtime);
+
+  /* olsr_msgsize */
+  pkt_get_u16(&curr, &olsr_msgsize);
+
+  if (olsr_msgsize < 8 + olsr_cnf->ipsize) {
+#ifndef WIN32
+    OLSR_PRINTF(1, "HNA message size %d too small (at least %zu)!\n", olsr_msgsize,
+                8 + olsr_cnf->ipsize);
+#endif
+    return false;
+  }
+
+  hnasize = olsr_msgsize - 8 - olsr_cnf->ipsize;
+  curr_end = (const uint8_t *)m + olsr_msgsize;
+
+  /* validate originator */
+  pkt_get_ipaddress(&curr, &originator);
+  /*printf("HNA from %s\n\n", olsr_ip_to_string(&buf, &originator)); */
+
+  /* ttl */
+  pkt_ignore_u8(&curr);
+
+  /* hopcnt */
+  pkt_get_u8(&curr, &hop_count);
+
+  /* seqno */
+  pkt_get_u16(&curr, &msg_seq_number);
+
+  if ((hnasize % (2 * olsr_cnf->ipsize)) != 0) {
+    OLSR_PRINTF(1, "Illegal HNA message from %s with size %d!\n",
+        olsr_ip_to_string(&buf, &originator), olsr_msgsize);
+    return false;
+  }
+
+  /*
+   *      If the sender interface (NB: not originator) of this message
+   *      is not in the symmetric 1-hop neighborhood of this node, the
+   *      message MUST be discarded.
+   */
+  if (check_neighbor_link(from_addr) != SYM_LINK) {
+    OLSR_PRINTF(2, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
+    return false;
+  }
+  while (curr < curr_end) {
+    struct olsr_ip_prefix prefix;
+    union olsr_ip_addr mask;
+
+    struct ip_prefix_list *entry;
+    struct interface *ifs;
+    bool stop = false;
+
+    pkt_get_ipaddress(&curr, &prefix.prefix);
+    pkt_get_ipaddress(&curr, &mask);
+    prefix.prefix_len = olsr_netmask_to_prefix(&mask);
+
+#ifndef WIN32
+    if (olsr_cnf->smart_gw_active && olsr_is_smart_gateway(&prefix, &mask)) {
+      olsr_update_gateway_entry(&originator, &mask, prefix.prefix_len, msg_seq_number);
+    }
+#endif
 
+#ifdef MAXIMUM_GATEWAY_PREFIX_LENGTH
+    if (olsr_cnf->smart_gw_active && prefix.prefix_len > 0 && prefix.prefix_len <= MAXIMUM_GATEWAY_PREFIX_LENGTH) {
+      continue;
+    }
+#endif
+
+#ifndef NO_DUPLICATE_DETECTION_HANDLER
+    for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
+      if (ipequal(&ifs->ip_addr, &prefix.prefix)) {
+      /* ignore your own main IP as an incoming MID */
+        olsr_handle_hna_collision(&prefix.prefix, &originator);
+        stop = true;
+        break;
+      }
+    }
+    if (stop) {
+      continue;
+    }
+#endif
+    entry = ip_prefix_list_find(olsr_cnf->hna_entries, &prefix.prefix, prefix.prefix_len);
+    if (entry == NULL) {
+      /* only update if it's not from us */
+      olsr_update_hna_entry(&originator, &prefix.prefix, prefix.prefix_len, vtime);
+    }
+  }
+  /* Forward the message */
+  return true;
 }
 
-
-
-
-/**
- *Deletes and dequeues a hna gw entry
- *NETWORKS MUST BE DELETED FIRST!
- *
- *@param entry the entry to delete
+/*
+ * Local Variables:
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * End:
  */
-void
-delete_hna_entry(struct hna_entry *entry)
-{
-  /* Dequeue */
-  entry->prev->next = entry->next;
-  entry->next->prev = entry->prev;
-
-  /* Delete */
-  free(entry);
-}
-
-
-
-
-