* replaced the bmf plugin with the most recent 1.3 from sf.net with the
authorBernd Petrovitsch <bernd@firmix.at>
Sat, 10 Feb 2007 17:05:56 +0000 (17:05 +0000)
committerBernd Petrovitsch <bernd@firmix.at>
Sat, 10 Feb 2007 17:05:56 +0000 (17:05 +0000)
  following changes:
  - We had a globally declared ioctl_s variable which is used exactly
    once in NetworkInterfaces.c.
    Sven-Ola proposed a global "extern" decalaretion but I inserted it
    there locally.
    Main reason: Where does this variable actually come from?
    I can only find one in the olsr_cnf struct. But since the compiler/linker finds
    one, there must be one somewhere.
  - I #if 0 ... #endif out the IsNullMacAddress() function since it is not used
    AFAICS (and the compiler actually).

16 files changed:
lib/bmf/Copyright-Disclaimer.txt [deleted file]
lib/bmf/Makefile
lib/bmf/README_BMF.txt
lib/bmf/src/Address.c
lib/bmf/src/Address.h
lib/bmf/src/Bmf.c
lib/bmf/src/Bmf.h
lib/bmf/src/DropList.c
lib/bmf/src/DropList.h
lib/bmf/src/NetworkInterfaces.c
lib/bmf/src/NetworkInterfaces.h
lib/bmf/src/Packet.c
lib/bmf/src/Packet.h
lib/bmf/src/PacketHistory.c
lib/bmf/src/PacketHistory.h
lib/bmf/src/olsrd_plugin.c

diff --git a/lib/bmf/Copyright-Disclaimer.txt b/lib/bmf/Copyright-Disclaimer.txt
deleted file mode 100644 (file)
index 6a06efd..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*\r
- * OLSR Basic Multicast Forwarding (BMF) plugin.\r
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.\r
- * Written by Erik Tromp.\r
- * All rights reserved.\r
- *\r
- * Redistribution and use in source and binary forms, with or without \r
- * modification, are permitted provided that the following conditions \r
- * are met:\r
- *\r
- * * Redistributions of source code must retain the above copyright \r
- *   notice, this list of conditions and the following disclaimer.\r
- * * Redistributions in binary form must reproduce the above copyright \r
- *   notice, this list of conditions and the following disclaimer in \r
- *   the documentation and/or other materials provided with the \r
- *   distribution.\r
- * * Neither the name of Thales, BMF nor the names of its \r
- *   contributors may be used to endorse or promote products derived \r
- *   from this software without specific prior written permission.\r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND \r
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED \r
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, \r
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, \r
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, \r
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY \r
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE \r
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED \r
- * OF THE POSSIBILITY OF SUCH DAMAGE.\r
- */\r
index e9f6adc..acced36 100644 (file)
 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 # POSSIBILITY OF SUCH DAMAGE.
 #
 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 # POSSIBILITY OF SUCH DAMAGE.
 #
-# $Id: Makefile,v 1.1 2006/05/03 08:59:04 kattemat Exp $
+# $Id: Makefile,v 1.2 2007/02/10 17:05:55 bernd67 Exp $
 
 OLSRD_PLUGIN = true
 PLUGIN_NAME =  olsrd_bmf
 
 OLSRD_PLUGIN = true
 PLUGIN_NAME =  olsrd_bmf
-PLUGIN_VER =   1.0.1
+PLUGIN_VER =   1.3
 
 TOPDIR = ../..
 include $(TOPDIR)/Makefile.inc
 
 TOPDIR = ../..
 include $(TOPDIR)/Makefile.inc
index bafacd1..a0748f3 100644 (file)
@@ -1,86 +1,53 @@
 BASIC MULTICAST FORWARDING PLUGIN FOR OLSRD
 BASIC MULTICAST FORWARDING PLUGIN FOR OLSRD
-by Erik Tromp (erik_tromp@hotmail.com)
-
-27-04-2006: Version 1.0.1 - First release.
-
+by Erik Tromp (erik.tromp@nl.thalesgroup.com, erik_tromp@hotmail.com)
+Version 1.3
 
 1. Introduction
 ---------------
 
 
 1. Introduction
 ---------------
 
-The Basic Multicast Flooding Plugin forwards IP-multicast and
-IP-local-broacast traffic over an OLSRD network. It uses the
+The Basic Multicast Forwarding Plugin floods IP-multicast and
+IP-local-broadcast traffic over an OLSRD network. It uses the
 Multi-Point Relays (MPRs) as identified by the OLSR protocol
 to optimize the flooding of multicast and local broadcast packets
 Multi-Point Relays (MPRs) as identified by the OLSR protocol
 to optimize the flooding of multicast and local broadcast packets
-to all the nodes in the network. To prevent broadcast storms, a
+to all the hosts in the network. To prevent broadcast storms, a
 history of packets is kept; only packets that have not been seen
 in the past 3-6 seconds are forwarded.
 
 history of packets is kept; only packets that have not been seen
 in the past 3-6 seconds are forwarded.
 
-In the IP header there is room for only two IP-addresses:
-* the destination IP address (in our case either a multicast
-  IP-address 224.0.0.0...239.255.255.255, or a local broadcast
-  address e.g. 192.168.1.255), and
-* the source IP address (the originator).
 
 
-For optimized flooding, however, we need more information. Let's
-assume we are the BMF process on one node. We will need to know which
-node forwarded the IP packet to us. Since OLSR keeps track of which
-nodes select our node as MPR (see the olsr_lookup_mprs_set function),
-we can determine if the node that forwarded the packet, has selected us as
-MPR. If so, we must also forward the packet, replacing the 'forwarded-by'
-IP-address to that of us.
+2. How to build and install
+---------------------------
 
 
-Because we need more information than fits in a normal IP-header, the
-original packets are encapsulated into a new IP packet. Encapsulated
-packets are transported in UDP, port 50505. The source address of the
-encapsulation packet is set to the address of the forwarder instead of
-the originator. Of course, the payload of the encapsulation packet is
-the original IP packet.
+Download the olsr-bmf-v1.3.tar.gz file and save it into your OLSRD
+base install directory.
 
 
-For local reception, each received encapsulated packets is unpacked
-and passed into a tuntap interface which is specially created for
-this purpose.
+Change directory (cd) to your OLSRD base install directory.
 
 
-Here is in short how the flooding works (see also the
-BmfEncapsulatedPacketReceived(...) function; details with respect to
-the forwarding towards non-OLSR enabled nodes are omitted):
-  
-  On all OLSR-enabled interfaces, setup reception of packets
-    on UDP port 50505.
-  Upon reception of such a packet:
-    If the received packet was sent by ourselves, drop it.
-    If the packet was recently seen, drop it.
-    Unpack the encapsulated packet and send a copy to myself via the
-      TunTap device.
-    If I am an MPR for the node that forwarded the packet to me,
-      forward the packet to all OLSR-enabled interfaces *including*
-      the one on which it was received.
+At the command prompt, type:
 
 
-As with all good things in life, it's so simple you could have
-thought of it yourself.
-    
+  tar -zxvf ./olsr-bmf-v1.3.tar.gz
 
 
-2. How to build and install
----------------------------
+then type:
+
+  make build_all
 
 
-Follow the instructions in the base directory README file under
-section II. - BUILDING AND RUNNING OLSRD. To be sure to install
-the BMF plugin, cd to the base directory and issue the follwing
-command at the shell prompt:
+followed by:
 
   make install_all
 
 
   make install_all
 
-Next, turn on the possibility to create a tuntap device (see also
-/usr/src/linux/Documentation/networking/tuntap.txt)
+Next, turn on the possibility to create a tuntap interface (see also
+/usr/src/linux/Documentation/networking/tuntap.txt):
 
   mkdir /dev/net # if it doesn't exist already
   mknod /dev/net/tun c 10 200
   
 Set permissions, e.g.:
 
   mkdir /dev/net # if it doesn't exist already
   mknod /dev/net/tun c 10 200
   
 Set permissions, e.g.:
+
   chmod 0700 /dev/net/tun
   chmod 0700 /dev/net/tun
-     
-Edit the file /etc/olsrd.conf to load the BMF plugin. For example:
 
 
-  LoadPlugin "olsrd_bmf.so.1.0.1"
+To configure BMF in OLSR, you must edit the file /etc/olsrd.conf
+to load the BMF plugin. For example, add the following lines:
+
+  LoadPlugin "olsrd_bmf.so.1.3"
   {
     # No PlParam entries required for basic operation
   }
   {
     # No PlParam entries required for basic operation
   }
@@ -90,39 +57,40 @@ Edit the file /etc/olsrd.conf to load the BMF plugin. For example:
 -------------
 
 After building and installing OLSRD with the BMF plugin, run the
 -------------
 
 After building and installing OLSRD with the BMF plugin, run the
-olsrd deamon by entering at the shell prompt:
+olsrd daemon by entering at the shell prompt:
+
   olsrd
 
 Look at the output; it should list the BMF plugin, e.g.:
 
   ---------- Plugin loader ----------
   olsrd
 
 Look at the output; it should list the BMF plugin, e.g.:
 
   ---------- Plugin loader ----------
-  Library: olsrd_bmf.so.1.0.1
-  OLSRD Basic Multicast Forwarding plugin 1.0.1 (Apr 29 2006 12:57:57)
+  Library: olsrd_bmf.so.1.3
+  OLSRD Basic Multicast Forwarding plugin 1.3 (Dec 18 2006 11:23:51)
     (C) Thales Communications Huizen, Netherlands
     (C) Thales Communications Huizen, Netherlands
-    Erik Tromp (erik_tromp@hotmail.com)
+    Erik Tromp (erik.tromp@nl.thalesgroup.com)
   Checking plugin interface version...  4 - OK
   Trying to fetch plugin init function... OK
   Trying to fetch param function... OK
   Sending parameters...
   Checking plugin interface version...  4 - OK
   Trying to fetch plugin init function... OK
   Trying to fetch param function... OK
   Sending parameters...
-  "NonOlsrIf"/"eth2"... OK
-  "Drop"/"00:0C:29:28:0E:CC"... OK
+  "NonOlsrIf"/"eth0"... OK
   Running plugin_init function...
   Running plugin_init function...
+  OLSRD Basic Multicast Forwarding (BMF) plugin: opened 6 sockets
   ---------- LIBRARY LOADED ----------
 
 
 4. How to check if it works
 ---------------------------
 
   ---------- LIBRARY LOADED ----------
 
 
 4. How to check if it works
 ---------------------------
 
-To check that BMF is working, enter the folliwing command on the
-command prompt:
+Enter the following command on the command prompt:
   
   
-  ping -I eth1 224.0.0.1
+  ping 224.0.0.1
     
     
-Replace eth1 with the name of any OLSR-enabled network interface.
+All OLSR-BMF hosts in the OLSR network should respond. For example,
+assume we have three hosts, with IP addresses 192.168.151.50,
+192.168.151.53 and 192.168.151.55. On host 192.168.151.50 we enter
+the following ping command:
 
 
-All OLSR-BMF nodes in the MANET should respond. For example:
-
-root@IsdbServer:~# ping -I eth1 224.0.0.1
+root@IsdbServer:~# ping 224.0.0.1
 PING 224.0.0.1 (224.0.0.1) from 192.168.151.50 eth1: 56(84) bytes of data.
 64 bytes from 192.168.151.50: icmp_seq=1 ttl=64 time=0.511 ms
 64 bytes from 192.168.151.53: icmp_seq=1 ttl=64 time=4.67 ms (DUP!)
 PING 224.0.0.1 (224.0.0.1) from 192.168.151.50 eth1: 56(84) bytes of data.
 64 bytes from 192.168.151.50: icmp_seq=1 ttl=64 time=0.511 ms
 64 bytes from 192.168.151.53: icmp_seq=1 ttl=64 time=4.67 ms (DUP!)
@@ -137,69 +105,482 @@ PING 224.0.0.1 (224.0.0.1) from 192.168.151.50 eth1: 56(84) bytes of data.
 64 bytes from 192.168.151.53: icmp_seq=4 ttl=64 time=1.14 ms (DUP!)
 64 bytes from 192.168.151.55: icmp_seq=4 ttl=63 time=1.16 ms (DUP!)
 
 64 bytes from 192.168.151.53: icmp_seq=4 ttl=64 time=1.14 ms (DUP!)
 64 bytes from 192.168.151.55: icmp_seq=4 ttl=63 time=1.16 ms (DUP!)
 
+We can see the response from the originating host (192.168.151.50)
+(it is normal behaviour for hosts sending multicast packets to
+receive their own packets). We can also see the responses by the
+other hosts (correctly seen as DUPlicates by ping).
+
+
+5. How does it work
+-------------------
+
+In the IP header there is room for only two IP-addresses:
+* the destination IP address (in our case either a multicast
+  IP-address 224.0.0.0...239.255.255.255, or a local broadcast
+  address e.g. 192.168.1.255), and
+* the source IP address (the originator).
+
+For optimized flooding, however, we need more information. Let's
+assume we are the BMF process on one host. We will need to know which
+host forwarded the IP packet to us. Since OLSR keeps track of which
+hosts select our host as MPR (see the olsr_lookup_mprs_set(...) function),
+we can determine if the host that forwarded the packet, has selected us as
+MPR. If so, we must also forward the packet, changing the 'forwarded-by'
+IP-address to that of us. If not, we do not forward the packet.
 
 
-5. Adding non-OLSR interfaces to the multicast flooding
+Because we need more information than fits in a normal IP-header, the
+original packets are encapsulated into a new IP packet. Encapsulated
+packets are transported in UDP, port 50698. The source address of the
+encapsulation packet is set to the address of the forwarder instead of
+the originator. Of course, the payload of the encapsulation packet is
+the original IP packet.
+
+For local reception, each received encapsulated packets is unpacked
+and passed into a tuntap interface which is specially created for
+this purpose.
+
+There are other flooding solutions available that do not use
+encapsulation. The problem with these solutions is that they cannot
+prevent duplicates of forwarded packets to enter the IP stack. For
+example, if a host is receiving flooded (unencapsulated, native IP)
+packets via two MPR hosts, there is no way to stop the reception of
+the packets coming in via the second MPR host. To prevent this, BMF
+uses a combination of encapsulated flooding and local reception via
+a tuntap interface.
+
+Here is in short how the flooding works (see also the
+BmfEncapsulatedPacketReceived(...) function; details with respect to
+the forwarding towards non-OLSR enabled hosts are omitted):
+  
+  On all OLSR-enabled interfaces, setup reception of packets
+    on UDP port 50698.
+  Upon reception of such a packet:
+    If the received packet was sent by myself, drop it.
+    If the packet was recently seen, drop it.
+    Unpack the encapsulated packet and send a copy to myself via the
+      TunTap interface.
+    If I am an MPR for the host that forwarded the packet to me,
+      forward the packet to all OLSR-enabled interfaces *including*
+      the interface on which it was received.
+
+
+6. Advanced configuration
+-------------------------
+
+All configuration of BMF is done via the "LoadPlugin" section in
+the /etc/olsrd.conf file.
+
+The following gives an overview of all plugin parameters that can be
+configured:
+
+  LoadPlugin "olsrd_bmf.so.1.3"
+  {
+    # Specify the name of the BMF network interface.
+    # Defaults to "bmf0".
+    PlParam "BmfInterface" "mybmf0"
+
+    # Specify the type of the BMF network interface: either "tun" or
+    # "tap". Defaults to "tun".
+    PlParam "BmfInterfaceType" "tap"
+
+    # Specify the IP address and mask for the BMF network interface.
+    # By default, the IP address of the first OLSR interface is copied.
+    # The default prefix length is 32.
+    PlParam "BmfInterfaceIp" "10.10.10.234/24"
+
+    # Enable or disable the flooding of local broadcast packets
+    # (e.g. packets with IP destination 192.168.1.255). Either "yes"
+    # or "no". Defaults to "yes".
+    PlParam "DoLocalBroadcast" "no"
+
+    # Enable or disable the capturing packets on the OLSR-enabled
+    # interfaces (in promiscuous mode). Either "yes" or "no". Defaults
+    # to "no".
+    # The multicast (and, if configured, local broadcast) packets sent on
+    # the non-OLSR network interfaces and on the BMF network interface will
+    # always be flooded over the OLSR network.
+    # If this parameter is "yes", also the packets sent on the OLSR-enabled
+    # network interfaces will be flooded over the OLSR network.
+    # NOTE: This parameter should be set consistently on all hosts throughout
+    # the network. If not, hosts may receive multicast packets in duplicate.
+    PlParam "CapturePacketsOnOlsrInterfaces" "yes"
+
+    # List of non-OLSR interfaces to include
+    PlParam     "NonOlsrIf"  "eth2"
+    PlParam     "NonOlsrIf"  "eth3"
+  }
+
+BmfInterfaceIp
+--------------
+
+By default, the BMF network interface will get the IP address of the
+first OLSR interface, with a prefix length of 32. Having two network
+interfaces with the same IP address may seem strange, but it is not
+a problem, since the BMF network interface is not used in any point-to-
+point routing.
+
+The advantage of assigning a known OLSR IP address to the BMF network
+interface is that multicast packets, sent via the BMF network interface,
+get a known IP source address, to which the receivers of the packets
+can reply. That is useful when using, for example, the command
+"ping 224.0.0.1".
+
+An advantage of using a prefix length of 32 is that the Linux IP
+stack will not automatically enter a subnet routing entry (via the BMF
+network interface) into the kernel routing table. Such a routing entry
+would be useless, because the BMF network interface does not forward
+point-to-point traffic.
+
+If you configure a specific IP address and mask via the "BmfInterfaceIp"
+parameter, BMF will cause the specified IP host address to be advertised
+into the OLSR network via the HNA mechanism, so that the other hosts in
+the network know how to route back.
+
+CapturePacketsOnOlsrInterfaces
+------------------------------
+
+If "CapturePacketsOnOlsrInterfaces" is set to "yes", any multicast
+or local broadcast IP packet, sent by an application on *any* OLSR
+interface, will be flooded over the OLSR network. Each OLSR host
+will receive the packet on its BMF network interface, "bmf0". The
+OLSR-interfaces will be in promiscuous mode to capture the multicast
+or local broadcast packets.
+
+For example, if "eth1" is an OLSR interface, the following command
+will result in one response from each OLSR host in the network:
+
+  ping -I eth1 224.0.0.1
+
+A disadvantage of this configuration is that a host may, in rare
+cases, receive a multicast packet twice. This is best explained
+by looking at the following network diagram:
+
+        eth0   eth0
+      A ----------- B
+ eth1 |            / eth1
+      |           /
+ eth0 |          /
+      C --------+
+        eth1
+
+Suppose host A is running a ping session that is sending ping
+packets on "eth1". The BMF process on host A will see the outgoing
+packets on "eth1", encapsulates these packets and sends the
+encapsulated packets on "eth0". Let's assume we are using the link
+quality extensions of OLSR, and the 2-hop path A - B - C is better
+(in terms of ETX) than the 1-hop path A - C. In that case host B is
+an MPR for host A. Host B receives the encapsulated packets of host A
+on its "eth0" interface, and, since it is an MPR, it decides to
+forward them on "eth1".
+
+In most cases, host C will receive the original, unencapsulated
+ping packet on its "eth0" interface before the encapsulated
+ping packet from host B arrives on its "eth1" interface. When the
+encapsulated packet from B arrives, the BMF process will then see
+that it is a duplicate and discard it.
+
+However, in the IP world, there are no guarantees, so it may
+happen that host C receives the encapsulated packet from host B
+first. That packet is then unpacked and locally delivered to the
+BMF network interface "bmf0". When the original, unencapsulated
+packet then comes in on "eth0", there is no way to stop it from
+being received (for a second time) by the Linux IP stack.
+
+As said, this may be a rare case. Besides, most applications
+can deal with a duplicate reception of the same packet. But if
+you're a purist and want everything to work correct, you should
+leave "CapturePacketsOnOlsrInterfaces" to its default value "no".
+
+A disadvantage of leaving "CapturePacketsOnOlsrInterfaces" to its
+default value "no" is that all multicast traffic must go via the
+BMF network interface "bmf0". However, this should not be a problem,
+since a route to all multicast addresses via the BMF network
+interface "bmf0" is automatically added when BMF is started.
+
+
+7. Adding non-OLSR interfaces to the multicast flooding
 -------------------------------------------------------
 
 -------------------------------------------------------
 
-As a special feature, it is possible to have multicast and local-broadcast
-IP packets forwarded also on non-OLSR interfaces.
+As a special feature, it is possible to also forward from and to
+non-OLSR interfaces.
 
 If you have network interfaces on which OLSR is *not* running, but you *do*
 want to forward multicast and local-broadcast IP packets, specify these
 interfaces one by one as "NonOlsrIf" parameters in the BMF plugin section
 of /etc/olsrd.conf. For example:
 
 
 If you have network interfaces on which OLSR is *not* running, but you *do*
 want to forward multicast and local-broadcast IP packets, specify these
 interfaces one by one as "NonOlsrIf" parameters in the BMF plugin section
 of /etc/olsrd.conf. For example:
 
-  LoadPlugin "olsrd_bmf.so.1.0.1"
+  LoadPlugin "olsrd_bmf.so.1.3"
   {
     # Non-OLSR interfaces to participate in the multicast flooding
     PlParam     "NonOlsrIf"  "eth2"
     PlParam     "NonOlsrIf"  "eth3"
   }
 
   {
     # Non-OLSR interfaces to participate in the multicast flooding
     PlParam     "NonOlsrIf"  "eth2"
     PlParam     "NonOlsrIf"  "eth3"
   }
 
-If an interface is listed both as NonOlsrIf for BMF, and in the
+If an interface is listed both as "NonOlsrIf" for BMF, and in the
 Interfaces { ... } section of olsrd.conf, it will be seen by BMF
 Interfaces { ... } section of olsrd.conf, it will be seen by BMF
