/*
 * The olsr.org Optimized Link-State Routing daemon (olsrd)
 * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
 * 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.38 2007/05/13 22:23:55 bernd67 Exp $
 */

#include "interfaces.h"
#include "olsr.h"
#include "parser.h"
#include "socket_parser.h"
#include "defs.h"
#include "net_os.h"
#include "ifnet.h"
#include "generate_msg.h"
#include "scheduler.h"
#include "mantissa.h"
#include "lq_packet.h"

#include <iphlpapi.h>
#include <iprtrmib.h>

struct MibIpInterfaceRow
{
  USHORT Family;
  ULONG64 InterfaceLuid;
  ULONG InterfaceIndex;
  ULONG MaxReassemblySize;
  ULONG64 InterfaceIdentifier;
  ULONG MinRouterAdvertisementInterval;
  ULONG MaxRouterAdvertisementInterval;
  BOOLEAN AdvertisingEnabled;
  BOOLEAN ForwardingEnabled;
  BOOLEAN WeakHostSend;
  BOOLEAN WeakHostReceive;
  BOOLEAN UseAutomaticMetric;
  BOOLEAN UseNeighborUnreachabilityDetection;   
  BOOLEAN ManagedAddressConfigurationSupported;
  BOOLEAN OtherStatefulConfigurationSupported;
  BOOLEAN AdvertiseDefaultRoute;
  INT RouterDiscoveryBehavior;
  ULONG DadTransmits;
  ULONG BaseReachableTime;
  ULONG RetransmitTime;
  ULONG PathMtuDiscoveryTimeout;
  INT LinkLocalAddressBehavior;
  ULONG LinkLocalAddressTimeout;
  ULONG ZoneIndices[16];
  ULONG SitePrefixLength;
  ULONG Metric;
  ULONG NlMtu;    
  BOOLEAN Connected;
  BOOLEAN SupportsWakeUpPatterns;   
  BOOLEAN SupportsNeighborDiscovery;
  BOOLEAN SupportsRouterDiscovery;
  ULONG ReachableTime;
  BYTE TransmitOffload;
  BYTE ReceiveOffload; 
  BOOLEAN DisableDefaultRoutes;
};

typedef DWORD (__stdcall *GETIPINTERFACEENTRY)
  (struct MibIpInterfaceRow *Row);

typedef DWORD (__stdcall *GETADAPTERSADDRESSES)
  (ULONG Family, DWORD Flags, PVOID Reserved,
   PIP_ADAPTER_ADDRESSES pAdapterAddresses, PULONG pOutBufLen);

struct InterfaceInfo
{
  unsigned int Index;
  int Mtu;
  int Metric;
  unsigned int Addr;
  unsigned int Mask;
  unsigned int Broad;
  char Guid[39];
};

void WinSockPError(char *);
char *StrError(unsigned int ErrNo);

void ListInterfaces(void);
int GetIntInfo(struct InterfaceInfo *Info, char *Name);
void RemoveInterface(struct olsr_if *IntConf);

#define MAX_INTERFACES 100

int __stdcall SignalHandler(unsigned long Signal);

static unsigned long __stdcall SignalHandlerWrapper(void *Dummy __attribute__((unused)))
{
  SignalHandler(0);
  return 0;
}

static void CallSignalHandler(void)
{
  unsigned long ThreadId;

  CreateThread(NULL, 0, SignalHandlerWrapper, NULL, 0, &ThreadId);
}

static void MiniIndexToIntName(char *String, int MiniIndex)
{
  char *HexDigits = "0123456789abcdef";

  String[0] = 'i';
  String[1] = 'f';

  String[2] = HexDigits[(MiniIndex >> 4) & 15];
  String[3] = HexDigits[MiniIndex & 15];

  String[4] = 0;
}

