[Olsr-cvs] olsrd-current/lib/bmf/src Address.c, NONE, 1.1 Address.h, NONE, 1.1 Bmf.c, NONE, 1.1 Bmf.h, NONE, 1.1 DropList.c, NONE, 1.1 DropList.h, NONE, 1.1 NetworkInterfaces.c, NONE, 1.1 NetworkInterfaces.h, NONE, 1.1 Packet.c, NONE, 1.1 Packet.h, NONE, 1.1 PacketHistory.c, NONE, 1.1 PacketHistory.h, NONE, 1.1 olsrd_plugin.c, NONE, 1.1

Andreas T�nnesen (spam-protected)
Wed May 3 10:59:06 CEST 2006


Update of /cvsroot/olsrd/olsrd-current/lib/bmf/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2222/bmf/src

Added Files:
	Address.c Address.h Bmf.c Bmf.h DropList.c DropList.h 
	NetworkInterfaces.c NetworkInterfaces.h Packet.c Packet.h 
	PacketHistory.c PacketHistory.h olsrd_plugin.c 
Log Message:
Initial addittion of the BMF multicast plugin

--- NEW FILE: Packet.h ---
#ifndef _BMF_PACKET_H
#define _BMF_PACKET_H

/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: Packet.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

/* System includes */
#include <net/if.h> /* IFNAMSIZ, IFHWADDRLEN */
#include <sys/types.h> /* u_int8_t, u_int16_t */

/* Offsets and sizes into IP-ethernet packets */
#define IPV4_ADDR_SIZE 4
#define ETH_TYPE_OFFSET (2*IFHWADDRLEN)
#define ETH_TYPE_LEN 2
#define IP_HDR_OFFSET (ETH_TYPE_OFFSET + ETH_TYPE_LEN)
#define IPV4_OFFSET_SRCIP 12
#define IPV4_OFFSET_DSTIP (IPV4_OFFSET_SRCIP + IPV4_ADDR_SIZE)

#define IPV4_TYPE 0x0800

struct TSaveTtl
{
  u_int8_t ttl;
  u_int16_t check;
};

int GetIpTtl(unsigned char* buffer);
void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl);
void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl);
void PacketDecreaseTtlAndUpdateHeaderChecksum(unsigned char* buffer);

#endif /* _BMF_PACKET_H */

--- NEW FILE: Address.h ---
#ifndef _BMF_ADDRESS_H
#define _BMF_ADDRESS_H

/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: Address.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

#include "olsr_types.h" /* olsr_ip_addr */
#include "interfaces.h" /* struct interface */

int IsMulticast(union olsr_ip_addr* ipAddress);
int IsLocalBroadcast(union olsr_ip_addr* destIp, struct interface* ifFrom);
int IsOlsrOrBmfPacket(unsigned char* buffer, ssize_t len);

#endif /* _BMF_ADDRESS_H */

--- NEW FILE: DropList.h ---
#ifndef _BMF_DROPLIST_H
#define _BMF_DROPLIST_H

/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: DropList.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

struct TMacAddress
{
  unsigned char addr[6];
  struct TMacAddress* next;
};

int DropMac(const char* macStr);
int IsInDropList(const unsigned char* macAddress);

#endif /* _BMF_DROPLIST_H */

--- NEW FILE: Packet.c ---
/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: Packet.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

#include "Packet.h"

/* System includes */
#include <assert.h> /* assert() */
#include <sys/types.h> /* u_int32_t */
#include <netinet/in.h> /* ntohs(), htons() */
#include <linux/ip.h>

/* Retrieve the TTL (Time To Live) value from the IP header of the
 * passed ethernet packet */
int GetIpTtl(unsigned char* buffer)
{
  struct iphdr* iph;

  assert(buffer != NULL);

  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
  return iph->ttl;
}

void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
{
  struct iphdr* iph;

  assert(buffer != NULL && sttl != NULL);

  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
  sttl->ttl = iph->ttl;
  sttl->check = ntohs(iph->check);
}

void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
{
  struct iphdr* iph;

  assert(buffer != NULL && sttl != NULL);

  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
  iph->ttl = sttl->ttl;
  iph->check = htons(sttl->check);
}

/* For an IP packet, decrement the TTL value and update the IP header
 * checksum accordingly. See also RFC1141. */
void PacketDecreaseTtlAndUpdateHeaderChecksum(unsigned char* buffer)
{
  struct iphdr* iph;
  u_int32_t sum;

  assert(buffer != NULL);

  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);

  iph->ttl--; /* decrement ttl */
  sum = ntohs(iph->check) + 0x100; /* increment checksum high byte */
  iph->check = htons(sum + (sum>>16)); /* add carry */
}

--- NEW FILE: olsrd_plugin.c ---
/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: olsrd_plugin.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

/*
 * Dynamic linked library for olsr.org olsrd
 */

/* System includes */
#include <assert.h> /* assert() */
#include <stdio.h>

/* OLSRD includes */
#include "olsrd_plugin.h"

/* BMF includes */
#include "Bmf.h" /* InitBmf(), CloseBmf(), RegisterBmfParameter() */

static void __attribute__ ((constructor)) my_init(void);
static void __attribute__ ((destructor)) my_fini(void);

void olsr_plugin_exit(void);

/* Plugin interface version
 * Used by main olsrd to check plugin interface version */
int olsrd_plugin_interface_version()
{
  return OLSRD_PLUGIN_INTERFACE_VERSION;
}

int olsrd_plugin_init()
{
  return InitBmf();
}

/* destructor - called at unload */
void olsr_plugin_exit()
{
  CloseBmf();
}

/* Register parameters from config file
 * Called for all plugin parameters */
int olsrd_plugin_register_param(char* key, char* value)
{
  assert(key != NULL && value != NULL);

  return RegisterBmfParameter(key, value);
}
 
static void my_init()
{
  /* Print plugin info to stdout */
  printf("%s\n", MOD_DESC);

  return;
}

static void my_fini()
{
  olsr_plugin_exit();
}

--- NEW FILE: DropList.c ---
/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: DropList.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */


#include "DropList.h"

/* System includes */
#include <assert.h> /* assert() */
#include <stdio.h> /* NULL */
#include <stdlib.h> /* malloc */
#include <string.h> /* memcmp */

/* OLSRD includes */
#include "olsr.h" /* olsr_printf */

/* Plugin includes */
#include "Bmf.h" /* PLUGIN_NAME */
#include "Packet.h" /* IFHWADDRLEN */

static struct TMacAddress* DroppedMacAddresses = NULL;

/* Register a MAC address in the drop list. The registered MAC address will be matched
 * to the source MAC address of incoming multicast packets. If matched, the multicast
 * packet will be silently dropped.
 * The drop list is needed only in lab environments, where hidden nodes are simulated
 * by using iptables with the -m mac --mac-source option (as in:
 * "iptables -A INPUT -m mac --mac-source 00:0C:29:EE:C9:D0 -j DROP")
 * The drop list is needed because network interfaces in promiscuous mode will still
 * capture packets even if they are specified to be dropped by iptables.
 */