-as an OLSR-enabled interface. Duh....
-  
+as an OLSR-enabled interface.
+
+
+8. Interworking with other multicast routers
+--------------------------------------------
+
+In a typical interworking configuration there is a network of OLSR hosts
+in which one host acts as a gateway to a fixed infrastructure network.
+Usually that host will be advertising a default route via the HNA
+mechanism, e.g. by adding the following lines to its /etc/olsrd.conf
+file:
+
+  Hna4
+  {
+  #   Internet gateway:
+      0.0.0.0      0.0.0.0
+  }
+
+Alternatively, the gateway is running OLSRDs dynamic internet gateway
+plugin; read the file ../../lib/dyn_gw/README_DYN_GW .
+
+The gateway host will usually have at least one OLSR-interface, and
+at least one non-OLSR interface, running a third-party routing protocol
+like OSPF.
+
+It is beyond the scope of this document to deal with the interworking
+between BMF and all possible multicast routing daemons. As an example,
+let's assume the gateway is running the mrouted multicast daemon (which
+implements the DVMRP protocol). Also, assume that all the IP addresses
+in the OLSR network are within the IP subnet 10.0.0.0/8 . Then mrouted
+on the gateway needs to be configured to accept IGMP requests from IP
+clients within the 10.0.0.0/8 subnet on the BMF network interface
+("bmf0"). This is easily configured by adding a line to the
+/etc/mrouted.conf configuration file:
+
+  phyint bmf0 altnet 10.0.0.0/8
 
 
-6. Testing in a lab environment
+Not strictly necessary, but clean, is to disable the DVMRP protocol
+on the OLSR interfaces, as no DVMRP routers are expected inside the
+OLSR network. Suppose the gateway is running OLSR on "eth1", then
+add the following line /etc/mrouted.conf :
+
+  phyint eth1 disable
+
+Finally, mrouted does not accept interfaces with prefix length 32.
+Therefore, override the default IP address and prefix length of
+the BMF network interface, by editing the /etc/olsrd.conf file.
+For example:
+
+  LoadPlugin "olsrd_bmf.so.1.3"
+  {
+      PlParam "BmfInterfaceIp" "10.10.10.4/24"
+  }
+
+Note that it is not necessary, and even incorrect, to pass the
+non-OLSR interface to BMF as a "NonOlsrIf" parameter in the
+"LoadPlugin" section of the gateway host. When the mrouted
+multicast daemon is running, the forwarding of multicast traffic
+between the OLSR interface and the non-OLSR interface is done by
+the Linux kernel.
+
+The remaining text in this section has nothing to do with BMF or
+OLSR, but is added to give a number of helpful hints you might
+need when your multicast interworking, for some reason, is not working.
+
+When using the mrouted multicast daemon, there is a useful command,
+mrinfo, that gives information about what mrouted thinks of its
+neighbor hosts. For example:
+
+  root@node-4:/# mrinfo
+  127.0.0.1 (localhost.localdomain) [DVMRPv3 compliant]:
+    10.1.2.4 -> 10.1.2.2 (10.1.2.2) [1/1/querier]
+    10.0.6.4 -> 0.0.0.0 (local) [1/1/disabled]
+    10.255.255.253 -> 0.0.0.0 (local) [1/1/querier/leaf]
+
+In this example, the line starting with "10.1.2.4" is for the
+non-OLSR interface "eth0", on which mrouted has found an
+mrouted-neighbor host "10.1.2.2". The next line is for the OLSR
+interface "eth1", which is disabled for mrouted. The last line
+is for the BMF interface "bmf0". It is clear that mrouted sees no
+mrouted-neighbors on that interface (leaf).
+
+To see what multicast traffic has flown through the gateway, view
+the files /proc/net/ip_mr_vif and /proc/net/ip_mr_cache:
+
+  root@node-4:/# cat /proc/net/ip_mr_vif
+  Interface      BytesIn  PktsIn  BytesOut PktsOut Flags Local    Remote
+   0 eth0          27832      98     14200      50 00000 0402010A 00000000
+   2 bmf0          14484      51     13916      49 00000 FDFFFF0A 00000000
+  root@node-4:/# cat /proc/net/ip_mr_cache
+  Group    Origin   Iif     Pkts    Bytes    Wrong Oifs
+  4D4237EA C747010A 0         51    14484        0  2:1
+  4D4237EA C702010A 0         51    14484        0  2:1
+  4D4237EA C84C000A 2         53    15052        0  0:1
+
+From the above we can deduce that traffic from input interface 0
+(Iif 0, "eth0") is forwarded on output interface 2 (Oifs 2, = "bmf0"),
+and traffic from input interface 2 (Iif 2, "bmf0") is forwarded on
+output interface 0 (Oifs 0, "eth0"). The ":1" behind the Oifs numbers
+indicates the TTL thresholds, in this case packets with TTL value 1
+or less will not be forwarded.
+
+When you are connecting an OLSR-BMF network to another multicast network
+(e.g. a DVMRP network), you might be surprised that, when you ping the
+all-routers multicast address 224.0.0.1 from within the OLSR network,
+only the OLSR hosts respond. This is, however, compliant behaviour:
+packets with their destination IP address in the range 224.0.0.0 -
+224.0.0.255 are not routed by normal multicast protocols (i.e. their
+TTL is implicitly assumed to be 1).
+
+
+9. Testing in a lab environment
 -------------------------------
 
 -------------------------------
 
-Setup IP-tables to drop packets from nodes which are not
-direct (1-hop) neigbors. For example, to drop all packets from
-a host with MAC address 00:0C:29:28:0E:CC, enter at the shell prompt:
+When using equipment like switches or hubs, usually all the hosts see each
+other. In an OLSR lab environment, we sometimes want to simulate the
+situation that some hosts in the network cannot directly see other hosts
+(as 1-hop neighbors) but only indirectly (as 2- or more-hop neighbors).
+To simulate that situation, the iptables tool is often used. For BMF,
+however, that is nog enough.
 
 
+For OLSR testing, setup iptables on each host to drop packets from
+all other hosts which are not direct (1-hop) neigbors. For example, to
+drop all packets from the hosts with MAC addresses 00:0C:29:51:32:88,
+00:0C:29:61:34:B7 and 00:0C:29:28:0E:CC, enter at the shell prompt:
+
+  iptables -A INPUT -m mac --mac-source 00:0C:29:51:32:88 -j DROP
+  iptables -A INPUT -m mac --mac-source 00:0C:29:61:34:B7 -j DROP
   iptables -A INPUT -m mac --mac-source 00:0C:29:28:0E:CC -j DROP
 
   iptables -A INPUT -m mac --mac-source 00:0C:29:28:0E:CC -j DROP
 
-Edit the file /etc/olsrd.conf, and specify the MAC addresses of the nodes
-we do not want to see; even though packets from these nodes are dropped
-by iptables, they are still received on network interfaces which are in
-promiscuous mode. For example:
+For BMF testing, edit the file /etc/olsrd.conf, and specify the MAC
+addresses of the hosts we do not want to see. (Even though packets from
+these hosts are dropped by iptables, they are still received on network
+interfaces if they are in promiscuous mode.) For example:
 
 
-  LoadPlugin "olsrd_bmf.so.1.0.1"
+  LoadPlugin "olsrd_bmf.so.1.3"
   {
     # Drop all packets received from the following MAC sources
   {
     # Drop all packets received from the following MAC sources
-    PlParam     "Drop"       "00:0C:29:C6:E2:61" # RemoteClient1
-    PlParam     "Drop"       "00:0C:29:61:34:B7" # SimpleClient1
-    PlParam     "Drop"       "00:0C:29:28:0E:CC" # SimpleClient2
+    PlParam     "DropMac"    "00:0C:29:51:32:88" # RemoteClient1
+    PlParam     "DropMac"    "00:0C:29:61:34:B7" # SimpleClient1
+    PlParam     "DropMac"    "00:0C:29:28:0E:CC" # SimpleClient2
   }
 
 
 
   }
 
 
 
-7. Common problems, FAQ
------------------------
+10. Common problems, FAQ
+------------------------
 
 
+---------
+Question:
+On which platforms does BMF currently compile?
+
+Answer:
+Only on Linux. No compilation on Windows (yet). The oldest Linux
+kernel on which the BMF plugin was tested was version 2.4.18.
+
+
+---------
 Question:
 When starting OLSRD with the BMF plugin, I can see the following
 Question:
 When starting OLSRD with the BMF plugin, I can see the following
-error messages:
+error message:
 
 
-OLSRD Basic Multicast Forwarding plugin: open() error: No such file or directory
-OLSRD Basic Multicast Forwarding plugin: error creating local EtherTunTap
-OLSRD Basic Multicast Forwarding plugin: could not initialize network interfaces!
+OLSRD Basic Multicast Forwarding (BMF) plugin: error opening /dev/net/tun: No such file or directory
 
 Wat to do?
 
 Answer:
 
 Wat to do?
 
 Answer:
-
-Turn on the possibility to create a tuntap device; see section 2 of this
+Turn on the possibility to create a tuntap interface; see section 2 of this
 file.
 
 file.
 
+---------
+Question:
+When starting OLSRD with the BMF plugin, I can see the following
+error message:
+
+OLSRD Basic Multicast Forwarding (BMF) plugin: error opening /dev/net/tun: No such device
+
+Wat to do?
+
+Answer:
+First, turn on the possibility to create a tuntap interface; see section 2 of this
+file. Check if the device is there:
+  ~ # ls -l /dev/net/tun
+  crw-------    1 root     root      10, 200 Sep  9  2006 /dev/net/tun
+
+If the device is there, but the error message remains to appear, the
+tap/tun device is not compiled in your kernel. Try the command:
+
+  modprobe tun
+
+If "modprobe tun" says something like "module tun not found", then either
+it is not compiled at all or it is not compiled into the kernel. 
+
+
+---------
+Question:
+I have enabled BMF, but my multicast application is not receiving any
+multicast packets.
+
+Answer:
+Many multicast applications must be configured to listen to a specific
+network interface. Make sure that your multicast application is listening on
+the BMF network interface, either by specifying the interface name itself
+(e.g. "bmf0") or by specifying its IP address.
+
+
+11. Version history
+-------------------
+
+18 Dec 2006: Version 1.3
+* Added the possibility to configure the BMF network interface:
+  name (e.g. "bmf0"), type (tun or tap), IP address and subnet
+  mask.
+* Flooding of local broadcast packets (e.g. with destination
+  IP address 192.168.1.255) can now be turned off by configuration.
+* When an application sends packets to the BMF network interface, BMF
+  also floods these packets over the OLSR network.
+* Removed the TTL decrementing so that equipment connected to
+  a non-OLSR interface can still send their IGMP messages (TTL = 1)
+  to a fixed multicast router (running e.g. mrouted - DVMRP)
+  connected to a non-OLSR interface on another host in
+  the OLSR network. In this way, a whole OLSR network, including
+  its non-OLSR capable hosts, can be made multicast-routable
+  from a fixed multicast-enabled IP network.
+  For an example of such a configuration read section 8 above.
+* Removed the check for 'IsNullMacAddress' when creating a network
+  interface object. The check was not necessary and prevented
+  BMF to work on non-ethernet interfaces such as ppp.
+* Bug fix: in case there are multiple OLSR interfaces, when an
+  application sends packets to one OLSR interface, BMF did not
+  flood these packets via the other OLSR interfaces. This is
+  fixed. Also, packets sent to an OLSR interface are transmitted
+  on the non-OLSR interfaces.
+
+23 Oct 2006: Version 1.2
+* Packets to a local broadcast destination have their destination
+  IP address adapted to the subnet on which they are forwarded.
+  This makes it possible to use broadcast-based services (such as
+  NetBIOS) across different IP subnets.
+* The code to relate fragments with their main IP packet did not
+  work when the fragment arrived earlier than the main packet.
+  This would cause fragments of BMF-packets to be falsely forwarded.
+  For now, removed the forwarding of IP fragments. (Who's using
+  IP-fragments anyway?)
+* Packets are forwarded from one non-OLSR interface to the other
+  non-OLSR interfaces.
+* Various small optimizations and style improvements.
+
+12 Jul 2006: Version 1.1
+* Major updates in code forwarding from and to non-OLSR enabled
+  network interfaces.
+* Debug level 9 gives a better indication of what happens to each
+  handled multicast/broadcast packet. To run the olsr daemon with
+  debug level 9, run "olsrd -d 9".
+* Can now deal with network interface removal ("ifdown eth1") and
+  addition ("ifup eth1").
+* CRC-calculation for duplicate detection is done over first 256
+  bytes in packet instead of over full packet length.
+* CRC calculated only on captured packets, and is subsequently
+  passed on in a special OLSR-BMF encapsulation header.
+* Deals correctly with fragmented packets
+
+27 Apr 2006: Version 1.0.1
+* First release.
+
index a902175..0f4bf74 100644 (file)
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  * 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 $ */
-
+/* -------------------------------------------------------------------------
+ * File       : Address.c
+ * Description: IP packet characterization functions
+ * Created    : 29 Jun 2006
+ *
+ * $Id: Address.c,v 1.2 2007/02/10 17:05:55 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 #include "Address.h"
 
 /* System includes */
 #include <assert.h> /* assert() */
 #include "Address.h"
 
 /* System includes */
 #include <assert.h> /* assert() */
+#include <netinet/ip.h> /* struct ip */
+#include <netinet/udp.h> /* struct udphdr */
 
 /* OLSRD includes */
 #include "defs.h" /* COMP_IP */
 
 /* Plugin includes */
 #include "Bmf.h" /* BMF_ENCAP_PORT */
 
 /* OLSRD includes */
 #include "defs.h" /* COMP_IP */
 
 /* Plugin includes */
 #include "Bmf.h" /* BMF_ENCAP_PORT */
+#include "NetworkInterfaces.h" /* TBmfInterface */
+
+/* Whether or not to flood local broadcast packets (e.g. packets with IP
+ * destination 192.168.1.255). May be overruled by setting the plugin
+ * parameter "DoLocalBroadcast" to "no" */
+int EnableLocalBroadcast = 1;
+
+/* -------------------------------------------------------------------------
+ * Function   : DoLocalBroadcast
+ * Description: Overrule the default setting, enabling or disabling the
+ *              flooding of local broadcast packets
+ * Input      : enable - either "yes" or "no"
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int DoLocalBroadcast(const char* enable)
+{
+  if (strcmp(enable, "yes") == 0)
+  {
+    EnableLocalBroadcast = 1;
+    return 1;
+  }
+  else if (strcmp(enable, "no") == 0)
+  {
+    EnableLocalBroadcast = 0;
+    return 1;
+  }
 
 
+  /* Value not recognized */
+  return 0;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : IsMulticast
+ * Description: Check if an IP address is a multicast address
+ * Input      : ipAddress
+ * Output     : none
+ * Return     : true (1) or false (0)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 int IsMulticast(union olsr_ip_addr* ipAddress)
 {
   assert(ipAddress != NULL);
 int IsMulticast(union olsr_ip_addr* ipAddress)
 {
   assert(ipAddress != NULL);
@@ -50,43 +98,133 @@ int IsMulticast(union olsr_ip_addr* ipAddress)
   return (ntohl(ipAddress->v4) & 0xF0000000) == 0xE0000000;
 }
 
   return (ntohl(ipAddress->v4) & 0xF0000000) == 0xE0000000;
 }
 
-int IsLocalBroadcast(union olsr_ip_addr* destIp, struct interface* ifFrom)
+/* -------------------------------------------------------------------------
+ * Function   : IsLocalBroadcast
+ * Description: Check if an IP address is a local broadcast address for a
+ *              given network interface
+ * Input      : destIp, broadAddr
+ * Output     : none
+ * Return     : true (1) or false (0)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int IsLocalBroadcast(union olsr_ip_addr* destIp, struct sockaddr* broadAddr)
 {
   struct sockaddr_in* sin;
   
 {
   struct sockaddr_in* sin;
   
-  assert(destIp != NULL);
-
-  /* Protect ourselves against bogus input */
-  if (ifFrom == NULL) return 0;
+  assert(destIp != NULL && broadAddr != NULL);
 
   /* Cast down to correct sockaddr subtype */
 
   /* 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;
+  sin = (struct sockaddr_in*)broadAddr;
 
   return COMP_IP(&(sin->sin_addr.s_addr), destIp);
 }
 
 
   return COMP_IP(&(sin->sin_addr.s_addr), destIp);
 }
 
-int IsOlsrOrBmfPacket(unsigned char* buffer, ssize_t len)
+/* -------------------------------------------------------------------------
+ * Function   : IsOlsrOrBmfPacket
+ * Description: Check if an ethernet packet is an OLSR packet or a BMF packet
+ * Input      : intf, ethPkt, len
+ * Output     : none
+ * Return     : true (1) or false (0)
+ * Data Used  : none
+ * Assumption : len >= IP_HDR_OFFSET + GetIpHeaderLength(ethPkt)
+ * ------------------------------------------------------------------------- */
+int IsOlsrOrBmfPacket(struct TBmfInterface* intf, unsigned char* ethPkt, size_t len)
 {
 {
-  u_int16_t port;
+  struct ip* ipData;
+  unsigned int ipHeaderLen;
+  struct udphdr* udpData;
+  u_int16_t destPort;
 
 
-  assert(buffer != NULL);
+  assert(ethPkt != NULL);
 
   /* Consider OLSR and BMF packets not to be local broadcast
    * OLSR packets are UDP - port 698
 
   /* Consider OLSR and BMF packets not to be local broadcast
    * OLSR packets are UDP - port 698
-   * BMF packets are UDP - port 50505 */
+   * OLSR-BMF packets are UDP - port 50698
+   * OLSR-Autodetect probe packets are UDP - port 51698
+   * Fragments of the above packets are also not local broadcast */
 
 
-  memcpy(&port, buffer + 0x24, 2);
-  port = ntohs(port);
+  ipData = (struct ip*) (ethPkt + IP_HDR_OFFSET);
+  if (ipData->ip_p != SOL_UDP)
+  {
+    return 0;
+  }
 
 
-  if (len > 0x25 &&
-      buffer[0x17] == 0x11 && /* UDP */
-      (port == OLSRPORT || port == BMF_ENCAP_PORT))
+  /* Check if the packet is an IP-fragment */
+  if ((ntohs(ipData->ip_off) & IP_OFFMASK) != 0)
   {
   {
+#if 0
+    int i;
+    for (i = 0; i < FRAGMENT_HISTORY_SIZE; i++)
+    {
+      /* Quick-access pointer */
+      struct TFragmentHistory* entry = &intf->fragmentHistory[i];
+
+      /* Match */
+      if (entry->ipId == ntohs(ipData->ip_id) &&
+          entry->ipProto == ipData->ip_p &&
+          entry->ipSrc.s_addr == ntohl(ipData->ip_src.s_addr) &&
+          entry->ipDst.s_addr == ntohl(ipData->ip_dst.s_addr))
+      {
+        /* Found matching history entry, so packet is assumed to be a fragment
+         * of an earlier OLSR/OLSR-BMF/OLSR-Autodetect packet */
+
+        /* More fragments? If not, invalidate entry */
+        if (((ntohs(ipData->ip_off) & IP_MF) == 0))
+        {
+          memset(entry, 0, sizeof(struct TFragmentHistory));
+        }
+
+        return 1;
+      }
+    }
+
+    /* Matching history entry not found, so packet is not assumed to be a fragment
+     * of an earlier OLSR/OLSR-BMF/OLSR-Autodetect packet */
+#endif
+    /* OOPS! IP-fragments may come in earlier than their main packet. In that case,
+     * their relation with the main packet is not detected by the above code, resulting
+     * in stray fragments being forwarded all ove the network. Solution for now is to
+     * not forward any IP-fragments at all. */
+    /*return 0;*/
     return 1;
   }
     return 1;
   }
+
+  /* The packet is the first (or only) IP-fragment */
+
+  /* Check length first */
+  ipHeaderLen = ipData->ip_hl << 2;
+  if (len < IP_HDR_OFFSET + ipHeaderLen + sizeof(struct udphdr))
+  {
+    return 0;
+  }
+
+  /* Go into the UDP header and check port number */
+  udpData = (struct udphdr*) (ethPkt + IP_HDR_OFFSET + ipHeaderLen);
+  destPort = ntohs(udpData->dest);
+
+  if (destPort == OLSRPORT || destPort == BMF_ENCAP_PORT || destPort == 51698)
+      /* TODO: #define for 51698 */
+  {
+#if 0
+    /* If more fragments are expected, keep a record in the fragment history */
+    if ((ntohs(ipData->ip_off) & IP_MF) != 0)
+    {
+      /* Quick-access pointer */
+      struct TFragmentHistory* entry = &intf->fragmentHistory[intf->nextFragmentHistoryEntry];
+
+      /* Store in fragment history */
+      entry->ipId = ntohs(ipData->ip_id);
+      entry->ipProto = ipData->ip_p;
+      entry->ipSrc.s_addr = ntohl(ipData->ip_src.s_addr);
+      entry->ipDst.s_addr = ntohl(ipData->ip_dst.s_addr);
+
+      /* Advance to next entry */
+      intf->nextFragmentHistoryEntry++;
+      intf->nextFragmentHistoryEntry %= FRAGMENT_HISTORY_SIZE;
+    }
+#endif
+    return 1;
+  }
+
   return 0;
 }
   return 0;
 }
index fd8fc3f..6424262 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: Address.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : Address.h
+ * Description: IP packet characterization functions
+ * Created    : 29 Jun 2006
+ *
+ * $Id: Address.h,v 1.2 2007/02/10 17:05:55 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 #include "olsr_types.h" /* olsr_ip_addr */
 #include "interfaces.h" /* struct interface */
 
 
 #include "olsr_types.h" /* olsr_ip_addr */
 #include "interfaces.h" /* struct interface */
 
+struct TBmfInterface;
+
+extern int EnableLocalBroadcast;
+
+int DoLocalBroadcast(const char* enable);
 int IsMulticast(union olsr_ip_addr* ipAddress);
 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);
+int IsLocalBroadcast(union olsr_ip_addr* destIp, struct sockaddr* broadAddr);
+int IsOlsrOrBmfPacket(struct TBmfInterface* intf, unsigned char* ethPkt, size_t len);
 
 #endif /* _BMF_ADDRESS_H */
 
 #endif /* _BMF_ADDRESS_H */
index 7cefe69..c5a3c40 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: Bmf.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : Bmf.c
+ * Description: Multicast forwarding functions
+ * Created    : 29 Jun 2006
+ *
+ * $Id: Bmf.c,v 1.2 2007/02/10 17:05:55 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 #define _MULTI_THREADED
 
 
 #define _MULTI_THREADED
 
 #include <errno.h> /* errno */
 #include <assert.h> /* assert() */
 #include <linux/if_packet.h> /* struct sockaddr_ll, PACKET_MULTICAST */
 #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 */