static int IntNameToMiniIndex(int *MiniIndex, char *String)
{
  char *HexDigits = "0123456789abcdef";
  int i, k;
  char ch;

  if ((String[0] != 'i' && String[0] != 'I') ||
      (String[1] != 'f' && String[1] != 'F'))
    return -1;

  *MiniIndex = 0;

  for (i = 2; i < 4; i++)
  {
    ch = String[i];

    if (ch >= 'A' && ch <= 'F')
      ch += 32;

    for (k = 0; k < 16 && ch != HexDigits[k]; k++);

    if (k == 16)
      return -1;

    *MiniIndex = (*MiniIndex << 4) | k;
  }

  return 0;
}

static int FriendlyNameToMiniIndex(int *MiniIndex, char *String)
{
  unsigned long BuffLen;
  unsigned long Res;
  IP_ADAPTER_ADDRESSES AdAddr[MAX_INTERFACES], *WalkerAddr;
  char FriendlyName[MAX_INTERFACE_NAME_LEN];
  HMODULE h;
  GETADAPTERSADDRESSES pfGetAdaptersAddresses;
  
  h = LoadLibrary("iphlpapi.dll");

  if (h == NULL)
  {
    fprintf(stderr, "LoadLibrary() = %08lx", GetLastError());
    return -1;
  }

  pfGetAdaptersAddresses = (GETADAPTERSADDRESSES) GetProcAddress(h, "GetAdaptersAddresses");

  if (pfGetAdaptersAddresses == NULL)
  {
    fprintf(stderr, "Unable to use adapter friendly name (GetProcAddress() = %08lx)\n", GetLastError());
    return -1;
  }
  
  BuffLen = sizeof (AdAddr);

  Res = pfGetAdaptersAddresses(AF_INET, 0, NULL, AdAddr, &BuffLen);

  if (Res != NO_ERROR)
  {  
    fprintf(stderr, "GetAdaptersAddresses() = %08lx", GetLastError());
    return -1;
  }

  for (WalkerAddr = AdAddr; WalkerAddr != NULL; WalkerAddr = WalkerAddr->Next)
  {
    OLSR_PRINTF(5, "Index = %08x - ", (int)WalkerAddr->IfIndex);

    wcstombs(FriendlyName, WalkerAddr->FriendlyName, MAX_INTERFACE_NAME_LEN); 

    OLSR_PRINTF(5, "Friendly name = %s\n", FriendlyName);

    if (strncmp(FriendlyName, String, MAX_INTERFACE_NAME_LEN) == 0)
      break;
  }

  if (WalkerAddr == NULL)
  {
    fprintf(stderr, "No such interface: %s!\n", String);
    return -1;
  }

  *MiniIndex = WalkerAddr->IfIndex & 255;
}