int DropMac(const char* macStr)
{
  unsigned int mac[6];
  int n;
  struct TMacAddress* newMacAddress;
  int i;

  assert(macStr != NULL);

  n = sscanf(macStr, "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
  if (n != 6)
  {
    olsr_printf(1, "%s: Invalid Ethernet address '%s'\n", PLUGIN_NAME, macStr);
    return 0;
  }

  newMacAddress = malloc(sizeof(struct TMacAddress));
  for (i = 0; i < 6; i++)
  {
    newMacAddress->addr[i] = (unsigned char) mac[i];
  }
  newMacAddress->next = DroppedMacAddresses;
  DroppedMacAddresses = newMacAddress;

  return 1;
}

/* Return 1 if macAddress is in the drop list, else 0 */
int IsInDropList(const unsigned char* macAddress)
{
  struct TMacAddress* ma = DroppedMacAddresses;

  assert(macAddress != NULL);

  while (ma != NULL)
  {
    if (memcmp(ma->addr, macAddress, IFHWADDRLEN) == 0) return 1;
    ma = ma->next;
  }
  return 0;
}


--- NEW FILE: Address.c ---
/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: Address.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

#include "Address.h"

/* System includes */
#include <assert.h> /* assert() */

/* OLSRD includes */
#include "defs.h" /* COMP_IP */

/* Plugin includes */
#include "Bmf.h" /* BMF_ENCAP_PORT */

int IsMulticast(union olsr_ip_addr* ipAddress)
{
  assert(ipAddress != NULL);

  return (ntohl(ipAddress->v4) & 0xF0000000) == 0xE0000000;
}

int IsLocalBroadcast(union olsr_ip_addr* destIp, struct interface* ifFrom)
{
  struct sockaddr_in* sin;
  
  assert(destIp != NULL);

  /* Protect ourselves against bogus input */
  if (ifFrom == NULL) return 0;

  /* Cast down to correct sockaddr subtype */
  sin = (struct sockaddr_in*)&(ifFrom->int_broadaddr);

  /* Just in case OLSR does not have int_broadaddr filled in for this
   * interface. */
  if (sin == NULL) return 0;

  return COMP_IP(&(sin->sin_addr.s_addr), destIp);
}

int IsOlsrOrBmfPacket(unsigned char* buffer, ssize_t len)
{
  u_int16_t port;

  assert(buffer != NULL);

  /* Consider OLSR and BMF packets not to be local broadcast
   * OLSR packets are UDP - port 698
   * BMF packets are UDP - port 50505 */

  memcpy(&port, buffer + 0x24, 2);
  port = ntohs(port);

  if (len > 0x25 &&
      buffer[0x17] == 0x11 && /* UDP */
      (port == OLSRPORT || port == BMF_ENCAP_PORT))
  {
    return 1;
  }
  return 0;
}

--- NEW FILE: Bmf.h ---
#ifndef _BMF_BMF_H
#define _BMF_BMF_H

/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: Bmf.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

/* BMF plugin data */
#define PLUGIN_NAME "OLSRD Basic Multicast Forwarding plugin"
#define PLUGIN_VERSION "1.0.1 (" __DATE__ " " __TIME__ ")"
#define PLUGIN_COPYRIGHT "  (C) Thales Communications Huizen, Netherlands"
#define PLUGIN_AUTHOR "  Erik Tromp ((spam-protected))"
#define MOD_DESC PLUGIN_NAME " " PLUGIN_VERSION "\n" PLUGIN_COPYRIGHT "\n" PLUGIN_AUTHOR

/* UDP-Port on which multicast packets are encapsulated */
#define BMF_ENCAP_PORT 50505

int InitBmf(void);
void CloseBmf(void);
int RegisterBmfParameter(char* key, char* value);

#endif /* _BMF_BMF_H */

--- NEW FILE: PacketHistory.c ---
/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: PacketHistory.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

#include "PacketHistory.h"

/* System includes */
#include <assert.h> /* assert() */
#include <sys/types.h> /* u_int16_t, u_int32_t */
#include <string.h> /* memset */

/* OLSRD includes */
#include "olsr.h" /* olsr_printf */

/* Plugin includes */
#include "Packet.h"

static u_int32_t PacketHistory[HISTORY_TABLE_SIZE];

/* Calculate 16-bits CRC according to CRC-CCITT specification, modified
 * to leave out some parts of the packet. */
static u_int16_t CalcCrcCcitt(unsigned char* buffer, ssize_t len)
{
  /* Initial value of 0xFFFF should be 0x1D0F according to
   * www.joegeluso.com/software/articles/ccitt.htm */
  u_int16_t crc = 0xFFFF; 
  int i;

  assert(buffer != NULL);

  for (i = 0; i < len; i++)
  {
    /* Skip IP header checksum; we want to avoid as much as possible
     * calculating a checksum over data containing a checksum */
    if (i >= 12 && i < 14) continue;

    crc  = (unsigned char)(crc >> 8) | (crc << 8);
    crc ^= buffer[i];
    crc ^= (unsigned char)(crc & 0xff) >> 4;
    crc ^= (crc << 8) << 4;
    crc ^= ((crc & 0xff) << 4) << 1;
  }
  return crc;

#if 0
  /* Alternative, simpler and perhaps just as good: add source IP address,
   * destination IP address and IP identification, in 16-bit */
  return
    ((buffer[0x0E] << 8) + buffer[0x0F]) + ((buffer[0x10] << 8) + buffer[0x11]) +
    ((buffer[0x12] << 8) + buffer[0x13]) + ((buffer[0x14] << 8) + buffer[0x15]) +
    ((buffer[0x06] << 8) + buffer[0x07]);
#endif
}

void InitPacketHistory()
{
  memset(PacketHistory, 0, sizeof(PacketHistory));
}

/* Record the fact that this packet was seen recently */
void MarkRecentPacket(unsigned char* buffer, ssize_t len)
{
  u_int16_t crc;
  u_int32_t index;
  uint offset;

  assert(buffer != NULL);

  /* Start CRC calculation at ethertype; skip source and destination MAC 
   * addresses */
  crc = CalcCrcCcitt(buffer + ETH_TYPE_OFFSET, len - ETH_TYPE_OFFSET);

  index = crc / NPACKETS_PER_ENTRY;
  assert(index < HISTORY_TABLE_SIZE);

  offset = (crc % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET;
  assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET);

  /* Mark "seen recently" */
  PacketHistory[index] = PacketHistory[index] | (0x3u << offset);
}

/* Check if this packet was seen recently */
int CheckMarkRecentPacket(unsigned char* buffer, ssize_t len)
{
  u_int16_t crc;
  u_int32_t index;
  uint offset;
  u_int32_t bitMask;
  int result;

  assert(buffer != NULL);

  /* Start CRC calculation at ethertype; skip source and destination MAC 
   * addresses */
  crc = CalcCrcCcitt(buffer + ETH_TYPE_OFFSET, len - ETH_TYPE_OFFSET);

  index = crc / NPACKETS_PER_ENTRY;
  assert(index < HISTORY_TABLE_SIZE);

  offset =  (crc % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET;
  assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET);

  bitMask = 0x1u << offset;
  result = ((PacketHistory[index] & bitMask) == bitMask);
  
  /* Always mark "seen recently" */
  PacketHistory[index] = PacketHistory[index] | (0x3u << offset);

  return result;
}
  
void PrunePacketHistory(void* useless)
{
  uint i;
  for (i = 0; i < HISTORY_TABLE_SIZE; i++)
  {
    if (PacketHistory[i] > 0)
    {
      uint j;
      for (j = 0; j < NPACKETS_PER_ENTRY; j++)
      {
        uint offset = j * NBITS_PER_PACKET;

        u_int32_t bitMask = 0x3u << offset;
        u_int32_t bitsSeenRecenty = 0x3u << offset;
        u_int32_t bitsTimingOut = 0x1u << offset;

        /* 10 should never occur */
        assert ((PacketHistory[i] & bitMask) != (0x2u << offset));
        
        if ((PacketHistory[i] & bitMask) == bitsSeenRecenty)
        {
          /* 11 -> 01 */
          PacketHistory[i] &= ~bitMask | bitsTimingOut;
        }
        else if ((PacketHistory[i] & bitMask) == bitsTimingOut)
        {
          /* 01 -> 00 */
          PacketHistory[i] &= ~bitMask;
        }
      } /* for (j = ...) */
    } /* if (PacketHistory[i] > 0) */
  } /* for (i = ...) */
}

--- NEW FILE: NetworkInterfaces.h ---
#ifndef _BMF_NETWORKINTERFACES_H
#define _BMF_NETWORKINTERFACES_H

/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: NetworkInterfaces.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

/* Plugin includes */
#include "Packet.h" /* IFHWADDRLEN */

struct TBmfInterface
{
  /* File descriptor of raw packet socket, used for capturing multicast packets */
  int capturingSkfd;

  /* File descriptor of UDP (datagram) socket for encapsulated multicast packets. 
   * Set to -1 if interface is not OLSR-enabled. */
  int encapsulatingSkfd;

  unsigned char macAddr[IFHWADDRLEN];

  char ifName[IFNAMSIZ];

  /* OLSRs idea of this network interface. NULL if this interface is not
   * OLSR-enabled. */
  struct interface* olsrIntf;

  /* Kernels index of this network interface */
  int ifIndex;
  
  /* Next element in list */
  struct TBmfInterface* next; 
};

extern struct TBmfInterface* BmfInterfaces;

extern int EtherTunTapFd;

extern const char* EtherTunTapIfName;

enum TTunOrTap { TT_TUN = 0, TT_TAP };
extern enum TTunOrTap TunOrTap;

int CreateBmfNetworkInterfaces(void);
void CloseBmfNetworkInterfaces(void);
int AddNonOlsrBmfIf(const char* ifName);
int IsNonOlsrBmfIf(const char* ifName);

#endif /* _BMF_NETWORKINTERFACES_H */

--- NEW FILE: Bmf.c ---
/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: Bmf.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

#define _MULTI_THREADED

#include "Bmf.h"

/* System includes */
#include <stdio.h> /* NULL */
#include <sys/types.h> /* ssize_t */
#include <string.h> /* strerror() */
#include <errno.h> /* errno */
#include <assert.h> /* assert() */
#include <linux/if_packet.h> /* struct sockaddr_ll, PACKET_MULTICAST */
#include <pthread.h> /* pthread_create() */
#include <signal.h> /* SIGINT */

/* OLSRD includes */
#include "defs.h" /* olsr_cnf */
#include "olsr.h" /* olsr_printf */
#include "scheduler.h" /* olsr_register_scheduler_event */
#include "mid_set.h" /* mid_lookup_main_addr() */
#include "mpr_selector_set.h" /* olsr_lookup_mprs_set() */

/* Plugin includes */
#include "NetworkInterfaces.h" /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */
#include "Address.h" /* IsMulticast(), IsLocalBroadcast() */
#include "Packet.h" /* ETH_TYPE_OFFSET, IFHWADDRLEN etc. */
#include "PacketHistory.h" /* InitPacketHistory() */
#include "DropList.h" /* DropMac() */

static pthread_t BmfThread;
static int BmfThreadRunning = 0;


static void BmfPacketCaptured(struct TBmfInterface* intf, unsigned char* buffer, ssize_t len)
{
  struct interface* ifFrom;
  unsigned char* srcMac;
  union olsr_ip_addr srcIp;
  union olsr_ip_addr destIp;
  union olsr_ip_addr* originator;
  struct sockaddr_in sin;
  struct TBmfInterface* nextFwIntf;

  /* Only forward IPv4 packets */
  u_int16_t type;
  memcpy(&type, buffer + ETH_TYPE_OFFSET, 2);
  if (ntohs(type) != IPV4_TYPE)
  {
    return;
  }

  /* Lookup the OLSR interface on which this packet is received */
  ifFrom = intf->olsrIntf;

  /* Only forward multicast or local broadcast packets */
  COPY_IP(&destIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_DSTIP);
  if (! IsMulticast(&destIp) && ! IsLocalBroadcast(&destIp, ifFrom))
  {
    return;
  }
  
  /* Discard OLSR packets (UDP port 698) and BMF encapsulated packets
   * (UDP port 50505) */
  if (IsOlsrOrBmfPacket(buffer, len))
  {
    return;
  }

  /* Apply drop list for testing purposes. */
  srcMac = buffer + IFHWADDRLEN;
  if (IsInDropList(srcMac))
  {
    return;
  }

  /* Lookup main address of source */
	COPY_IP(&srcIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_SRCIP);
  originator = mid_lookup_main_addr(&srcIp);
  if (originator == NULL)
  {
    originator = &srcIp;
  }

  olsr_printf(
    9,
    "MC pkt to %s received from originator %s (%s) via \"%s\"\n",
    olsr_ip_to_string(&destIp),
    olsr_ip_to_string(originator),
    olsr_ip_to_string(&srcIp),
    intf->ifName);

  /* Check if I am MPR for that originator */
  if (ifFrom != NULL && olsr_lookup_mprs_set(originator) == NULL)
  {
    olsr_printf(
      9,
      "--> Discarding pkt: I am not selected as MPR by that originator\n");
    return;
  }

  /* If this packet is captured on a non-OLSR interface, decrease
   * the TTL and re-calculate the IP header checksum */
  if (ifFrom == NULL)
  {
    PacketDecreaseTtlAndUpdateHeaderChecksum(buffer);
  }

  /* If the TTL is <= 0, do not forward this packet */
  if (GetIpTtl(buffer) <= 0)
  {
    return;
  }

  /* Check if this packet was seen recently */
  if (CheckMarkRecentPacket(buffer, len))
  {
    olsr_printf(
      9,
      "--> Discarding pkt: was a duplicate\n");
    return;
  }

  /* Encapsulate and forward packet on all OLSR interfaces */
  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port = htons(BMF_ENCAP_PORT);

  nextFwIntf = BmfInterfaces;
  while (nextFwIntf != NULL)
  {
    struct TBmfInterface* fwIntf = nextFwIntf;
    nextFwIntf = fwIntf->next;

    if (fwIntf->olsrIntf != NULL)
    {
      int nBytesWritten;

      /* Change source MAC address to that of myself */
      memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);

      /* Destination address is local broadcast */
      sin.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr;

      nBytesWritten = sendto(
        fwIntf->encapsulatingSkfd,
        buffer,
        len,
        MSG_DONTROUTE,
        (struct sockaddr*) &sin,
        sizeof(sin));                   

      if (nBytesWritten != len)
      {
        olsr_printf(
          1,
          "%s: sendto() error forwarding MC pkt for %s to \"%s\": %s\n",
          PLUGIN_NAME,
          olsr_ip_to_string(&destIp),
          fwIntf->olsrIntf->int_name,
          strerror(errno));
      }
      else
      {
        olsr_printf(
          9,
          "Successfully encapsulated one MC pkt for %s to \"%s\"\n",
          olsr_ip_to_string(&destIp),
          fwIntf->olsrIntf->int_name);
      } /* if (nBytesWritten != len) */
    } /* if (fwIntf->olsrIntf != NULL) */
  } /* while (nextFwIntf != NULL) */
}