+#include <pthread.h> /* pthread_t, pthread_create() */
+#include <signal.h> /* sigset_t, sigfillset(), sigdelset(), SIGINT */
+#include <netinet/ip.h> /* struct ip */
 
 /* OLSRD includes */
 
 /* OLSRD includes */
-#include "defs.h" /* olsr_cnf */
+#include "defs.h" /* olsr_cnf, OLSR_PRINTF */
 #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() */
 #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() */
+#include "link_set.h" /* get_best_link_to_neighbor() */
 
 /* Plugin includes */
 #include "NetworkInterfaces.h" /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */
 
 /* Plugin includes */
 #include "NetworkInterfaces.h" /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */
 static pthread_t BmfThread;
 static int BmfThreadRunning = 0;
 
 static pthread_t BmfThread;
 static int BmfThreadRunning = 0;
 
+/* -------------------------------------------------------------------------
+ * Function   : EncapsulateAndForwardPacket
+ * Description: Encapsulate a captured raw IP packet and forward it
+ * Input      : intf - the network interface on which to forward the packet
+ *              buffer - space for the encapsulation header, followed by
+ *                the captured packet
+ *              len - the number of octets in the encapsulation header plus
+ *                captured packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+static void EncapsulateAndForwardPacket(struct TBmfInterface* intf, unsigned char* buffer, ssize_t len)
+{
+  unsigned char* ethPkt = buffer + ENCAP_HDR_LEN;
+  int nBytesWritten;
+  struct sockaddr_in encapDest;
+
+  /* Change encapsulated source MAC address to that of sending interface */
+  memcpy(ethPkt + IFHWADDRLEN, intf->macAddr, IFHWADDRLEN);
+
+  /* Destination address is local broadcast */
+  memset(&encapDest, 0, sizeof(encapDest));
+  encapDest.sin_family = AF_INET;
+  encapDest.sin_port = htons(BMF_ENCAP_PORT);
+  encapDest.sin_addr.s_addr = ((struct sockaddr_in*)&intf->olsrIntf->int_broadaddr)->sin_addr.s_addr;
+
+  nBytesWritten = sendto(
+    intf->encapsulatingSkfd,
+    buffer,
+    len,
+    MSG_DONTROUTE,
+    (struct sockaddr*) &encapDest,
+    sizeof(encapDest));                   
+  if (nBytesWritten != len)
+  {
+    olsr_printf(
+      1,
+      "%s: sendto() error forwarding pkt to \"%s\": %s\n",
+      PLUGIN_NAME,
+      intf->ifName,
+      strerror(errno));
+  }
+  else
+  {
+    OLSR_PRINTF(
+      9,
+      "%s: --> encapsulated and forwarded to \"%s\"\n",
+      PLUGIN_NAME_SHORT,
+      intf->ifName);
+  } /* if (nBytesWritten != len) */
+}
 
 
-static void BmfPacketCaptured(struct TBmfInterface* intf, unsigned char* buffer, ssize_t len)
+/* -------------------------------------------------------------------------
+ * Function   : BmfPacketCaptured
+ * Description: Handle a captured raw IP packet
+ * Input      : intf - the network interface on which the packet was captured
+ *              sllPkttype - the type of packet. Either PACKET_OUTGOING,
+ *                PACKET_BROADCAST or PACKET_MULTICAST.
+ *              buffer - space for the encapsulation header, followed by
+ *                the captured packet
+ *              len - the number of octets in the encapsulation header plus
+ *                captured packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfInterfaces
+ * Notes      : The packet is assumed to be captured on a socket of family
+ *              PF_PACKET and type SOCK_RAW.
+ * ------------------------------------------------------------------------- */
+static void BmfPacketCaptured(
+  struct TBmfInterface* intf,
+  unsigned char sllPkttype,
+  unsigned char* buffer,
+  ssize_t len)
 {
 {
-  struct interface* ifFrom;
   unsigned char* srcMac;
   union olsr_ip_addr srcIp;
   union olsr_ip_addr destIp;
   unsigned char* srcMac;
   union olsr_ip_addr srcIp;
   union olsr_ip_addr destIp;
-  union olsr_ip_addr* originator;
-  struct sockaddr_in sin;
+  union olsr_ip_addr* origIp;
   struct TBmfInterface* nextFwIntf;
   struct TBmfInterface* nextFwIntf;
+  int isFromOlsrIntf;
+  int isFromOlsrNeighbor;
+  int iAmMpr;
+  unsigned char* ethPkt = buffer + ENCAP_HDR_LEN;
+  ssize_t ethPktLen = len - ENCAP_HDR_LEN;
+  struct ip* ipData;
+  u_int32_t crc32;
+  struct TEncapHeader* encapHdr;
 
   /* Only forward IPv4 packets */
   u_int16_t type;
 
   /* Only forward IPv4 packets */
   u_int16_t type;
-  memcpy(&type, buffer + ETH_TYPE_OFFSET, 2);
+  memcpy(&type, ethPkt + ETH_TYPE_OFFSET, 2);
   if (ntohs(type) != IPV4_TYPE)
   {
     return;
   }
 
   if (ntohs(type) != IPV4_TYPE)
   {
     return;
   }
 
-  /* Lookup the OLSR interface on which this packet is received */
-  ifFrom = intf->olsrIntf;
+  ipData = (struct ip*)(ethPkt + IP_HDR_OFFSET);
 
 
-  /* Only forward multicast or local broadcast packets */
-  COPY_IP(&destIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_DSTIP);
-  if (! IsMulticast(&destIp) && ! IsLocalBroadcast(&destIp, ifFrom))
+  /* Only forward multicast packets. Also forward local broadcast packets,
+   * if configured */
+  COPY_IP(&destIp, &ipData->ip_dst);
+  if (IsMulticast(&destIp) ||
+      (EnableLocalBroadcast != 0 && IsLocalBroadcast(&destIp, &intf->broadAddr)))
   {
   {
-    return;
+    /* continue */
   }
   }
-  
-  /* Discard OLSR packets (UDP port 698) and BMF encapsulated packets
-   * (UDP port 50505) */
-  if (IsOlsrOrBmfPacket(buffer, len))
+  else
   {
     return;
   }
 
   {
     return;
   }
 
-  /* Apply drop list for testing purposes. */
-  srcMac = buffer + IFHWADDRLEN;
-  if (IsInDropList(srcMac))
+  /* Discard OLSR packets (UDP port 698) and BMF encapsulated packets */
+  if (IsOlsrOrBmfPacket(intf, ethPkt, ethPktLen))
   {
     return;
   }
 
   {
     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;
-  }
+  /* Check if this packet is captured on an OLSR-enabled interface */
+  isFromOlsrIntf = (intf->olsrIntf != NULL);
 
 
-  olsr_printf(
+  COPY_IP(&srcIp, &ipData->ip_src);
+  OLSR_PRINTF(
     9,
     9,
-    "MC pkt to %s received from originator %s (%s) via \"%s\"\n",
-    olsr_ip_to_string(&destIp),
-    olsr_ip_to_string(originator),
+    "%s: %s pkt of %d bytes captured on %s interface \"%s\": %s->%s\n",
+    PLUGIN_NAME_SHORT,
+    sllPkttype == PACKET_OUTGOING ? "outgoing" : "incoming",
+    ethPktLen,
+    isFromOlsrIntf ? "OLSR" : "non-OLSR",
+    intf->ifName,
     olsr_ip_to_string(&srcIp),
     olsr_ip_to_string(&srcIp),
-    intf->ifName);
+    olsr_ip_to_string(&destIp));
 
 
-  /* Check if I am MPR for that originator */
-  if (ifFrom != NULL && olsr_lookup_mprs_set(originator) == NULL)
+  /* Apply drop list for testing purposes. */
+  srcMac = ethPkt + IFHWADDRLEN;
+  if (IsInDropList(srcMac))
   {
   {
-    olsr_printf(
+    OLSR_PRINTF(
       9,
       9,
-      "--> Discarding pkt: I am not selected as MPR by that originator\n");
+      "%s: --> discarding: source MAC (%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) found in drop list\n",
+      PLUGIN_NAME_SHORT,
+      *srcMac, *(srcMac + 1), *(srcMac + 2), *(srcMac + 3), *(srcMac + 4), *(srcMac + 5));
     return;
   }
 
     return;
   }
 
-  /* If this packet is captured on a non-OLSR interface, decrease
-   * the TTL and re-calculate the IP header checksum */
-  if (ifFrom == NULL)
+  /* Lookup main address of source in the MID table of OLSR */
+  origIp = mid_lookup_main_addr(&srcIp);
+  if (origIp == NULL)
   {
   {
-    PacketDecreaseTtlAndUpdateHeaderChecksum(buffer);
+    origIp = &srcIp;
   }
 
   }
 
-  /* If the TTL is <= 0, do not forward this packet */
-  if (GetIpTtl(buffer) <= 0)
+#ifdef DO_TTL_STUFF
+  /* If this packet is captured on a non-OLSR interface, decrease
+   * the TTL and re-calculate the IP header checksum. */
+  if (! isFromOlsrIntf)
+  {
+    DecreaseTtlAndUpdateHeaderChecksum(ethPkt);
+  } */
+
+  /* If the resulting TTL is <= 0, this packet life has ended, so do not forward it */
+  if (GetIpTtl(ethPkt) <= 0)
   {
   {
+    OLSR_PRINTF(
+      9,
+      "%s: --> discarding: TTL=0\n",
+      PLUGIN_NAME_SHORT);
     return;
     return;
-  }
+  } */
+#endif
 
   /* Check if this packet was seen recently */
 
   /* Check if this packet was seen recently */
-  if (CheckMarkRecentPacket(buffer, len))
+  crc32 = PacketCrc32(ethPkt, ethPktLen);
+  if (CheckAndMarkRecentPacket(Hash16(crc32)))
   {
   {
-    olsr_printf(
+    OLSR_PRINTF(
       9,
       9,
-      "--> Discarding pkt: was a duplicate\n");
+      "%s: --> discarding: packet is duplicate\n",
+      PLUGIN_NAME_SHORT);
     return;
   }
 
     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);
+  /* Compose encapsulation header */
+  encapHdr = (struct TEncapHeader*) buffer;
+  memset (encapHdr, 0, ENCAP_HDR_LEN);
+  encapHdr->crc32 = htonl(crc32);
+
+  /* Check if this packet is captured on an OLSR interface from an OLSR neighbor */
+  isFromOlsrNeighbor =
+    (isFromOlsrIntf /* The packet is captured on an OLSR interface... */
+    && get_best_link_to_neighbor(origIp) != NULL); /* ...from an OLSR neighbor */ 
+
+  /* Check with OLSR if I am MPR for that neighbor */
+  iAmMpr = olsr_lookup_mprs_set(origIp) != NULL;
 
 
+  /* Check with each interface what needs to be done on it */
   nextFwIntf = BmfInterfaces;
   while (nextFwIntf != NULL)
   {
   nextFwIntf = BmfInterfaces;
   while (nextFwIntf != NULL)
   {
+    int isToOlsrIntf;
+
     struct TBmfInterface* fwIntf = nextFwIntf;
     nextFwIntf = fwIntf->next;
 
     struct TBmfInterface* fwIntf = nextFwIntf;
     nextFwIntf = fwIntf->next;
 
-    if (fwIntf->olsrIntf != NULL)
+    /* Is the forwarding interface OLSR-enabled? */
+    isToOlsrIntf = (fwIntf->olsrIntf != NULL);
+
+    /* Depending on certain conditions, we decide whether or not to forward
+     * the packet, and if it is forwarded, in which form (encapsulated
+     * or not, TTL decreased or not). These conditions are:
+     * - is the packet is coming in on an OLSR interface or not? (isFromOlsrIntf)
+     * - is the packet going out on an OLSR interface or not? (isToOlsrIntf)
+     * - if the packet if coming in on an OLSR interface:
+     *   - is the node that forwarded the packet my OLSR-neighbor? (isFromOlsrNeighbor)
+     *   - has the node that forwarded the packet selected me as MPR? (iAmMpr)
+     *
+     * Based on these conditions, the following cases can be distinguished:
+     *
+     * - Case 1: Packet coming in on an OLSR interface. What to
+     *   do with it on an OLSR interface?
+     *   Answer:
+     *   - Case 1.1: If the forwarding node is an OLSR neighbor that has *not*
+     *     selected me as MPR: don't forward the packet.
+     *   - Case 1.2: If the forwarding node is an OLSR neighbor that has selected
+     *     me as MPR: encapsulate and forward the packet.
+     *   - Case 1.3: If the forwarding node is not an OLSR neighbor: encapsulate
+     *     and forward the packet.
+     *     NOTE: Case 1.3 is a special case. In the perfect world, we expect to
+     *     see only OLSR-neighbors on OLSR-enabled interfaces. Sometimes, however,
+     *     ignorant users will connect a host not running OLSR, to a LAN in
+     *     which there are hosts running OLSR. Of course these ignorant users,
+     *     expecting magic, want to see their multicast packets being forwarded
+     *     through the network.
+     *
+     * - Case 2: Packet coming in on an OLSR interface. What to do with it on a
+     *   non-OLSR interface?
+     *   Answer: [Decrease the packet's TTL and] forward it.
+     *
+     * - Case 3: Packet coming in on a non-OLSR interface. What to
+     *   do with it on an OLSR interface?
+     *   Answer: [Decrease the packet's TTL, then] encapsulate and forward it.
+     *
+     * - Case 4: Packet coming in on non-OLSR interface. What to do with it on a
+     *   non-OLSR interface?
+     *   Answer 1: nothing. Multicast routing between non-OLSR interfaces
+     *   is to be done by other protocols (e.g. PIM, DVMRP).
+     *   Answer 2 (better): [Decrease the packet's TTL, then] forward it.
+     */
+
+    if (isFromOlsrIntf && isToOlsrIntf)
     {
     {
-      int nBytesWritten;
+      /* Case 1: Forward from an OLSR interface to an OLSR interface */
 
 
-      /* 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;
+      if (isFromOlsrNeighbor && !iAmMpr)
+      {
+        /* Case 1.1 */
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: --> not encap-forwarding to \"%s\": I am not selected as MPR by neighbor %s\n",
+            PLUGIN_NAME_SHORT,
+            fwIntf->ifName,
+            olsr_ip_to_string(&srcIp));
+        }    
+      }
+      else if (sllPkttype == PACKET_OUTGOING && intf == fwIntf)
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: --> not encap-forwarding to \"%s\": pkt was captured on that interface\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
+      }
+      else
+      {
+        /* Case 1.2 and 1.3 */
+        EncapsulateAndForwardPacket(fwIntf, buffer, len);
+      }
+    } /* if (isFromOlsrIntf && isToOlsrIntf) */
 
 
-      nBytesWritten = sendto(
-        fwIntf->encapsulatingSkfd,
-        buffer,
-        len,
-        MSG_DONTROUTE,
-        (struct sockaddr*) &sin,
-        sizeof(sin));                   
+    else if (isFromOlsrIntf && !isToOlsrIntf)
+    {
+      /* Case 2: Forward from OLSR interface to non-OLSR interface.
+       * [Decrease TTL and] forward */
 
 
-      if (nBytesWritten != len)
+#ifdef DO_TTL_STUFF
+      /* If the TTL is to become 0, do not forward this packet */
+      if (GetIpTtl(ethPkt) <= 1)
       {
       {
-        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));
+        OLSR_PRINTF(
+          9,
+          "%s: --> not forwarding to \"%s\": TTL=0\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
       }
       else
       {
       }
       else
       {
-        olsr_printf(
+        struct TSaveTtl sttl;
+#endif
+        int nBytesWritten;
+
+        /* Change source MAC address to that of sending interface */
+        memcpy(ethPkt + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
+
+        /* If the destination address is not a multicast address, it is assumed to be
+         * a local broadcast packet. Update the destination address to match the subnet
+         * of the network interface on which the packet is being sent. */
+        CheckAndUpdateLocalBroadcast(ethPkt, &fwIntf->broadAddr);
+
+#ifdef DO_TTL_STUFF
+        /* Save IP header checksum and the TTL-value of the packet */ 
+        SaveTtlAndChecksum(ethPkt, &sttl);
+
+        /* Decrease the TTL by 1 before writing */
+        DecreaseTtlAndUpdateHeaderChecksum(ethPkt);
+#endif
+
+        nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
+        if (nBytesWritten != ethPktLen)
+        {
+          olsr_printf(
+            1,
+            "%s: write() error forwarding pkt for %s to \"%s\": %s\n",
+            PLUGIN_NAME,
+            olsr_ip_to_string(&destIp),
+            fwIntf->ifName,
+            strerror(errno));
+        }
+        else
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: --> forwarded to \"%s\"\n",
+            PLUGIN_NAME_SHORT,
+            fwIntf->ifName);
+        }
+
+#ifdef DO_TTL_STUFF
+        /* Restore the IP header checksum and the TTL-value of the packet */
+        RestoreTtlAndChecksum(ethPkt, &sttl);
+
+      } /* if (GetIpTtl(ethPkt) <= 1) */
+#endif
+    } /* else if (isFromOlsrIntf && !isToOlsrIntf) */
+
+    else if (!isFromOlsrIntf && isToOlsrIntf)
+    {
+      /* Case 3: Forward from a non-OLSR interface to an OLSR interface.
+       * Encapsulate and forward packet.
+       * Note that packets from non-OLSR interfaces already had their TTL decreased. */
+
+      EncapsulateAndForwardPacket(fwIntf, buffer, len);
+    } /* else if (!isFromOlsrIntf && isToOlsrIntf) */
+
+    else
+    {
+      /* Case 4: Forward from non-OLSR interface to non-OLSR interface.
+       * Note that packets from non-OLSR interfaces already had their TTL decreased. */
+
+      /* Don't forward on interface on which packet was received */
+      if (intf == fwIntf)
+      {
+        OLSR_PRINTF(
           9,
           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) */
+          "%s: --> not forwarding to \"%s\": pkt was captured on that interface\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
+      }
+
+#ifdef DO_TTL_STUFF
+      /* If the TTL is <= 0, do not forward this packet */
+      else if (GetIpTtl(ethPkt) <= 0)
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: --> not forwarding to \"%s\": TTL=0\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
+      }
+#endif
+      else
+      {
+        int nBytesWritten;
+
+        /* Change source MAC address to that of sending interface */
+        memcpy(ethPkt + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
+
+        /* If the destination address is not a multicast address, it is assumed to be
+         * a local broadcast packet. Update the destination address to match the subnet
+         * of the network interface on which the packet is being sent. */
+        CheckAndUpdateLocalBroadcast(ethPkt, &fwIntf->broadAddr);
+
+        nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
+        if (nBytesWritten != ethPktLen)
+        {
+          olsr_printf(
+            1,
+            "%s: write() error forwarding pkt for %s to \"%s\": %s\n",
+            PLUGIN_NAME,
+            olsr_ip_to_string(&destIp),
+            fwIntf->ifName,
+            strerror(errno));
+        }
+        else
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: --> forwarded from non-OLSR to non-OLSR \"%s\"\n",
+            PLUGIN_NAME_SHORT,
+            fwIntf->ifName);
+        }
+      } /* if (intf == fwIntf) */
+    }
   } /* while (nextFwIntf != NULL) */
 }
 
   } /* while (nextFwIntf != NULL) */
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : BmfEncapsulatedPacketReceived
+ * Description: Handle a received BMF-encapsulated IP packet
+ * Input      : intf - the network interface on which the packet was received
+ *              fromIp - the IP node that forwarded the packet to us
+ *              buffer - the received encapsulated packet
+ *              len - the number of octets in the received encapsulated packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfInterfaces
+ * Notes      : The packet is assumed to be received on a socket of family
+ *              PF_INET and type SOCK_DGRAM (UDP).
+ * ------------------------------------------------------------------------- */
 static void BmfEncapsulatedPacketReceived(
   struct TBmfInterface* intf, 
 static void BmfEncapsulatedPacketReceived(
   struct TBmfInterface* intf, 
-  struct in_addr srcIp,
+  union olsr_ip_addr* fromIp,
   unsigned char* buffer,
   ssize_t len)
 {
   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;
   union olsr_ip_addr* forwarder;
   int nBytesToWrite;
   unsigned char* bufferToWrite;
   int nBytesWritten;
   int iAmMpr;
-  struct sockaddr_in sin;
+  struct sockaddr_in encapDest;
   struct TBmfInterface* nextFwIntf;
   struct TBmfInterface* nextFwIntf;
-
-  COPY_IP(&fromAddr, &srcIp.s_addr);
+  struct ip* ipData;
+  unsigned char* ethPkt;
+  ssize_t ethPktLen;
+  struct TEncapHeader* encapHdr;
 
   /* Are we talking to ourselves? */
 
   /* Are we talking to ourselves? */
-  if (if_ifwithaddr(&fromAddr) != NULL)
+  if (if_ifwithaddr(fromIp) != NULL)
   {
     return;
   }
 
   {
     return;
   }
 
-  /* Lookup the OLSR interface on which this packet is received */
-  ifFrom = intf->olsrIntf;
-
   /* Encapsulated packet received on non-OLSR interface? Then discard */
   /* Encapsulated packet received on non-OLSR interface? Then discard */
-  if (ifFrom == NULL)
+  if (intf->olsrIntf == NULL)
   {
     return;
   }
   {
     return;
   }
@@ -242,74 +535,86 @@ static void BmfEncapsulatedPacketReceived(
    * chain, e.g.:
    * iptables -A FORWARD -m mac --mac-source 00:0C:29:28:0E:CC -j DROP */
 
    * 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);
-  }
+  ethPkt = buffer + ENCAP_HDR_LEN;
+  ethPktLen = len - ENCAP_HDR_LEN;
+
+  ipData = (struct ip*) (ethPkt + IP_HDR_OFFSET);
+
+  OLSR_PRINTF(
+    9,
+    "%s: encapsulated pkt of %d bytes incoming on \"%s\": %s->",
+    PLUGIN_NAME_SHORT,
+    ethPktLen,
+    intf->ifName,
+    inet_ntoa(ipData->ip_src));
+  OLSR_PRINTF(
+    9,
+    "%s, forwarded by %s\n",
+    inet_ntoa(ipData->ip_dst), /* not possible to call inet_ntoa twice in same printf */
+    olsr_ip_to_string(fromIp));
+
+  /* Get encapsulation header */
+  encapHdr = (struct TEncapHeader*) buffer;
 
   /* Check if this packet was seen recently */
 
   /* Check if this packet was seen recently */
-  if (CheckMarkRecentPacket(buffer, len))
+  if (CheckAndMarkRecentPacket(Hash16(ntohl(encapHdr->crc32))))
   {
   {
-    olsr_printf(
+    OLSR_PRINTF(
       9,
       9,
-      "--> Discarding encapsulated pkt: was a duplicate\n");
+      "%s: --> discarding: packet is duplicate\n",
+      PLUGIN_NAME_SHORT);
     return;
   }
 
     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)
+  if (EtherTunTapFd >= 0)
   {
   {
-    olsr_printf(
-      1,
-      "%s: write() error sending encapsulated MC pkt to \"%s\": %s\n",
-      PLUGIN_NAME,
-      EtherTunTapIfName,
-      strerror(errno));
+    struct sockaddr broadAddr;
+
+    /* Unpack encapsulated packet and send a copy to myself via the EtherTunTap interface */
+    bufferToWrite = ethPkt;
+    nBytesToWrite = ethPktLen;
+    if (TunOrTap == TT_TUN)
+    {
+      bufferToWrite += IP_HDR_OFFSET;
+      nBytesToWrite -= IP_HDR_OFFSET;
+    }
+
+    ((struct sockaddr_in*)&broadAddr)->sin_addr.s_addr = htonl(EtherTunTapIpBroadcast);
+    CheckAndUpdateLocalBroadcast(ethPkt, &broadAddr);
+
+    nBytesWritten = write(EtherTunTapFd, bufferToWrite, nBytesToWrite);
+    if (nBytesWritten != nBytesToWrite)
+    {
+      olsr_printf(
+        1,
+        "%s: write() error forwarding encapsulated pkt to \"%s\": %s\n",
+        PLUGIN_NAME,
+        EtherTunTapIfName,
+        strerror(errno));
+    }
+    else
+    {
+      OLSR_PRINTF(
+        9,
+        "%s: --> unpacked and forwarded to \"%s\"\n",
+        PLUGIN_NAME_SHORT,
+        EtherTunTapIfName);
+    }
   }
   }
-  else
+
+  /* Lookup main address of forwarding node */
+  forwarder = mid_lookup_main_addr(fromIp);
+  if (forwarder == NULL)
   {
   {
-    olsr_printf(
-      9,
-      "Successfully unpacked and sent encapsulated MC pkt to \"%s\"\n",
-      EtherTunTapIfName);
+    forwarder = fromIp;
   }
 
   /* Check if I am MPR for the forwarder */
   iAmMpr = (olsr_lookup_mprs_set(forwarder) != NULL);
   }
 
   /* 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);
+  memset(&encapDest, 0, sizeof(encapDest));
+  encapDest.sin_family = AF_INET;
+  encapDest.sin_port = htons(BMF_ENCAP_PORT);
 
   nextFwIntf = BmfInterfaces;
   while (nextFwIntf != NULL)
 
   nextFwIntf = BmfInterfaces;
   while (nextFwIntf != NULL)
@@ -317,123 +622,310 @@ static void BmfEncapsulatedPacketReceived(
     struct TBmfInterface* fwIntf = nextFwIntf;
     nextFwIntf = fwIntf->next;
 
     struct TBmfInterface* fwIntf = nextFwIntf;
     nextFwIntf = fwIntf->next;
 
-    /* On non-OLSR interfaces: unpack encapsulated packet, decrease TTL
-     * and send */
+    /* Depending on certain conditions, decide whether or not to forward
+     * the packet, and if it is forwarded, in which form (encapsulated
+     * or not). These conditions are:
+     * - is the packet going out on an OLSR interface or not? (isToOlsrIntf)
+     * - is this node selected as MPR by the node that forwarded the packet,
+     *   or not? (iAmMpr)
+     * Note that the packet is always coming in on an OLSR interface, because
+     * it is an encapsulated BMF packet.
+     *
+     * Based on these conditions, 3 cases can be distinguished:
+     * - Case 1: What to do with the packet on a non-OLSR interface?
+     *   Answer: unpack encapsulated packet, [decrease its TTL and] forward it.
+     * - Case 2: The forwarding node has selected us as MPR. What to
+     *   do with the packet on an OLSR interface?
+     *   Answer: Forward it.
+     * - Case 3: The forwarding node has not selected us as MPR. What to
+     *   do with the packet on an OLSR interface?
+     *   Answer: nothing. Nodes not selected as MPR must not participate in
+     *   the flooding.
+     */
+
+    /* Forward from OLSR interface to non-OLSR interface: unpack encapsulated
+     * packet, [decrease TTL] and forward */
     if (fwIntf->olsrIntf == NULL)
     {
     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)
+#ifdef DO_TTL_STUFF
+      /* If the TTL is to become 0, do not forward this packet */
+      if (GetIpTtl(ethPkt) <= 1)
       {
       {
-        olsr_printf(
-          1,
-          "%s: write() error sending unpacked encapsulated MC pkt to \"%s\": %s\n",
-          PLUGIN_NAME,
-          fwIntf->ifName,
-          strerror(errno));
-      }
-      else
-      {
-        olsr_printf(
+        OLSR_PRINTF(
           9,
           9,
-          "Successfully unpacked and sent one encapsulated MC pkt to \"%s\"\n",
+          "%s: --> not forwarding on \"%s\": TTL=0\n",
+          PLUGIN_NAME_SHORT,
           fwIntf->ifName);
       }
           fwIntf->ifName);
       }
+      else
+      {
+        struct TSaveTtl sttl;
+#endif
+
+        /* If the destination address is not a multicast address, it is assumed to be
+         * a local broadcast packet. Update the destination address to match the subnet
+         * of the network interface on which the packet is being sent. */
+        CheckAndUpdateLocalBroadcast(ethPkt, &fwIntf->broadAddr);
+
+#ifdef DO_TTL_STUFF
+        /* Save IP header checksum and the TTL-value of the packet, then 
+         * decrease the TTL by 1 before writing */
+        SaveTtlAndChecksum(ethPkt, &sttl);
+
+        /* Decrease the TTL by 1 before writing */
+        DecreaseTtlAndUpdateHeaderChecksum(ethPkt);
+#endif
+
+        nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
+        if (nBytesWritten != ethPktLen)
+        {
+          olsr_printf(
+            1,
+            "%s: write() error forwarding unpacked encapsulated pkt to \"%s\": %s\n",
+            PLUGIN_NAME,
+            fwIntf->ifName,
+            strerror(errno));
+        }
+        else
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: --> unpacked and forwarded to \"%s\"\n",
+            PLUGIN_NAME_SHORT,
+            fwIntf->ifName);
+        }
+
+#ifdef DO_TTL_STUFF
+        /* Restore the IP header checksum and the TTL-value of the packet */
+        RestoreTtlAndChecksum(ethPkt, &sttl);
 
 
-      /* Restore the IP header checksum and the TTL-value of the packet */
-      RestoreTtlAndChecksum(buffer, &sttl);
+      } /* if (GetIpTtl(ethPkt) <= 1) */
+#endif
     } /* if (fwIntf->olsrIntf == NULL) */
 
     } /* if (fwIntf->olsrIntf == NULL) */
 