int GetIntInfo(struct InterfaceInfo *Info, char *Name)
{
  int MiniIndex;
  unsigned char Buff[MAX_INTERFACES * sizeof (MIB_IFROW) + 4];
  MIB_IFTABLE *IfTable;
  unsigned long BuffLen;
  unsigned long Res;
  int TabIdx;
  IP_ADAPTER_INFO AdInfo[MAX_INTERFACES], *Walker;
  HMODULE Lib;
  struct MibIpInterfaceRow Row;
  GETIPINTERFACEENTRY InterfaceEntry;

  if (olsr_cnf->ip_version == AF_INET6)
  {
    fprintf(stderr, "IPv6 not supported by GetIntInfo()!\n");
    return -1;
  }

  if ((Name[0] != 'i' && Name[0] != 'I') ||
      (Name[1] != 'f' && Name[1] != 'F'))
  {
    if (FriendlyNameToMiniIndex(&MiniIndex, Name) < 0)
    {
      fprintf(stderr, "No such interface: %s!\n", Name);
      return -1;
    }
  }

  else
  {
    if (IntNameToMiniIndex(&MiniIndex, Name) < 0)
    {
      fprintf(stderr, "No such interface: %s!\n", Name);
      return -1;
    }
  }

  IfTable = (MIB_IFTABLE *)Buff;

  BuffLen = sizeof (Buff);

  Res = GetIfTable(IfTable, &BuffLen, FALSE);

  if (Res != NO_ERROR)
  {
    fprintf(stderr, "GetIfTable() = %08lx, %s", Res, StrError(Res));
    return -1;
  }

  for (TabIdx = 0; TabIdx < (int)IfTable->dwNumEntries; TabIdx++)
  {
    OLSR_PRINTF(5, "Index = %08x\n", (int)IfTable->table[TabIdx].dwIndex);

    if ((int)(IfTable->table[TabIdx].dwIndex & 255) == MiniIndex)
      break;
  }

  if (TabIdx == (int)IfTable->dwNumEntries)
  {
    fprintf(stderr, "No such interface: %s!\n", Name);
    return -1;
  }
    
  Info->Index = IfTable->table[TabIdx].dwIndex;
  Info->Mtu = (int)IfTable->table[TabIdx].dwMtu;

  Info->Mtu -= (olsr_cnf->ip_version == AF_INET6) ?
    UDP_IPV6_HDRSIZE : UDP_IPV4_HDRSIZE;

  Lib = LoadLibrary("iphlpapi.dll");

  if (Lib == NULL)
  {
    fprintf(stderr, "Cannot load iphlpapi.dll: %08lx\n", GetLastError());
    return -1;
  }

  InterfaceEntry = (GETIPINTERFACEENTRY)GetProcAddress(Lib, "GetIpInterfaceEntry");

  if (InterfaceEntry == NULL)
  {
    OLSR_PRINTF(5, "Not running on Vista - setting interface metric to 0.\n");

    Info->Metric = 0;
  }

  else
  {
    memset(&Row, 0, sizeof (struct MibIpInterfaceRow));

    Row.Family = AF_INET;
    Row.InterfaceIndex = Info->Index;

    Res = InterfaceEntry(&Row);

    if (Res != NO_ERROR)
    {
      fprintf(stderr, "GetIpInterfaceEntry() = %08lx", Res);
      FreeLibrary(Lib);
      return -1;
    }

    Info->Metric = Row.Metric;

    OLSR_PRINTF(5, "Running on Vista - interface metric is %d.\n", Info->Metric);
  }

  FreeLibrary(Lib);

  BuffLen = sizeof (AdInfo);

  Res = GetAdaptersInfo(AdInfo, &BuffLen);

  if (Res != NO_ERROR)
  {
    fprintf(stderr, "GetAdaptersInfo() = %08lx, %s", GetLastError(),
            StrError(Res));
    return -1;
  }

  for (Walker = AdInfo; Walker != NULL; Walker = Walker->Next)
  {
    OLSR_PRINTF(5, "Index = %08x\n", (int)Walker->Index);

    if ((int)(Walker->Index & 255) == MiniIndex)
      break;
  }

  if (Walker == NULL)
  {
    fprintf(stderr, "No such interface: %s!\n", Name);
    return -1;
  }

  inet_pton(AF_INET, Walker->IpAddressList.IpAddress.String, &Info->Addr);
  inet_pton(AF_INET, Walker->IpAddressList.IpMask.String, &Info->Mask);

  Info->Broad = Info->Addr | ~Info->Mask;

  strcpy(Info->Guid, Walker->AdapterName);

  if ((IfTable->table[TabIdx].dwOperStatus != MIB_IF_OPER_STATUS_CONNECTED &&
      IfTable->table[TabIdx].dwOperStatus != MIB_IF_OPER_STATUS_OPERATIONAL) ||
      Info->Addr == 0)
  {
    OLSR_PRINTF(3, "Interface %s not up!\n", Name);
    return -1;
  }

  return 0;
}

#if !defined OID_802_11_CONFIGURATION
#define OID_802_11_CONFIGURATION 0x0d010211
#endif

#if !defined IOCTL_NDIS_QUERY_GLOBAL_STATS
#define IOCTL_NDIS_QUERY_GLOBAL_STATS 0x00170002
#endif