static void BmfEncapsulatedPacketReceived(
  struct TBmfInterface* intf, 
  struct in_addr srcIp,
  unsigned char* buffer,
  ssize_t len)
{
  union olsr_ip_addr fromAddr;
  struct interface* ifFrom;
  union olsr_ip_addr* forwarder;
  int nBytesToWrite;
  unsigned char* bufferToWrite;
  int nBytesWritten;
  int iAmMpr;
  struct sockaddr_in sin;
  struct TBmfInterface* nextFwIntf;

  COPY_IP(&fromAddr, &srcIp.s_addr);

  /* Are we talking to ourselves? */
  if (if_ifwithaddr(&fromAddr) != NULL)
  {
    return;
  }

  /* Lookup the OLSR interface on which this packet is received */
  ifFrom = intf->olsrIntf;

  /* Encapsulated packet received on non-OLSR interface? Then discard */
  if (ifFrom == NULL)
  {
    return;
  }

  /* Apply drop list? No, not needed: encapsulated packets are routed,
   * so filtering should be done by adding a rule to the iptables FORWARD
   * chain, e.g.:
   * iptables -A FORWARD -m mac --mac-source 00:0C:29:28:0E:CC -j DROP */

  /* Lookup main address of forwarding node */
  forwarder = mid_lookup_main_addr(&fromAddr);
  if (forwarder == NULL)
  {
    forwarder = &fromAddr;
    olsr_printf(
      9,
      "Encapsulated MC pkt received; forwarder to me by %s on \"%s\"\n",
      olsr_ip_to_string(forwarder),
      intf->ifName);
  }
  else
  {
    olsr_printf(
      9,
      "Encapsulated MC pkt received; forwarder to me by %s (thru %s) on \"%s\"\n",
      olsr_ip_to_string(forwarder),
      olsr_ip_to_string(&fromAddr),
      intf->ifName);
  }

  /* Check if this packet was seen recently */
  if (CheckMarkRecentPacket(buffer, len))
  {
    olsr_printf(
      9,
      "--> Discarding encapsulated pkt: was a duplicate\n");
    return;
  }

  /* Unpack encapsulated packet and send a copy to myself via the EtherTunTap device */
  nBytesToWrite = len;
  bufferToWrite = buffer;
  if (TunOrTap == TT_TUN)
  {
    nBytesToWrite -= IP_HDR_OFFSET;
    bufferToWrite += IP_HDR_OFFSET;
  }
  nBytesWritten = write(EtherTunTapFd, bufferToWrite, nBytesToWrite);
  if (nBytesWritten != nBytesToWrite)
  {
    olsr_printf(
      1,
      "%s: write() error sending encapsulated MC pkt to \"%s\": %s\n",
      PLUGIN_NAME,
      EtherTunTapIfName,
      strerror(errno));
  }
  else
  {
    olsr_printf(
      9,
      "Successfully unpacked and sent encapsulated MC pkt to \"%s\"\n",
      EtherTunTapIfName);
  }

  /* Check if I am MPR for the forwarder */
  iAmMpr = (olsr_lookup_mprs_set(forwarder) != NULL);
  if (! iAmMpr)
  {
    olsr_printf(
      9,
      "--> Not forwarding encapsulated pkt: I am not selected as MPR by that forwarder\n");
  }

  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port = htons(BMF_ENCAP_PORT);

  nextFwIntf = BmfInterfaces;
  while (nextFwIntf != NULL)
  {
    struct TBmfInterface* fwIntf = nextFwIntf;
    nextFwIntf = fwIntf->next;

    /* On non-OLSR interfaces: unpack encapsulated packet, decrease TTL
     * and send */
    if (fwIntf->olsrIntf == NULL)
    {
      struct TSaveTtl sttl;

      /* Change source MAC address to that of sending interface */
      memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);

      /* Save IP header checksum and the TTL-value of the packet, then 
       * decrease the TTL by 1 before writing */
      SaveTtlAndChecksum(buffer, &sttl);
      PacketDecreaseTtlAndUpdateHeaderChecksum(buffer);

      /* If the TTL is <= 0, do not forward this packet */
      if (GetIpTtl(buffer) <= 0)
      {
        return;
      }

      nBytesWritten = write(fwIntf->capturingSkfd, buffer, len);
      if (nBytesWritten != len)
      {
        olsr_printf(
          1,
          "%s: write() error sending unpacked encapsulated MC pkt to \"%s\": %s\n",
          PLUGIN_NAME,
          fwIntf->ifName,
          strerror(errno));
      }
      else
      {
        olsr_printf(
          9,
          "Successfully unpacked and sent one encapsulated MC pkt to \"%s\"\n",
          fwIntf->ifName);
      }

      /* Restore the IP header checksum and the TTL-value of the packet */
      RestoreTtlAndChecksum(buffer, &sttl);
    } /* if (fwIntf->olsrIntf == NULL) */

    /* On OLSR interfaces, forward the packet if this node is selected as MPR by the 
     * forwarding node */
    else if (iAmMpr)
    {
      /* Change source MAC address to that of sending interface */
      memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);

      /* Destination address is local broadcast */
      sin.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr;

      nBytesWritten = sendto(
        fwIntf->encapsulatingSkfd,
        buffer,
        len,
        MSG_DONTROUTE,
        (struct sockaddr*) &sin,
        sizeof(sin));                   

      if (nBytesWritten != len)
      {
        olsr_printf(
          1,
          "%s: sendto() error forwarding encapsulated MC pkt to \"%s\": %s\n",
          PLUGIN_NAME,
          fwIntf->olsrIntf->int_name,
          strerror(errno));
      }
      else
      {
        olsr_printf(
          9,
          "Successfully forwarded one encapsulated MC pkt to \"%s\"\n",
          fwIntf->olsrIntf->int_name);
      }
    } /* else if (iAmMpr) */
  } /* while (nextFwIntf != NULL) */
}