-    /* On OLSR interfaces, forward the packet if this node is selected as MPR by the 
-     * forwarding node */
+    /* Forward from OLSR interface to OLSR interface: 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 */
     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;
+      encapDest.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr;
 
       nBytesWritten = sendto(
         fwIntf->encapsulatingSkfd,
         buffer,
         len,
         MSG_DONTROUTE,
 
       nBytesWritten = sendto(
         fwIntf->encapsulatingSkfd,
         buffer,
         len,
         MSG_DONTROUTE,
-        (struct sockaddr*) &sin,
-        sizeof(sin));                   
+        (struct sockaddr*) &encapDest,
+        sizeof(encapDest));                   
 
       if (nBytesWritten != len)
       {
         olsr_printf(
           1,
 
       if (nBytesWritten != len)
       {
         olsr_printf(
           1,
-          "%s: sendto() error forwarding encapsulated MC pkt to \"%s\": %s\n",
+          "%s: sendto() error forwarding encapsulated pkt via \"%s\": %s\n",
           PLUGIN_NAME,
           PLUGIN_NAME,
-          fwIntf->olsrIntf->int_name,
+          fwIntf->ifName,
           strerror(errno));
       }
       else
       {
           strerror(errno));
       }
       else
       {
-        olsr_printf(
+        OLSR_PRINTF(
           9,
           9,
-          "Successfully forwarded one encapsulated MC pkt to \"%s\"\n",
-          fwIntf->olsrIntf->int_name);
+          "%s: --> forwarded to \"%s\"\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
       }
       }
-    } /* else if (iAmMpr) */
+    }  /* else if (iAmMpr) */
+    else /* fwIntf->olsrIntf != NULL && !iAmMpr */
+    {
+      /* fwIntf is an OLSR interface and I am not selected as MPR */
+      OLSR_PRINTF(
+        9,
+        "%s: --> not forwarding to \"%s\": I am not selected as MPR by %s\n",
+        PLUGIN_NAME_SHORT,
+        fwIntf->ifName,
+        olsr_ip_to_string(fromIp));
+    }
   } /* while (nextFwIntf != NULL) */
 }
 
   } /* while (nextFwIntf != NULL) */
 }
 
-static void DoBmf(void* useless)
+/* -------------------------------------------------------------------------
+ * Function   : BmfTunPacketCaptured
+ * Description: Handle a raw IP packet captured outgoing on the tuntap interface
+ * Input      : buffer - space for the encapsulation header, followed by
+ *                the captured packet
+ *              len - the number of octets in the encapsulation header plus
+ *                captured packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * Notes      : The packet is assumed to be captured on a socket of family
+ *              PF_PACKET and type SOCK_RAW.
+ * ------------------------------------------------------------------------- */
+static void BmfTunPacketCaptured(
+  unsigned char* buffer,
+  ssize_t len)
 {
 {
-#define BUFFER_MAX 2048
-  struct TBmfInterface* intf;
-  int nFdBitsSet;
+  union olsr_ip_addr srcIp;
+  union olsr_ip_addr destIp;
+  struct TBmfInterface* nextFwIntf;
+  unsigned char* ethPkt = buffer + ENCAP_HDR_LEN;
+  ssize_t ethPktLen = len - ENCAP_HDR_LEN;
+  struct ip* ipData;
+  u_int32_t crc32;
+  struct TEncapHeader* encapHdr;
+  struct sockaddr broadAddr;
+  u_int16_t type;
+
+  /* Only forward IPv4 packets */
+  memcpy(&type, ethPkt + ETH_TYPE_OFFSET, 2);
+  if (ntohs(type) != IPV4_TYPE)
+  {
+    return;
+  }
 
 
-  /* Compose set of socket file descriptors. 
-   * Keep the highest descriptor seen. */
-  int highestSkfd = -1;
-  fd_set input_set;
-  FD_ZERO(&input_set);
+  ipData = (struct ip*)(ethPkt + IP_HDR_OFFSET);
 
 
-  intf = BmfInterfaces;
-  while (intf != NULL)
+  /* Only forward multicast packets, or local broadcast packets if specified */
+  COPY_IP(&destIp, &ipData->ip_dst);
+  ((struct sockaddr_in*)&broadAddr)->sin_addr.s_addr = htonl(EtherTunTapIpBroadcast);
+  if (IsMulticast(&destIp) ||
+      (EnableLocalBroadcast != 0 && IsLocalBroadcast(&destIp, &broadAddr)))
   {
   {
-    FD_SET(intf->capturingSkfd, &input_set);
-    if (intf->capturingSkfd > highestSkfd)
+    /* continue */
+  }
+  else
+  {
+    return;
+  }
+
+  COPY_IP(&srcIp, &ipData->ip_src);
+  OLSR_PRINTF(
+    9,
+    "%s: outgoing pkt of %d bytes captured on tuntap interface \"%s\": %s->%s\n",
+    PLUGIN_NAME_SHORT,
+    ethPktLen,
+    EtherTunTapIfName,
+    olsr_ip_to_string(&srcIp),
+    olsr_ip_to_string(&destIp));
+
+  /* Check if this packet was seen recently */
+  crc32 = PacketCrc32(ethPkt, ethPktLen);
+  if (CheckAndMarkRecentPacket(Hash16(crc32)))
+  {
+    OLSR_PRINTF(
+      9,
+      "%s: --> discarding: packet is duplicate\n",
+      PLUGIN_NAME_SHORT);
+    return;
+  }
+
+  /* Compose encapsulation header */
+  encapHdr = (struct TEncapHeader*) buffer;
+  memset (encapHdr, 0, ENCAP_HDR_LEN);
+  encapHdr->crc32 = htonl(crc32);
+
+  /* Check with each interface what needs to be done on it */
+  nextFwIntf = BmfInterfaces;
+  while (nextFwIntf != NULL)
+  {
+    int isToOlsrIntf;
+
+    struct TBmfInterface* fwIntf = nextFwIntf;
+    nextFwIntf = fwIntf->next;
+
+    /* Is the forwarding interface OLSR-enabled? */
+    isToOlsrIntf = (fwIntf->olsrIntf != NULL);
+
+    /* Depending on certain conditions, we decide whether or not to forward
+     * the packet, and if it is forwarded, in which form (encapsulated
+     * or not). These conditions are:
+     * - is the packet going out on an OLSR interface or not? (isToOlsrIntf)
+     *
+     * Based on these conditions, the following cases can be distinguished:
+     *
+     * - Case 1: What to do with a packet for an OLSR interface?
+     *   Answer: Encapsulate and forward it.
+     *
+     * - Case 2: What to do with a packet for a non-OLSR interface?
+     *   Answer 1: nothing. Multicast routing between non-OLSR interfaces
+     *   is to be done by other protocols (e.g. PIM, DVMRP).
+     *   Answer 2 (better): Forward it.
+     */
+
+    if (isToOlsrIntf)
     {
     {
-      highestSkfd = intf->capturingSkfd;
-    }
+      /* Case 1: Forward to an OLSR interface.
+       * Encapsulate and forward packet. */
 
 
-    if (intf->encapsulatingSkfd >= 0)
+      EncapsulateAndForwardPacket(fwIntf, buffer, len);
+    }
+    else
     {
     {
-      FD_SET(intf->encapsulatingSkfd, &input_set);
-      if (intf->encapsulatingSkfd > highestSkfd)
+      /* Case 2: Forward to a non-OLSR interface. */
+
+      int nBytesWritten;
+
+      /* Change source MAC address to that of sending interface */
+      memcpy(ethPkt + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
+
+      /* If the destination address is not a multicast address, it is assumed to be
+       * a local broadcast packet. Update the destination address to match the subnet
+       * of the network interface on which the packet is being sent. */
+      CheckAndUpdateLocalBroadcast(ethPkt, &fwIntf->broadAddr);
+
+      nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
+      if (nBytesWritten != ethPktLen)
       {
       {
-        highestSkfd = intf->encapsulatingSkfd;
+        olsr_printf(
+          1,
+          "%s: write() error forwarding pkt for %s to \"%s\": %s\n",
+          PLUGIN_NAME,
+          olsr_ip_to_string(&destIp),
+          fwIntf->ifName,
+          strerror(errno));
       }
       }
-    }
+      else
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: --> forwarded from non-OLSR to non-OLSR \"%s\"\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
+      }
+    } /* if (isToOlsrIntf) */
+  } /* while (nextFwIntf != NULL) */
+}
 
 
-    intf = intf->next;    
-  }
+/* -------------------------------------------------------------------------
+ * Function   : DoBmf
+ * Description: Wait (blocking) for IP packets, then call the handler for each
+ *              received packet
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfInterfaces
+ * ------------------------------------------------------------------------- */
+static void DoBmf(void)
+{
+  struct TBmfInterface* currIf;
+  int nFdBitsSet;
+  /*unsigned char* rxBuffer = malloc(BMF_BUFFER_SIZE);*/
+  unsigned char rxBuffer[BMF_BUFFER_SIZE];
+  fd_set rxFdSet;
+
+  assert(HighestSkfd >= 0/* && rxBuffer != NULL*/);
 
 
-  assert(highestSkfd >= 0);
+  /* Make a local copy of the set of file descriptors that select() can
+   * modify to indicate which descriptors actually changed status */
+  rxFdSet = InputSet;
 
 
-  /* Wait (blocking) for packets received on any of the sockets */
-  nFdBitsSet = select(highestSkfd + 1, &input_set, NULL, NULL, NULL);
+  /* Wait (blocking) for packets received on any of the sockets.
+   * NOTE: don't use a timeout (last parameter). It causes a high system CPU load! */
+  nFdBitsSet = select(HighestSkfd + 1, &rxFdSet, NULL, NULL, NULL);
   if (nFdBitsSet < 0)
   {
     if (errno != EINTR)
   if (nFdBitsSet < 0)
   {
     if (errno != EINTR)
@@ -442,109 +934,277 @@ static void DoBmf(void* useless)
     }
     return;
   }
     }
     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)
   {
 
   while (nFdBitsSet > 0)
   {
-    intf = BmfInterfaces;
-    while (intf != NULL)
+    /* Check if a packet was received on the capturing socket (if any)
+     * of each network interface */
+    struct TBmfInterface* nextIf = BmfInterfaces;
+    while (nextIf != NULL)
     {
     {
-      int skfd = intf->capturingSkfd;
-      if (FD_ISSET(skfd, &input_set))
+      int skfd;
+
+      currIf = nextIf;
+      nextIf = currIf->next;
+
+      skfd = currIf->capturingSkfd;
+      if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
       {
       {
-        unsigned char buffer[BUFFER_MAX];
         struct sockaddr_ll pktAddr;
         struct sockaddr_ll pktAddr;
-        socklen_t addrLen;
+        socklen_t addrLen = sizeof(pktAddr);
         int nBytes;
         int nBytes;
+        unsigned char* ethPkt;
 
 
-        /* A packet was captured */
+        /* A packet was captured. */
 
         nFdBitsSet--;
 
 
         nFdBitsSet--;
 
-        memset(&pktAddr, 0, sizeof(struct sockaddr_ll));
-        addrLen = sizeof(pktAddr);
-
-        nBytes = recvfrom(skfd, buffer, BUFFER_MAX, 0, (struct sockaddr*)&pktAddr, &addrLen);
+        /* Receive the packet, leaving space for the BMF encapsulation header */
+        ethPkt = rxBuffer + ENCAP_HDR_LEN;
+        nBytes = recvfrom(
+          skfd,
+          ethPkt,
+          BMF_BUFFER_SIZE - ENCAP_HDR_LEN,
+          0,
+          (struct sockaddr*)&pktAddr,
+          &addrLen);
         if (nBytes < 0)
         {
         if (nBytes < 0)
         {
-          olsr_printf(1, "%s: recvfrom() error: %s\n", PLUGIN_NAME, strerror(errno));
+          olsr_printf(
+            1,
+            "%s: recvfrom() error on \"%s\": %s\n",
+            PLUGIN_NAME,
+            currIf->ifName,
+            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)
+        else if (nBytes < IP_HDR_OFFSET + (int)sizeof(struct iphdr))
+        {
+          olsr_printf(
+            1,
+            "%s: captured packet too short (%d bytes) on \"%s\"\n",
+            PLUGIN_NAME,
+            nBytes,
+            currIf->ifName);
+        }
+        else
         {
         {
-          if (pktAddr.sll_pkttype == PACKET_OUTGOING)
+          /* Don't trust the number of bytes as returned from 'recvfrom':
+           * that number may be 4 bytes too large, in case the receiving
+           * network interface is a VLAN interface. */
+          nBytes = IP_HDR_OFFSET + GetIpPacketLength(ethPkt);
+
+          /* Don't let BMF crash by sending too short packets */
+          if (nBytes >= IP_HDR_OFFSET + GetIpHeaderLength(ethPkt))
           {
           {
-            union olsr_ip_addr destIp;
-            COPY_IP(&destIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_DSTIP);
-            if (IsMulticast(&destIp) || IsLocalBroadcast(&destIp, intf->olsrIntf))
+            if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
+                pktAddr.sll_pkttype == PACKET_MULTICAST ||
+                pktAddr.sll_pkttype == PACKET_BROADCAST)
             {
             {
-              if (! IsOlsrOrBmfPacket(buffer, nBytes))
-              {
-                MarkRecentPacket(buffer, nBytes);
-              }
+              /* A multicast or broadcast packet was captured */
+              BmfPacketCaptured(currIf, pktAddr.sll_pkttype, rxBuffer, nBytes + ENCAP_HDR_LEN);
             }
           }
             }
           }
-          else if (pktAddr.sll_pkttype == PACKET_MULTICAST ||
-                   pktAddr.sll_pkttype == PACKET_BROADCAST)
+          else
           {
           {
-            BmfPacketCaptured(intf, buffer, nBytes);
+            olsr_printf(
+              1,
+              "%s: captured packet too short (%d bytes) on \"%s\"\n",
+              PLUGIN_NAME,
+              nBytes,
+              currIf->ifName);
           }
           }
-        } /* if (nBytes >= 34) */
-      } /* if (FD_ISSET...) */
+        } /* if (nBytes < 0) */
+      } /* if (skfd >= 0 && (FD_ISSET...)) */
+    } /* while (nextIf != NULL) */
+    
+    /* Check if a packet was received on the encapsulating socket (if any)
+     * of each network interface */
+    nextIf = BmfInterfaces;
+    while (nextIf != NULL)
+    {
+      int skfd;
+
+      currIf = nextIf;
+      nextIf = currIf->next;
 
 
-      skfd = intf->encapsulatingSkfd;
-      if (skfd >= 0 && (FD_ISSET(skfd, &input_set)))
+      skfd = currIf->encapsulatingSkfd;
+      if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
       {
       {
-        unsigned char buffer[BUFFER_MAX];
-        struct sockaddr_in addr;
-        socklen_t addrLen = sizeof(addr);
+        struct sockaddr_in from;
+        socklen_t fromLen = sizeof(from);
         int nBytes;
 
         /* An encapsulated packet was received */
 
         nFdBitsSet--;
 
         int nBytes;
 
         /* An encapsulated packet was received */
 
         nFdBitsSet--;
 
-        memset(&addr, 0, sizeof(addr));
-
-        nBytes = recvfrom(skfd, buffer, BUFFER_MAX, 0, (struct sockaddr*)&addr, &addrLen);
+        nBytes = recvfrom(
+          skfd,
+          rxBuffer,
+          BMF_BUFFER_SIZE,
+          0,
+          (struct sockaddr*)&from,
+          &fromLen);
         if (nBytes < 0)
         {
         if (nBytes < 0)
         {
-          olsr_printf(1, "%s: recvfrom() error: %s\n", PLUGIN_NAME, strerror(errno));
+          olsr_printf(
+            1,
+            "%s: recvfrom() error on \"%s\": %s\n",
+            PLUGIN_NAME,
+            currIf->ifName,
+            strerror(errno));
         }
         }
-        if (nBytes > 0)
+        else
         {
         {
-          BmfEncapsulatedPacketReceived(intf, addr.sin_addr, buffer, nBytes);
+          /* Don't let BMF crash by sending too short packets. */
+          if (nBytes >= IP_HDR_OFFSET + GetIpHeaderLength(rxBuffer))
+          {
+            union olsr_ip_addr srcIp;
+            COPY_IP(&srcIp, &from.sin_addr.s_addr);
+            BmfEncapsulatedPacketReceived(currIf, &srcIp, rxBuffer, nBytes);
+          }
+          else
+          {
+            olsr_printf(
+              1,
+              "%s: encapsulated packet too short (%d bytes) from %s on \"%s\"\n",
+              PLUGIN_NAME,
+              nBytes,
+              inet_ntoa(from.sin_addr),
+              currIf->ifName);
+          }
+        } /* if (nBytes < 0) */
+      } /* if (skfd >= 0 && (FD_ISSET...)) */
+    } /* while (nextIf != NULL) */
+
+    if (nFdBitsSet > 0 && FD_ISSET(EtherTunTapFd, &rxFdSet))
+    {
+      /* Check if an application has sent a packet to the tuntap
+       * network interface */
+
+      int nBytes;
+      unsigned char* ethPkt;
+      unsigned char* bufferToRead;
+      size_t nBytesToRead;
+
+      nFdBitsSet--;
+
+      /* Receive the packet, leaving space for the BMF encapsulation header */
+      ethPkt = rxBuffer + ENCAP_HDR_LEN;
+    
+      bufferToRead = ethPkt;
+      nBytesToRead = BMF_BUFFER_SIZE - ENCAP_HDR_LEN;
+      if (TunOrTap == TT_TUN)
+      {
+        u_int16_t type;
+
+        /* When using a tun-interface, also leave space for an Ethernet header */
+        bufferToRead += IP_HDR_OFFSET;
+        nBytesToRead -= IP_HDR_OFFSET;
+
+        /* Compose an Ethernet header, in case other BMF-nodes are receiving
+         * their BMF packets on a tap-interface. */
+
+        /* Use all-ones as destination MAC address. When the IP destination is
+         * a multicast address, the destination MAC address should normally also
+         * be a multicast address. E.g., when the destination IP is 224.0.0.1,
+         * the destination MAC should be 01:00:5e:00:00:01. However, it does not
+         * seem to matter when the destination MAC address is set to all-ones
+         * in that case. */
+        memset(ethPkt, 0xFF, IFHWADDRLEN);
+
+        /* Source MAC address is not important. Set to all-zeros */
+        memset(ethPkt + IFHWADDRLEN, 0x00, IFHWADDRLEN);
+
+        /* Ethertype = 0800 = IP */
+        type = htons(0x0800);
+        memcpy(ethPkt + ETH_TYPE_OFFSET, &type, 2);
+      }
+
+      nBytes = read(
+        EtherTunTapFd,
+        bufferToRead,
+        nBytesToRead);
+
+      if (nBytes < 0)
+      {
+        if (errno != EAGAIN)
+        {
+          olsr_printf(
+            1,
+            "%s: recvfrom() error on \"%s\": %s\n",
+            PLUGIN_NAME,
+            EtherTunTapIfName,
+            strerror(errno));
         }
         }
-      } /* if (skfd >= 0 && (FD_ISSET...) */
+      }
+      else if (nBytes < (int)sizeof(struct iphdr))
+      {
+        olsr_printf(
+          1,
+          "%s: captured packet too short (%d bytes) on \"%s\"\n",
+          PLUGIN_NAME,
+          nBytes,
+          EtherTunTapIfName);
+      }
+      else
+      {
+        /* Don't trust the number of bytes as returned from 'recvfrom':
+         * that number may be 4 bytes too large, in case the receiving
+         * network interface is a VLAN interface. */
+        nBytes = IP_HDR_OFFSET + GetIpPacketLength(ethPkt);
 
 
-      intf = intf->next;    
-    } /* while (intf != NULL) */
+        /* Don't let BMF crash by sending too short packets */
+        if (nBytes >= IP_HDR_OFFSET + GetIpHeaderLength(ethPkt))
+        {
+          /* An outbound packet was captured */
+          BmfTunPacketCaptured(rxBuffer, nBytes + ENCAP_HDR_LEN);
+        }
+        else
+        {
+          olsr_printf(
+            1,
+            "%s: captured packet too short (%d bytes) on \"%s\"\n",
+            PLUGIN_NAME,
+            nBytes,
+            EtherTunTapIfName);
+        } /* if (nBytes >= IP_HDR_OFFSET... */
+      } /* if (nBytes < 0) */
+    } /* if (nFdBitsSet > 0 && ... */
   } /* while (nFdBitsSet > 0) */
   } /* while (nFdBitsSet > 0) */
+  /*free(rxBuffer);*/
 }
 
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : BmfSignalHandler
+ * Description: Signal handler function
+ * Input      : signo - signal being handled
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfThreadRunning
+ * ------------------------------------------------------------------------- */
 static void BmfSignalHandler(int signo)
 {
 static void BmfSignalHandler(int signo)
 {
-  /* Dummy handler function */
-  return;
+  BmfThreadRunning = 0;
 }
 
 }
 