static int IsWireless(char *IntName)
{
#if !defined WINCE
  struct InterfaceInfo Info;
  char DevName[43];
  HANDLE DevHand;
  unsigned int ErrNo;
  unsigned int Oid;
  unsigned char OutBuff[100];
  unsigned long OutBytes;

  if (GetIntInfo(&Info, IntName) < 0)
    return -1;

  DevName[0] = '\\';
  DevName[1] = '\\';
  DevName[2] = '.';
  DevName[3] = '\\';

  strcpy(DevName + 4, Info.Guid);

  OLSR_PRINTF(5, "Checking whether interface %s is wireless.\n", DevName);

  DevHand = CreateFile(DevName, GENERIC_READ,
                       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL, NULL);

  if (DevHand == INVALID_HANDLE_VALUE)
  {
    ErrNo = GetLastError();

    OLSR_PRINTF(5, "CreateFile() = %08x, %s\n", ErrNo, StrError(ErrNo));
    return -1;
  }

  Oid = OID_802_11_CONFIGURATION;

  if (!DeviceIoControl(DevHand, IOCTL_NDIS_QUERY_GLOBAL_STATS,
                       &Oid, sizeof (Oid),
                       OutBuff, sizeof (OutBuff),
                       &OutBytes, NULL))
  {
    ErrNo = GetLastError();

    CloseHandle(DevHand);

    if (ErrNo == ERROR_GEN_FAILURE || ErrNo == ERROR_INVALID_PARAMETER)
    {
      OLSR_PRINTF(5, "OID not supported. Device probably not wireless.\n");
      return 0;
    }

    OLSR_PRINTF(5, "DeviceIoControl() = %08x, %s\n", ErrNo, StrError(ErrNo));
    return -1;
  }

  CloseHandle(DevHand);
#endif
  return 1;
}

void ListInterfaces(void)
{
  IP_ADAPTER_INFO AdInfo[MAX_INTERFACES], *Walker;
  unsigned long AdInfoLen;
  char IntName[5];
  IP_ADDR_STRING *Walker2;
  unsigned long Res;
  int IsWlan;
  
  if (olsr_cnf->ip_version == AF_INET6)
  {
    fprintf(stderr, "IPv6 not supported by ListInterfaces()!\n");
    return;
  }

  AdInfoLen = sizeof (AdInfo);

  Res = GetAdaptersInfo(AdInfo, &AdInfoLen);

  if (Res == ERROR_NO_DATA)
  {
    printf("No interfaces detected.\n");
    return;
  }
  
  if (Res != NO_ERROR)
  {
    fprintf(stderr, "GetAdaptersInfo() = %08lx, %s", Res, StrError(Res));
    return;
  }

  for (Walker = AdInfo; Walker != NULL; Walker = Walker->Next)
  {
    OLSR_PRINTF(5, "Index = %08x\n", (int)Walker->Index);

    MiniIndexToIntName(IntName, Walker->Index);

    printf("%s: ", IntName);

    IsWlan = IsWireless(IntName);

    if (IsWlan < 0)
      printf("?");

    else if (IsWlan == 0)
      printf("-");

    else
      printf("+");

    for (Walker2 = &Walker->IpAddressList; Walker2 != NULL;
         Walker2 = Walker2->Next)
      printf(" %s", Walker2->IpAddress.String);

    printf("\n");
  }
}