static void DoBmf(void* useless)
{
#define BUFFER_MAX 2048
  struct TBmfInterface* intf;
  int nFdBitsSet;

  /* Compose set of socket file descriptors. 
   * Keep the highest descriptor seen. */
  int highestSkfd = -1;
  fd_set input_set;
  FD_ZERO(&input_set);

  intf = BmfInterfaces;
  while (intf != NULL)
  {
    FD_SET(intf->capturingSkfd, &input_set);
    if (intf->capturingSkfd > highestSkfd)
    {
      highestSkfd = intf->capturingSkfd;
    }

    if (intf->encapsulatingSkfd >= 0)
    {
      FD_SET(intf->encapsulatingSkfd, &input_set);
      if (intf->encapsulatingSkfd > highestSkfd)
      {
        highestSkfd = intf->encapsulatingSkfd;
      }
    }

    intf = intf->next;    
  }

  assert(highestSkfd >= 0);

  /* Wait (blocking) for packets received on any of the sockets */
  nFdBitsSet = select(highestSkfd + 1, &input_set, NULL, NULL, NULL);
  if (nFdBitsSet < 0)
  {
    if (errno != EINTR)
    {
      olsr_printf(1, "%s: select() error: %s\n", PLUGIN_NAME, strerror(errno));
    }
    return;
  }
    
  if (nFdBitsSet == 0)
  {
    /* No packets waiting. This is unexpected; normally we would excpect select(...)
     * to return only if at least one packet was received (so nFdBitsSet > 0), or
     * if this thread received a signal (so nFdBitsSet < 0). */
    return;
  }

  while (nFdBitsSet > 0)
  {
    intf = BmfInterfaces;
    while (intf != NULL)
    {
      int skfd = intf->capturingSkfd;
      if (FD_ISSET(skfd, &input_set))
      {
        unsigned char buffer[BUFFER_MAX];
        struct sockaddr_ll pktAddr;
        socklen_t addrLen;
        int nBytes;

        /* A packet was captured */

        nFdBitsSet--;

        memset(&pktAddr, 0, sizeof(struct sockaddr_ll));
        addrLen = sizeof(pktAddr);

        nBytes = recvfrom(skfd, buffer, BUFFER_MAX, 0, (struct sockaddr*)&pktAddr, &addrLen);
        if (nBytes < 0)
        {
          olsr_printf(1, "%s: recvfrom() error: %s\n", PLUGIN_NAME, strerror(errno));
        }

        /* Don't let BMF crash by sending too short packets. IP packets are always
         * at least 14 (Ethernet header) + 20 (IP header) = 34 bytes long. */
        if (nBytes >= 34)
        {
          if (pktAddr.sll_pkttype == PACKET_OUTGOING)
          {
            union olsr_ip_addr destIp;
            COPY_IP(&destIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_DSTIP);
            if (IsMulticast(&destIp) || IsLocalBroadcast(&destIp, intf->olsrIntf))
            {
              if (! IsOlsrOrBmfPacket(buffer, nBytes))
              {
                MarkRecentPacket(buffer, nBytes);
              }
            }
          }
          else if (pktAddr.sll_pkttype == PACKET_MULTICAST ||
                   pktAddr.sll_pkttype == PACKET_BROADCAST)
          {
            BmfPacketCaptured(intf, buffer, nBytes);
          }
        } /* if (nBytes >= 34) */
      } /* if (FD_ISSET...) */

      skfd = intf->encapsulatingSkfd;
      if (skfd >= 0 && (FD_ISSET(skfd, &input_set)))
      {
        unsigned char buffer[BUFFER_MAX];
        struct sockaddr_in addr;
        socklen_t addrLen = sizeof(addr);
        int nBytes;

        /* An encapsulated packet was received */

        nFdBitsSet--;

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

        nBytes = recvfrom(skfd, buffer, BUFFER_MAX, 0, (struct sockaddr*)&addr, &addrLen);
        if (nBytes < 0)
        {
          olsr_printf(1, "%s: recvfrom() error: %s\n", PLUGIN_NAME, strerror(errno));
        }
        if (nBytes > 0)
        {
          BmfEncapsulatedPacketReceived(intf, addr.sin_addr, buffer, nBytes);
        }
      } /* if (skfd >= 0 && (FD_ISSET...) */

      intf = intf->next;    
    } /* while (intf != NULL) */
  } /* while (nFdBitsSet > 0) */
}