-/* Thread entry function. Another thread can gracefully stop this thread by writing a
- * '0' into global variable 'BmfThreadRunning' followed by sending a SIGALRM signal. */
+/* -------------------------------------------------------------------------
+ * Function   : BmfRun
+ * Description: Receiver thread function
+ * Input      : useless - not used
+ * Output     : none
+ * Return     : not used
+ * Data Used  : BmfThreadRunning
+ * Notes      : Another thread can gracefully stop this thread by sending
+ *              a SIGALRM signal.
+ * ------------------------------------------------------------------------- */
 static void* BmfRun(void* useless)
 {
 static void* BmfRun(void* useless)
 {
+  /* Mask all signals except SIGALRM */
   sigset_t blockedSigs;
   sigfillset(&blockedSigs);
   sigdelset(&blockedSigs, SIGALRM);
   sigset_t blockedSigs;
   sigfillset(&blockedSigs);
   sigdelset(&blockedSigs, SIGALRM);
-  if (pthread_sigmask(SIG_BLOCK, &blockedSigs, NULL) < 0)
+  if (pthread_sigmask(SIG_BLOCK, &blockedSigs, NULL) != 0)
   {
     olsr_printf(1, "%s: pthread_sigmask() error: %s\n", PLUGIN_NAME, strerror(errno));
   }
   {
     olsr_printf(1, "%s: pthread_sigmask() error: %s\n", PLUGIN_NAME, strerror(errno));
   }
@@ -563,47 +1223,93 @@ static void* BmfRun(void* useless)
   /* Call the thread function until flagged to exit */
   while (BmfThreadRunning != 0)
   {
   /* Call the thread function until flagged to exit */
   while (BmfThreadRunning != 0)
   {
-    DoBmf(useless);
+    DoBmf();
   }
   }
-  
+
   return NULL;
 }
 
   return NULL;
 }
 
-/* Initialize the BMF plugin */
-int InitBmf()
+/* -------------------------------------------------------------------------
+ * Function   : InterfaceChange
+ * Description: Callback function passed to OLSRD for it to call whenever a
+ *              network interface has been added, removed or updated
+ * Input      : interf - the network interface to deal with
+ *              action - indicates if the specified network interface was
+ *                added, removed or updated.
+ * Output     : none
+ * Return     : always 0
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int InterfaceChange(struct interface* interf, int action)
 {
 {
-  /* Check validity */
-  if (olsr_cnf->ip_version != AF_INET)
+  switch (action)
   {
   {
-    fprintf(stderr, PLUGIN_NAME ": This plugin only supports IPv4!\n");
-    return 0;
+  case (IFCHG_IF_ADD):
+    AddInterface(interf);
+    olsr_printf(1, "%s: interface %s added\n", PLUGIN_NAME, interf->int_name);
+    break;
+
+  case (IFCHG_IF_REMOVE):
+    /* We cannot just remove the interface, because the receive-thread is likely
+     * to be waiting in select(...) for packets coming in via the interface.
+     * Therefore we first close BMF (CloseBmf()), interrupting and kiling the
+     * receive-thread so that it is safe to remove this (and all other)
+     * interfaces. After that, BMF is re-started (InitBmf(interf)). */
+    CloseBmf();
+    InitBmf(interf);
+    olsr_printf(1, "%s: interface %s removed\n", PLUGIN_NAME, interf->int_name);
+    break;
+
+  case (IFCHG_IF_UPDATE):
+    olsr_printf(1, "%s: interface %s updated\n", PLUGIN_NAME, interf->int_name);
+    break;
+      
+  default:
+    olsr_printf(
+      1,
+      "%s: interface %s: error - unknown action (%d)\n",
+      PLUGIN_NAME,
+      interf->int_name, action);
+    break;
   }
   }
+  return 0;
+}
 
 
-  /* Clear the packet history */
-  InitPacketHistory();
+/* -------------------------------------------------------------------------
+ * Function   : InitBmf
+ * Description: Initialize the BMF plugin
+ * Input      : skipThisIntf - specifies which network interface should not
+ *              be enabled for BMF. Pass NULL if not applicable.
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : BmfThreadRunning, BmfThread
+ * ------------------------------------------------------------------------- */
+int InitBmf(struct interface* skipThisIntf)
+{
+  CreateBmfNetworkInterfaces(skipThisIntf);
 
 
-  if (CreateBmfNetworkInterfaces() < 0)
+  /* Start running the multicast packet processing thread */
+  BmfThreadRunning = 1;
+  if (pthread_create(&BmfThread, NULL, BmfRun, NULL) != 0)
   {
   {
-    fprintf(stderr, PLUGIN_NAME ": could not initialize network interfaces!\n");
+    olsr_printf(1, "%s: pthread_create error: %s\n", PLUGIN_NAME, strerror(errno));
     return 0;
   }
     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;
 }
 
   return 1;
 }
 
-/* Close the BMF plugin */
+/* -------------------------------------------------------------------------
+ * Function   : CloseBmf
+ * Description: Close the BMF plugin and clean up
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfThreadRunning, BmfThread
+ * ------------------------------------------------------------------------- */
 void CloseBmf()
 {
   /* Signal BmfThread to exit */
 void CloseBmf()
 {
   /* Signal BmfThread to exit */
-  BmfThreadRunning = 0;
-  if (pthread_kill(BmfThread, SIGALRM) < 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(...). */
   /* 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(...). */
@@ -612,7 +1318,7 @@ void CloseBmf()
   }
 
   /* Wait for BmfThread to acknowledge */
   }
 
   /* Wait for BmfThread to acknowledge */
-  if (pthread_join(BmfThread, NULL) < 0)
+  if (pthread_join(BmfThread, NULL) != 0)
   {
     olsr_printf(1, "%s: pthread_join() error: %s\n", PLUGIN_NAME, strerror(errno));
   }
   {
     olsr_printf(1, "%s: pthread_join() error: %s\n", PLUGIN_NAME, strerror(errno));
   }
@@ -621,9 +1327,18 @@ void CloseBmf()
   CloseBmfNetworkInterfaces();
 }
 
   CloseBmfNetworkInterfaces();
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : RegisterBmfParameter
+ * Description: Register a configuration parameter with the BMF process
+ * Input      : key - the parameter name, e.g. "DropMac" or "NonOlsrIf"
+ *              value - the parameter value
+ * Output     : none
+ * Return     : fatal error (<0), minor error (0) or success (>0)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 int RegisterBmfParameter(char* key, char* value)
 {
 int RegisterBmfParameter(char* key, char* value)
 {
-  if (strcmp(key, "Drop") == 0)
+  if (strcmp(key, "DropMac") == 0)
   {
     return DropMac(value);
   }
   {
     return DropMac(value);
   }
@@ -631,6 +1346,27 @@ int RegisterBmfParameter(char* key, char* value)
   {
     return AddNonOlsrBmfIf(value);
   }
   {
     return AddNonOlsrBmfIf(value);
   }
+  else if (strcmp(key, "DoLocalBroadcast") == 0)
+  {
+    return DoLocalBroadcast(value);
+  }
+  else if (strcmp(key, "BmfInterface") == 0)
+  {
+    return SetBmfInterfaceName(value);
+  }
+  else if (strcmp(key, "BmfInterfaceType") == 0)
+  {
+    return SetBmfInterfaceType(value);
+  }
+  else if (strcmp(key, "BmfInterfaceIp") == 0)
+  {
+    return SetBmfInterfaceIp(value);
+  }
+  else if (strcmp(key, "CapturePacketsOnOlsrInterfaces") == 0)
+  {
+    return SetCapturePacketsOnOlsrInterfaces(value);
+  }
 
 
+  /* Key not recognized */
   return 0;
 }
   return 0;
 }
index 24c78e6..180e185 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: Bmf.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : Bmf.h
+ * Description: Multicast forwarding functions
+ * Created    : 29 Jun 2006
+ *
+ * $Id: Bmf.h,v 1.2 2007/02/10 17:05:55 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 /* BMF plugin data */
 
 /* BMF plugin data */
-#define PLUGIN_NAME "OLSRD Basic Multicast Forwarding plugin"
-#define PLUGIN_VERSION "1.0.1 (" __DATE__ " " __TIME__ ")"
+#define PLUGIN_NAME "OLSRD Basic Multicast Forwarding (BMF) plugin"
+#define PLUGIN_NAME_SHORT "OLSRD BMF"
+#define PLUGIN_VERSION "1.3 (" __DATE__ " " __TIME__ ")"
 #define PLUGIN_COPYRIGHT "  (C) Thales Communications Huizen, Netherlands"
 #define PLUGIN_COPYRIGHT "  (C) Thales Communications Huizen, Netherlands"
-#define PLUGIN_AUTHOR "  Erik Tromp (erik_tromp@hotmail.com)"
+#define PLUGIN_AUTHOR "  Erik Tromp (erik.tromp@nl.thalesgroup.com)"
 #define MOD_DESC PLUGIN_NAME " " PLUGIN_VERSION "\n" PLUGIN_COPYRIGHT "\n" PLUGIN_AUTHOR
 
 /* UDP-Port on which multicast packets are encapsulated */
 #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
+#define BMF_ENCAP_PORT 50698
+
+struct interface;
 
 
-int InitBmf(void);
+int InterfaceChange(struct interface* interf, int action);
+int InitBmf(struct interface* skipThisIntf);
 void CloseBmf(void);
 int RegisterBmfParameter(char* key, char* value);
 
 void CloseBmf(void);
 int RegisterBmfParameter(char* key, char* value);
 
index 57beafe..e2f97ae 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: DropList.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : DropList.c
+ * Description: List of MAC addresses of hosts from which received multicast
+ *              and local broadcast packets are dropped.
+ * Created    : 29 Jun 2006
+ *
+ * $Id: DropList.c,v 1.2 2007/02/10 17:05:55 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 
 #include "DropList.h"
 
 
 #include "DropList.h"
 
 static struct TMacAddress* DroppedMacAddresses = NULL;
 
 
 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.
- */
+/* -------------------------------------------------------------------------
+ * Function   : DropMac
+ * Description: Register a MAC address in the drop list
+ * Input      : macStr - MAC address as string
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : DroppedMacAddresses
+ * Notes      : The registered MAC address will be matched to the source MAC 
+ *              address of incoming multicast packets. If matched, the multicast 
+ *              packet will be dropped. 
+ *              The drop list is needed only in lab environments, where hidden
+ *              nodes are simulated by using iptables with the
+ *              -m mac helper and --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 DropMac(const char* macStr)
 {
   unsigned int mac[6];
@@ -86,7 +102,14 @@ int DropMac(const char* macStr)
   return 1;
 }
 
   return 1;
 }
 
-/* Return 1 if macAddress is in the drop list, else 0 */
+/* -------------------------------------------------------------------------
+ * Function   : IsInDropList
+ * Description: Check if a MAC address is in the drop list
+ * Input      : macAddress
+ * Output     : none
+ * Return     : true (1) or false (0)
+ * Data Used  : DroppedMacAddresses
+ * ------------------------------------------------------------------------- */
 int IsInDropList(const unsigned char* macAddress)
 {
   struct TMacAddress* ma = DroppedMacAddresses;
 int IsInDropList(const unsigned char* macAddress)
 {
   struct TMacAddress* ma = DroppedMacAddresses;
index 02e0932..dc79294 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: DropList.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : DropList.h
+ * Description: List of MAC addresses of hosts from which all packets are dropped.
+ * Created    : 29 Jun 2006
+ *
+ * $Id: DropList.h,v 1.2 2007/02/10 17:05:56 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 struct TMacAddress
 {
 
 struct TMacAddress
 {
index 8bbad8b..310d1b3 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: NetworkInterfaces.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : NetworkInterfaces.c
+ * Description: Functions to open and close sockets
+ * Created    : 29 Jun 2006
+ *
+ * $Id: NetworkInterfaces.c,v 1.2 2007/02/10 17:05:56 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 #include "NetworkInterfaces.h"
 
 /* System includes */
 #include <syslog.h> /* syslog() */
 
 #include "NetworkInterfaces.h"
 
 /* System includes */
 #include <syslog.h> /* syslog() */
-#include <string.h> /* strerror() */
+#include <string.h> /* strerror(), strchr(), strcmp() */
 #include <errno.h> /* errno */
 #include <unistd.h> /* close() */
 #include <sys/ioctl.h> /* ioctl() */
 #include <fcntl.h> /* fcntl() */
 #include <assert.h> /* assert() */
 #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 <net/if.h> /* socket(), ifreq, if_indextoname(), if_nametoindex() */
 #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 */
 #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 */
+#include <netinet/ip.h> /* struct ip */
+#include <netinet/udp.h> /* SOL_UDP */
 
 /* OLSRD includes */
 
 /* OLSRD includes */
-#include "olsr.h" /* olsr_printf */
+#include "olsr.h" /* olsr_printf() */
 #include "defs.h" /* olsr_cnf */
 #include "defs.h" /* olsr_cnf */
+#include "local_hna_set.h" /* add_local_hna4_entry() */
 
 /* Plugin includes */
 #include "Packet.h" /* IFHWADDRLEN */
 #include "Bmf.h" /* PLUGIN_NAME */
 
 /* Plugin includes */
 #include "Packet.h" /* IFHWADDRLEN */
 #include "Bmf.h" /* PLUGIN_NAME */
+#include "Address.h" /* IsMulticast() */
 
 
-/* List of network interfaces used by BMF plugin */
+/* List of network interface objects used by BMF plugin */
 struct TBmfInterface* BmfInterfaces = NULL;
 
 struct TBmfInterface* BmfInterfaces = NULL;
 
-/* File descriptor of EtherTunTap device */
-int EtherTunTapFd = -1;
+/* Highest-numbered open socket file descriptor. To be used as first
+ * parameter in calls to select(...). */
+int HighestSkfd = -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"; */
+/* Set of socket file descriptors */
+fd_set InputSet;
 
 
-/* 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;
+/* File descriptor of EtherTunTap interface */
+int EtherTunTapFd = -1;
 
 
-/* Create raw packet socket for capturing multicast IP traffic. Returns
- * the socket descriptor, or -1 if an error occurred. */
-static int CreateCaptureSocket(int ifIndex)
+/* Network interface name of EtherTunTap interface. May be overruled by
+ * setting the plugin parameter "BmfInterface". */
+char EtherTunTapIfName[IFNAMSIZ] = "bmf0";
+
+/* If the plugin parameter "BmfInterfaceType" is set to "tap", an
+ * EtherTap interface will be used, and this variable will be set to TT_TAP. If
+ * "BmfInterfaceType" is set to "tun" or not set at all, an IP tunnel interface 
+ * used, and this variable will be set to TT_TUN. */
+enum TTunOrTap TunOrTap = TT_TUN;
+
+#define ETHERTUNTAPIPNOTSET 0
+
+/* 10.255.255.253 in host byte order */
+#define ETHERTUNTAPDEFAULTIP 0x0AFFFFFD
+
+/* The IP address of the BMF network interface in host byte order.
+ * May be overruled by setting the plugin parameter "BmfInterfaceIp". */
+u_int32_t EtherTunTapIp = ETHERTUNTAPIPNOTSET;
+
+/* 255.255.255.255 in host byte order. May be overruled by
+ * setting the plugin parameter "BmfInterfaceIp". */
+u_int32_t EtherTunTapIpMask = 0xFFFFFFFF;
+
+/* The IP broadcast address of the BMF network interface in host byte order.
+ * May be overruled by setting the plugin parameter "BmfinterfaceIp". */
+u_int32_t EtherTunTapIpBroadcast = ETHERTUNTAPDEFAULTIP;
+
+/* Whether or not the configuration has overruled the default IP
+ * configuration of the EtherTunTap interface */
+int TunTapIpOverruled = 0;
+
+/* Whether or not to capture packets on the OLSR-enabled
+ * interfaces (in promiscuous mode). May be overruled by setting the plugin
+ * parameter "CapturePacketsOnOlsrInterfaces" to "yes". */
+int CapturePacketsOnOlsrInterfaces = 0;
+
+/* -------------------------------------------------------------------------
+ * Function   : SetBmfInterfaceName
+ * Description: Overrule the default network interface name ("bmf0") of the
+ *              EtherTunTap interface
+ * Input      : ifname - network interface name (e.g. "mybmf0")
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int SetBmfInterfaceName(const char* ifname)
 {
 {
-  struct packet_mreq mreq;
-  struct ifreq req;
-  struct sockaddr_ll iface_addr;
+  strncpy(EtherTunTapIfName, ifname, IFNAMSIZ - 1);
+  EtherTunTapIfName[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
+  return 1;
+}
 
 
-  /* Open raw packet socket */
-  int skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-  if (skfd < 0)
+/* -------------------------------------------------------------------------
+ * Function   : SetBmfInterfaceType
+ * Description: Overrule the default network interface type ("tun") of the
+ *              EtherTunTap interface
+ * Input      : iftype - network interface type, either "tun" or "tap"
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int SetBmfInterfaceType(const char* iftype)
+{
+  if (strcmp(iftype, "tun") == 0)
   {
   {
-    olsr_printf(1, "%s: socket(PF_PACKET) error: %s\n", PLUGIN_NAME, strerror(errno));
-    return -1;
+    TunOrTap = TT_TUN;
+    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)
+  else if (strcmp(iftype, "tap") == 0)
   {
   {
-    olsr_printf(1, "%s: setsockopt(PACKET_MR_PROMISC) error: %s\n", PLUGIN_NAME, strerror(errno));
-    close(skfd);
-    return -1;
+    TunOrTap = TT_TAP;
+    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)
+  /* Value not recognized */
+  return 0;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : SetBmfInterfaceIp
+ * Description: Overrule the default IP address and prefix length
+ *              ("10.255.255.253/30") of the EtherTunTap interface
+ * Input      : ip - IP address, followed by '/' and prefix length
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int SetBmfInterfaceIp(const char* ip)
+{
+#define IPV4_MAX_ADDRLEN 16
+#define IPV4_MAX_PREFIXLEN 32
+  char* slashAt;
+  char ipAddr[IPV4_MAX_ADDRLEN];
+  struct in_addr sinaddr;
+  int prefixLen;
+  int i;
+
+  /* Inspired by function str2prefix_ipv4 as found in Quagga source
+   * file lib/prefix.c */
+
+  /* Find slash inside string. */
+  slashAt = strchr(ip, '/');
+
+  /* String doesn't contain slash. */
+  if (slashAt == NULL || slashAt - ip >= IPV4_MAX_ADDRLEN)
   {
   {
-    olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
-    close(skfd);
-    return -1;
+    /* No prefix length specified, or IP address too long */
+    return 0;
   }
 
   }
 
-  /* Set socket to blocking operation */
-  if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
+  strncpy(ipAddr, ip, slashAt - ip);
+  *(ipAddr + (slashAt - ip)) = '\0';
+  if (inet_aton(ipAddr, &sinaddr) == 0)
   {
   {
-    olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno));
-    close(skfd);
-    return -1;
+    /* Invalid address passed */
+    return 0;
   }
 
   }
 
-  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;
+  EtherTunTapIp = ntohl(sinaddr.s_addr);
 
 
-  /* Open UDP-IP socket */
-  int skfd = socket(PF_INET, SOCK_DGRAM, 0);
-  if (skfd < 0)
+  /* Get prefix length. */
+  prefixLen = atoi(++slashAt);
+  if (prefixLen <= 0 || prefixLen > IPV4_MAX_PREFIXLEN)
   {
   {
-    olsr_printf(1, "%s: socket(PF_INET) error: %s\n", PLUGIN_NAME, strerror(errno));
-    return -1;
-  }
+         return 0;
+       }
 
 
-  /* Enable sending to broadcast addresses */
-  if (setsockopt(skfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
+  /* Compose IP subnet mask in host byte order */
+  EtherTunTapIpMask = 0;
+  for (i = 0; i < prefixLen; i++)
   {
   {
-    olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno));
-    close(skfd);
-    return -1;
+    EtherTunTapIpMask |= (1 << (IPV4_MAX_PREFIXLEN - 1 - i));
   }
   }
-       
-  /* 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)
+
+  /* Compose IP broadcast address in host byte order */
+  EtherTunTapIpBroadcast = EtherTunTapIp;
+  for (i=prefixLen; i < IPV4_MAX_PREFIXLEN; i++)
   {
   {
-    olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno));
-    close(skfd);
-    return -1;
+    EtherTunTapIpBroadcast |= (1 << (IPV4_MAX_PREFIXLEN - 1 - i));
   }
   }
-    
-  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) 
+
+  TunTapIpOverruled = 1;
+
+  return 1;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : SetCapturePacketsOnOlsrInterfaces
+ * Description: Overrule the default setting, enabling or disabling the
+ *              capturing of packets on OLSR-enabled interfaces.
+ * Input      : enable - either "yes" or "no"
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int SetCapturePacketsOnOlsrInterfaces(const char* enable)
+{
+  if (strcmp(enable, "yes") == 0)
   {
   {
-    olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
-    close(skfd);
-    return -1;
+    CapturePacketsOnOlsrInterfaces = 1;
+    return 1;
   }
   }
-
-  /* Set socket to blocking operation */
-  if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
+  else if (strcmp(enable, "no") == 0)
   {
   {
-    olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno));
-    close(skfd);
-    return -1;
+    CapturePacketsOnOlsrInterfaces = 0;
+    return 1;
   }
 
   }
 
