/*
 * The olsr.org Optimized Link-State Routing daemon(olsrd)
 * Copyright (c) 2004, Andreas Tønnesen(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:
 *
 * * 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.
 *
 * 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.
 *
 * 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.
 *
 * $Id: ifnet.c,v 1.51 2007/08/23 21:20:02 bernd67 Exp $
 */


#if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
#define ifr_netmask ifr_addr
#endif

#include "interfaces.h"
#include "ifnet.h"
#include "defs.h"
#include "olsr.h"
#include "net_os.h"
#include "net_olsr.h"
#include "socket_parser.h"
#include "parser.h"
#include "scheduler.h"
#include "generate_msg.h"
#include "mantissa.h"
#include "lq_packet.h"
#include "log.h"
#include "link_set.h"
#include <signal.h>
#include <sys/types.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>

int bufspace = 127*1024;	/* max. input buffer size to request */


int
set_flag(char *ifname, short flag __attribute__((unused)))
{
  struct ifreq ifr;

  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

  /* Get flags */
  if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) 
    {
      fprintf(stderr,"ioctl (get interface flags)");
      return -1;
    }

  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  
  //printf("Setting flags for if \"%s\"\n", ifr.ifr_name);

  if(!(ifr.ifr_flags & (IFF_UP | IFF_RUNNING)))
    {
      /* Add UP */
      ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
      /* Set flags + UP */
      if(ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0)
	{
	  fprintf(stderr, "ERROR(%s): %s\n", ifr.ifr_name, strerror(errno));
	  return -1;
	}
    }
  return 1;

}




void
check_interface_updates(void *foo __attribute__((unused)))
{
  struct olsr_if *tmp_if;

#ifdef DEBUG
  OLSR_PRINTF(3, "Checking for updates in the interface set\n");
#endif

  for(tmp_if = olsr_cnf->interfaces; tmp_if != NULL; tmp_if = tmp_if->next)
    {
      if(tmp_if->host_emul)
	continue;
      
      if(olsr_cnf->host_emul) /* XXX: TEMPORARY! */
	continue;

      if(!tmp_if->cnf->autodetect_chg) 
        {
#ifdef DEBUG
          /* Don't check this interface */
          OLSR_PRINTF(3, "Not checking interface %s\n", tmp_if->name)
#endif
          continue;
        }

      if(tmp_if->configured)
        {
          chk_if_changed(tmp_if);
        }
      else
        {
          chk_if_up(tmp_if, 3);
        }
    }

  return;
}

/**
 * Checks if an initialized interface is changed
 * that is if it has been set down or the address
 * has been changed.
 *
 *@param iface the olsr_if struct describing the interface
 */