static void BmfSignalHandler(int signo)
{
  /* Dummy handler function */
  return;
}

/* Thread entry function. Another thread can gracefully stop this thread by writing a
 * '0' into global variable 'BmfThreadRunning' followed by sending a SIGALRM signal. */
static void* BmfRun(void* useless)
{
  sigset_t blockedSigs;
  sigfillset(&blockedSigs);
  sigdelset(&blockedSigs, SIGALRM);
  if (pthread_sigmask(SIG_BLOCK, &blockedSigs, NULL) < 0)
  {
    olsr_printf(1, "%s: pthread_sigmask() error: %s\n", PLUGIN_NAME, strerror(errno));
  }

  /* Set up the signal handler for the process: use SIGALRM to terminate
   * the BMF thread. Only if a signal handler is specified, does a blocking
   * system call return with errno set to EINTR; if a signal hander is not
   * specified, any system call in which the thread may be waiting will not
   * return. Note that the BMF thread is usually blocked in the select()
   * function (see DoBmf()). */
  if (signal(SIGALRM, BmfSignalHandler) == SIG_ERR)
  {
    olsr_printf(1, "%s: signal() error: %s\n", PLUGIN_NAME, strerror(errno));
  }

  /* Call the thread function until flagged to exit */
  while (BmfThreadRunning != 0)
  {
    DoBmf(useless);
  }
  
  return NULL;
}