-  return skfd;
+  /* Value not recognized */
+  return 0;
 }
 
 }
 
-/* To save the state of the IP spoof filter for the EtherTunTap device */
+/* To save the state of the IP spoof filter for the EtherTunTap interface */
 static char EthTapSpoofState = '1';
 
 static char EthTapSpoofState = '1';
 
-static int DeactivateSpoofFilter(const char* ifName)
+/* -------------------------------------------------------------------------
+ * Function   : DeactivateSpoofFilter
+ * Description: Deactivates the Linux anti-spoofing filter for the tuntap
+ *              interface
+ * Input      : tunTapName - name used for the tuntap interface (e.g. "tun0" or "tap1")
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : EthTapSpoofState
+ * Notes      : Saves the current filter state for later restoring
+ * ------------------------------------------------------------------------- */
+static int DeactivateSpoofFilter(const char* tunTapName)
 {
   FILE* procSpoof;
   char procFile[FILENAME_MAX];
 
 {
   FILE* procSpoof;
   char procFile[FILENAME_MAX];
 
-  assert(ifName != NULL);
+  assert(tunTapName != NULL);
 
   /* Generate the procfile name */
 
   /* Generate the procfile name */
-  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", ifName);
+  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", tunTapName);
 
 
+  /* Open procfile for reading */
   procSpoof = fopen(procFile, "r");
   if (procSpoof == NULL)
   {
   procSpoof = fopen(procFile, "r");
   if (procSpoof == NULL)
   {
@@ -222,6 +294,7 @@ static int DeactivateSpoofFilter(const char* ifName)
   EthTapSpoofState = fgetc(procSpoof);
   fclose(procSpoof);
 
   EthTapSpoofState = fgetc(procSpoof);
   fclose(procSpoof);
 
+  /* Open procfile for writing */
   procSpoof = fopen(procFile, "w");
   if (procSpoof == NULL)
   {
   procSpoof = fopen(procFile, "w");
   if (procSpoof == NULL)
   {
@@ -242,16 +315,26 @@ static int DeactivateSpoofFilter(const char* ifName)
   return 1;
 }
 
   return 1;
 }
 
-static void RestoreSpoofFilter(const char* ifName)
+/* -------------------------------------------------------------------------
+ * Function   : RestoreSpoofFilter
+ * Description: Restores the Linux anti-spoofing filter setting for the tuntap
+ *              interface
+ * Input      : tunTapName - name used for the tuntap interface (e.g. "tun0" or "tap1")
+ * Output     : none
+ * Return     : none
+ * Data Used  : EthTapSpoofState
+ * ------------------------------------------------------------------------- */
+static void RestoreSpoofFilter(const char* tunTapName)
 {
   FILE* procSpoof;
   char procFile[FILENAME_MAX];
 
 {
   FILE* procSpoof;
   char procFile[FILENAME_MAX];
 
-  assert(ifName != NULL);
+  assert(tunTapName != NULL);
 
   /* Generate the procfile name */
 
   /* Generate the procfile name */
-  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", ifName);
+  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", tunTapName);
 
 
+  /* Open procfile for writing */
   procSpoof = fopen(procFile, "w");
   if (procSpoof == NULL)
   {
   procSpoof = fopen(procFile, "w");
   if (procSpoof == NULL)
   {
@@ -266,113 +349,406 @@ static void RestoreSpoofFilter(const char* ifName)
   }
 }
 
   }
 }
 
-/* Creates and brings up an EtherTunTap device e.g. "tun0" or "tap0"
- * (as specified in const char* EtherTunTapIfName) */
+/* -------------------------------------------------------------------------
+ * Function   : CreateCaptureSocket
+ * Description: Create socket for promiscuously capturing multicast IP traffic
+ * Input      : ifname - network interface (e.g. "eth0")
+ * Output     : none
+ * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
+ * Data Used  : none
+ * Notes      : The socket is a raw packet socket, bound to the specified
+ *              network interface
+ * ------------------------------------------------------------------------- */
+static int CreateCaptureSocket(const char* ifName)
+{
+  int ifIndex = if_nametoindex(ifName);
+  struct packet_mreq mreq;
+  struct ifreq req;
+  struct sockaddr_ll bindTo;
+
+  /* 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));
+  strncpy(req.ifr_name, ifName, IFNAMSIZ - 1);
+  req.ifr_name[IFNAMSIZ-1] = '\0'; /* Ensures null termination */
+  if (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(&bindTo, 0, sizeof(bindTo));
+  bindTo.sll_protocol = htons(ETH_P_ALL);
+  bindTo.sll_ifindex = ifIndex;
+  bindTo.sll_family = AF_PACKET;
+  memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
+  bindTo.sll_halen = IFHWADDRLEN;
+    
+  if (bind(skfd, (struct sockaddr*)&bindTo, sizeof(bindTo)) < 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;
+  }
+
+  /* Keep the highest-numbered descriptor */
+  if (skfd > HighestSkfd)
+  {
+    HighestSkfd = skfd;
+  }
+
+  /* Add descriptor to input set */
+  FD_SET(skfd, &InputSet);
+
+  return skfd;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : CreateEncapsulateSocket
+ * Description: Create a socket for sending and receiving encapsulated
+ *              multicast packets
+ * Input      : ifname - network interface (e.g. "eth0")
+ * Output     : none
+ * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
+ * Data Used  : none
+ * Notes      : The socket is an UDP (datagram) over IP socket, bound to the
+ *              specified network interface
+ * ------------------------------------------------------------------------- */
+static int CreateEncapsulateSocket(const char* ifName)
+{
+  int on = 1;
+  struct sockaddr_in bindTo;
+
+  /* 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 ifName. */
+  /* When using Kernel 2.6 this must happer prior to the port binding! */
+  if (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;
+  }
+
+  /* Bind to port */
+  memset(&bindTo, 0, sizeof(bindTo));
+  bindTo.sin_family = AF_INET;
+  bindTo.sin_port = htons(BMF_ENCAP_PORT);
+  bindTo.sin_addr.s_addr = htonl(INADDR_ANY);
+      
+  if (bind(skfd, (struct sockaddr*)&bindTo, sizeof(bindTo)) < 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;
+  }
+
+  /* Keep the highest-numbered descriptor */
+  if (skfd > HighestSkfd)
+  {
+    HighestSkfd = skfd;
+  }
+
+  /* Add descriptor to input set */
+  FD_SET(skfd, &InputSet);
+
+  return skfd;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : CreateLocalEtherTunTap
+ * Description: Creates and brings up an EtherTunTap interface
+ * Input      : none
+ * Output     : none
+ * Return     : the socket file descriptor (>= 0), or -1 in case of failure
+ * Data Used  : EtherTunTapIfName - name used for the tuntap interface (e.g.
+ *                "bmf0")
+ *              EtherTunTapIp
+ *              EtherTunTapIpMask
+ *              EtherTunTapIpBroadcast
+ *              BmfInterfaces
+ * Note       : Order dependency: call this function only if BmfInterfaces
+ *              is filled with a list of network interfaces.
+ * ------------------------------------------------------------------------- */
 static int CreateLocalEtherTunTap(void)
 {
 static int CreateLocalEtherTunTap(void)
 {
+  static char* deviceName = "/dev/net/tun";
   struct ifreq ifreq;
   struct ifreq ifreq;
-  int etfd = open("/dev/net/tun", O_RDWR);
-  int skfd;
-  int ioctlres = 0;
+  int etfd;
+  int ioctl_s;
+  int ioctlres;
 
 
+  etfd = open(deviceName, O_RDWR | O_NONBLOCK);
   if (etfd < 0)
   {
   if (etfd < 0)
   {
-    olsr_printf(1, "%s: open() error: %s\n", PLUGIN_NAME, strerror(errno));
+    olsr_printf(1, "%s: error opening %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
     return -1;
   }
 
   memset(&ifreq, 0, sizeof(ifreq));
     return -1;
   }
 
   memset(&ifreq, 0, sizeof(ifreq));
+  strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
+  ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
 
   /* 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. */
 
   /* 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)
+  if (TunOrTap == TT_TUN)
   {
     ifreq.ifr_flags = IFF_TUN;
   {
     ifreq.ifr_flags = IFF_TUN;
-    TunOrTap = TT_TUN;
   }
   else
   {
     ifreq.ifr_flags = IFF_TAP;
   }
   else
   {
     ifreq.ifr_flags = IFF_TAP;
-    TunOrTap = TT_TAP;
   }
   ifreq.ifr_flags |= IFF_NO_PI;
 
   }
   ifreq.ifr_flags |= IFF_NO_PI;
 
-  strcpy(ifreq.ifr_name, EtherTunTapIfName);
   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0)
   {
   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0)
   {
-    olsr_printf(1, "%s: ioctl() error: %s\n", PLUGIN_NAME, strerror(errno));
+    olsr_printf(1, "%s: ioctl(TUNSETIFF) error on %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
     close(etfd);
     return -1;
   }
 
   memset(&ifreq, 0, sizeof(ifreq));
     close(etfd);
     return -1;
   }
 
   memset(&ifreq, 0, sizeof(ifreq));
-  strcpy(ifreq.ifr_name, EtherTunTapIfName);
+  strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
+  ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
   ifreq.ifr_addr.sa_family = AF_INET;
   ifreq.ifr_addr.sa_family = AF_INET;
-  skfd = socket(PF_INET, SOCK_DGRAM, 0);
-  if (skfd >= 0)
+
+  ioctl_s = socket(PF_INET, SOCK_DGRAM, 0);
+  if (ioctl_s < 0)
   {
   {
-    if (ioctl(skfd, SIOCGIFADDR, &ifreq) < 0)
+    olsr_printf(1, "%s: socket(PF_INET) error on %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
+    close(etfd);
+    return -1;
+  }
+
+  /* Give the EtherTunTap interface an IP address.
+   * The default IP address is the address of the first OLSR interface;
+   * the default netmask is 255.255.255.255 . Having an all-ones netmask prevents
+   * automatic entry of the BMF network interface in the routing table. */
+  if (EtherTunTapIp == ETHERTUNTAPIPNOTSET)
+  {
+    struct TBmfInterface* nextBmfIf = BmfInterfaces;
+    while (nextBmfIf != NULL)
     {
     {
-      /* 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);
+      struct TBmfInterface* bmfIf = nextBmfIf;
+      nextBmfIf = bmfIf->next;
+
+      if (bmfIf->olsrIntf != NULL)
+      {
+        EtherTunTapIp = ntohl(((struct sockaddr_in*)&bmfIf->intAddr)->sin_addr.s_addr);
+        EtherTunTapIpBroadcast = EtherTunTapIp;
+      }
+    }
+  }
 
 
+  if (EtherTunTapIp == ETHERTUNTAPIPNOTSET)
+  {
+    /* No IP address configured for BMF network interface, and no OLSR interface found to
+     * copy IP address from. Fall back to default: 10.255.255.253 . */
+    EtherTunTapIp = ETHERTUNTAPDEFAULTIP;
+  }
+
+  ((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr.s_addr = htonl(EtherTunTapIp);
+  ioctlres = ioctl(ioctl_s, SIOCSIFADDR, &ifreq);
+  if (ioctlres >= 0)
+  {
+    /* Set net mask */
+    ((struct sockaddr_in*)&ifreq.ifr_netmask)->sin_addr.s_addr = htonl(EtherTunTapIpMask);
+    ioctlres = ioctl(ioctl_s, SIOCSIFNETMASK, &ifreq);
+    if (ioctlres >= 0)
+    {
+      /* Set broadcast IP */
+      ((struct sockaddr_in*)&ifreq.ifr_broadaddr)->sin_addr.s_addr = htonl(EtherTunTapIpBroadcast);
+      ioctlres = ioctl(ioctl_s, SIOCSIFBRDADDR, &ifreq);
       if (ioctlres >= 0)
       {
         /* Bring EtherTunTap interface up (if not already) */
       if (ioctlres >= 0)
       {
         /* Bring EtherTunTap interface up (if not already) */
-        ioctlres = ioctl(skfd, SIOCGIFFLAGS, &ifreq);
+        ioctlres = ioctl(ioctl_s, SIOCGIFFLAGS, &ifreq);
         if (ioctlres >= 0)
         {
         if (ioctlres >= 0)
         {
-          ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING);
-          ioctlres = ioctl(skfd, SIOCSIFFLAGS, &ifreq);
+          ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING | IFF_BROADCAST);
+          ioctlres = ioctl(ioctl_s, SIOCSIFFLAGS, &ifreq);
         }
         }
-      } /* if (ioctlres >= 0) */
-    } /* if (ioctl...) */
-  } /* if (skfd >= 0) */
-  if (skfd < 0 || ioctlres < 0)
+      }
+    }
+  }
+
+  if (ioctlres < 0)
   {
   {
+    /* Any of the above ioctl() calls failed */
     olsr_printf(
       1,
     olsr_printf(
       1,
-      "%s: Error bringing up EtherTunTap interface: %s\n",
+      "%s: error bringing up EtherTunTap interface \"%s\": %s\n",
       PLUGIN_NAME,
       PLUGIN_NAME,
+      EtherTunTapIfName,
       strerror(errno));
 
     close(etfd);
       strerror(errno));
 
     close(etfd);
-    if (skfd >= 0)
-    {
-      close(skfd);
-    }
+    close(ioctl_s);
     return -1;
     return -1;
-  } /* if (skfd < 0 || ioctlres < 0) */
+  } /* if (ioctlres < 0) */
 
 
-  /* Set the multicast flag on the interface. TODO: Maybe also set
-   * IFF_ALLMULTI. */
+  /* Set the multicast flag on the interface */
   memset(&ifreq, 0, sizeof(ifreq));
   memset(&ifreq, 0, sizeof(ifreq));
-  strcpy(ifreq.ifr_name, EtherTunTapIfName);
-  ioctlres = ioctl(skfd, SIOCGIFFLAGS, &ifreq);
+  strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
+  ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
+
+  ioctlres = ioctl(ioctl_s, SIOCGIFFLAGS, &ifreq);
   if (ioctlres >= 0)
   {
     ifreq.ifr_flags |= IFF_MULTICAST;
   if (ioctlres >= 0)
   {
     ifreq.ifr_flags |= IFF_MULTICAST;
-    ioctlres = ioctl(skfd, SIOCSIFFLAGS, &ifreq);
+    ioctlres = ioctl(ioctl_s, SIOCSIFFLAGS, &ifreq);
   }
   if (ioctlres < 0)
   {
   }
   if (ioctlres < 0)
   {
+    /* Any of the two above ioctl() calls failed */
     olsr_printf(
       1,
     olsr_printf(
       1,
-      "%s: Error setting the multicast flag on EtherTunTap interface: %s\n",
+      "%s: error setting multicast flag on EtherTunTap interface \"%s\": %s\n",
       PLUGIN_NAME,
       PLUGIN_NAME,
+      EtherTunTapIfName,
       strerror(errno));
       strerror(errno));
+    /* Continue anyway */
   }
   }
-  close(skfd);
-  
-  /* Deactivate IP spoof filter for EtherTunTap device */
-  DeactivateSpoofFilter(ifreq.ifr_name);
+
+  /* Use ioctl to make the tuntap persistent. Otherwise it will disappear
+   * when this program exits. That is not desirable, since a multicast
+   * daemon (e.g. mrouted) may be using the tuntap interface. */
+  if (ioctl(etfd, TUNSETPERSIST, (void *)&ifreq) < 0)
+  {
+    olsr_printf(
+      1,
+      "%s: error making EtherTunTap interface \"%s\" persistent: %s\n",
+      PLUGIN_NAME,
+      EtherTunTapIfName,
+      strerror(errno));
+    /* Continue anyway */
+  }
+
+  /* Deactivate IP spoof filter for EtherTunTap interface */
+  DeactivateSpoofFilter(EtherTunTapIfName);
+
+  OLSR_PRINTF(9, "%s: opened 1 socket on \"%s\"\n", PLUGIN_NAME_SHORT, EtherTunTapIfName);
+
+  /* Keep the highest-numbered descriptor */
+  if (etfd > HighestSkfd)
+  {
+    HighestSkfd = etfd;
+  }
+
+  /* Add descriptor to input set */
+  FD_SET(etfd, &InputSet);
+
+  /* If the user configured a specific IP address for the BMF network interface,
+   * help the user and advertise the IP address of the BMF network interface
+   * on the OLSR network */
+  if (TunTapIpOverruled != 0)
+  {
+    union olsr_ip_addr temp_net;
+    union olsr_ip_addr temp_netmask;
+
+    temp_net.v4 = htonl(EtherTunTapIp);
+    temp_netmask.v4 = htonl(0xFFFFFFFF);
+    add_local_hna4_entry(&temp_net, &temp_netmask);
+  }
+
+  /* If the BMF network interface has a sensible IP address, it is a good idea
+   * to route all multicast traffic through that interface */
+  if (EtherTunTapIp != ETHERTUNTAPDEFAULTIP)
+  {
+    struct rtentry kernel_route;
+
+    memset(&kernel_route, 0, sizeof(struct rtentry));
+
+    ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET;
+    ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET;
+    ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET;
+
+    /* 224.0.0.0/4 */
+    ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = htonl(0xE0000000);
+    ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = htonl(0xF0000000);
+
+    kernel_route.rt_metric = 0;
+    kernel_route.rt_flags = RTF_UP;
+
+    kernel_route.rt_dev = EtherTunTapIfName;
+
+    if (ioctl(ioctl_s, SIOCADDRT, &kernel_route) < 0)
+    {
+      olsr_printf(
+        1,
+        "%s: error setting multicast route via EtherTunTap interface \"%s\": %s\n",
+        PLUGIN_NAME,
+        EtherTunTapIfName,
+        strerror(errno));
+      /* Continue anyway */
+    }
+  }
+
+  close(ioctl_s);
 
   return etfd;
 }
 
 
   return etfd;
 }
 
+#if 0
+/* -------------------------------------------------------------------------
+ * Function   : IsNullMacAddress
+ * Description: Checks if a MAC address is all-zeroes
+ * Input      : mac - address to check
+ * Output     : none
+ * Return     : true (1) or false (0)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 static int IsNullMacAddress(char* mac)
 {
   int i;
 static int IsNullMacAddress(char* mac)
 {
   int i;
@@ -385,28 +761,203 @@ static int IsNullMacAddress(char* mac)
   }
   return 1;
 }
   }
   return 1;
 }
+#endif
+
+/* -------------------------------------------------------------------------
+ * Function   : CreateInterface
+ * Description: Create a new TBmfInterface object and adds it to the global
+ *              BmfInterfaces list
+ * Input      : ifName - name of the network interface (e.g. "eth0")
+ *            : olsrIntf - OLSR interface object of the network interface, or
+ *                NULL if the network interface is not OLSR-enabled
+ * Output     : none
+ * Return     : the number of opened sockets
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+static int CreateInterface(
+  const char* ifName,
+  struct interface* olsrIntf)
+{
+  int capturingSkfd = -1;
+  int encapsulatingSkfd = -1;
+  int ioctlSkfd;
+  struct ifreq ifr;
+  int nOpened = 0;
+  struct TBmfInterface* newIf = malloc(sizeof(struct TBmfInterface));
+
+  assert(ifName != NULL);
+
+  if (newIf == NULL)
+  {
+    return 0;
+  }
+
+  if (olsrIntf != NULL)
+  {
+    /* On OLSR interfaces, create socket for encapsulating and forwarding 
+     * multicast packets */
+    encapsulatingSkfd = CreateEncapsulateSocket(ifName);
+    if (encapsulatingSkfd < 0)
+    {
+      free(newIf);
+      return 0;
+    }
+    nOpened++;
+  }
+
+  /* Create socket for capturing and sending of multicast packets on
+   * non-OLSR interfaces, and on OLSR-interfaces if configured. */
+  if ((olsrIntf == NULL) || (CapturePacketsOnOlsrInterfaces != 0))
+  {
+    capturingSkfd = CreateCaptureSocket(ifName);
+    if (capturingSkfd < 0)
+    {
+      close(encapsulatingSkfd);
+      free(newIf);
+      return 0;
+    }
+
+    nOpened++;
+  }
+
+  /* For ioctl operations on the network interface, use either capturingSkfd
+   * or encapsulatingSkfd, whichever is available */
+  ioctlSkfd = (capturingSkfd >= 0) ? capturingSkfd : encapsulatingSkfd;
+
+  /* Retrieve the MAC address of the interface. */
+  memset(&ifr, 0, sizeof(struct ifreq));
+  strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
+  ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
+  if (ioctl(ioctlSkfd, SIOCGIFHWADDR, &ifr) < 0)
+  {
+    olsr_printf(
+      1,
+      "%s: ioctl(SIOCGIFHWADDR) error for interface \"%s\": %s\n",
+      PLUGIN_NAME,
+      ifName,
+      strerror(errno));
+    close(capturingSkfd);
+    close(encapsulatingSkfd);
+    free(newIf);
+    return 0;
+  }
+
+  /* If null-interface, cancel the whole creation and return NULL */
+  /* -- Not needed, all goes well with interfaces that have a
+   * null-address, such as ppp interfaces. */
+  /*
+  if (IsNullMacAddress(ifr.ifr_hwaddr.sa_data))
+  {
+    close(capturingSkfd);
+    close(encapsulatingSkfd);
+    free(newIf);
+    return 0;
+  }
+  */
+
+  /* Copy data into TBmfInterface object */
+  newIf->capturingSkfd = capturingSkfd;
+  newIf->encapsulatingSkfd = encapsulatingSkfd;
+  memcpy(newIf->macAddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
+  memcpy(newIf->ifName, ifName, IFNAMSIZ);
+  newIf->olsrIntf = olsrIntf;
+  if (olsrIntf != NULL)
+  {
+    /* For an OLSR-interface, copy the interface address and broadcast
+     * address from the OLSR interface object */
+    newIf->intAddr = olsrIntf->int_addr;
+    newIf->broadAddr = olsrIntf->int_broadaddr;
+  }
+  else
+  {
+    /* For a non-OLSR interface, retrieve the IP address ourselves */
+    memset(&ifr, 0, sizeof(struct ifreq));
+    strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
+    ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
+    if (ioctl(ioctlSkfd, SIOCGIFADDR, &ifr) < 0) 
+    {
+      olsr_printf(
+        1,
+        "%s: ioctl(SIOCGIFADDR) error for interface \"%s\": %s\n",
+        PLUGIN_NAME,
+        ifName,
+        strerror(errno));
+
+      ((struct sockaddr_in*)&newIf->intAddr)->sin_addr.s_addr = inet_addr("0.0.0.0");
+         }
+         else
+         {
+      newIf->intAddr = ifr.ifr_addr;
+    }
+
+    /* For a non-OLSR interface, retrieve the IP broadcast address ourselves */
+    memset(&ifr, 0, sizeof(struct ifreq));
+    strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
+    ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
+    if (ioctl(ioctlSkfd, SIOCGIFBRDADDR, &ifr) < 0) 
+    {
+      olsr_printf(
+        1,
+        "%s: ioctl(SIOCGIFBRDADDR) error for interface \"%s\": %s\n",
+        PLUGIN_NAME,
+        ifName,
+        strerror(errno));
+
+      ((struct sockaddr_in*)&newIf->broadAddr)->sin_addr.s_addr = inet_addr("0.0.0.0");
+         }
+         else
+         {
+      newIf->broadAddr = ifr.ifr_broadaddr;
+    }
+  }
+
+  /* Initialize fragment history table */
+  memset(&newIf->fragmentHistory, 0, sizeof(newIf->fragmentHistory));
+  newIf->nextFragmentHistoryEntry = 0;
+
+  /* Add new TBmfInterface object to global list */
+  newIf->next = BmfInterfaces;
+  BmfInterfaces = newIf;
+
+  OLSR_PRINTF(
+    9,
+    "%s: opened %d socket%s on %s interface \"%s\"\n",
+    PLUGIN_NAME_SHORT,
+    nOpened,
+    nOpened == 1 ? "" : "s",
+    olsrIntf != NULL ? "OLSR" : "non-OLSR",
+    ifName);
+
+  return nOpened;
+}
 
 
-int CreateBmfNetworkInterfaces(void)
+/* -------------------------------------------------------------------------
+ * Function   : CreateBmfNetworkInterfaces
+ * Description: Create a list of TBmfInterface objects, one for each network
+ *              interface on which BMF runs
+ * Input      : skipThisIntf - network interface to skip, if seen
+ * Output     : none
+ * Return     : fail (-1) or success (0)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int CreateBmfNetworkInterfaces(struct interface* skipThisIntf)
 {
   int skfd;
   struct ifconf ifc;
   int numreqs = 30;
   struct ifreq* ifr;
   int n;
 {
   int skfd;
   struct ifconf ifc;
   int numreqs = 30;
   struct ifreq* ifr;
   int n;
+  int nOpenedSockets = 0;
 
 
-  EtherTunTapFd = CreateLocalEtherTunTap();
-  if (EtherTunTapFd < 0)
-  {
-    olsr_printf(1, "%s: error creating local EtherTunTap\n", PLUGIN_NAME);
-    return -1;    
-  }
+  /* Clear input descriptor set */
+  FD_ZERO(&InputSet);
 
   skfd = socket(PF_INET, SOCK_DGRAM, 0);
   if (skfd < 0)
   {
     olsr_printf(
       1,
 
   skfd = socket(PF_INET, SOCK_DGRAM, 0);
   if (skfd < 0)
   {
     olsr_printf(
       1,
-      "%s: No inet socket available: %s\n",
+      "%s: no inet socket available to retrieve interface list: %s\n",
       PLUGIN_NAME,
       strerror(errno));
     return -1;
       PLUGIN_NAME,
       strerror(errno));
     return -1;
@@ -421,7 +972,7 @@ int CreateBmfNetworkInterfaces(void)
 
     if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
     {
 
     if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
     {
-      olsr_printf(1, "%s: SIOCGIFCONF error: %s\n", PLUGIN_NAME, strerror(errno));
+      olsr_printf(1, "%s: ioctl(SIOCGIFCONF) error: %s\n", PLUGIN_NAME, strerror(errno));
 
       close(skfd);
       free(ifc.ifc_buf);
 
       close(skfd);
       free(ifc.ifc_buf);
@@ -437,100 +988,92 @@ int CreateBmfNetworkInterfaces(void)
     break; /* for (;;) */
   } /* for (;;) */
 
     break; /* for (;;) */
   } /* for (;;) */
 
+  close(skfd);
+
   /* 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;
   /* 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);
 
 
     /* ...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))
+    if (skipThisIntf != NULL && olsrIntf == skipThisIntf)
     {
     {
-      /* Interface is neither OLSR interface, nor specified as non-OLSR BMF
-       * interface in the BMF plugin parameter list */
       continue; /* for (n = ...) */
     }
 
       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))
+    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 = ...) */
     }
 
       continue; /* for (n = ...) */
     }
 
-    /* Create socket for capturing and sending multicast packets */
-    capturingSkfd = CreateCaptureSocket(if_nametoindex(ifr->ifr_name));
-    if (capturingSkfd < 0)
-    {
-      continue; /* for (n = ...) */
-    }
+    nOpenedSockets += CreateInterface(ifr->ifr_name, olsrIntf);
 
 
-    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 = ...) */
   } /* for (n = ...) */
+
+  free(ifc.ifc_buf);
   
   
+  /* Create the BMF network interface */
+  EtherTunTapFd = CreateLocalEtherTunTap();
+  if (EtherTunTapFd >= 0)
+  {
+    nOpenedSockets++;
+  }
+
   if (BmfInterfaces == NULL)
   {
     olsr_printf(1, "%s: could not initialize any network interface\n", PLUGIN_NAME);
   if (BmfInterfaces == NULL)
   {
     olsr_printf(1, "%s: could not initialize any network interface\n", PLUGIN_NAME);
-    return -1;
   }
   }
-
-  close(skfd);
-  free(ifc.ifc_buf);
+  else
+  {
+    olsr_printf(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpenedSockets);
+  }
   return 0;
 }
 
   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 */