void RemoveInterface(struct olsr_if *IntConf)
{
  struct interface *Int, *Prev;

  OLSR_PRINTF(1, "Removing interface %s.\n", IntConf->name);
  
  Int = IntConf->interf;

  run_ifchg_cbs(Int, IFCHG_IF_ADD);

  if (Int == ifnet)
    ifnet = Int->int_next;

  else
  {
    for (Prev = ifnet; Prev->int_next != Int; Prev = Prev->int_next);

    Prev->int_next = Int->int_next;
  }

  if(COMP_IP(&olsr_cnf->main_addr, &Int->ip_addr))
  {
    if(ifnet == NULL)
    {
      memset(&olsr_cnf->main_addr, 0, olsr_cnf->ipsize);
      OLSR_PRINTF(1, "Removed last interface. Cleared main address.\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));
    }
  }

  if (olsr_cnf->lq_level == 0)
    {
      olsr_remove_scheduler_event(&generate_hello, Int,
                                  IntConf->cnf->hello_params.emission_interval,
                                  0, NULL);

      olsr_remove_scheduler_event(&generate_tc, Int,
                                  IntConf->cnf->tc_params.emission_interval,
                                  0, NULL);
    }

  else
    {
      olsr_remove_scheduler_event(&olsr_output_lq_hello, Int,
                                  IntConf->cnf->hello_params.emission_interval,
                                  0, NULL);

      olsr_remove_scheduler_event(&olsr_output_lq_tc, Int,
                                  IntConf->cnf->tc_params.emission_interval,
                                  0, NULL);
    }

  olsr_remove_scheduler_event(&generate_mid, Int,
                              IntConf->cnf->mid_params.emission_interval,
                              0, NULL);

  olsr_remove_scheduler_event(&generate_hna, Int,
                              IntConf->cnf->hna_params.emission_interval,
                              0, NULL);

  net_remove_buffer(Int);

  IntConf->configured = 0;
  IntConf->interf = NULL;

  closesocket(Int->olsr_socket);
  remove_olsr_socket(Int->olsr_socket, &olsr_input);

  free(Int->int_name);
  free(Int);

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

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));
    }

  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");
	  exit(1);
	}

    }
  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");
	  exit(1);
	}
      
#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, (char *)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;
}

int chk_if_changed(struct olsr_if *IntConf)
{
  struct interface *Int;
  struct InterfaceInfo Info;
  int Res;
  int IsWlan;
  union olsr_ip_addr OldVal, NewVal;
  struct sockaddr_in *AddrIn;

  if (olsr_cnf->ip_version == AF_INET6)
  {
    fprintf(stderr, "IPv6 not supported by chk_if_changed()!\n");
    return 0;
  }

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

  Int = IntConf->interf;

  if (GetIntInfo(&Info, IntConf->name) < 0)
  {
    RemoveInterface(IntConf);
    return 1;
  }

  Res = 0;

  IsWlan = IsWireless(IntConf->name);

  if (IsWlan < 0)
    IsWlan = 1;

  if (Int->is_wireless != IsWlan)
  {
    OLSR_PRINTF(1, "\tLAN/WLAN change: %d -> %d.\n", Int->is_wireless, IsWlan);

    Int->is_wireless = IsWlan;

    if (IntConf->cnf->weight.fixed)
      Int->int_metric = IntConf->cnf->weight.value;

    else
      Int->int_metric = Info.Metric;

    Res = 1;
  }

  if (Int->int_mtu != Info.Mtu)
  {
    OLSR_PRINTF(1, "\tMTU change: %d -> %d.\n", (int)Int->int_mtu,
                Info.Mtu);

    Int->int_mtu = Info.Mtu;

    net_remove_buffer(Int);
    net_add_buffer(Int);

    Res = 1;
  }

  OldVal.v4 = ((struct sockaddr_in *)&Int->int_addr)->sin_addr.s_addr;
  NewVal.v4 = Info.Addr;

#ifdef DEBUG
  OLSR_PRINTF(3, "\tAddress: %s\n", olsr_ip_to_string(&NewVal));
#endif

  if (NewVal.v4 != OldVal.v4)
  {
    OLSR_PRINTF(1, "\tAddress change.\n");
    OLSR_PRINTF(1, "\tOld: %s\n", olsr_ip_to_string(&OldVal));
    OLSR_PRINTF(1, "\tNew: %s\n", olsr_ip_to_string(&NewVal));

    Int->ip_addr.v4 = NewVal.v4;

    AddrIn = (struct sockaddr_in *)&Int->int_addr;

    AddrIn->sin_family = AF_INET;
    AddrIn->sin_port = 0;
    AddrIn->sin_addr.s_addr = NewVal.v4;

    if (olsr_cnf->main_addr.v4 == OldVal.v4)
    {
      OLSR_PRINTF(1, "\tMain address change.\n");

      olsr_cnf->main_addr.v4 = NewVal.v4;
    }

    Res = 1;
  }

  else
    OLSR_PRINTF(3, "\tNo address change.\n");

  OldVal.v4 = ((struct sockaddr_in *)&Int->int_netmask)->sin_addr.s_addr;
  NewVal.v4 = Info.Mask;

#ifdef DEBUG
  OLSR_PRINTF(3, "\tNetmask: %s\n", olsr_ip_to_string(&NewVal));
#endif

  if (NewVal.v4 != OldVal.v4)
  {
    OLSR_PRINTF(1, "\tNetmask change.\n");
    OLSR_PRINTF(1, "\tOld: %s\n", olsr_ip_to_string(&OldVal));
    OLSR_PRINTF(1, "\tNew: %s\n", olsr_ip_to_string(&NewVal));

    AddrIn = (struct sockaddr_in *)&Int->int_netmask;

    AddrIn->sin_family = AF_INET;
    AddrIn->sin_port = 0;
    AddrIn->sin_addr.s_addr = NewVal.v4;

    Res = 1;
  }

  else
    OLSR_PRINTF(3, "\tNo netmask change.\n");

  OldVal.v4 = ((struct sockaddr_in *)&Int->int_broadaddr)->sin_addr.s_addr;
  NewVal.v4 = Info.Broad;

#ifdef DEBUG
  OLSR_PRINTF(3, "\tBroadcast address: %s\n", olsr_ip_to_string(&NewVal));
#endif

  if (NewVal.v4 != OldVal.v4)
  {
    OLSR_PRINTF(1, "\tBroadcast address change.\n");
    OLSR_PRINTF(1, "\tOld: %s\n", olsr_ip_to_string(&OldVal));
    OLSR_PRINTF(1, "\tNew: %s\n", olsr_ip_to_string(&NewVal));

    AddrIn = (struct sockaddr_in *)&Int->int_broadaddr;

    AddrIn->sin_family = AF_INET;
    AddrIn->sin_port = 0;
    AddrIn->sin_addr.s_addr = NewVal.v4;

    Res = 1;
  }

  else
    OLSR_PRINTF(3, "\tNo broadcast address change.\n");

  if (Res != 0)
    run_ifchg_cbs(Int, IFCHG_IF_UPDATE);

  return Res;
}