/* Initialize the BMF plugin */
int InitBmf()
{
  /* Check validity */
  if (olsr_cnf->ip_version != AF_INET)
  {
    fprintf(stderr, PLUGIN_NAME ": This plugin only supports IPv4!\n");
    return 0;
  }

  /* Clear the packet history */
  InitPacketHistory();

  if (CreateBmfNetworkInterfaces() < 0)
  {
    fprintf(stderr, PLUGIN_NAME ": could not initialize network interfaces!\n");
    return 0;
  }
  
  /* Run the multicast packet processing thread */
  BmfThreadRunning = 1;
  pthread_create(&BmfThread, NULL, BmfRun, NULL);

  /* Register the duplicate registration pruning process */
  olsr_register_scheduler_event(&PrunePacketHistory, NULL, 3.0, 2.0, NULL);

  return 1;
}

/* Close the BMF plugin */
void CloseBmf()
{
  /* Signal BmfThread to exit */
  BmfThreadRunning = 0;
  if (pthread_kill(BmfThread, SIGALRM) < 0)
  /* Strangely enough, all running threads receive the SIGALRM signal. But only the
   * BMF thread is affected by this signal, having specified a handler for this
   * signal in its thread entry function BmfRun(...). */
  {
    olsr_printf(1, "%s: pthread_kill() error: %s\n", PLUGIN_NAME, strerror(errno));
  }

  /* Wait for BmfThread to acknowledge */
  if (pthread_join(BmfThread, NULL) < 0)
  {
    olsr_printf(1, "%s: pthread_join() error: %s\n", PLUGIN_NAME, strerror(errno));
  }

  /* Time to clean up */
  CloseBmfNetworkInterfaces();
}

int RegisterBmfParameter(char* key, char* value)
{
  if (strcmp(key, "Drop") == 0)
  {
    return DropMac(value);
  }
  else if (strcmp(key, "NonOlsrIf") == 0)
  {
    return AddNonOlsrBmfIf(value);
  }

  return 0;
}

--- NEW FILE: NetworkInterfaces.c ---
/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: NetworkInterfaces.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

#include "NetworkInterfaces.h"

/* System includes */
#include <syslog.h> /* syslog() */
#include <string.h> /* strerror() */
#include <errno.h> /* errno */
#include <unistd.h> /* close() */
#include <sys/ioctl.h> /* ioctl() */
#include <fcntl.h> /* fcntl() */
#include <assert.h> /* assert() */
#include <net/if.h> /* if_indextoname() */
#include <netinet/in.h> /* htons() */
#include <linux/if_ether.h> /* ETH_P_ALL */
#include <linux/if_packet.h> /* packet_mreq, PACKET_MR_PROMISC, PACKET_ADD_MEMBERSHIP */
#include <linux/if_tun.h> /* IFF_TAP */

/* OLSRD includes */
#include "olsr.h" /* olsr_printf */
#include "defs.h" /* olsr_cnf */

/* Plugin includes */
#include "Packet.h" /* IFHWADDRLEN */
#include "Bmf.h" /* PLUGIN_NAME */

/* List of network interfaces used by BMF plugin */
struct TBmfInterface* BmfInterfaces = NULL;

/* File descriptor of EtherTunTap device */
int EtherTunTapFd = -1;

/* Network interface name of EtherTunTap device. If the name starts with "tun", an
 * IP tunnel interface will be used. Otherwise, an EtherTap device will be used. */
const char* EtherTunTapIfName = "tun0"; /* "tap0"; */

/* If the network interface name starts with "tun", an IP tunnel interface will be
 * used, and this variable will be set to TUN. Otherwise, an EtherTap device will
 * be used, and this variable will be set to TAP. */
enum TTunOrTap TunOrTap;

/* Create raw packet socket for capturing multicast IP traffic. Returns
 * the socket descriptor, or -1 if an error occurred. */
static int CreateCaptureSocket(int ifIndex)
{
  struct packet_mreq mreq;
  struct ifreq req;
  struct sockaddr_ll iface_addr;

  /* Open raw packet socket */
  int skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  if (skfd < 0)
  {
    olsr_printf(1, "%s: socket(PF_PACKET) error: %s\n", PLUGIN_NAME, strerror(errno));
    return -1;
  }

  /* Set interface to promiscuous mode */
  memset(&mreq, 0, sizeof(struct packet_mreq));
  mreq.mr_ifindex = ifIndex;
  mreq.mr_type = PACKET_MR_PROMISC;
  if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
  {
    olsr_printf(1, "%s: setsockopt(PACKET_MR_PROMISC) error: %s\n", PLUGIN_NAME, strerror(errno));
    close(skfd);
    return -1;
  }

  /* Get hardware (MAC) address */
  memset(&req, 0, sizeof(struct ifreq));
  if (if_indextoname(ifIndex, req.ifr_name) == NULL ||
      ioctl(skfd, SIOCGIFHWADDR, &req) < 0)
  {
    olsr_printf(1, "%s: error retrieving MAC address: %s\n", PLUGIN_NAME, strerror(errno));
    close(skfd);
    return -1;
  }
   
  /* Bind the socket to the specified interface */
  memset(&iface_addr, 0, sizeof(iface_addr));
  iface_addr.sll_protocol = htons(ETH_P_ALL);
  iface_addr.sll_ifindex = ifIndex;
  iface_addr.sll_family = AF_PACKET;
  memcpy(iface_addr.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
  iface_addr.sll_halen = IFHWADDRLEN;
    
  if (bind(skfd, (struct sockaddr*)&iface_addr, sizeof(iface_addr)) < 0)
  {
    olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
    close(skfd);
    return -1;
  }

  /* Set socket to blocking operation */
  if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
  {
    olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno));
    close(skfd);
    return -1;
  }

  return skfd;
}

/* Create UDP (datagram) over IP socket to send encapsulated multicast packets over.
 * Returns the socket descriptor, or -1 if an error occurred. */
static int CreateEncapsulateSocket(int ifIndex)
{
  int on = 1;
  char ifName[IFNAMSIZ];
  struct sockaddr_in sin;

  /* Open UDP-IP socket */
  int skfd = socket(PF_INET, SOCK_DGRAM, 0);
  if (skfd < 0)
  {
    olsr_printf(1, "%s: socket(PF_INET) error: %s\n", PLUGIN_NAME, strerror(errno));
    return -1;
  }

  /* Enable sending to broadcast addresses */
  if (setsockopt(skfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
  {
    olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno));
    close(skfd);
    return -1;
  }
	
  /* Bind to the specific network interfaces indicated by ifIndex */
  if (if_indextoname(ifIndex, ifName) == NULL ||
      setsockopt(skfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, strlen(ifName) + 1) < 0)
  {
    olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno));
    close(skfd);
    return -1;
  }
    
  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port = htons(BMF_ENCAP_PORT);
  sin.sin_addr.s_addr = htonl(INADDR_ANY);
      
  if (bind(skfd, (struct sockaddr*)&sin, sizeof(sin)) < 0) 
  {
    olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
    close(skfd);
    return -1;
  }

  /* Set socket to blocking operation */
  if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
  {
    olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno));
    close(skfd);
    return -1;
  }

  return skfd;
}

