Let interface monitor take interface down and up
[olsrd.git] / src / interfaces.c
index 9b6c862..d5c855c 100644 (file)
@@ -1,33 +1,80 @@
+
 /*
- * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
  *
- * This file is part of the olsr.org OLSR daemon.
+ * * 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 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.
+ * 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.
  *
- * 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.
+ * Visit http://www.olsr.org for more information.
  *
- * 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: interfaces.c,v 1.10 2004/11/01 20:13:27 kattemat Exp $
+ * 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 <signal.h>
+#include <unistd.h>
+
 #include "defs.h"
 #include "interfaces.h"
 #include "ifnet.h"
 #include "scheduler.h"
-#include "main.h"
+#include "olsr.h"
+#include "net_olsr.h"
+#include "ipcalc.h"
+#include "log.h"
+#include "parser.h"
+#include "socket_parser.h"
+
+#ifdef WIN32
+#include <winbase.h>
+#define close(x) closesocket(x)
+#endif
+
+/* The interface linked-list */
+struct interface *ifnet;
+
+/* Ifchange functions */
+struct ifchgf {
+  int (*function) (struct interface *, enum olsr_ifchg_flag);
+  struct ifchgf *next;
+};
+
+static struct ifchgf *ifchgf_list;
+
+/* Some cookies for stats keeping */
+struct olsr_cookie_info *interface_poll_timer_cookie = NULL;
+struct olsr_cookie_info *hello_gen_timer_cookie = NULL;
+struct olsr_cookie_info *tc_gen_timer_cookie = NULL;
+struct olsr_cookie_info *mid_gen_timer_cookie = NULL;
+struct olsr_cookie_info *hna_gen_timer_cookie = NULL;
 
 /**
  *Do initialization of various data needed for
  *@return the number of interfaces configured
  */
 int