int
chk_if_changed(struct olsr_if *iface)
{
  struct interface *ifp, *tmp_ifp;
  struct ifreq ifr;
  struct sockaddr_in6 tmp_saddr6;
  int if_changes;
  if_changes = 0;

#ifdef DEBUG
  OLSR_PRINTF(3, "Checking if %s is set down or changed\n", iface->name);
#endif

  if(iface->host_emul)
    return -1;

  ifp = iface->interf;

  if(ifp == NULL)
    {
      /* Should not happen */
      iface->configured = 0;
      return 0;
    }

  memset(&ifr, 0, sizeof(struct ifreq));
  strncpy(ifr.ifr_name, iface->name, IFNAMSIZ);


  /* Get flags (and check if interface exists) */
  if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) 
    {
      OLSR_PRINTF(3, "No such interface: %s\n", iface->name);
      goto remove_interface;
    }

  ifp->int_flags = ifr.ifr_flags;

  /*
   * First check if the interface is set DOWN
   */

  if ((ifp->int_flags & IFF_UP) == 0)
    {
      OLSR_PRINTF(1, "\tInterface %s not up - removing it...\n", iface->name);
      goto remove_interface;
    }

  /*
   * We do all the interface type checks over.
   * This is because the interface might be a PCMCIA card. Therefore
   * It might not be the same physical interface as we configured earlier.
   */

  /* Check broadcast */
  if ((olsr_cnf->ip_version == AF_INET) && 
      !iface->cnf->ipv4_broadcast.v4 && /* Skip if fixed bcast */ 
      (!(ifp->int_flags & IFF_BROADCAST))) 
    {
      OLSR_PRINTF(3, "\tNo broadcast - removing\n");
      goto remove_interface;
    }

  if (ifp->int_flags & IFF_LOOPBACK)
    {
      OLSR_PRINTF(3, "\tThis is a loopback interface - removing it...\n");
      goto remove_interface;
    }

  ifp->is_hcif = OLSR_FALSE;

  /* trying to detect if interface is wireless. */
  ifp->is_wireless = check_wireless_interface(ifr.ifr_name);

  /* Set interface metric */
  if(iface->cnf->weight.fixed)
    ifp->int_metric = iface->cnf->weight.value;
  else
    ifp->int_metric = calculate_if_metric(ifr.ifr_name);

  /* Get MTU */
  if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMTU, &ifr) < 0)
    ifp->int_mtu = 0;
  else
    {
      ifr.ifr_mtu -= (olsr_cnf->ip_version == AF_INET6) ? UDP_IPV6_HDRSIZE : UDP_IPV4_HDRSIZE;

      if(ifp->int_mtu != ifr.ifr_mtu)
	{
	  ifp->int_mtu = ifr.ifr_mtu;
	  /* Create new outputbuffer */
	  net_remove_buffer(ifp); /* Remove old */
	  net_add_buffer(ifp);
	}
    }


  /* Get interface index */
  ifp->if_index = if_nametoindex(ifr.ifr_name);

  /*
   * Now check if the IP has changed
   */
  
  /* IP version 6 */
  if(olsr_cnf->ip_version == AF_INET6)
    {
      /* Get interface address */
      
      if(get_ipv6_address(ifr.ifr_name, &tmp_saddr6, iface->cnf->ipv6_addrtype) <= 0)
	{
	  if(iface->cnf->ipv6_addrtype == IPV6_ADDR_SITELOCAL)
	    OLSR_PRINTF(3, "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
	  else
	    OLSR_PRINTF(3, "\tCould not find global IPv6 address for %s\n", ifr.ifr_name);
	  
	  
	  goto remove_interface;
	}
      
#ifdef DEBUG
      OLSR_PRINTF(3, "\tAddress: %s\n", ip6_to_string(&tmp_saddr6.sin6_addr));
#endif

      if(memcmp(&tmp_saddr6.sin6_addr, &ifp->int6_addr.sin6_addr, olsr_cnf->ipsize) != 0)
	{
	  OLSR_PRINTF(1, "New IP address for %s:\n", ifr.ifr_name);
	  OLSR_PRINTF(1, "\tOld: %s\n", ip6_to_string(&ifp->int6_addr.sin6_addr));
	  OLSR_PRINTF(1, "\tNew: %s\n", ip6_to_string(&tmp_saddr6.sin6_addr));

	  /* Check main addr */
	  if(memcmp(&olsr_cnf->main_addr, &tmp_saddr6.sin6_addr, olsr_cnf->ipsize) == 0)
	    {
	      /* Update main addr */
	      memcpy(&olsr_cnf->main_addr, &tmp_saddr6.sin6_addr, olsr_cnf->ipsize);
	    }

	  /* Update address */
	  memcpy(&ifp->int6_addr.sin6_addr, &tmp_saddr6.sin6_addr, olsr_cnf->ipsize);
	  memcpy(&ifp->ip_addr, &tmp_saddr6.sin6_addr, olsr_cnf->ipsize);

	  run_ifchg_cbs(ifp, IFCHG_IF_UPDATE);

	  return 1;	  	  
	}
      return 0;

    }
  else
  /* IP version 4 */
    {
      /* Check interface address (IPv4)*/
      if(ioctl(olsr_cnf->ioctl_s, SIOCGIFADDR, &ifr) < 0) 
	{
	  OLSR_PRINTF(1, "\tCould not get address of interface - removing it\n");
	  goto remove_interface;
	}

#ifdef DEBUG
      OLSR_PRINTF(3, "\tAddress:%s\n", sockaddr_to_string(&ifr.ifr_addr));
#endif

      if(memcmp(&((struct sockaddr_in *)&ifp->int_addr)->sin_addr.s_addr,
		&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr, 
		olsr_cnf->ipsize) != 0)
	{
	  /* New address */
	  OLSR_PRINTF(1, "IPv4 address changed for %s\n", ifr.ifr_name);
	  OLSR_PRINTF(1, "\tOld:%s\n", sockaddr_to_string(&ifp->int_addr));
	  OLSR_PRINTF(1, "\tNew:%s\n", sockaddr_to_string(&ifr.ifr_addr));

	  ifp->int_addr = ifr.ifr_addr;

	  if(memcmp(&olsr_cnf->main_addr, 
		    &ifp->ip_addr,
		    olsr_cnf->ipsize) == 0)
	    {
	      OLSR_PRINTF(1, "New main address: %s\n", sockaddr_to_string(&ifr.ifr_addr));
	      olsr_syslog(OLSR_LOG_INFO, "New main address: %s\n", sockaddr_to_string(&ifr.ifr_addr));
	      memcpy(&olsr_cnf->main_addr, 
		     &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr, 
		     olsr_cnf->ipsize);
	    }

	  memcpy(&ifp->ip_addr, 
		 &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr, 
		 olsr_cnf->ipsize);

	  if_changes = 1;
	}

      /* Check netmask */
      if (ioctl(olsr_cnf->ioctl_s, SIOCGIFNETMASK, &ifr) < 0) 
	{
	  olsr_syslog(OLSR_LOG_ERR, "%s: ioctl (get broadaddr)", ifr.ifr_name);
	  goto remove_interface;
	}

#ifdef DEBUG
      OLSR_PRINTF(3, "\tNetmask:%s\n", sockaddr_to_string(&ifr.ifr_netmask));
#endif

      if(memcmp(&((struct sockaddr_in *)&ifp->int_netmask)->sin_addr.s_addr,
		&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr, 
		olsr_cnf->ipsize) != 0)
	{
	  /* New address */
	  OLSR_PRINTF(1, "IPv4 netmask changed for %s\n", ifr.ifr_name);
	  OLSR_PRINTF(1, "\tOld:%s\n", sockaddr_to_string(&ifp->int_netmask));
	  OLSR_PRINTF(1, "\tNew:%s\n", sockaddr_to_string(&ifr.ifr_netmask));

	  ifp->int_netmask = ifr.ifr_netmask;

	  if_changes = 1;
	}
      
      if(!iface->cnf->ipv4_broadcast.v4)
	{
	  /* Check broadcast address */      
	  if (ioctl(olsr_cnf->ioctl_s, SIOCGIFBRDADDR, &ifr) < 0) 
	    {
	      olsr_syslog(OLSR_LOG_ERR, "%s: ioctl (get broadaddr)", ifr.ifr_name);
	      goto remove_interface;
	    }
	  
#ifdef DEBUG
	  OLSR_PRINTF(3, "\tBroadcast address:%s\n", sockaddr_to_string(&ifr.ifr_broadaddr));
#endif
	  
	  if(memcmp(&((struct sockaddr_in *)&ifp->int_broadaddr)->sin_addr.s_addr,
		    &((struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr.s_addr, 
		    olsr_cnf->ipsize) != 0)
	    {
	      
	      /* New address */
	      OLSR_PRINTF(1, "IPv4 broadcast changed for %s\n", ifr.ifr_name);
	      OLSR_PRINTF(1, "\tOld:%s\n", sockaddr_to_string(&ifp->int_broadaddr));
	      OLSR_PRINTF(1, "\tNew:%s\n", sockaddr_to_string(&ifr.ifr_broadaddr));
	      
	      ifp->int_broadaddr = ifr.ifr_broadaddr;
	      if_changes = 1;
	    }            
	}
    }

  if(if_changes)
    run_ifchg_cbs(ifp, IFCHG_IF_UPDATE);

  return if_changes;


 remove_interface:
  OLSR_PRINTF(1, "Removing interface %s\n", iface->name);
  olsr_syslog(OLSR_LOG_INFO, "Removing interface %s\n", iface->name);

  del_if_link_entries(&ifp->ip_addr);

  /*
   *Call possible ifchange functions registered by plugins  
   */
  run_ifchg_cbs(ifp, IFCHG_IF_REMOVE);
  
  /* 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 */
  if(COMP_IP(&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
	{
	  COPY_IP(&olsr_cnf->main_addr, &ifnet->ip_addr);
	  OLSR_PRINTF(1, "New main address: %s\n", olsr_ip_to_string(&olsr_cnf->main_addr));
	  olsr_syslog(OLSR_LOG_INFO, "New main address: %s\n", olsr_ip_to_string(&olsr_cnf->main_addr));
	}
    }


  /*
   * Deregister scheduled functions 
   */

  if (olsr_cnf->lq_level == 0)
    {
      olsr_remove_scheduler_event(&generate_hello, 
                                  ifp, 
                                  iface->cnf->hello_params.emission_interval, 
                                  0, 
                                  NULL);
      olsr_remove_scheduler_event(&generate_tc, 
                                  ifp, 
                                  iface->cnf->tc_params.emission_interval,
                                  0, 
                                  NULL);
    }

  else
    {
      olsr_remove_scheduler_event(&olsr_output_lq_hello, 
                                  ifp, 
                                  iface->cnf->hello_params.emission_interval, 
                                  0, 
                                  NULL);
      olsr_remove_scheduler_event(&olsr_output_lq_tc, 
                                  ifp, 
                                  iface->cnf->tc_params.emission_interval,
                                  0, 
                                  NULL);
    }

  olsr_remove_scheduler_event(&generate_mid, 
			      ifp, 
			      iface->cnf->mid_params.emission_interval,
			      0, 
			      NULL);
  olsr_remove_scheduler_event(&generate_hna, 
			      ifp, 
			      iface->cnf->hna_params.emission_interval,
			      0, 
			      NULL);



  iface->configured = 0;
  iface->interf = NULL;
  /* Close olsr socket */
  close(ifp->olsr_socket);
  remove_olsr_socket(ifp->olsr_socket, &olsr_input);

  /* Free memory */
  free(ifp->int_name);
  free(ifp);

  if((ifnet == NULL) && (!olsr_cnf->allow_no_interfaces))
    {
      OLSR_PRINTF(1, "No more active interfaces - exiting.\n");
      olsr_syslog(OLSR_LOG_INFO, "No more active interfaces - exiting.\n");
      olsr_cnf->exit_value = EXIT_FAILURE;
      kill(getpid(), SIGINT);
    }

  return 0;

}

/**
 * Initializes the special interface used in
 * host-client emulation
 */
int
add_hemu_if(struct olsr_if *iface)
{
  struct interface *ifp;
  union olsr_ip_addr null_addr;
  olsr_u32_t addr[4];

  if(!iface->host_emul)
    return -1;

  ifp = olsr_malloc(sizeof (struct interface), "Interface update 2");

  memset(ifp, 0, sizeof (struct interface));

  iface->configured = OLSR_TRUE;
  iface->interf = ifp;

  ifp->is_hcif = OLSR_TRUE;
  ifp->int_name = olsr_malloc(strlen("hcif01") + 1, "Interface update 3");
  ifp->int_metric = 0;

  strcpy(ifp->int_name, "hcif01");

  OLSR_PRINTF(1, "Adding %s(host emulation):\n", ifp->int_name);

  OLSR_PRINTF(1, "       Address:%s\n", olsr_ip_to_string(&iface->hemu_ip));

  OLSR_PRINTF(1, "       NB! This is a emulated interface\n       that does not exist in the kernel!\n");

  ifp->int_next = ifnet;
  ifnet = ifp;

  memset(&null_addr, 0, olsr_cnf->ipsize);
  if(COMP_IP(&null_addr, &olsr_cnf->main_addr))
    {
      COPY_IP(&olsr_cnf->main_addr, &iface->hemu_ip);
      OLSR_PRINTF(1, "New main address: %s\n", olsr_ip_to_string(&olsr_cnf->main_addr));
	olsr_syslog(OLSR_LOG_INFO, "New main address: %s\n", olsr_ip_to_string(&olsr_cnf->main_addr));
    }

  ifp->int_mtu = OLSR_DEFAULT_MTU;

  ifp->int_mtu -= (olsr_cnf->ip_version == AF_INET6) ? UDP_IPV6_HDRSIZE : UDP_IPV4_HDRSIZE;

  /* Set up buffer */
  net_add_buffer(ifp);


  if(olsr_cnf->ip_version == AF_INET)
    {
      struct sockaddr_in sin;

      memset(&sin, 0, sizeof(sin));

      sin.sin_family = AF_INET;
      sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
      sin.sin_port = htons(10150);
 
     /* IP version 4 */
      ifp->ip_addr.v4 = iface->hemu_ip.v4;

      memcpy(&((struct sockaddr_in *)&ifp->int_addr)->sin_addr, &iface->hemu_ip, olsr_cnf->ipsize);
      
      /*
       *We create one socket for each interface and bind
       *the socket to it. This to ensure that we can control
       *on what interface the message is transmitted
       */
      
      ifp->olsr_socket = gethemusocket(&sin);
      
      if (ifp->olsr_socket < 0)
	{
	  fprintf(stderr, "Could not initialize socket... exiting!\n\n");
	  olsr_syslog(OLSR_LOG_ERR, "Could not initialize socket... exiting!\n\n");
	  olsr_cnf->exit_value = EXIT_FAILURE;
	  kill(getpid(), SIGINT);
	}

    }
  else
    {
      /* IP version 6 */
      memcpy(&ifp->ip_addr, &iface->hemu_ip, olsr_cnf->ipsize);

#if 0      
      /*
       *We create one socket for each interface and bind
       *the socket to it. This to ensure that we can control
       *on what interface the message is transmitted
       */
      
      ifp->olsr_socket = gethcsocket6(&addrsock6, bufspace, ifp->int_name);
      
      join_mcast(ifp, ifp->olsr_socket);
      
      if (ifp->olsr_socket < 0)
	{
	  fprintf(stderr, "Could not initialize socket... exiting!\n\n");
	  olsr_syslog(OLSR_LOG_ERR, "Could not initialize socket... exiting!\n\n");
	  olsr_cnf->exit_value = EXIT_FAILURE;
	  kill(getpid(), SIGINT);
	}
      
#endif
    }

  /* Send IP as first 4/16 bytes on socket */
  memcpy(addr, iface->hemu_ip.v6.s6_addr, olsr_cnf->ipsize);
  addr[0] = htonl(addr[0]);
  addr[1] = htonl(addr[1]);
  addr[2] = htonl(addr[2]);
  addr[3] = htonl(addr[3]);

  if(send(ifp->olsr_socket, addr , olsr_cnf->ipsize, 0) != (int)olsr_cnf->ipsize)
    {
      fprintf(stderr, "Error sending IP!");
    }  
  
  /* Register socket */
  add_olsr_socket(ifp->olsr_socket, &olsr_input_hostemu);


  if (olsr_cnf->lq_level == 0)
    {
      olsr_register_scheduler_event(&generate_hello, 
                                    ifp, 
                                    iface->cnf->hello_params.emission_interval, 
                                    0, 
                                    NULL);
      olsr_register_scheduler_event(&generate_tc, 
                                    ifp, 
                                    iface->cnf->tc_params.emission_interval,
                                    0, 
                                    NULL);
    }

  else
    {
      olsr_register_scheduler_event(&olsr_output_lq_hello, 
                                    ifp, 
                                    iface->cnf->hello_params.emission_interval, 
                                    0, 
                                    NULL);
      olsr_register_scheduler_event(&olsr_output_lq_tc, 
                                    ifp, 
                                    iface->cnf->tc_params.emission_interval,
                                    0, 
                                    NULL);
    }

  olsr_register_scheduler_event(&generate_mid, 
				ifp, 
				iface->cnf->mid_params.emission_interval,
				0, 
				NULL);
  olsr_register_scheduler_event(&generate_hna, 
				ifp, 
				iface->cnf->hna_params.emission_interval,
				0, 
				NULL);

  /* Recalculate max jitter */

  if((olsr_cnf->max_jitter == 0) || 
     ((iface->cnf->hello_params.emission_interval / 4) < olsr_cnf->max_jitter))
    olsr_cnf->max_jitter = iface->cnf->hello_params.emission_interval / 4;

  /* Recalculate max topology hold time */
  if(olsr_cnf->max_tc_vtime < iface->cnf->tc_params.emission_interval)
    olsr_cnf->max_tc_vtime = iface->cnf->tc_params.emission_interval;

  ifp->hello_etime = iface->cnf->hello_params.emission_interval;
  ifp->valtimes.hello = double_to_me(iface->cnf->hello_params.validity_time);
  ifp->valtimes.tc = double_to_me(iface->cnf->tc_params.validity_time);
  ifp->valtimes.mid = double_to_me(iface->cnf->mid_params.validity_time);
  ifp->valtimes.hna = double_to_me(iface->cnf->hna_params.validity_time);

  return 1;
}

static char basenamestr[32];
static const char* if_basename(const char* name);
static const char* if_basename(const char* name)
{
	char *p = strchr(name, ':');
	if (NULL == p || p - name >= (int)(sizeof(basenamestr) / sizeof(basenamestr[0]) - 1)) {
        	return name;
        }
	memcpy(basenamestr, name, p - name);
	basenamestr[p - name] = 0;
	return basenamestr;
}

/**
 * Initializes a interface described by iface,
 * if it is set up and is of the correct type.
 *
 *@param iface the olsr_if struct describing the interface
 *@param so the socket to use for ioctls
 *
 */
int
chk_if_up(struct olsr_if *iface, int debuglvl)
{
  struct interface ifs, *ifp;
  struct ifreq ifr;
  union olsr_ip_addr null_addr;
#ifdef linux
  int precedence = IPTOS_PREC(olsr_cnf->tos);
  int tos_bits = IPTOS_TOS(olsr_cnf->tos);
#endif

  if(iface->host_emul)
    return -1;

  memset(&ifr, 0, sizeof(struct ifreq));
  strncpy(ifr.ifr_name, iface->name, IFNAMSIZ);

  OLSR_PRINTF(debuglvl, "Checking %s:\n", ifr.ifr_name);

  /* Get flags (and check if interface exists) */
  if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) 
    {
      OLSR_PRINTF(debuglvl, "\tNo such interface!\n");
      return 0;
    }

  memset(&ifs.netbuf, 0, sizeof(struct olsr_netbuf));
  ifs.int_flags = ifr.ifr_flags;      


  if ((ifs.int_flags & IFF_UP) == 0)
    {
      OLSR_PRINTF(debuglvl, "\tInterface not up - skipping it...\n");
      return 0;
    }

  /* Check broadcast */
  if ((olsr_cnf->ip_version == AF_INET) &&
      !iface->cnf->ipv4_broadcast.v4 && /* Skip if fixed bcast */ 
      (!(ifs.int_flags & IFF_BROADCAST))) 
    {
      OLSR_PRINTF(debuglvl, "\tNo broadcast - skipping\n");
      return 0;
    }


  if (ifs.int_flags & IFF_LOOPBACK)
    {
      OLSR_PRINTF(debuglvl, "\tThis is a loopback interface - skipping it...\n");
      return 0;
    }

  ifs.is_hcif = OLSR_FALSE;

  /* trying to detect if interface is wireless. */
  ifs.is_wireless = check_wireless_interface(ifr.ifr_name);

  if(ifs.is_wireless)
    OLSR_PRINTF(debuglvl, "\tWireless interface detected\n");
  else
    OLSR_PRINTF(debuglvl, "\tNot a wireless interface\n");

  
  /* IP version 6 */
  if(olsr_cnf->ip_version == AF_INET6)
    {
      /* Get interface address */
      
      if(get_ipv6_address(ifr.ifr_name, &ifs.int6_addr, iface->cnf->ipv6_addrtype) <= 0)
	{
	  if(iface->cnf->ipv6_addrtype == IPV6_ADDR_SITELOCAL)
	    OLSR_PRINTF(debuglvl, "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
	  else
	    OLSR_PRINTF(debuglvl, "\tCould not find global IPv6 address for %s\n", ifr.ifr_name);
	  
	  return 0;
	}
      
      OLSR_PRINTF(debuglvl, "\tAddress: %s\n", ip6_to_string(&ifs.int6_addr.sin6_addr));
      
      /* Multicast */
      ifs.int6_multaddr.sin6_addr = (iface->cnf->ipv6_addrtype == IPV6_ADDR_SITELOCAL) ? 
	iface->cnf->ipv6_multi_site.v6 :
	iface->cnf->ipv6_multi_glbl.v6;
      /* Set address family */
      ifs.int6_multaddr.sin6_family = AF_INET6;
      /* Set port */
      ifs.int6_multaddr.sin6_port = htons(OLSRPORT);
      
#ifdef __MacOSX__
      ifs.int6_multaddr.sin6_scope_id = 0;
#endif

      OLSR_PRINTF(debuglvl, "\tMulticast: %s\n", ip6_to_string(&ifs.int6_multaddr.sin6_addr));
      
    }
  /* IP version 4 */
  else
    {
      /* Get interface address (IPv4)*/
      if(ioctl(olsr_cnf->ioctl_s, SIOCGIFADDR, &ifr) < 0) 
	{
	  OLSR_PRINTF(debuglvl, "\tCould not get address of interface - skipping it\n");
	  return 0;
	}
      
      ifs.int_addr = ifr.ifr_addr;
      
      /* Find netmask */
      
      if (ioctl(olsr_cnf->ioctl_s, SIOCGIFNETMASK, &ifr) < 0) 
	{
	  olsr_syslog(OLSR_LOG_ERR, "%s: ioctl (get netmask)", ifr.ifr_name);
	  return 0;
	}
      
      ifs.int_netmask = ifr.ifr_netmask;
      
      /* Find broadcast address */
      if(iface->cnf->ipv4_broadcast.v4)
	{
	  /* Specified broadcast */
	  memset(&ifs.int_broadaddr, 0, sizeof(struct sockaddr));
	  memcpy(&((struct sockaddr_in *)&ifs.int_broadaddr)->sin_addr.s_addr, 
		 &iface->cnf->ipv4_broadcast.v4, 
		 sizeof(olsr_u32_t));
	}
      else
	{
	  /* Autodetect */
	  if (ioctl(olsr_cnf->ioctl_s, SIOCGIFBRDADDR, &ifr) < 0) 
	    {
	      olsr_syslog(OLSR_LOG_ERR, "%s: ioctl (get broadaddr)", ifr.ifr_name);
	      return 0;
	    }
	  
	  ifs.int_broadaddr = ifr.ifr_broadaddr;
	}
      
      /* Deactivate IP spoof filter */
      deactivate_spoof(if_basename(ifr.ifr_name), &ifs, olsr_cnf->ip_version);
      
      /* Disable ICMP redirects */
      disable_redirects(if_basename(ifr.ifr_name), &ifs, olsr_cnf->ip_version);
      
    }
  
  
  /* Get interface index */
  
  ifs.if_index = if_nametoindex(ifr.ifr_name);
  
  /* Set interface metric */
  if(iface->cnf->weight.fixed)
    ifs.int_metric = iface->cnf->weight.value;
  else
    ifs.int_metric = calculate_if_metric(ifr.ifr_name);
  OLSR_PRINTF(1, "\tMetric: %d\n", ifs.int_metric);

  /* Get MTU */
  if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMTU, &ifr) < 0)
    ifs.int_mtu = OLSR_DEFAULT_MTU;
  else
    ifs.int_mtu = ifr.ifr_mtu;

  ifs.int_mtu -= (olsr_cnf->ip_version == AF_INET6) ? UDP_IPV6_HDRSIZE : UDP_IPV4_HDRSIZE;

  ifs.ttl_index = 0;

  /* Set up buffer */
  net_add_buffer(&ifs);
	       
  OLSR_PRINTF(1, "\tMTU - IPhdr: %d\n", ifs.int_mtu);

  olsr_syslog(OLSR_LOG_INFO, "Adding interface %s\n", iface->name);
  OLSR_PRINTF(1, "\tIndex %d\n", ifs.if_index);

  if(olsr_cnf->ip_version == AF_INET)
    {
      OLSR_PRINTF(1, "\tAddress:%s\n", sockaddr_to_string(&ifs.int_addr));
      OLSR_PRINTF(1, "\tNetmask:%s\n", sockaddr_to_string(&ifs.int_netmask));
      OLSR_PRINTF(1, "\tBroadcast address:%s\n", sockaddr_to_string(&ifs.int_broadaddr));
    }
  else
    {
      OLSR_PRINTF(1, "\tAddress: %s\n", ip6_to_string(&ifs.int6_addr.sin6_addr));
      OLSR_PRINTF(1, "\tMulticast: %s\n", ip6_to_string(&ifs.int6_multaddr.sin6_addr));
    }
  
  ifp = olsr_malloc(sizeof (struct interface), "Interface update 2");

  iface->configured = 1;
  iface->interf = ifp;
  
  memcpy(ifp, &ifs, sizeof(struct interface));
  
  ifp->gen_properties = NULL;
  ifp->int_name = olsr_malloc(strlen(ifr.ifr_name) + 1, "Interface update 3");
      
  strcpy(ifp->int_name, if_basename(ifr.ifr_name));
  /* Segfaults if using strncpy(IFNAMSIZ) why oh why?? */
  ifp->int_next = ifnet;
  ifnet = ifp;

  if(olsr_cnf->ip_version == AF_INET)
    {
      /* IP version 4 */
      ifp->ip_addr.v4 = ((struct sockaddr_in *)&ifp->int_addr)->sin_addr.s_addr;
      /*
       *We create one socket for each interface and bind
       *the socket to it. This to ensure that we can control
       *on what interface the message is transmitted
       */
      
      ifp->olsr_socket = getsocket((struct sockaddr *)&addrsock, bufspace, ifp->int_name);
      
      if (ifp->olsr_socket < 0)
	{
	  fprintf(stderr, "Could not initialize socket... exiting!\n\n");
	  olsr_syslog(OLSR_LOG_ERR, "Could not initialize socket... exiting!\n\n");
	  olsr_cnf->exit_value = EXIT_FAILURE;
	  kill(getpid(), SIGINT);
	}

    }
  else
    {
      /* IP version 6 */
      memcpy(&ifp->ip_addr, &ifp->int6_addr.sin6_addr, olsr_cnf->ipsize);

      
      /*
       *We create one socket for each interface and bind
       *the socket to it. This to ensure that we can control
       *on what interface the message is transmitted
       */
      
      ifp->olsr_socket = getsocket6(&addrsock6, bufspace, ifp->int_name);
      
      join_mcast(ifp, ifp->olsr_socket);
      
      if (ifp->olsr_socket < 0)
	{
	  fprintf(stderr, "Could not initialize socket... exiting!\n\n");
	  olsr_syslog(OLSR_LOG_ERR, "Could not initialize socket... exiting!\n\n");
	  olsr_cnf->exit_value = EXIT_FAILURE;
	  kill(getpid(), SIGINT);
	}
      
    }

  set_buffer_timer(ifp);

  /* Register socket */
  add_olsr_socket(ifp->olsr_socket, &olsr_input);
  
#ifdef linux 
  /* Set TOS */
  
  if (setsockopt(ifp->olsr_socket, SOL_SOCKET, SO_PRIORITY, (char*)&precedence, sizeof(precedence)) < 0)
    {
      perror("setsockopt(SO_PRIORITY)");
      olsr_syslog(OLSR_LOG_ERR, "OLSRD: setsockopt(SO_PRIORITY) error %m");
    }
  if (setsockopt(ifp->olsr_socket, SOL_IP, IP_TOS, (char*)&tos_bits, sizeof(tos_bits)) < 0)    
    {
      perror("setsockopt(IP_TOS)");
      olsr_syslog(OLSR_LOG_ERR, "setsockopt(IP_TOS) error %m");
    }
#endif
  
  /*
   *Initialize sequencenumber as a random 16bit value
   */
  ifp->olsr_seqnum = random() & 0xFFFF;

  /*
   * Set main address if this is the only interface
   */
  memset(&null_addr, 0, olsr_cnf->ipsize);
  if(COMP_IP(&null_addr, &olsr_cnf->main_addr))
    {
      COPY_IP(&olsr_cnf->main_addr, &ifp->ip_addr);
      OLSR_PRINTF(1, "New main address: %s\n", olsr_ip_to_string(&olsr_cnf->main_addr));
      olsr_syslog(OLSR_LOG_INFO, "New main address: %s\n", olsr_ip_to_string(&olsr_cnf->main_addr));
    }
  
  /*
   * Register scheduled functions 
   */

  if (olsr_cnf->lq_level == 0)
    {
      olsr_register_scheduler_event(&generate_hello, 
                                    ifp, 
                                    iface->cnf->hello_params.emission_interval, 
                                    0, 
                                    NULL);
      olsr_register_scheduler_event(&generate_tc, 
                                    ifp, 
                                    iface->cnf->tc_params.emission_interval,
                                    0, 
                                    NULL);
    }

  else
    {
      olsr_register_scheduler_event(&olsr_output_lq_hello, 
                                    ifp, 
                                    iface->cnf->hello_params.emission_interval, 
                                    0, 
                                    NULL);
      olsr_register_scheduler_event(&olsr_output_lq_tc, 
                                    ifp, 
                                    iface->cnf->tc_params.emission_interval,
                                    0, 
                                    NULL);
    }

  olsr_register_scheduler_event(&generate_mid, 
				ifp, 
				iface->cnf->mid_params.emission_interval,
				0, 
				NULL);
  olsr_register_scheduler_event(&generate_hna, 
				ifp, 
				iface->cnf->hna_params.emission_interval,
				0, 
				NULL);

  /* Recalculate max jitter */

  if((olsr_cnf->max_jitter == 0) || 
     ((iface->cnf->hello_params.emission_interval / 4) < olsr_cnf->max_jitter))
    olsr_cnf->max_jitter = iface->cnf->hello_params.emission_interval / 4;

  /* Recalculate max topology hold time */
  if(olsr_cnf->max_tc_vtime < iface->cnf->tc_params.emission_interval)
    olsr_cnf->max_tc_vtime = iface->cnf->tc_params.emission_interval;

  ifp->hello_etime = iface->cnf->hello_params.emission_interval;
  ifp->valtimes.hello = double_to_me(iface->cnf->hello_params.validity_time);
  ifp->valtimes.tc = double_to_me(iface->cnf->tc_params.validity_time);
  ifp->valtimes.mid = double_to_me(iface->cnf->mid_params.validity_time);
  ifp->valtimes.hna = double_to_me(iface->cnf->hna_params.validity_time);


  /*
   *Call possible ifchange functions registered by plugins  
   */
  run_ifchg_cbs(ifp, IFCHG_IF_ADD);

  return 1;
}




syntax highlighted by Code2HTML, v. 0.9.1