+/* -------------------------------------------------------------------------
+ * Function   : AddInterface
+ * Description: Add an OLSR-enabled network interface to the list of BMF-enabled
+ *              network interfaces
+ * Input      : newIntf - network interface to add
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+void AddInterface(struct interface* newIntf)
+{
+  int nOpened;
+
+  assert(newIntf != NULL);
+
+  nOpened = CreateInterface(newIntf->int_name, newIntf);
+
+  olsr_printf(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpened);
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : CloseBmfNetworkInterfaces
+ * Description: Closes every socket on each network interface used by BMF
+ * Input      : newIntf - network interface to add
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * Notes      : Closes
+ *              - the local EtherTunTap interface (e.g. "tun0" or "tap0")
+ *              - for each BMF-enabled interface, the socket used for
+ *                capturing multicast packets
+ *              - for each OLSR-enabled interface, the socket used for
+ *                encapsulating packets
+ *              Also restores the network state to the situation before BMF
+ *              was started.
+ * ------------------------------------------------------------------------- */
+
 void CloseBmfNetworkInterfaces()
 {
   int nClosed = 0;
 void CloseBmfNetworkInterfaces()
 {
   int nClosed = 0;
@@ -542,30 +1085,91 @@ void CloseBmfNetworkInterfaces()
     struct TBmfInterface* bmfIf = nextBmfIf;
     nextBmfIf = bmfIf->next;
 
     struct TBmfInterface* bmfIf = nextBmfIf;
     nextBmfIf = bmfIf->next;
 
-    close(bmfIf->capturingSkfd);
-    nClosed++;
+    if (bmfIf->capturingSkfd >= 0)
+    {
+      close(bmfIf->capturingSkfd);
+      nClosed++;
+    }
     if (bmfIf->encapsulatingSkfd >= 0) 
     {
       close(bmfIf->encapsulatingSkfd);
       nClosed++;
     }
 
     if (bmfIf->encapsulatingSkfd >= 0) 
     {
       close(bmfIf->encapsulatingSkfd);
       nClosed++;
     }
 
+    OLSR_PRINTF(
+      9,
+      "%s: closed %s interface \"%s\"\n", 
+      PLUGIN_NAME_SHORT,
+      bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR",
+      bmfIf->ifName);
+
     free(bmfIf);
   }
   
     free(bmfIf);
   }
   
-  /* Restore IP spoof filter for EtherTunTap device */
-  RestoreSpoofFilter(EtherTunTapIfName);
+  if (EtherTunTapFd >= 0)
+  {
+    /* Restore IP spoof filter for EtherTunTap interface */
+    RestoreSpoofFilter(EtherTunTapIfName);
+
+    close(EtherTunTapFd);
+    nClosed++;
+
+    OLSR_PRINTF(9, "%s: closed \"%s\"\n", PLUGIN_NAME_SHORT, EtherTunTapIfName);
+  }
 
 
-  close(EtherTunTapFd);
-  nClosed++;
+  BmfInterfaces = NULL;
 
   olsr_printf(1, "%s: closed %d sockets\n", PLUGIN_NAME, nClosed);
 
   olsr_printf(1, "%s: closed %d sockets\n", PLUGIN_NAME, nClosed);
+
+  /* If there is a multicast route, delete it */
+  if (EtherTunTapIp != ETHERTUNTAPDEFAULTIP)
+  {
+    struct rtentry kernel_route;
+
+    memset(&kernel_route, 0, sizeof(struct rtentry));
+
+    ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET;
+    ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET;
+    ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET;
+
+    /* 224.0.0.0/4 */
+    ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = htonl(0xE0000000);
+    ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = htonl(0xF0000000);
+
+    kernel_route.rt_metric = 0;
+    kernel_route.rt_flags = RTF_UP;
+
+    kernel_route.rt_dev = EtherTunTapIfName;
+
+    /* Sven-Ola@gmx.de: not available in olsrd-0.5/src/defs.h */
+    extern int ioctl_s;
+
+    if (ioctl(ioctl_s, SIOCDELRT, &kernel_route) < 0)
+    {
+      olsr_printf(
+        1,
+        "%s: error deleting multicast route via EtherTunTap interface \"%s\": %s\n",
+        PLUGIN_NAME,
+        EtherTunTapIfName,
+        strerror(errno));
+      /* Continue anyway */
+    }
+  }
 }
 
 }
 
-#define MAX_NON_OLSR_IFS 10
+#define MAX_NON_OLSR_IFS 32
 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
 static int nNonOlsrIfs = 0;
 
 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
 static int nNonOlsrIfs = 0;
 
+/* -------------------------------------------------------------------------
+ * Function   : AddNonOlsrBmfIf
+ * Description: Add an non-OLSR enabled network interface to the list of BMF-enabled
+ *              network interfaces
+ * Input      : ifName - network interface (e.g. "eth0")
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 int AddNonOlsrBmfIf(const char* ifName)
 {
   assert(ifName != NULL);
 int AddNonOlsrBmfIf(const char* ifName)
 {
   assert(ifName != NULL);
@@ -574,17 +1178,26 @@ int AddNonOlsrBmfIf(const char* ifName)
   {
     olsr_printf(
       1,
   {
     olsr_printf(
       1,
-      "%s: too many non-OLSR interfaces specified, maximum %d\n",
+      "%s: too many non-OLSR interfaces specified, maximum is %d\n",
       PLUGIN_NAME,
       MAX_NON_OLSR_IFS);
     return 0;
   }
 
       PLUGIN_NAME,
       MAX_NON_OLSR_IFS);
     return 0;
   }
 
-  strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ);
+  strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ - 1);
+  NonOlsrIfNames[nNonOlsrIfs][IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
   nNonOlsrIfs++;
   return 1;
 }
 
   nNonOlsrIfs++;
   return 1;
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : IsNonOlsrBmfIf
+ * Description: Checks if a network interface is OLSR-enabled
+ * Input      : ifName - network interface (e.g. "eth0")
+ * Output     : none
+ * Return     : true (1) or false (0)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 int IsNonOlsrBmfIf(const char* ifName)
 {
   int i;
 int IsNonOlsrBmfIf(const char* ifName)
 {
   int i;
@@ -597,3 +1210,73 @@ int IsNonOlsrBmfIf(const char* ifName)
   }
   return 0;
 }
   }
   return 0;
 }
+
+/* -------------------------------------------------------------------------
+ * Function   : CheckAndUpdateLocalBroadcast
+ * Description: For an IP packet, check if the destination address is not a
+ *              multicast address. If it is not, the packet is assumed to be
+ *              a local broadcast packet. Update the destination address to
+ *              match the passed network interface.
+ * Input      : buffer - the ethernet-IP packet
+ *              broadAddr - the broadcast address to fill in
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * Notes      : See also RFC1141
+ * ------------------------------------------------------------------------- */
+void CheckAndUpdateLocalBroadcast(unsigned char* buffer, struct sockaddr* broadAddr)
+{
+  struct iphdr* iph;
+  union olsr_ip_addr destIp;
+
+  assert(buffer != NULL && broadAddr != NULL);
+
+  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  COPY_IP(&destIp, &iph->daddr);
+  if (! IsMulticast(&destIp))
+  {
+    u_int32_t origDaddr, newDaddr;
+    struct sockaddr_in* sin;
+    u_int32_t check;
+
+    /* Cast down to correct sockaddr subtype */
+    sin = (struct sockaddr_in*)broadAddr;
+    
+    origDaddr = ntohl(iph->daddr);
+
+    iph->daddr = sin->sin_addr.s_addr;
+    newDaddr = ntohl(iph->daddr);
+
+    /* Re-calculate IP header checksum for new destination */
+    check = ntohs(iph->check);
+
+    check = ~ (~ check - ((origDaddr >> 16) & 0xFFFF) + ((newDaddr >> 16) & 0xFFFF));
+    check = ~ (~ check - (origDaddr & 0xFFFF) + (newDaddr & 0xFFFF));
+
+    /* Add carry */
+    check = check + (check >> 16);
+
+    iph->check = htons(check);
+
+    if (iph->protocol == SOL_UDP)
+    {
+      /* Re-calculate UDP/IP checksum for new destination */
+
+      int ipHeaderLen = GetIpHeaderLength(buffer);
+      struct udphdr* udph = (struct udphdr*) (buffer + IP_HDR_OFFSET + ipHeaderLen);
+
+      /* RFC 1624, Eq. 3: HC' = ~(~HC - m + m') */
+
+      check = ntohs(udph->check);
+
+      check = ~ (~ check - ((origDaddr >> 16) & 0xFFFF) + ((newDaddr >> 16) & 0xFFFF));
+      check = ~ (~ check - (origDaddr & 0xFFFF) + (newDaddr & 0xFFFF));
+
+      /* Add carry */
+      check = check + (check >> 16);
+
+      udph->check = htons(check);
+     }
+  }
+}
+
index 0a3c754..0e4f9c2 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: NetworkInterfaces.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : NetworkInterfaces.h
+ * Description: Functions to open and close sockets
+ * Created    : 29 Jun 2006
+ *
+ * $Id: NetworkInterfaces.h,v 1.2 2007/02/10 17:05:56 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
+
+/* System includes */
+#include <netinet/in.h> /* struct in_addr */
 
 /* Plugin includes */
 #include "Packet.h" /* IFHWADDRLEN */
 
 
 /* Plugin includes */
 #include "Packet.h" /* IFHWADDRLEN */
 
+/* Size of buffer in which packets are received */
+#define BMF_BUFFER_SIZE 2048
+
 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. 
 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. */
+   * Only used for OLSR-enabled interfaces; set to -1 if interface is not OLSR-enabled. */
   int encapsulatingSkfd;
 
   unsigned char macAddr[IFHWADDRLEN];
   int encapsulatingSkfd;
 
   unsigned char macAddr[IFHWADDRLEN];
@@ -55,25 +67,54 @@ struct TBmfInterface
    * OLSR-enabled. */
   struct interface* olsrIntf;
 
    * OLSR-enabled. */
   struct interface* olsrIntf;
 
-  /* Kernels index of this network interface */
-  int ifIndex;
-  
+  /* IP address of this network interface */
+  struct sockaddr intAddr;
+
+  /* Broadcast address of this network interface */
+  struct sockaddr broadAddr;
+
+  #define FRAGMENT_HISTORY_SIZE 10
+  struct TFragmentHistory
+  {
+    u_int16_t ipId;
+    u_int8_t ipProto;
+    struct in_addr ipSrc;
+    struct in_addr ipDst;
+  } fragmentHistory [FRAGMENT_HISTORY_SIZE];
+
+  int nextFragmentHistoryEntry;
+
   /* Next element in list */
   struct TBmfInterface* next; 
 };
 
 extern struct TBmfInterface* BmfInterfaces;
 
   /* Next element in list */
   struct TBmfInterface* next; 
 };
 
 extern struct TBmfInterface* BmfInterfaces;
 
+extern int HighestSkfd;
+extern fd_set InputSet;
+
 extern int EtherTunTapFd;
 
 extern int EtherTunTapFd;
 
-extern const char* EtherTunTapIfName;
+extern char EtherTunTapIfName[];
+
+extern u_int32_t EtherTunTapIp;
+extern u_int32_t EtherTunTapIpMask;
+extern u_int32_t EtherTunTapIpBroadcast;
+
+extern int CapturePacketsOnOlsrInterfaces;
 
 enum TTunOrTap { TT_TUN = 0, TT_TAP };
 extern enum TTunOrTap TunOrTap;
 
 
 enum TTunOrTap { TT_TUN = 0, TT_TAP };
 extern enum TTunOrTap TunOrTap;
 