int chk_if_up(struct olsr_if *IntConf, int DebugLevel __attribute__((unused)))
{
  struct InterfaceInfo Info;
  struct interface *New;
  union olsr_ip_addr NullAddr;
  unsigned int AddrSockAddr;
  int IsWlan;
  struct sockaddr_in *AddrIn;
  
  if (olsr_cnf->ip_version == AF_INET6)
  {
    fprintf(stderr, "IPv6 not supported by chk_if_up()!\n");
    return 0;
  }

  if (GetIntInfo(&Info, IntConf->name) < 0)
    return 0;

  New = olsr_malloc(sizeof (struct interface), "Interface 1");
  New->gen_properties = NULL;

  AddrIn = (struct sockaddr_in *)&New->int_addr;

  AddrIn->sin_family = AF_INET;
  AddrIn->sin_port = 0;
  AddrIn->sin_addr.s_addr = Info.Addr;

  AddrIn = (struct sockaddr_in *)&New->int_netmask;

  AddrIn->sin_family = AF_INET;
  AddrIn->sin_port = 0;
  AddrIn->sin_addr.s_addr = Info.Mask;

  AddrIn = (struct sockaddr_in *)&New->int_broadaddr;

  AddrIn->sin_family = AF_INET;
  AddrIn->sin_port = 0;
  AddrIn->sin_addr.s_addr = Info.Broad;

  if (IntConf->cnf->ipv4_broadcast.v4 != 0)
    AddrIn->sin_addr.s_addr = IntConf->cnf->ipv4_broadcast.v4;

  New->int_flags = 0;

  New->is_hcif = OLSR_FALSE;

  New->int_mtu = Info.Mtu;

  New->int_name = olsr_malloc(strlen (IntConf->name) + 1, "Interface 2");
  strcpy(New->int_name, IntConf->name);

  IsWlan = IsWireless(IntConf->name);

  if (IsWlan < 0)
    IsWlan = 1;

  New->is_wireless = IsWlan;

  if (IntConf->cnf->weight.fixed)
    New->int_metric = IntConf->cnf->weight.value;

  else
    New->int_metric = Info.Metric;

  New->olsr_seqnum = random() & 0xffff;

  New->ttl_index = 0;
    
  OLSR_PRINTF(1, "\tInterface %s set up for use with index %d\n\n",
              IntConf->name, New->if_index);
      
  OLSR_PRINTF(1, "\tMTU: %d\n", New->int_mtu);
  OLSR_PRINTF(1, "\tAddress: %s\n", sockaddr_to_string(&New->int_addr));
  OLSR_PRINTF(1, "\tNetmask: %s\n", sockaddr_to_string(&New->int_netmask));
  OLSR_PRINTF(1, "\tBroadcast address: %s\n",
              sockaddr_to_string(&New->int_broadaddr));

  New->ip_addr.v4 =
    ((struct sockaddr_in *)&New->int_addr)->sin_addr.s_addr;
      
  New->if_index = Info.Index;

  OLSR_PRINTF(3, "\tKernel index: %08x\n", New->if_index);

  AddrSockAddr = addrsock.sin_addr.s_addr;
  addrsock.sin_addr.s_addr = New->ip_addr.v4;

  New->olsr_socket = getsocket((struct sockaddr *)&addrsock,
                               127 * 1024, New->int_name);
      
  addrsock.sin_addr.s_addr = AddrSockAddr;

  if (New->olsr_socket < 0)
  {
    fprintf(stderr, "Could not initialize socket... exiting!\n\n");
    exit(1);
  }

  add_olsr_socket(New->olsr_socket, &olsr_input);

  New->int_next = ifnet;
  ifnet = New;

  IntConf->interf = New;
  IntConf->configured = 1;

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

  net_add_buffer(New);

  if (olsr_cnf->lq_level == 0)
  {
    olsr_register_scheduler_event(&generate_hello, New,
                                  IntConf->cnf->hello_params.emission_interval,
                                  0, NULL);

    olsr_register_scheduler_event(&generate_tc, New,
                                  IntConf->cnf->tc_params.emission_interval,
                                  0, NULL);
  }

  else
  {
    olsr_register_scheduler_event(&olsr_output_lq_hello, New,
                                  IntConf->cnf->hello_params.emission_interval,
                                  0, NULL);

    olsr_register_scheduler_event(&olsr_output_lq_tc, New,
                                  IntConf->cnf->tc_params.emission_interval,
                                  0, NULL);
  }

  olsr_register_scheduler_event(&generate_mid, New,
                                IntConf->cnf->mid_params.emission_interval,
                                0, NULL);

  olsr_register_scheduler_event(&generate_hna, New,
                                IntConf->cnf->hna_params.emission_interval,
                                0, NULL);

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

  if(olsr_cnf->max_tc_vtime < IntConf->cnf->tc_params.emission_interval)
    olsr_cnf->max_tc_vtime = IntConf->cnf->tc_params.emission_interval;

  New->hello_etime = IntConf->cnf->hello_params.emission_interval;

  New->valtimes.hello = double_to_me(IntConf->cnf->hello_params.validity_time);
  New->valtimes.tc = double_to_me(IntConf->cnf->tc_params.validity_time);
  New->valtimes.mid = double_to_me(IntConf->cnf->mid_params.validity_time);
  New->valtimes.hna = double_to_me(IntConf->cnf->hna_params.validity_time);

  run_ifchg_cbs(New, IFCHG_IF_ADD);

  return 1;
}

void check_interface_updates(void *dummy __attribute__((unused)))
{
  struct olsr_if *IntConf;

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

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

    else
      chk_if_up(IntConf, 3);
  }
}


syntax highlighted by Code2HTML, v. 0.9.1