/* To save the state of the IP spoof filter for the EtherTunTap device */
static char EthTapSpoofState = '1';

static int DeactivateSpoofFilter(const char* ifName)
{
  FILE* procSpoof;
  char procFile[FILENAME_MAX];

  assert(ifName != NULL);

  /* Generate the procfile name */
  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", ifName);

  procSpoof = fopen(procFile, "r");
  if (procSpoof == NULL)
  {
    fprintf(
      stderr,
      "WARNING! Could not open the %s file to check/disable the IP spoof filter!\n"
      "Are you using the procfile filesystem?\n"
      "Does your system support IPv4?\n"
      "I will continue (in 3 sec) - but you should manually ensure that IP spoof\n"
      "filtering is disabled!\n\n",
      procFile);
      
    sleep(3);
    return 0;
  }

  EthTapSpoofState = fgetc(procSpoof);
  fclose(procSpoof);

  procSpoof = fopen(procFile, "w");
  if (procSpoof == NULL)
  {
    fprintf(stderr, "Could not open %s for writing!\n", procFile);
    fprintf(
      stderr,
      "I will continue (in 3 sec) - but you should manually ensure that IP"
      " spoof filtering is disabled!\n\n");
    sleep(3);
    return 0;
  }

  syslog(LOG_INFO, "Writing \"0\" to %s", procFile);
  fputs("0", procSpoof);

  fclose(procSpoof);

  return 1;
}

static void RestoreSpoofFilter(const char* ifName)
{
  FILE* procSpoof;
  char procFile[FILENAME_MAX];

  assert(ifName != NULL);

  /* Generate the procfile name */
  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", ifName);

  procSpoof = fopen(procFile, "w");
  if (procSpoof == NULL)
  {
    fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procFile);
  }
  else
  {
    syslog(LOG_INFO, "Resetting %s to %c\n", procFile, EthTapSpoofState);

    fputc(EthTapSpoofState, procSpoof);
    fclose(procSpoof);
  }
}

/* Creates and brings up an EtherTunTap device e.g. "tun0" or "tap0"
 * (as specified in const char* EtherTunTapIfName) */
static int CreateLocalEtherTunTap(void)
{
  struct ifreq ifreq;
  int etfd = open("/dev/net/tun", O_RDWR);
  int skfd;
  int ioctlres = 0;

  if (etfd < 0)
  {
    olsr_printf(1, "%s: open() error: %s\n", PLUGIN_NAME, strerror(errno));
    return -1;
  }

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

  /* Specify either the IFF_TAP flag for Ethernet frames, or the IFF_TUN flag for IP.
   * Specify IFF_NO_PI for not receiving extra meta packet information. */
  if (strncmp(EtherTunTapIfName, "tun", 3) == 0)
  {
    ifreq.ifr_flags = IFF_TUN;
    TunOrTap = TT_TUN;
  }
  else
  {
    ifreq.ifr_flags = IFF_TAP;
    TunOrTap = TT_TAP;
  }
  ifreq.ifr_flags |= IFF_NO_PI;

  strcpy(ifreq.ifr_name, EtherTunTapIfName);
  if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0)
  {
    olsr_printf(1, "%s: ioctl() error: %s\n", PLUGIN_NAME, strerror(errno));
    close(etfd);
    return -1;
  }

  memset(&ifreq, 0, sizeof(ifreq));
  strcpy(ifreq.ifr_name, EtherTunTapIfName);
  ifreq.ifr_addr.sa_family = AF_INET;
  skfd = socket(PF_INET, SOCK_DGRAM, 0);
  if (skfd >= 0)
  {
    if (ioctl(skfd, SIOCGIFADDR, &ifreq) < 0)
    {
      /* EtherTunTap interface does not yet have an IP address.
       * Give it a dummy IP address "1.2.3.4". */
      struct sockaddr_in *inaddr = (struct sockaddr_in *)&ifreq.ifr_addr;
      inet_aton("1.2.3.4", &inaddr->sin_addr);
      ioctlres = ioctl(skfd, SIOCSIFADDR, &ifreq);

      if (ioctlres >= 0)
      {
        /* Bring EtherTunTap interface up (if not already) */
        ioctlres = ioctl(skfd, SIOCGIFFLAGS, &ifreq);
        if (ioctlres >= 0)
        {
          ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING);
          ioctlres = ioctl(skfd, SIOCSIFFLAGS, &ifreq);
        }
      } /* if (ioctlres >= 0) */
    } /* if (ioctl...) */
  } /* if (skfd >= 0) */
  if (skfd < 0 || ioctlres < 0)
  {
    olsr_printf(
      1,
      "%s: Error bringing up EtherTunTap interface: %s\n",
      PLUGIN_NAME,
      strerror(errno));

    close(etfd);
    if (skfd >= 0)
    {
      close(skfd);
    }
    return -1;
  } /* if (skfd < 0 || ioctlres < 0) */

  /* Set the multicast flag on the interface. TODO: Maybe also set
   * IFF_ALLMULTI. */
  memset(&ifreq, 0, sizeof(ifreq));
  strcpy(ifreq.ifr_name, EtherTunTapIfName);
  ioctlres = ioctl(skfd, SIOCGIFFLAGS, &ifreq);
  if (ioctlres >= 0)
  {
    ifreq.ifr_flags |= IFF_MULTICAST;
    ioctlres = ioctl(skfd, SIOCSIFFLAGS, &ifreq);
  }
  if (ioctlres < 0)
  {
    olsr_printf(
      1,
      "%s: Error setting the multicast flag on EtherTunTap interface: %s\n",
      PLUGIN_NAME,
      strerror(errno));
  }
  close(skfd);
  
  /* Deactivate IP spoof filter for EtherTunTap device */
  DeactivateSpoofFilter(ifreq.ifr_name);

  return etfd;
}

static int IsNullMacAddress(char* mac)
{
  int i;

  assert(mac != NULL);

  for (i = 0; i < IFHWADDRLEN; i++)
  {
    if (mac[i] != 0) return 0;
  }
  return 1;
}