-ifinit()
+olsr_init_interfacedb(void)
 {
   struct olsr_if *tmp_if;
 
-
   /* Initial values */
   ifnet = NULL;
 
   /*
-   *Initializing addrsock struct to be
-   *used on all the sockets
+   * Get some cookies for getting stats to ease troubleshooting.
    */
-  if(olsr_cnf->ip_version == AF_INET)
-    {
-      /* IP version 4 */
-      memset(&addrsock, 0, sizeof (addrsock));
-      addrsock.sin_family = AF_INET;
-      addrsock.sin_port = olsr_udp_port;
-      (addrsock.sin_addr).s_addr = INADDR_ANY;
-    }
-  else
-    {
-      /* IP version 6 */
-      memset(&addrsock6, 0, sizeof (addrsock6));
-      addrsock6.sin6_family = AF_INET6;
-      addrsock6.sin6_port = olsr_udp_port;
-      //(addrsock6.sin6_addr).s_addr = IN6ADDR_ANY_INIT;
-    }
+  interface_poll_timer_cookie = olsr_alloc_cookie("Interface Polling", OLSR_COOKIE_TYPE_TIMER);
+
+  hello_gen_timer_cookie = olsr_alloc_cookie("Hello Generation", OLSR_COOKIE_TYPE_TIMER);
+  tc_gen_timer_cookie = olsr_alloc_cookie("TC Generation", OLSR_COOKIE_TYPE_TIMER);
+  mid_gen_timer_cookie = olsr_alloc_cookie("MID Generation", OLSR_COOKIE_TYPE_TIMER);
+  hna_gen_timer_cookie = olsr_alloc_cookie("HNA Generation", OLSR_COOKIE_TYPE_TIMER);
 
-  olsr_printf(1, "\n ---- Interface configuration ---- \n\n");
+  OLSR_PRINTF(1, "\n ---- Interface configuration ---- \n\n");
   /* Run trough all interfaces immedeatly */
-  for(tmp_if = olsr_cnf->interfaces; tmp_if != NULL; tmp_if = tmp_if->next)
-    {
-      chk_if_up(tmp_if, 1);    
+  for (tmp_if = olsr_cnf->interfaces; tmp_if != NULL; tmp_if = tmp_if->next) {
+    if (!tmp_if->host_emul) {
+      if (!olsr_cnf->host_emul) /* XXX: TEMPORARY! */
+        chk_if_up(tmp_if, 1);
+    } else {
+      add_hemu_if(tmp_if);
     }
-  
-  /* register network interface update function with scheduler */
-  olsr_register_scheduler_event(&check_interface_updates, NULL, 5.0, 0, NULL);
+  }
+
+  /* Kick a periodic timer for the network interface update function */
+  olsr_start_timer((unsigned int)olsr_cnf->nic_chgs_pollrate * MSEC_PER_SEC, 5, OLSR_TIMER_PERIODIC, &check_interface_updates, NULL,
+                   interface_poll_timer_cookie->ci_id);
 
   return (ifnet == NULL) ? 0 : 1;
 }
 
+void
+olsr_trigger_ifchange(struct interface *ifp, enum olsr_ifchg_flag flag)
+{
+  struct ifchgf *tmp_ifchgf_list = ifchgf_list;
 
+  while (tmp_ifchgf_list != NULL) {
+    tmp_ifchgf_list->function(ifp, flag);
+    tmp_ifchgf_list = tmp_ifchgf_list->next;
+  }
+}
 
 /**
  *Find the local interface with a given address.
@@ -91,35 +140,32 @@ ifinit()
  */
 
 struct interface *
-if_ifwithaddr(union olsr_ip_addr *addr)
+if_ifwithaddr(const union olsr_ip_addr *addr)
 {
   struct interface *ifp;
 
-  for (ifp = ifnet; ifp; ifp = ifp->int_next)
-    {
-      if(olsr_cnf->ip_version == AF_INET)
-       {
-         /* IPv4 */
-         //printf("Checking: %s == ", inet_ntoa(((struct sockaddr_in *)&ifp->int_addr)->sin_addr));
-         //printf("%s\n", olsr_ip_to_string(addr));
-
-         if (COMP_IP(&((struct sockaddr_in *)&ifp->int_addr)->sin_addr, addr))
-             return ifp;
-       }
-      else
-       {
-         /* IPv6 */
-         //printf("Checking %s ", olsr_ip_to_string((union olsr_ip_addr *)&ifp->int6_addr.sin6_addr));
-         //printf("== %s\n", olsr_ip_to_string((union olsr_ip_addr *)&((struct sockaddr_in6 *)addr)->sin6_addr));
-         if (COMP_IP(&ifp->int6_addr.sin6_addr, addr))
-           return ifp;
-       }
+  if (!addr)
+    return NULL;
+
+  for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+    if (olsr_cnf->ip_version == AF_INET) {
+      /* IPv4 */
+      //printf("Checking: %s == ", inet_ntoa(((struct sockaddr_in *)&ifp->int_addr)->sin_addr));
+      //printf("%s\n", olsr_ip_to_string(addr));
+
+      if (((struct sockaddr_in *)&ifp->int_addr)->sin_addr.s_addr == addr->v4.s_addr)
+        return ifp;
+    } else {
+      /* IPv6 */
+      //printf("Checking %s ", olsr_ip_to_string((union olsr_ip_addr *)&ifp->int6_addr.sin6_addr));
+      //printf("== %s\n", olsr_ip_to_string((union olsr_ip_addr *)&((struct sockaddr_in6 *)addr)->sin6_addr));
+      if (ip6equal(&ifp->int6_addr.sin6_addr, &addr->v6))
+        return ifp;
     }
+  }
   return NULL;
 }
 
-
-
 /**
  *Find the interface with a given number.
  *
@@ -134,16 +180,93 @@ if_ifwithsock(int fd)
   struct interface *ifp;
   ifp = ifnet;
 
-  while (ifp) 
-    {
-      if (ifp->olsr_socket == fd)
-       return ifp;
-      ifp = ifp->int_next;
+  while (ifp) {
+    if (ifp->olsr_socket == fd || ifp->send_socket == fd)
+      return ifp;
+    ifp = ifp->int_next;
+  }
+
+  return NULL;
+}
+
+/**
+ *Find the interface with a given label.
+ *
+ *@param if_name the label of the interface to find.
+ *
+ *@return return the interface struct representing the interface
+ *that matched the label.
+ */
+struct interface *
+if_ifwithname(const char *if_name)
+{
+  struct interface *ifp = ifnet;
+  while (ifp) {
+    /* good ol' strcmp should be sufficcient here */
+    if (strcmp(ifp->int_name, if_name) == 0) {
+      return ifp;
     }
-  
-  return (ifp);
+    ifp = ifp->int_next;
+  }
+  return NULL;
 }
 
+/**
+ *Find the olsr_if with a given label.
+ *
+ *@param if_name the label of the interface to find.
+ *
+ *@return return the interface struct representing the interface
+ *that matched the label.
+ */
+struct olsr_if *
+olsrif_ifwithname(const char *if_name)
+{
+  struct olsr_if *oifp = olsr_cnf->interfaces;
+  while (oifp) {
+    /* good ol' strcmp should be sufficcient here */
+    if (strcmp(oifp->name, if_name) == 0) {
+      return oifp;
+    }
+    oifp = oifp->next;
+  }
+  return NULL;
+}
+
+/**
+ *Find the interface with a given interface index.
+ *
+ *@param iif_index of the interface to find.
+ *
+ *@return return the interface struct representing the interface
+ *that matched the iif_index.
+ */
+struct interface *
+if_ifwithindex(const int if_index)
+{
+  struct interface *ifp = ifnet;
+  while (ifp != NULL) {
+    if (ifp->if_index == if_index) {
+      return ifp;
+    }
+    ifp = ifp->int_next;
+  }
+  return NULL;
+}
+
+/**
+ *Get an interface name for a given interface index
+ *
+ *@param iif_index of the interface to find.
+ *
+ *@return "" or interface name.
+ */
+const char *
+if_ifwithindex_name(const int if_index)
+{
+  const struct interface *const ifp = if_ifwithindex(if_index);
+  return ifp == NULL ? "void" : ifp->int_name;
+}
 
 /**
  *Create a new interf_name struct using a given
@@ -153,42 +276,43 @@ if_ifwithsock(int fd)
  *
  *@return nada
  */
-void
-queue_if(char *name)
+struct olsr_if *
+olsr_create_olsrif(const char *name, int hemu)
 {
-
   struct olsr_if *interf_n = olsr_cnf->interfaces;
+  size_t name_size;
 
   //printf("Adding interface %s\n", name);
 
   /* check if the inerfaces already exists */
-  while(interf_n != NULL)
-    {
-      if(memcmp(interf_n->name, name, strlen(name)) == 0)
-       {
-         fprintf(stderr, "Duplicate interfaces defined... not adding %s\n", name);
-         return;
-       }
-      interf_n = interf_n->next;
+  while (interf_n != NULL) {
+    if (strcmp(interf_n->name, name) == 0) {
+      fprintf(stderr, "Duplicate interfaces defined... not adding %s\n", name);
+      return NULL;
     }
+    interf_n = interf_n->next;
+  }
 
   interf_n = olsr_malloc(sizeof(struct olsr_if), "queue interface");
 
-  /* strlen () does not return length including terminating /0 */
-  interf_n->name = olsr_malloc(strlen(name) + 1, "queue interface name");
-  interf_n->cnf = NULL;
-  interf_n->interf = NULL;
-  interf_n->configured = 0;
-  interf_n->index = olsr_cnf->ifcnt++;
+  name_size = strlen(name) + 1;
+  interf_n->name = olsr_malloc(name_size, "queue interface name");
+  strscpy(interf_n->name, name, name_size);
+
+  interf_n->cnf = olsr_malloc(sizeof(*interf_n->cnf), "queue cnf");
+
+  interf_n->cnfi = olsr_malloc(sizeof(*interf_n->cnfi), "queue cnfi");
+  memset(interf_n->cnfi, 0xFF, sizeof(*interf_n->cnfi));
+  interf_n->cnfi->orig_lq_mult_cnt=0;
+
+  interf_n->host_emul = hemu ? true : false;
 
-  strcpy(interf_n->name, name);
   interf_n->next = olsr_cnf->interfaces;
   olsr_cnf->interfaces = interf_n;
 
+  return interf_n;
 }
 
-
-
 /**
  *Add an ifchange function. These functions are called on all (non-initial)
  *changes in the interface set.
@@ -198,7 +322,7 @@ queue_if(char *name)
  *@return
  */
 int
-add_ifchgf(int (*f)(struct interface *, int))
+olsr_add_ifchange_handler(int (*f) (struct interface *, enum olsr_ifchg_flag))
 {
 
   struct ifchgf *new_ifchgf;
@@ -213,39 +337,118 @@ add_ifchgf(int (*f)(struct interface *, int))
   return 1;
 }
 
-
-
 /*
  * Remove an ifchange function
  */
 int
-del_ifchgf(int (*f)(struct interface *, int))
+olsr_remove_ifchange_handler(int (*f) (struct interface *, enum olsr_ifchg_flag))
 {
   struct ifchgf *tmp_ifchgf, *prev;
 
   tmp_ifchgf = ifchgf_list;
   prev = NULL;
 
-  while(tmp_ifchgf)
-    {
-      if(tmp_ifchgf->function == f)
-       {
-         /* Remove entry */
-         if(prev == NULL)
-           {
-             ifchgf_list = tmp_ifchgf->next;
-             free(tmp_ifchgf);
-           }
-         else
-           {
-             prev->next = tmp_ifchgf->next;
-             free(tmp_ifchgf);
-           }
-         return 1;
-       }
-      prev = tmp_ifchgf;
-      tmp_ifchgf = tmp_ifchgf->next;
+  while (tmp_ifchgf) {
+    if (tmp_ifchgf->function == f) {
+      /* Remove entry */
+      if (prev == NULL) {
+        ifchgf_list = tmp_ifchgf->next;
+        free(tmp_ifchgf);
+      } else {
+        prev->next = tmp_ifchgf->next;
+        free(tmp_ifchgf);
+      }
+      return 1;
     }
+    prev = tmp_ifchgf;
+    tmp_ifchgf = tmp_ifchgf->next;
+  }
 
   return 0;
 }
+
+void
+olsr_remove_interface(struct olsr_if * iface)
+{
+  struct interface *ifp, *tmp_ifp;
+  ifp = iface->interf;
+
+  OLSR_PRINTF(1, "Removing interface %s\n", iface->name);
+  olsr_syslog(OLSR_LOG_INFO, "Removing interface %s\n", iface->name);
+
+  olsr_delete_link_entry_by_ip(&ifp->ip_addr);
+
+  /*
+   *Call possible ifchange functions registered by plugins
+   */
+  olsr_trigger_ifchange(ifp, IFCHG_IF_REMOVE);
+
+  /* cleanup routes over this interface */
+  olsr_delete_interface_routes(ifp->if_index);
+
+  /* Dequeue */
+  if (ifp == ifnet) {
+    ifnet = ifp->int_next;
+  } else {
+    tmp_ifp = ifnet;
+    while (tmp_ifp->int_next != ifp) {
+      tmp_ifp = tmp_ifp->int_next;
+    }
+    tmp_ifp->int_next = ifp->int_next;
+  }
+
+  /* Remove output buffer */
+  net_remove_buffer(ifp);
+
+  /* Check main addr */
+  /* deactivated to prevent change of originator IP */
+#if 0
+  if (ipequal(&olsr_cnf->main_addr, &ifp->ip_addr)) {
+    if (ifnet == NULL) {
+      /* No more interfaces */
+      memset(&olsr_cnf->main_addr, 0, olsr_cnf->ipsize);
+      OLSR_PRINTF(1, "No more interfaces...\n");
+    } else {
+      struct ipaddr_str buf;
+      olsr_cnf->main_addr = ifnet->ip_addr;
+      OLSR_PRINTF(1, "New main address: %s\n", olsr_ip_to_string(&buf, &olsr_cnf->main_addr));
+      olsr_syslog(OLSR_LOG_INFO, "New main address: %s\n", olsr_ip_to_string(&buf, &olsr_cnf->main_addr));
+    }
+  }
+#endif
+  /*
+   * Deregister functions for periodic message generation
+   */
+  olsr_stop_timer(ifp->hello_gen_timer);
+  olsr_stop_timer(ifp->tc_gen_timer);
+  olsr_stop_timer(ifp->mid_gen_timer);
+  olsr_stop_timer(ifp->hna_gen_timer);
+
+  iface->configured = 0;
+  iface->interf = NULL;
+
+  /* Close olsr socket */
+  close(ifp->olsr_socket);
+  remove_olsr_socket(ifp->olsr_socket, &olsr_input);
+
+  if (ifp->send_socket != ifp->olsr_socket) {
+    close(ifp->send_socket);
+    remove_olsr_socket(ifp->send_socket, &olsr_input);
+  }
+
+  /* Free memory */
+  free(ifp->int_name);
+  free(ifp);
+
+  if ((ifnet == NULL) && (!olsr_cnf->allow_no_interfaces)) {
+    olsr_syslog(OLSR_LOG_INFO, "No more active interfaces - exiting.\n");
+    olsr_exit("No more active interfaces - exiting.\n", EXIT_FAILURE);
+  }
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * End:
+ */