-int CreateBmfNetworkInterfaces(void);
+int SetBmfInterfaceName(const char* ifname);
+int SetBmfInterfaceType(const char* iftype);
+int SetBmfInterfaceIp(const char* ip);
+int SetCapturePacketsOnOlsrInterfaces(const char* enable);
+int CreateBmfNetworkInterfaces(struct interface* skipThisIntf);
+void AddInterface(struct interface* newIntf);
 void CloseBmfNetworkInterfaces(void);
 int AddNonOlsrBmfIf(const char* ifName);
 int IsNonOlsrBmfIf(const char* ifName);
 void CloseBmfNetworkInterfaces(void);
 int AddNonOlsrBmfIf(const char* ifName);
 int IsNonOlsrBmfIf(const char* ifName);
+void CheckAndUpdateLocalBroadcast(unsigned char* buffer, struct sockaddr* broadAddr);
 
 #endif /* _BMF_NETWORKINTERFACES_H */
 
 #endif /* _BMF_NETWORKINTERFACES_H */
index 5bb8ee1..c353744 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: Packet.c,v 1.2 2007/02/08 10:31:43 bernd67 Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : Packet.c
+ * Description: BMF and IP packet processing functions
+ * Created    : 29 Jun 2006
+ *
+ * $Id: Packet.c,v 1.3 2007/02/10 17:05:56 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 #include "Packet.h"
 
 
 #include "Packet.h"
 
 #include <assert.h> /* assert() */
 #include <sys/types.h> /* u_int32_t */
 #include <netinet/in.h> /* ntohs(), htons() */
 #include <assert.h> /* assert() */
 #include <sys/types.h> /* u_int32_t */
 #include <netinet/in.h> /* ntohs(), htons() */
-#include <asm/byteorder.h>
-#include <linux/ip.h>
+#include <netinet/ip.h> /* struct iphdr */
+
+#include <stdio.h>
+/* -------------------------------------------------------------------------
+ * Function   : GetIpPacketLength
+ * Description: Retrieve the IP packet length (in bytes) of the passed
+ *              ethernet-IP packet
+ * Input      : buffer - the ethernet-IP packet
+ * Output     : none
+ * Return     : IP packet length
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int GetIpPacketLength(unsigned char* buffer)
+{
+  struct iphdr* iph;
+
+  assert(buffer != NULL);
+
+  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  return ntohs(iph->tot_len);
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : GetIpHeaderLength
+ * Description: Retrieve the IP header length (in bytes) of the passed
+ *              ethernet-IP packet
+ * Input      : buffer - the ethernet-IP packet
+ * Output     : none
+ * Return     : IP header length
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int GetIpHeaderLength(unsigned char* buffer)
+{
+  struct iphdr* iph;
+
+  assert(buffer != NULL);
+
+  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  return iph->ihl << 2;
+}
 
 
-/* Retrieve the TTL (Time To Live) value from the IP header of the
- * passed ethernet packet */
+/* -------------------------------------------------------------------------
+ * Function   : GetIpTtl
+ * Description: Retrieve the TTL (Time To Live) value from the IP header of
+ *              the passed ethernet-IP packet
+ * Input      : buffer - the ethernet-IP packet
+ * Output     : none
+ * Return     : TTL value
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 int GetIpTtl(unsigned char* buffer)
 {
   struct iphdr* iph;
 int GetIpTtl(unsigned char* buffer)
 {
   struct iphdr* iph;
@@ -53,6 +104,15 @@ int GetIpTtl(unsigned char* buffer)
   return iph->ttl;
 }
 
   return iph->ttl;
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : SaveTtlAndChecksum
+ * Description: Save the TTL (Time To Live) value and IP checksum as found in
+ *              the IP header of the passed ethernet-IP packet
+ * Input      : buffer - the ethernet-IP packet
+ * Output     : sttl - the TTL and checksum values
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
 {
   struct iphdr* iph;
 void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
 {
   struct iphdr* iph;
@@ -64,6 +124,16 @@ void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
   sttl->check = ntohs(iph->check);
 }
 
   sttl->check = ntohs(iph->check);
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : RestoreTtlAndChecksum
+ * Description: Restore the TTL (Time To Live) value and IP checksum in
+ *              the IP header of the passed ethernet-IP packet
+ * Input      : buffer - the ethernet-IP packet
+ *              sttl - the TTL and checksum values
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
 {
   struct iphdr* iph;
 void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
 {
   struct iphdr* iph;
@@ -75,9 +145,17 @@ void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
   iph->check = htons(sttl->check);
 }
 
   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)
+/* -------------------------------------------------------------------------
+ * Function   : DecreaseTtlAndUpdateHeaderChecksum
+ * Description: For an IP packet, decrement the TTL value and update the IP header
+ *              checksum accordingly.
+ * Input      : buffer - the ethernet-IP packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * Notes      : See also RFC1141
+ * ------------------------------------------------------------------------- */
+void DecreaseTtlAndUpdateHeaderChecksum(unsigned char* buffer)
 {
   struct iphdr* iph;
   u_int32_t sum;
 {
   struct iphdr* iph;
   u_int32_t sum;
index 2897766..0b0e903 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: Packet.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : Packet.h
+ * Description: BMF and IP packet processing functions
+ * Created    : 29 Jun 2006
+ *
+ * $Id: Packet.h,v 1.2 2007/02/10 17:05:56 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 /* System includes */
 #include <net/if.h> /* IFNAMSIZ, IFHWADDRLEN */
 
 /* System includes */
 #include <net/if.h> /* IFNAMSIZ, IFHWADDRLEN */
 
 #define IPV4_TYPE 0x0800
 
 
 #define IPV4_TYPE 0x0800
 
+/* BMF-encapsulated packets are Ethernet-IP-UDP packets, which start
+ * with a 16-bytes BMF header (struct TEncapHeader), followed by the
+ * encapsulated Ethernet-IP packet itself */
+
+struct TEncapHeader
+{
+  u_int32_t crc32;
+  u_int32_t futureExpansion1;
+  u_int32_t futureExpansion2;
+  u_int32_t futureExpansion3;
+} __attribute__((__packed__));
+
+#define        ENCAP_HDR_LEN (sizeof(struct TEncapHeader))
+
 struct TSaveTtl
 {
   u_int8_t ttl;
   u_int16_t check;
 struct TSaveTtl
 {
   u_int8_t ttl;
   u_int16_t check;
-};
+} __attribute__((__packed__));
 
 
+int GetIpPacketLength(unsigned char* buffer);
+int GetIpHeaderLength(unsigned char* buffer);
 int GetIpTtl(unsigned char* buffer);
 void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl);
 void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl);
 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);
+void DecreaseTtlAndUpdateHeaderChecksum(unsigned char* buffer);
 
 #endif /* _BMF_PACKET_H */
 
 #endif /* _BMF_PACKET_H */
index 1bd5bb2..5e8dba5 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: PacketHistory.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : PacketHistory.c
+ * Description: Functions for keeping and accessing the history of processed
+ *              multicast IP packets.
+ * Created    : 29 Jun 2006
+ *
+ * $Id: PacketHistory.c,v 1.2 2007/02/10 17:05:56 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 #include "PacketHistory.h"
 
 /* System includes */
 #include <assert.h> /* assert() */
 
 #include "PacketHistory.h"
 
 /* System includes */
 #include <assert.h> /* assert() */
-#include <sys/types.h> /* u_int16_t, u_int32_t */
 #include <string.h> /* memset */
 #include <string.h> /* memset */
+#include <sys/types.h> /* u_int16_t, u_int32_t */
+#include <netinet/ip.h> /* struct iphdr */
 
 /* OLSRD includes */
 #include "olsr.h" /* olsr_printf */
 
 /* OLSRD includes */
 #include "olsr.h" /* olsr_printf */
 
 static u_int32_t PacketHistory[HISTORY_TABLE_SIZE];
 
 
 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. */
+#define CRC_UPTO_NBYTES 256
+
+#if 0
+/* -------------------------------------------------------------------------
+ * Function   : CalcCrcCcitt
+ * Description: Calculate 16-bits CRC according to CRC-CCITT specification
+ * Input      : buffer - the bytes to calculate the CRC value over
+ *              len - the number of bytes to calculate the CRC value over
+ * Output     : none
+ * Return     : CRC-16 value
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 static u_int16_t CalcCrcCcitt(unsigned char* buffer, ssize_t len)
 {
   /* Initial value of 0xFFFF should be 0x1D0F according to
 static u_int16_t CalcCrcCcitt(unsigned char* buffer, ssize_t len)
 {
   /* Initial value of 0xFFFF should be 0x1D0F according to
@@ -60,10 +78,6 @@ static u_int16_t CalcCrcCcitt(unsigned char* buffer, ssize_t len)
 
   for (i = 0; i < len; i++)
   {
 
   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  = (unsigned char)(crc >> 8) | (crc << 8);
     crc ^= buffer[i];
     crc ^= (unsigned char)(crc & 0xff) >> 4;
@@ -71,75 +85,198 @@ static u_int16_t CalcCrcCcitt(unsigned char* buffer, ssize_t len)
     crc ^= ((crc & 0xff) << 4) << 1;
   }
   return crc;
     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
 #endif
+
+/* -------------------------------------------------------------------------
+ * Function   : GenerateCrc32Table
+ * Description: Generate the table of CRC remainders for all possible bytes,
+ *              according to CRC-32-IEEE 802.3
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+#define CRC32_POLYNOMIAL 0xedb88320UL /* bit-inverse of 0x04c11db7UL */
+
+static unsigned long CrcTable[256];
+
+static void GenerateCrc32Table(void)
+{
+  int i, j;
+  u_int32_t crc;
+  for (i = 0; i < 256; i++)
+  {
+    crc = (u_int32_t) i;
+    for (j = 0; j < 8; j++)
+    {
+      if (crc & 1)
+      {
+        crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
+      }
+      else
+      {
+        crc = (crc >> 1);
+      }
+    }
+    CrcTable[i] = crc;
+  }
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : CalcCrc32
+ * Description: Calculate CRC-32 according to CRC-32-IEEE 802.3
+ * Input      : buffer - the bytes to calculate the CRC value over
+ *              len - the number of bytes to calculate the CRC value over
+ * Output     : none
+ * Return     : CRC-32 value
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+static u_int32_t CalcCrc32(unsigned char* buffer, ssize_t len)
+{
+  int i, j;
+  u_int32_t crc = 0xffffffffUL;
+  for (i = 0; i < len; i++)
+  {
+    j = ((int) (crc & 0xFF) ^ *buffer++);
+    crc = (crc >> 8) ^ CrcTable[j];
+  }
+  return crc ^ 0xffffffffUL;
 }
 
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : PacketCrc32
+ * Description: Calculates the CRC-32 value for an Ethernet packet
+ * Input      : ethPkt - the Ethernet packet
+ *              len - the number of octets in the Ethernet packet
+ * Output     : none
+ * Return     : 32-bits hash value
+ * Data Used  : none
+ * Notes      : The source and destination MAC address are not taken into account
+ *              in the CRC calculation.
+ * ------------------------------------------------------------------------- */
+u_int32_t PacketCrc32(unsigned char* ethPkt, ssize_t len)
+{
+  ssize_t nCrcBytes;
+  struct TSaveTtl sttl;
+  struct iphdr* iph;
+  u_int32_t result;
+
+  assert(ethPkt != NULL);
+
+  /* Start CRC calculation at ethertype; skip source and destination MAC 
+   * addresses, and ethertype.
+   *
+   * Also skip TTL: in a multi-homed OLSR-network, the same multicast packet
+   * may enter the network multiple times, each copy differing only in its
+   * TTL value. BMF must not calculate a different CRC for packets that
+   * differ only in TTL. Skip also the IP-header checksum, because it changes
+   * along with TTL. Besides, it is not a good idea to calculate a CRC over
+   * data that already contains a checksum.
+   *
+   * Clip number of bytes over which CRC is calculated to prevent
+   * long packets from possibly claiming too much CPU resources. */
+  nCrcBytes = len - IP_HDR_OFFSET;
+  assert(nCrcBytes > 0);
+  if (nCrcBytes > CRC_UPTO_NBYTES)
+  {
+    nCrcBytes = CRC_UPTO_NBYTES;
+  }
+
+  SaveTtlAndChecksum(ethPkt, &sttl);
+
+  iph = (struct iphdr*) (ethPkt + IP_HDR_OFFSET);
+  iph->ttl = 0xFF; /* fixed value of TTL for CRC-32 calculation */
+  iph->check = 0x5A5A; /* fixed value of IP header checksum for CRC-32 calculation */
+
+  result = CalcCrc32(ethPkt + IP_HDR_OFFSET, nCrcBytes);
+
+  RestoreTtlAndChecksum(ethPkt, &sttl);
+  return result;
+}
+
+/* Calculates a 16-bit hash value from a 32-bit hash value */
+u_int16_t Hash16(u_int32_t hash32)
+{
+  return ((hash32 >> 16) + hash32) & 0xFFFFU;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : InitPacketHistory
+ * Description: Initialize the packet history table and CRC-32 table
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : PacketHistory
+ * ------------------------------------------------------------------------- */
 void InitPacketHistory()
 {
   memset(PacketHistory, 0, sizeof(PacketHistory));
 void InitPacketHistory()
 {
   memset(PacketHistory, 0, sizeof(PacketHistory));
+  GenerateCrc32Table();
 }
 
 }
 
-/* Record the fact that this packet was seen recently */
-void MarkRecentPacket(unsigned char* buffer, ssize_t len)
+/* -------------------------------------------------------------------------
+ * Function   : MarkRecentPacket
+ * Description: Record the fact that this packet was seen recently
+ * Input      : hash16
+ * Output     : none
+ * Return     : none
+ * Data Used  : PacketHistory
+ * ------------------------------------------------------------------------- */
+void MarkRecentPacket(u_int16_t hash16)
 {
 {
-  u_int16_t crc;
   u_int32_t index;
   uint offset;
 
   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;
+  index = hash16 / NPACKETS_PER_ENTRY;
   assert(index < HISTORY_TABLE_SIZE);
 
   assert(index < HISTORY_TABLE_SIZE);
 
-  offset = (crc % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET;
+  offset = (hash16 % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET;
   assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET);
 
   assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET);
 
-  /* Mark "seen recently" */
+  /* Mark as "seen recently" */
   PacketHistory[index] = PacketHistory[index] | (0x3u << offset);
 }
 
   PacketHistory[index] = PacketHistory[index] | (0x3u << offset);
 }
 
-/* Check if this packet was seen recently */
-int CheckMarkRecentPacket(unsigned char* buffer, ssize_t len)
+/* -------------------------------------------------------------------------
+ * Function   : CheckAndMarkRecentPacket
+ * Description: Check if this packet was seen recently, then record the fact
+ *              that this packet was seen recently.
+ * Input      : hash16
+ * Output     : none
+ * Return     : not recently seen (0), recently seen (1)
+ * Data Used  : PacketHistory
+ * ------------------------------------------------------------------------- */
+int CheckAndMarkRecentPacket(u_int16_t hash16)
 {
 {
-  u_int16_t crc;
   u_int32_t index;
   uint offset;
   u_int32_t bitMask;
   int result;
 
   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;
+  index = hash16 / NPACKETS_PER_ENTRY;
   assert(index < HISTORY_TABLE_SIZE);
 
   assert(index < HISTORY_TABLE_SIZE);
 
-  offset =  (crc % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET;
+  offset =  (hash16 % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET;
   assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET);
 
   bitMask = 0x1u << offset;
   result = ((PacketHistory[index] & bitMask) == bitMask);
   
   assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET);
 
   bitMask = 0x1u << offset;
   result = ((PacketHistory[index] & bitMask) == bitMask);
   
-  /* Always mark "seen recently" */
+  /* Always mark as "seen recently" */
   PacketHistory[index] = PacketHistory[index] | (0x3u << offset);
 
   return result;
 }
   
   PacketHistory[index] = PacketHistory[index] | (0x3u << offset);
 
   return result;
 }
   
+/* -------------------------------------------------------------------------
+ * Function   : PrunePacketHistory
+ * Description: Prune the packet history table.
+ * Input      : useless - not used
+ * Output     : none
+ * Return     : none
+ * Data Used  : PacketHistory
+ * ------------------------------------------------------------------------- */
 void PrunePacketHistory(void* useless)
 {
   uint i;
 void PrunePacketHistory(void* useless)
 {
   uint i;
index d4c39fb..4f814ed 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: PacketHistory.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : PacketHistory.h
+ * Description: Functions for keeping and accessing the history of processed
+ *              multicast IP packets.
+ * Created    : 29 Jun 2006
+ *
+ * $Id: PacketHistory.h,v 1.2 2007/02/10 17:05:56 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 #include <sys/types.h> /* ssize_t */
 
 
 #include <sys/types.h> /* ssize_t */
 
-/* 2 bits per seen packet fingerping
+/* 2 bits per seen packet: 
  * 11 = "seen recently",
  * 01 = "timing out"
  * 00 = "not seen recently"
  * 11 = "seen recently",
  * 01 = "timing out"
  * 00 = "not seen recently"
 #define HISTORY_TABLE_SIZE ((1 << NBITS_IN_UINT16) / NPACKETS_PER_ENTRY)
 
 void InitPacketHistory(void);
 #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);
+u_int32_t PacketCrc32(unsigned char* ethPkt, ssize_t len);
+u_int16_t Hash16(u_int32_t hash32);
+void MarkRecentPacket(u_int16_t hash16);
+int CheckAndMarkRecentPacket(u_int16_t hash16);
 void PrunePacketHistory(void*);
 
 #endif /* _BMF_PACKETHISTORY_H */
 void PrunePacketHistory(void*);
 
 #endif /* _BMF_PACKETHISTORY_H */
index ae6afe6..4d91a68 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * 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
- */
+/* -------------------------------------------------------------------------
+ * File       : olsrd_plugin.c
+ * Description: Interface to the OLSRD plugin system
+ * Created    : 29 Jun 2006
+ *
+ * $Id: olsrd_plugin.c,v 1.2 2007/02/10 17:05:56 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 /* System includes */
 #include <assert.h> /* assert() */
 
 /* System includes */
 #include <assert.h> /* assert() */
 
 /* OLSRD includes */
 #include "olsrd_plugin.h"
 
 /* OLSRD includes */
 #include "olsrd_plugin.h"
+#include "defs.h" /* olsr_u8_t, olsr_cnf */
+#include "scheduler.h" /* olsr_register_scheduler_event */
 
 /* BMF includes */
 #include "Bmf.h" /* InitBmf(), CloseBmf(), RegisterBmfParameter() */
 
 /* BMF includes */
 #include "Bmf.h" /* InitBmf(), CloseBmf(), RegisterBmfParameter() */
+#include "PacketHistory.h" /* InitPacketHistory() */
 
 static void __attribute__ ((constructor)) my_init(void);
 static void __attribute__ ((destructor)) my_fini(void);
 
 void olsr_plugin_exit(void);
 
 
 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 */
+/* -------------------------------------------------------------------------
+ * Function   : olsrd_plugin_interface_version
+ * Description: Plugin interface version
+ * Input      : none
+ * Output     : none
+ * Return     : BMF plugin interface version number
+ * Data Used  : none
+ * Notes      : Called by main OLSRD (olsr_load_dl) to check plugin interface
+ *              version
+ * ------------------------------------------------------------------------- */
 int olsrd_plugin_interface_version()
 {
   return OLSRD_PLUGIN_INTERFACE_VERSION;
 }
 
 int olsrd_plugin_interface_version()
 {
   return OLSRD_PLUGIN_INTERFACE_VERSION;
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : olsrd_plugin_init
+ * Description: Plugin initialisation
+ * Input      : none
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : olsr_cnf
+ * Notes      : Called by main OLSRD (init_olsr_plugin) to initialize plugin
+ * ------------------------------------------------------------------------- */
 int olsrd_plugin_init()
 {
 int olsrd_plugin_init()
 {
-  return 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();
+
+  /* Register ifchange function */
+  add_ifchgf(&InterfaceChange);
+
+  /* Register the duplicate registration pruning process */
+  olsr_register_scheduler_event(&PrunePacketHistory, NULL, 3.0, 2.0, NULL);
+
+  return InitBmf(NULL);
 }
 
 }
 
-/* destructor - called at unload */
+/* -------------------------------------------------------------------------
+ * Function   : olsr_plugin_exit
+ * Description: Plugin cleanup
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * Notes      : Called by my_fini() at unload of shared object
+ * ------------------------------------------------------------------------- */
 void olsr_plugin_exit()
 {
   CloseBmf();
 }
 
 void olsr_plugin_exit()
 {
   CloseBmf();
 }
 
-/* Register parameters from config file
- * Called for all plugin parameters */
+/* -------------------------------------------------------------------------
+ * Function   : olsrd_plugin_register_param
+ * Description: Register parameters from config file
+ * Input      : key - the parameter name
+ *              value - the parameter value
+ * Output     : none
+ * Return     : fatal error (<0), minor error (0) or success (>0)
+ * Data Used  : none
+ * Notes      : Called by main OLSR (init_olsr_plugin) for all plugin parameters
+ * ------------------------------------------------------------------------- */
 int olsrd_plugin_register_param(char* key, char* value)
 {
   assert(key != NULL && value != NULL);
 int olsrd_plugin_register_param(char* key, char* value)
 {
   assert(key != NULL && value != NULL);
@@ -78,6 +132,15 @@ int olsrd_plugin_register_param(char* key, char* value)
   return RegisterBmfParameter(key, value);
 }
  
   return RegisterBmfParameter(key, value);
 }
  
+/* -------------------------------------------------------------------------
+ * Function   : my_init
+ * Description: Plugin constructor
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * Notes      : Called at load of shared object
+ * ------------------------------------------------------------------------- */
 static void my_init()
 {
   /* Print plugin info to stdout */
 static void my_init()
 {
   /* Print plugin info to stdout */
@@ -86,6 +149,15 @@ static void my_init()
   return;
 }
 
   return;
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : my_fini
+ * Description: Plugin destructor
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * Notes      : Called at unload of shared object
+ * ------------------------------------------------------------------------- */
 static void my_fini()
 {
   olsr_plugin_exit();
 static void my_fini()
 {
   olsr_plugin_exit();