int CreateBmfNetworkInterfaces(void)
{
  int skfd;
  struct ifconf ifc;
  int numreqs = 30;
  struct ifreq* ifr;
  int n;

  EtherTunTapFd = CreateLocalEtherTunTap();
  if (EtherTunTapFd < 0)
  {
    olsr_printf(1, "%s: error creating local EtherTunTap\n", PLUGIN_NAME);
    return -1;    
  }

  skfd = socket(PF_INET, SOCK_DGRAM, 0);
  if (skfd < 0)
  {
    olsr_printf(
      1,
      "%s: No inet socket available: %s\n",
      PLUGIN_NAME,
      strerror(errno));
    return -1;
  }

  /* Retrieve the network interface configuration list */
  ifc.ifc_buf = NULL;
  for (;;)
  {
    ifc.ifc_len = sizeof(struct ifreq) * numreqs;
    ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);

    if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
    {
      olsr_printf(1, "%s: SIOCGIFCONF error: %s\n", PLUGIN_NAME, strerror(errno));

      close(skfd);
      free(ifc.ifc_buf);
      return -1;
    }
    if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs)
    {
      /* Assume it overflowed; double the space and try again */
      numreqs *= 2;
      assert(numreqs < 1024);
      continue; /* for (;;) */
    }
    break; /* for (;;) */
  } /* for (;;) */

  /* For each item in the interface configuration list... */
  ifr = ifc.ifc_req;
  for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++)
  {
    struct interface* olsrIntf;
    struct ifreq ifrAddr;
    int capturingSkfd;
    int encapsulatingSkfd = -1;
    struct TBmfInterface* newBmfInterface;

    /* ...find the OLSR interface structure, if any */
    union olsr_ip_addr ipAddr;
    COPY_IP(&ipAddr, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr.s_addr);
    olsrIntf = if_ifwithaddr(&ipAddr);

    if (olsrIntf == NULL && ! IsNonOlsrBmfIf(ifr->ifr_name))
    {
      /* Interface is neither OLSR interface, nor specified as non-OLSR BMF
       * interface in the BMF plugin parameter list */
      continue; /* for (n = ...) */
    }

    /* Retrieve the MAC address */
    memset(&ifrAddr, 0, sizeof(struct ifreq));
    strcpy(ifrAddr.ifr_name, ifr->ifr_name); 
    if (ioctl(skfd, SIOCGIFHWADDR, &ifrAddr) < 0)
    {
      olsr_printf(
        1,
        "%s: SIOCGIFHWADDR error for device \"%s\": %s\n",
        PLUGIN_NAME,
        ifrAddr.ifr_name,
        strerror(errno));
      continue; /* for (n = ...) */
    }

    if (IsNullMacAddress(ifrAddr.ifr_hwaddr.sa_data))
    {
      continue; /* for (n = ...) */
    }

    /* Create socket for capturing and sending multicast packets */
    capturingSkfd = CreateCaptureSocket(if_nametoindex(ifr->ifr_name));
    if (capturingSkfd < 0)
    {
      continue; /* for (n = ...) */
    }

    if (olsrIntf != NULL)
    {
      /* Create socket for encapsulating and forwarding multicast packets */
      encapsulatingSkfd = CreateEncapsulateSocket(olsrIntf->if_index);
      if (encapsulatingSkfd < 0)
      {
        close(capturingSkfd);
        continue; /* for (n = ...) */
      }
    }

    newBmfInterface = malloc(sizeof(struct TBmfInterface));
    if (newBmfInterface == NULL)
    {
      close(capturingSkfd);
      close(encapsulatingSkfd);
      continue; /* for (n = ...) */
    }

    newBmfInterface->capturingSkfd = capturingSkfd;
    newBmfInterface->encapsulatingSkfd = encapsulatingSkfd;
    memcpy(newBmfInterface->macAddr, ifrAddr.ifr_hwaddr.sa_data, IFHWADDRLEN);
    memcpy(newBmfInterface->ifName, ifr->ifr_name, IFNAMSIZ);
    newBmfInterface->olsrIntf = olsrIntf;
    newBmfInterface->next = BmfInterfaces;
    BmfInterfaces = newBmfInterface;
  } /* for (n = ...) */
  
  if (BmfInterfaces == NULL)
  {
    olsr_printf(1, "%s: could not initialize any network interface\n", PLUGIN_NAME);
    return -1;
  }

  close(skfd);
  free(ifc.ifc_buf);
  return 0;
}

/* Closes every socket on each network interface used by BMF:
 * -- the local EtherTunTap interface (e.g. "tun0" or "tap0")
 * -- for each OLSR-enabled interface:
 *    - the socket used for capturing multicast packets
 *    - the socket used for encapsulating packets
 * Also restores the network state to the situation before OLSR was
 * started */
void CloseBmfNetworkInterfaces()
{
  int nClosed = 0;
  
  /* Close all opened sockets */
  struct TBmfInterface* nextBmfIf = BmfInterfaces;
  while (nextBmfIf != NULL)
  {
    struct TBmfInterface* bmfIf = nextBmfIf;
    nextBmfIf = bmfIf->next;

    close(bmfIf->capturingSkfd);
    nClosed++;
    if (bmfIf->encapsulatingSkfd >= 0) 
    {
      close(bmfIf->encapsulatingSkfd);
      nClosed++;
    }

    free(bmfIf);
  }
  
  /* Restore IP spoof filter for EtherTunTap device */
  RestoreSpoofFilter(EtherTunTapIfName);

  close(EtherTunTapFd);
  nClosed++;

  olsr_printf(1, "%s: closed %d sockets\n", PLUGIN_NAME, nClosed);
}

#define MAX_NON_OLSR_IFS 10
static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
static int nNonOlsrIfs = 0;

int AddNonOlsrBmfIf(const char* ifName)
{
  assert(ifName != NULL);

  if (nNonOlsrIfs >= MAX_NON_OLSR_IFS)
  {
    olsr_printf(
      1,
      "%s: too many non-OLSR interfaces specified, maximum %d\n",
      PLUGIN_NAME,
      MAX_NON_OLSR_IFS);
    return 0;
  }

  strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ);
  nNonOlsrIfs++;
  return 1;
}

int IsNonOlsrBmfIf(const char* ifName)
{
  int i;

  assert(ifName != NULL);

  for (i = 0; i < nNonOlsrIfs; i++)
  {
    if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0) return 1;
  }
  return 0;
}

--- NEW FILE: PacketHistory.h ---
#ifndef _BMF_PACKETHISTORY_H
#define _BMF_PACKETHISTORY_H

/*
 * OLSR Basic Multicast Forwarding (BMF) plugin.
 * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
 * Written by Erik Tromp.
 * 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 Thales, BMF 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.
 */

/* $Id: PacketHistory.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */

#include <sys/types.h> /* ssize_t */

/* 2 bits per seen packet fingerping: 
 * 11 = "seen recently",
 * 01 = "timing out"
 * 00 = "not seen recently"
 * Note that 10 is unused */
#define NBITS_PER_PACKET 2
#define NBITS_IN_UINT16 (sizeof(u_int16_t) * 8)
#define NBITS_IN_UINT32 (sizeof(u_int32_t) * 8)
#define NPACKETS_PER_ENTRY (NBITS_IN_UINT32 / NBITS_PER_PACKET)
#define HISTORY_TABLE_SIZE ((1 << NBITS_IN_UINT16) / NPACKETS_PER_ENTRY)

void InitPacketHistory(void);
void MarkRecentPacket(unsigned char* buffer, ssize_t len);
int CheckMarkRecentPacket(unsigned char* buffer, ssize_t len);
void PrunePacketHistory(void*);

#endif /* _BMF_PACKETHISTORY_H */





More information about the Olsr-cvs mailing list