* bmf-plugin 1.4
authorBernd Petrovitsch <bernd@firmix.at>
Sun, 22 Apr 2007 17:40:39 +0000 (17:40 +0000)
committerBernd Petrovitsch <bernd@firmix.at>
Sun, 22 Apr 2007 17:40:39 +0000 (17:40 +0000)
15 files changed:
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

index acced36..d17a244 100644 (file)
 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 # POSSIBILITY OF SUCH DAMAGE.
 #
-# $Id: Makefile,v 1.2 2007/02/10 17:05:55 bernd67 Exp $
 
 OLSRD_PLUGIN = true
 PLUGIN_NAME =  olsrd_bmf
-PLUGIN_VER =   1.3
+PLUGIN_VER =   1.4
 
 TOPDIR = ../..
 include $(TOPDIR)/Makefile.inc
index a0748f3..6d1e377 100644 (file)
@@ -1,6 +1,6 @@
 BASIC MULTICAST FORWARDING PLUGIN FOR OLSRD
 by Erik Tromp (erik.tromp@nl.thalesgroup.com, erik_tromp@hotmail.com)
-Version 1.3
+Version 1.4
 
 1. Introduction
 ---------------
@@ -17,14 +17,14 @@ in the past 3-6 seconds are forwarded.
 2. How to build and install
 ---------------------------
 
-Download the olsr-bmf-v1.3.tar.gz file and save it into your OLSRD
+Download the olsr-bmf-v1.4.tar.gz file and save it into your OLSRD
 base install directory.
 
 Change directory (cd) to your OLSRD base install directory.
 
 At the command prompt, type:
 
-  tar -zxvf ./olsr-bmf-v1.3.tar.gz
+  tar -zxvf ./olsr-bmf-v1.4.tar.gz
 
 then type:
 
@@ -47,7 +47,7 @@ Set permissions, e.g.:
 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"
+  LoadPlugin "olsrd_bmf.so.1.4"
   {
     # No PlParam entries required for basic operation
   }
@@ -64,8 +64,8 @@ olsrd daemon by entering at the shell prompt:
 Look at the output; it should list the BMF plugin, e.g.:
 
   ---------- Plugin loader ----------
-  Library: olsrd_bmf.so.1.3
-  OLSRD Basic Multicast Forwarding plugin 1.3 (Dec 18 2006 11:23:51)
+  Library: olsrd_bmf.so.1.4
+  OLSRD Basic Multicast Forwarding plugin 1.4 (Mar 30 2007 14:30:57)
     (C) Thales Communications Huizen, Netherlands
     Erik Tromp (erik.tromp@nl.thalesgroup.com)
   Checking plugin interface version...  4 - OK
@@ -84,14 +84,14 @@ Look at the output; it should list the BMF plugin, e.g.:
 Enter the following command on the command prompt:
   
   ping 224.0.0.1
-    
+
 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:
 
 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.
+PING 224.0.0.1 (224.0.0.1) 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!)
 64 bytes from 192.168.151.55: icmp_seq=1 ttl=63 time=10.7 ms (DUP!)
@@ -110,6 +110,22 @@ We can see the response from the originating host (192.168.151.50)
 receive their own packets). We can also see the responses by the
 other hosts (correctly seen as DUPlicates by ping).
 
+Note: when using an older version of ping than the standard from
+iputils-20020927, as found in most current Linux distributions, you may want
+to test BMF by specifying the output interface to the ping command:
+
+  ping -I bmf0 224.0.0.1
+
+Older versions of 'ping' (e.g. as found in iputils-20020124) may bind to the
+autoselected source address, which may be incorrect. Since BMF re-uses
+one of the existing IP addresses for the "bmf0" network interface, the
+older-version ping command may 'autobind' to the wrong interface.
+
+See also the note in the iputils-20020927/RELNOTES file:
+"* Mads Martin Jørgensen <mmj@suse.de>: ping should not bind to autoselected
+  source address, it used to work when routing changes. Return classic
+  behaviour, option -B is added to enforce binding."
+
 
 5. How does it work
 -------------------
@@ -173,7 +189,7 @@ the /etc/olsrd.conf file.
 The following gives an overview of all plugin parameters that can be
 configured:
 
-  LoadPlugin "olsrd_bmf.so.1.3"
+  LoadPlugin "olsrd_bmf.so.1.4"
   {
     # Specify the name of the BMF network interface.
     # Defaults to "bmf0".
@@ -205,6 +221,15 @@ configured:
     # the network. If not, hosts may receive multicast packets in duplicate.
     PlParam "CapturePacketsOnOlsrInterfaces" "yes"
 
+    # The forwarding mechanism to use. Either "Broadcast" or
+    # "UnicastPromiscuous". Defaults to "Broadcast".
+    # In the "UnicastPromiscuous" mode, packets are forwarded (unicast) to the
+    # best candidate neighbor; other neighbors listen promiscuously. IP-local
+    # broadcast is not used. This saves air time on 802.11 WLAN networks,
+    # on which unicast packets are usually sent at a much higher bit rate
+    # than broadcast packets (which are sent at a basic bit rate).
+    PlParam "BmfMechanism" "UnicastPromiscuous"
+
     # List of non-OLSR interfaces to include
     PlParam     "NonOlsrIf"  "eth2"
     PlParam     "NonOlsrIf"  "eth3"
@@ -309,7 +334,7 @@ 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.3"
+  LoadPlugin "olsrd_bmf.so.1.4"
   {
     # Non-OLSR interfaces to participate in the multicast flooding
     PlParam     "NonOlsrIf"  "eth2"
@@ -367,7 +392,7 @@ 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"
+  LoadPlugin "olsrd_bmf.so.1.4"
   {
       PlParam "BmfInterfaceIp" "10.10.10.4/24"
   }
@@ -436,8 +461,8 @@ 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.
+To simulate that situation, the iptables tool is often used (see
+www.netfilter.org). 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
@@ -453,7 +478,7 @@ 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.3"
+  LoadPlugin "olsrd_bmf.so.1.4"
   {
     # Drop all packets received from the following MAC sources
     PlParam     "DropMac"    "00:0C:29:51:32:88" # RemoteClient1
@@ -461,6 +486,8 @@ interfaces if they are in promiscuous mode.) For example:
     PlParam     "DropMac"    "00:0C:29:28:0E:CC" # SimpleClient2
   }
 
+See also the notes in the 'packet' manpage ("Packet sockets are not
+subject to the input or output firewall chains").
 
 
 10. Common problems, FAQ
@@ -488,6 +515,7 @@ Answer:
 Turn on the possibility to create a tuntap interface; see section 2 of this
 file.
 
+
 ---------
 Question:
 When starting OLSRD with the BMF plugin, I can see the following
@@ -509,9 +537,17 @@ 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
+If "modprobe tun" says something like "modprobe: Can't locate module tun", then either
 it is not compiled at all or it is not compiled into the kernel. 
 
+Note: if you do not want to receive multicast packets, only forward the packets
+that other hosts send, then you do not need the tuntap interface. This could be the
+case if your host is purely an OLSR router; normally no traffic will be directed
+to the router itself. In that case you can ignore this error message. Beware, though,
+that you will then not be able to do the simple 'ping 224.0.0.1' test (as described in
+section 4. How to check if it works) to check for the presence of all OLSR-BMF routers
+in the network. 
+
 
 ---------
 Question:
@@ -528,6 +564,28 @@ the BMF network interface, either by specifying the interface name itself
 11. Version history
 -------------------
 
+31 Mar 2007: Version 1.4
+* Optimized the standard forwarding mechanism in such a way that
+  retransmissions of packets are only done on those network interfaces
+  that make a host a multi-point relay (MPR) for the sender. I.e.:
+  retransmitting a packet on a network interface is not done if that
+  does not lead to any new hosts being reached.
+* Optimized the standard forwarding mechanism such that, if the network
+  topology indicates there is only one neighbor on an interface, packets are
+  sent to the specific IP address (unicast) of that neighbor. If the network
+  topology indicates there are multiple neighbors, then BMF will still send
+  packets to the IP local-broadcast address.
+* Introduced a new forwarding mechanism, using only IP-unicast to
+  forward packets. Packets are forwarded to the best candidate neighbor;
+  other neighbors listen promiscuously. IP-local broadcast is not used.
+  This saves air time on 802.11 WLAN networks, on which unicast packets are
+  usually sent at a much higher bit rate than broadcast packets (which are
+  sent at a basic bit rate).
+  This mechanism can be activated by specifying the following plugin
+  parameter:
+    PlParam "BmfMechanism" "UnicastPromiscuous"
+  See also section 6 - Advanced configuration.
+
 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
@@ -572,7 +630,8 @@ the BMF network interface, either by specifying the interface name itself
   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".
+  debug level 9, run "olsrd -d 9"; if you're only interested in
+  BMF debug messages, run "olsrd -d 9 | grep -i bmf".
 * Can now deal with network interface removal ("ifdown eth1") and
   addition ("ifup eth1").
 * CRC-calculation for duplicate detection is done over first 256
index f064d44..6132818 100644 (file)
  * Description: IP packet characterization functions
  * Created    : 29 Jun 2006
  *
- * $Id: Address.c,v 1.3 2007/04/20 14:06:17 bernd67 Exp $ 
  * ------------------------------------------------------------------------- */
  
 #include "Address.h"
 
 /* System includes */
+#include <stddef.h> /* NULL */
 #include <assert.h> /* assert() */
 #include <netinet/ip.h> /* struct ip */
 #include <netinet/udp.h> /* struct udphdr */
@@ -99,130 +99,49 @@ int IsMulticast(union olsr_ip_addr* ipAddress)
 }
 
 /* -------------------------------------------------------------------------
- * 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;
-  
-  assert(destIp != NULL && broadAddr != NULL);
-
-  /* Cast down to correct sockaddr subtype */
-  sin = (struct sockaddr_in*)broadAddr;
-
-  return COMP_IP(&(sin->sin_addr.s_addr), destIp);
-}
-
-/* -------------------------------------------------------------------------
  * Function   : IsOlsrOrBmfPacket
- * Description: Check if an ethernet packet is an OLSR packet or a BMF packet
- * Input      : intf, ethPkt, len
+ * Description: Check if an IP packet is either an OLSR packet or a BMF packet
+ * Input      : ipPacket
  * Output     : none
  * Return     : true (1) or false (0)
  * Data Used  : none
- * Assumption : len >= IP_HDR_OFFSET + GetIpHeaderLength(ethPkt)
  * ------------------------------------------------------------------------- */
-int IsOlsrOrBmfPacket(struct TBmfInterface* intf __attribute__((unused)), unsigned char* ethPkt, size_t len)
+int IsOlsrOrBmfPacket(unsigned char* ipPacket)
 {
-  struct ip* ipData;
+  struct ip* ipHeader;
   unsigned int ipHeaderLen;
-  struct udphdr* udpData;
+  struct udphdr* udpHeader;
   u_int16_t destPort;
 
-  assert(ethPkt != NULL);
+  assert(ipPacket != NULL);
 
-  /* Consider OLSR and BMF packets not to be local broadcast
-   * OLSR packets are UDP - port 698
+  /* OLSR packets are UDP - port 698
    * 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 */
+   * OLSR-Autodetect probe packets are UDP - port 51698 */
 
-  ipData = (struct ip*) (ethPkt + IP_HDR_OFFSET);
-  if (ipData->ip_p != SOL_UDP)
+  /* Check if UDP */
+  ipHeader = (struct ip*) ipPacket;
+  if (ipHeader->ip_p != SOL_UDP)
   {
+    /* Not UDP */
     return 0;
   }
 
-  /* 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;
-  }
-
-  /* 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))
+  /* The total length must be at least large enough to store the UDP header */
+  ipHeaderLen = GetHeaderLength(ipPacket);
+  if (GetTotalLength(ipPacket) < ipHeaderLen + sizeof(struct udphdr))
   {
+    /* Not long enough */
     return 0;
   }
 
   /* Go into the UDP header and check port number */
-  udpData = (struct udphdr*) (ethPkt + IP_HDR_OFFSET + ipHeaderLen);
-  destPort = ntohs(udpData->dest);
+  udpHeader = (struct udphdr*) (ipPacket + ipHeaderLen);
+  destPort = ntohs(udpHeader->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;
   }
 
index 6424262..8c73573 100644 (file)
@@ -38,7 +38,6 @@
  * 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 */
@@ -50,7 +49,6 @@ extern int EnableLocalBroadcast;
 
 int DoLocalBroadcast(const char* enable);
 int IsMulticast(union olsr_ip_addr* ipAddress);
-int IsLocalBroadcast(union olsr_ip_addr* destIp, struct sockaddr* broadAddr);
-int IsOlsrOrBmfPacket(struct TBmfInterface* intf, unsigned char* ethPkt, size_t len);
+int IsOlsrOrBmfPacket(unsigned char* ipPacket);
 
 #endif /* _BMF_ADDRESS_H */
index 1684878..2bf8ae6 100644 (file)
@@ -35,7 +35,6 @@
  * Description: Multicast forwarding functions
  * Created    : 29 Jun 2006
  *
- * $Id: Bmf.c,v 1.4 2007/04/20 14:58:35 bernd67 Exp $ 
  * ------------------------------------------------------------------------- */
 
 #define _MULTI_THREADED
 #include "Bmf.h"
 
 /* System includes */
-#include <stdio.h> /* NULL */
+#include <stddef.h> /* NULL */
 #include <sys/types.h> /* ssize_t */
 #include <string.h> /* strerror() */
+#include <stdarg.h> /* va_list, va_start, va_end */
 #include <errno.h> /* errno */
 #include <assert.h> /* assert() */
 #include <linux/if_packet.h> /* struct sockaddr_ll, PACKET_MULTICAST */
 #include <pthread.h> /* pthread_t, pthread_create() */
 #include <signal.h> /* sigset_t, sigfillset(), sigdelset(), SIGINT */
 #include <netinet/ip.h> /* struct ip */
+#include <netinet/udp.h> /* struct udphdr */
 
 /* OLSRD includes */
 #include "defs.h" /* olsr_cnf, OLSR_PRINTF */
@@ -63,7 +64,7 @@
 
 /* Plugin includes */
 #include "NetworkInterfaces.h" /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */
-#include "Address.h" /* IsMulticast(), IsLocalBroadcast() */
+#include "Address.h" /* IsMulticast() */
 #include "Packet.h" /* ETH_TYPE_OFFSET, IFHWADDRLEN etc. */
 #include "PacketHistory.h" /* InitPacketHistory() */
 #include "DropList.h" /* DropMac() */
@@ -72,109 +73,226 @@ static pthread_t BmfThread;
 static int BmfThreadRunning = 0;
 
 /* -------------------------------------------------------------------------
+ * Function   : BmfPError
+ * Description: Prints an error message at OLSR debug level 1.
+ *              First the plug-in name is printed. Then (if format is not NULL
+ *              and *format is not empty) the arguments are printed, followed
+ *              by a colon and a blank. Then the message and a new-line.
+ * Input      : format, arguments
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+void BmfPError(char* format, ...)
+{
+#define MAX_STR_DESC 255
+  char* strErr = strerror(errno);
+  char strDesc[MAX_STR_DESC];
+
+  /* Rely on short-circuit boolean evaluation */
+  if (format == NULL || *format == '\0')
+  {
+    olsr_printf(1, "%s: %s\n", PLUGIN_NAME, strErr);
+  }
+  else
+  {
+    va_list arglist;
+
+    olsr_printf(1, "%s: ", PLUGIN_NAME);
+
+    va_start(arglist, format);
+    vsnprintf(strDesc, MAX_STR_DESC, format, arglist);
+    va_end(arglist);
+
+    strDesc[MAX_STR_DESC - 1] = '\0'; /* Ensures null termination */
+
+    olsr_printf(1, "%s: %s\n", strDesc, strErr);
+  }
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : MainAddressOf
+ * Description: Lookup the main address of a node
+ * Input      : ip - IP address of the node
+ * Output     : none
+ * Return     : The main IP address of the node
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+union olsr_ip_addr* MainAddressOf(union olsr_ip_addr* ip)
+{
+  union olsr_ip_addr* result;
+
+  /* TODO: mid_lookup_main_addr() is not thread-safe! */
+  result = mid_lookup_main_addr(ip);
+  if (result == NULL)
+  {
+    result = ip;
+  }
+  return result;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : ComposeEnapsulationDestination
+ * Description: Compose a next destination for an encapsulated packet
+ * Input      : intf - the network interface on which to forward the
+ *                encapsulation packet
+ *              src - the IP source of the encapsulated packet. Pass NULL if
+ *                not applicable.
+ *              forwardedBy - the IP address of the last host that forwarded
+ *                the packet. Pass NULL if not applicable.
+ *              forwardedTo - the IP address to which the last host has
+ *                forwarded the packet. Pass NULL if not applicable.
+ * Output     : nextDest - the composed next destination
+ * Return     : 1 if a valid next destination could be composed, or 0 if not
+ * Data Used  : BmfMechanism
+ * ------------------------------------------------------------------------- */
+static int ComposeEnapsulationDestination(
+  struct TBmfInterface* intf,
+  union olsr_ip_addr* src,
+  union olsr_ip_addr* forwardedBy,
+  union olsr_ip_addr* forwardedTo,
+  struct sockaddr_in* nextDest)
+{
+  struct link_entry* bestNeighborLink;
+  int nPossibleNeighbors;
+
+  memset(nextDest, 0, sizeof(nextDest));
+  nextDest->sin_family = AF_INET;
+  nextDest->sin_port = htons(BMF_ENCAP_PORT);
+
+  bestNeighborLink = GetBestNeighbor(intf, src, forwardedBy, forwardedTo, &nPossibleNeighbors);
+
+  if (bestNeighborLink != NULL)
+  {
+    /* Depending on the how many neighbors there are, and on the BMF mechanism... */
+    if (nPossibleNeighbors == 1 || BmfMechanism == BM_UNICAST_PROMISCUOUS)
+    {
+      /* ...destination IP address is address of best neighbor... */
+      COPY_IP(&nextDest->sin_addr.s_addr, &bestNeighborLink->neighbor_iface_addr);
+    }
+    else
+    {
+      /* ...or destination IP address is local broadcast. */
+      COPY_IP(&nextDest->sin_addr.s_addr, &intf->broadAddr);
+    }
+  }
+  else
+  {
+    /* No (good enough) neighbor on the specified interface: don't forward
+     * the packet */
+    return 0;
+  }
+
+  return 1;
+}
+
+/* -------------------------------------------------------------------------
  * 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
+ *              encapsulationUdpData - The encapsulation header, followed by
+ *                the encapsulated Ethernet frame
  * Output     : none
  * Return     : none
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-static void EncapsulateAndForwardPacket(struct TBmfInterface* intf, unsigned char* buffer, ssize_t len)
+static void EncapsulateAndForwardPacket(
+  struct TBmfInterface* intf,
+  unsigned char* encapsulationUdpData)
 {
-  unsigned char* ethPkt = buffer + ENCAP_HDR_LEN;
+  unsigned char* ethernetFrame = GetEthernetFrame(encapsulationUdpData);
   int nBytesWritten;
-  struct sockaddr_in encapDest;
+  struct sockaddr_in forwardTo; /* Next destination of encapsulation packet */
+  u_int16_t udpDataLen = GetEncapsulationUdpDataLength(encapsulationUdpData);
 
   /* Change encapsulated source MAC address to that of sending interface */
-  memcpy(ethPkt + IFHWADDRLEN, intf->macAddr, IFHWADDRLEN);
+  SetFrameSourceMac(ethernetFrame, intf->macAddr);
 
-  /* 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;
+  /* Compose destination of encapsulation packet */
+  if (ComposeEnapsulationDestination(intf, NULL, NULL, NULL, &forwardTo) == 0)
+  {
+    OLSR_PRINTF(
+      8,
+      "%s: --> not encap-forwarding on \"%s\": there is no neighbor that needs my retransmission\n",
+      PLUGIN_NAME_SHORT,
+      intf->ifName);
+    return;
+  }
 
   nBytesWritten = sendto(
     intf->encapsulatingSkfd,
-    buffer,
-    len,
+    encapsulationUdpData,
+    udpDataLen,
     MSG_DONTROUTE,
-    (struct sockaddr*) &encapDest,
-    sizeof(encapDest));                   
-  if (nBytesWritten != len)
+    (struct sockaddr*) &forwardTo,
+    sizeof(forwardTo));                   
+  if (nBytesWritten != udpDataLen)
   {
-    olsr_printf(
-      1,
-      "%s: sendto() error forwarding pkt to \"%s\": %s\n",
-      PLUGIN_NAME,
-      intf->ifName,
-      strerror(errno));
+    BmfPError("sendto() error forwarding pkt on \"%s\"", intf->ifName);
   }
   else
   {
+    /* Increase counter */
+    intf->nBmfPacketsTx++;
+
     OLSR_PRINTF(
-      9,
-      "%s: --> encapsulated and forwarded to \"%s\"\n",
+      8,
+      "%s: --> encapsulated and forwarded on \"%s\" to %s\n",
       PLUGIN_NAME_SHORT,
-      intf->ifName);
-  } /* if (nBytesWritten != len) */
+      intf->ifName,
+      inet_ntoa(forwardTo.sin_addr));
+  } /* if (nBytesWritten != udpDataLen) */
 }
 
 /* -------------------------------------------------------------------------
  * Function   : BmfPacketCaptured
- * Description: Handle a captured raw IP packet
+ * Description: Handle a captured raw Ethernet frame
  * 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
+ *              encapsulationUdpData - space for the encapsulation header, followed by
+ *                the captured Ethernet frame
  * Output     : none
  * Return     : none
  * Data Used  : BmfInterfaces
- * Notes      : The packet is assumed to be captured on a socket of family
+ * Notes      : The Ethernet frame 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)
+  unsigned char* encapsulationUdpData)
 {
   unsigned char* srcMac;
-  union olsr_ip_addr srcIp;
-  union olsr_ip_addr destIp;
-  union olsr_ip_addr* origIp;
-  struct TBmfInterface* nextFwIntf;
+  union olsr_ip_addr src; /* Source IP address in captured frame */
+  union olsr_ip_addr dst; /* Destination IP address in captured frame */
+  union olsr_ip_addr* origIp; /* Main OLSR address of source of captured frame */
+  struct TBmfInterface* walker;
   int isFromOlsrIntf;
   int isFromOlsrNeighbor;
   int iAmMpr;
-  unsigned char* ethPkt = buffer + ENCAP_HDR_LEN;
-  ssize_t ethPktLen = len - ENCAP_HDR_LEN;
-  struct ip* ipData;
+  unsigned char* ethernetFrame; /* The captured Ethernet frame... */
+  u_int16_t ethernetFrameLen; /* ...and its length */
+  struct ip* ipHeader; /* The IP header inside the captured Ethernet frame */
+  unsigned char* ipPacket; /* The IP packet inside the captured Ethernet frame */
   u_int32_t crc32;
   struct TEncapHeader* encapHdr;
 
+  ethernetFrame = GetEthernetFrame(encapsulationUdpData);
+
   /* Only forward IPv4 packets */
-  u_int16_t type;
-  memcpy(&type, ethPkt + ETH_TYPE_OFFSET, 2);
-  if (ntohs(type) != IPV4_TYPE)
+  if (GetEtherType(ethernetFrame) != IPV4_TYPE)
   {
     return;
   }
 
-  ipData = (struct ip*)(ethPkt + IP_HDR_OFFSET);
+  ipHeader = GetIpHeader(ethernetFrame);
+
+  COPY_IP(&dst, &ipHeader->ip_dst);
 
-  /* 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)))
+  /* Only forward multicast packets. If configured, also forward local broadcast packets */
+  if (IsMulticast(&dst) ||
+      (EnableLocalBroadcast != 0 && COMP_IP(&dst, &intf->broadAddr)))
   {
     /* continue */
   }
@@ -183,33 +301,42 @@ static void BmfPacketCaptured(
     return;
   }
 
-  /* Discard OLSR packets (UDP port 698) and BMF encapsulated packets */
-  if (IsOlsrOrBmfPacket(intf, ethPkt, ethPktLen))
+  ipPacket = GetIpPacket(ethernetFrame);
+
+  /* Don't forward fragments of IP packets. Also, don't forward OLSR packets (UDP
+   * port 698) and BMF encapsulated packets */
+  if (IsIpFragment(ipPacket) || IsOlsrOrBmfPacket(ipPacket))
   {
     return;
   }
 
-  /* Check if this packet is captured on an OLSR-enabled interface */
+  /* Increase counter */
+  intf->nBmfPacketsRx++;
+
+  /* Check if the frame is captured on an OLSR-enabled interface */
   isFromOlsrIntf = (intf->olsrIntf != NULL);
 
-  COPY_IP(&srcIp, &ipData->ip_src);
+  /* Retrieve the length of the captured frame */
+  ethernetFrameLen = GetFrameLength(ethernetFrame);
+
+  COPY_IP(&src, &ipHeader->ip_src);
   OLSR_PRINTF(
-    9,
+    8,
     "%s: %s pkt of %ld bytes captured on %s interface \"%s\": %s->%s\n",
     PLUGIN_NAME_SHORT,
     sllPkttype == PACKET_OUTGOING ? "outgoing" : "incoming",
-    (long)ethPktLen,
+    (long)ethernetFrameLen,
     isFromOlsrIntf ? "OLSR" : "non-OLSR",
     intf->ifName,
-    olsr_ip_to_string(&srcIp),
-    olsr_ip_to_string(&destIp));
+    olsr_ip_to_string(&src),
+    olsr_ip_to_string(&dst));
 
   /* Apply drop list for testing purposes. */
-  srcMac = ethPkt + IFHWADDRLEN;
+  srcMac = ethernetFrame + IFHWADDRLEN;
   if (IsInDropList(srcMac))
   {
     OLSR_PRINTF(
-      9,
+      8,
       "%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));
@@ -217,66 +344,44 @@ static void BmfPacketCaptured(
   }
 
   /* Lookup main address of source in the MID table of OLSR */
-  origIp = mid_lookup_main_addr(&srcIp);
-  if (origIp == NULL)
-  {
-    origIp = &srcIp;
-  }
-
-#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;
-  } */
-#endif
+  origIp = MainAddressOf(&src);
 
   /* Check if this packet was seen recently */
-  crc32 = PacketCrc32(ethPkt, ethPktLen);
+  crc32 = PacketCrc32(ethernetFrame, ethernetFrameLen);
   if (CheckAndMarkRecentPacket(Hash16(crc32)))
   {
+    /* Increase counter */
+    intf->nBmfPacketsRxDup++;
+
     OLSR_PRINTF(
-      9,
+      8,
       "%s: --> discarding: packet is duplicate\n",
       PLUGIN_NAME_SHORT);
     return;
   }
 
   /* Compose encapsulation header */
-  encapHdr = (struct TEncapHeader*) buffer;
+  encapHdr = (struct TEncapHeader*) encapsulationUdpData;
   memset (encapHdr, 0, ENCAP_HDR_LEN);
   encapHdr->crc32 = htonl(crc32);
 
-  /* Check if this packet is captured on an OLSR interface from an OLSR neighbor */
+  /* Check if the frame is captured on an OLSR interface from an OLSR neighbor.
+   * TODO1: get_best_link_to_neighbor() is not thread-safe.
+   * TODO2: get_best_link_to_neighbor() may be very CPU-expensive, a simpler call
+   * would do here (something like 'get_any_link_to_neighbor()'). */
   isFromOlsrNeighbor =
-    (isFromOlsrIntf /* The packet is captured on an OLSR interface... */
+    (isFromOlsrIntf /* The frame 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 */
+  /* TODO: olsr_lookup_mprs_set() is not thread-safe! */
   iAmMpr = olsr_lookup_mprs_set(origIp) != NULL;
 
-  /* Check with each interface what needs to be done on it */
-  nextFwIntf = BmfInterfaces;
-  while (nextFwIntf != NULL)
+  /* Check with each network interface what needs to be done on it */
+  for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
   {
-    int isToOlsrIntf;
-
-    struct TBmfInterface* fwIntf = nextFwIntf;
-    nextFwIntf = fwIntf->next;
-
     /* Is the forwarding interface OLSR-enabled? */
-    isToOlsrIntf = (fwIntf->olsrIntf != NULL);
+    int isToOlsrIntf = (walker->olsrIntf != NULL);
 
     /* Depending on certain conditions, we decide whether or not to forward
      * the packet, and if it is forwarded, in which form (encapsulated
@@ -307,17 +412,17 @@ static void BmfPacketCaptured(
      *
      * - 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.
+     *   Answer: 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.
+     *   Answer: 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.
+     *   Answer 2 (better): Forward it.
      */
 
     if (isFromOlsrIntf && isToOlsrIntf)
@@ -329,238 +434,195 @@ static void BmfPacketCaptured(
         /* Case 1.1 */
         {
           OLSR_PRINTF(
-            9,
-            "%s: --> not encap-forwarding to \"%s\": I am not selected as MPR by neighbor %s\n",
+            8,
+            "%s: --> not encap-forwarding on \"%s\": I am not selected as MPR by neighbor %s\n",
             PLUGIN_NAME_SHORT,
-            fwIntf->ifName,
-            olsr_ip_to_string(&srcIp));
+            walker->ifName,
+            olsr_ip_to_string(&src));
         }    
       }
-      else if (sllPkttype == PACKET_OUTGOING && intf == fwIntf)
+      else if (sllPkttype == PACKET_OUTGOING && intf == walker)
       {
         OLSR_PRINTF(
-          9,
-          "%s: --> not encap-forwarding to \"%s\": pkt was captured on that interface\n",
+          8,
+          "%s: --> not encap-forwarding on \"%s\": pkt was captured on that interface\n",
           PLUGIN_NAME_SHORT,
-          fwIntf->ifName);
+          walker->ifName);
       }
       else
       {
         /* Case 1.2 and 1.3 */
-        EncapsulateAndForwardPacket(fwIntf, buffer, len);
+        EncapsulateAndForwardPacket(walker, encapsulationUdpData);
       }
     } /* if (isFromOlsrIntf && isToOlsrIntf) */
 
     else if (isFromOlsrIntf && !isToOlsrIntf)
     {
-      /* Case 2: Forward from OLSR interface to non-OLSR interface.
-       * [Decrease TTL and] forward */
+      /* Case 2: Forward from OLSR interface to non-OLSR interface */
+
+      int nBytesWritten;
 
-#ifdef DO_TTL_STUFF
-      /* If the TTL is to become 0, do not forward this packet */
-      if (GetIpTtl(ethPkt) <= 1)
+      /* Change source MAC address to that of sending interface */
+      SetFrameSourceMac(ethernetFrame, walker->macAddr);
+
+      /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+       * update its destination address to match the subnet of the network
+       * interface on which the packet is being sent. */
+      CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &walker->broadAddr);
+
+      nBytesWritten = write(walker->capturingSkfd, ethernetFrame, ethernetFrameLen);
+      if (nBytesWritten != ethernetFrameLen)
       {
-        OLSR_PRINTF(
-          9,
-          "%s: --> not forwarding to \"%s\": TTL=0\n",
-          PLUGIN_NAME_SHORT,
-          fwIntf->ifName);
+        BmfPError("write() error forwarding pkt on \"%s\"", walker->ifName);
       }
       else
       {
-        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);
-        }
+        /* Increase counter */
+        walker->nBmfPacketsTx++;
 
-#ifdef DO_TTL_STUFF
-        /* Restore the IP header checksum and the TTL-value of the packet */
-        RestoreTtlAndChecksum(ethPkt, &sttl);
-
-      } /* if (GetIpTtl(ethPkt) <= 1) */
-#endif
+        OLSR_PRINTF(8, "%s: --> forwarded on \"%s\"\n", PLUGIN_NAME_SHORT, walker->ifName);
+      }
     } /* 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. */
+       * Encapsulate and forward packet. */
 
-      EncapsulateAndForwardPacket(fwIntf, buffer, len);
+      EncapsulateAndForwardPacket(walker, encapsulationUdpData);
     } /* 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. */
+      /* Case 4: Forward from non-OLSR interface to non-OLSR interface. */
 
       /* Don't forward on interface on which packet was received */
-      if (intf == fwIntf)
+      if (intf == walker)
       {
         OLSR_PRINTF(
-          9,
-          "%s: --> not forwarding to \"%s\": pkt was captured on that interface\n",
+          8,
+          "%s: --> not forwarding on \"%s\": pkt was captured on that interface\n",
           PLUGIN_NAME_SHORT,
-          fwIntf->ifName);
+          walker->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);
+        SetFrameSourceMac(ethernetFrame, walker->macAddr);
 
-        /* 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);
+        /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+         * update its destination address to match the subnet of the network
+         * interface on which the packet is being sent. */
+        CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &walker->broadAddr);
 
-        nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
-        if (nBytesWritten != ethPktLen)
+        nBytesWritten = write(walker->capturingSkfd, ethernetFrame, ethernetFrameLen);
+        if (nBytesWritten != ethernetFrameLen)
         {
-          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));
+          BmfPError("write() error forwarding pkt on \"%s\"", walker->ifName);
         }
         else
         {
+          /* Increase counter */
+          walker->nBmfPacketsTx++;
+
           OLSR_PRINTF(
-            9,
-            "%s: --> forwarded from non-OLSR to non-OLSR \"%s\"\n",
+            8,
+            "%s: --> forwarded from non-OLSR on non-OLSR \"%s\"\n",
             PLUGIN_NAME_SHORT,
-            fwIntf->ifName);
+            walker->ifName);
         }
-      } /* if (intf == fwIntf) */
-    }
-  } /* while (nextFwIntf != NULL) */
+      } /* if (intf == walker) */
+    } /* if */
+  } /* for */
 }
 
 /* -------------------------------------------------------------------------
- * Function   : BmfEncapsulatedPacketReceived
- * Description: Handle a received BMF-encapsulated IP packet
+ * Function   : BmfEncapsulationPacketReceived
+ * Description: Handle a received BMF-encapsulation 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
+ *              forwardedBy - the IP node that forwarded the packet to me
+ *              forwardedTo - the destination IP address of the encapsulation
+ *                packet, in case the packet was received promiscuously.
+ *                Pass NULL if the packet is received normally (unicast or
+ *                broadcast).
+ *              encapsulationUdpData - the encapsulating IP UDP data, containting
+ *                the BMF encapsulation header, followed by the encapsulated
+ *                Ethernet frame
  * 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, 
-  union olsr_ip_addr* fromIp,
-  unsigned char* buffer,
-  ssize_t len)
+static void BmfEncapsulationPacketReceived(
+  struct TBmfInterface* intf,
+  union olsr_ip_addr* forwardedBy,
+  union olsr_ip_addr* forwardedTo,
+  unsigned char* encapsulationUdpData)
 {
-  union olsr_ip_addr* forwarder;
-  int nBytesToWrite;
-  unsigned char* bufferToWrite;
-  int nBytesWritten;
-  int iAmMpr;
-  struct sockaddr_in encapDest;
-  struct TBmfInterface* nextFwIntf;
-  struct ip* ipData;
-  unsigned char* ethPkt;
-  ssize_t ethPktLen;
-  struct TEncapHeader* encapHdr;
+  int iAmMpr; /* True (1) if I am selected as MPR by 'forwardedBy' */
+  struct sockaddr_in forwardTo; /* Next destination of encapsulation packet */
+  struct TBmfInterface* walker;
+  unsigned char* ethernetFrame; /* The encapsulated Ethernet packet */
+  u_int16_t ethernetFrameLen; /* Length of the encapsulated Ethernet packet */
+  struct ip* ipHeader; /* IP header inside the encapsulated Ethernet packet */
+  union olsr_ip_addr mcSrc; /* Original source of the encapsulated multicast packet */
+  union olsr_ip_addr mcDst; /* Multicast destination of the encapsulated packet */
+  struct TEncapHeader* encapsulationHdr;
+  u_int16_t encapsulationUdpDataLen;
 
   /* Are we talking to ourselves? */
-  if (if_ifwithaddr(fromIp) != NULL)
+  if (if_ifwithaddr(forwardedBy) != NULL)
   {
     return;
   }
 
-  /* Encapsulated packet received on non-OLSR interface? Then discard */
+  /* Discard encapsulated packets received on a non-OLSR interface */
   if (intf->olsrIntf == NULL)
   {
     return;
   }
 
-  /* Apply drop list? No, not needed: encapsulated packets are routed,
+  ethernetFrame = GetEthernetFrame(encapsulationUdpData);
+  ethernetFrameLen = GetFrameLength(ethernetFrame);
+
+  ipHeader = GetIpHeader(ethernetFrame);
+
+  COPY_IP(&mcSrc, &ipHeader->ip_src);
+  COPY_IP(&mcDst, &ipHeader->ip_dst);
+
+  /* Apply drop list? No, not needed: encapsulation packets are IP-routed,
    * so filtering should be done by adding a rule to the iptables FORWARD
    * chain, e.g.:
    * iptables -A FORWARD -m mac --mac-source 00:0C:29:28:0E:CC -j DROP */
 
-  ethPkt = buffer + ENCAP_HDR_LEN;
-  ethPktLen = len - ENCAP_HDR_LEN;
-
-  ipData = (struct ip*) (ethPkt + IP_HDR_OFFSET);
+  /* Increase counter */
+  intf->nBmfPacketsRx++;
 
+  /* Beware: not possible to call olsr_ip_to_string more than 4 times in same printf */
   OLSR_PRINTF(
-    9,
-    "%s: encapsulated pkt of %ld bytes incoming on \"%s\": %s->",
+    8,
+    "%s: encapsulated pkt of %ld bytes incoming on \"%s\": %s->%s, forwarded by %s to %s\n",
     PLUGIN_NAME_SHORT,
-    (long)ethPktLen,
+    (long)ethernetFrameLen,
     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));
+    olsr_ip_to_string(&mcSrc),
+    olsr_ip_to_string(&mcDst),
+    olsr_ip_to_string(forwardedBy),
+    forwardedTo != NULL ? olsr_ip_to_string(forwardedTo) : "me");
 
   /* Get encapsulation header */
-  encapHdr = (struct TEncapHeader*) buffer;
+  encapsulationHdr = (struct TEncapHeader*) encapsulationUdpData;
 
   /* Check if this packet was seen recently */
-  if (CheckAndMarkRecentPacket(Hash16(ntohl(encapHdr->crc32))))
+  if (CheckAndMarkRecentPacket(Hash16(ntohl(encapsulationHdr->crc32))))
   {
+    /* Increase counter */
+    intf->nBmfPacketsRxDup++;
+
     OLSR_PRINTF(
-      9,
+      8,
       "%s: --> discarding: packet is duplicate\n",
       PLUGIN_NAME_SHORT);
     return;
@@ -568,60 +630,59 @@ static void BmfEncapsulatedPacketReceived(
 
   if (EtherTunTapFd >= 0)
   {
-    struct sockaddr broadAddr;
+    /* Unpack the encapsulated Ethernet packet and send a copy to myself via
+     * the EtherTunTap interface */
+
+    union olsr_ip_addr broadAddr;
+    int nBytesToWrite, nBytesWritten;
+    unsigned char* bufferToWrite;
+
+    /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+     * update its destination address to match the subnet of the EtherTunTap
+     * interface */
+    broadAddr.v4 = htonl(EtherTunTapIpBroadcast);
+    CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &broadAddr);
 
-    /* Unpack encapsulated packet and send a copy to myself via the EtherTunTap interface */
-    bufferToWrite = ethPkt;
-    nBytesToWrite = ethPktLen;
+    /* Start off by assuming a TAP device */
+    bufferToWrite = ethernetFrame;
+    nBytesToWrite = ethernetFrameLen;
+
+    /* If we're using the TUN device instead, we need to write an IP packet instead
+     * of an Ethernet packet */
     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));
+      BmfPError("write() error forwarding encapsulated pkt on \"%s\"", EtherTunTapIfName);
     }
     else
     {
       OLSR_PRINTF(
-        9,
-        "%s: --> unpacked and forwarded to \"%s\"\n",
+        8,
+        "%s: --> unpacked and delivered locally on \"%s\"\n",
         PLUGIN_NAME_SHORT,
         EtherTunTapIfName);
     }
   }
 
-  /* Lookup main address of forwarding node */
-  forwarder = mid_lookup_main_addr(fromIp);
-  if (forwarder == NULL)
-  {
-    forwarder = fromIp;
-  }
-
   /* Check if I am MPR for the forwarder */
-  iAmMpr = (olsr_lookup_mprs_set(forwarder) != NULL);
+  /* TODO: olsr_lookup_mprs_set() is not thread-safe! */
+  iAmMpr = (olsr_lookup_mprs_set(MainAddressOf(forwardedBy)) != NULL);
 
-  memset(&encapDest, 0, sizeof(encapDest));
-  encapDest.sin_family = AF_INET;
-  encapDest.sin_port = htons(BMF_ENCAP_PORT);
+  memset(&forwardTo, 0, sizeof(forwardTo));
+  forwardTo.sin_family = AF_INET;
+  forwardTo.sin_port = htons(BMF_ENCAP_PORT);
 
-  nextFwIntf = BmfInterfaces;
-  while (nextFwIntf != NULL)
-  {
-    struct TBmfInterface* fwIntf = nextFwIntf;
-    nextFwIntf = fwIntf->next;
+  encapsulationUdpDataLen = GetEncapsulationUdpDataLength(encapsulationUdpData);
 
+  /* Check with each network interface what needs to be done on it */
+  for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
+  {
     /* 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:
@@ -643,157 +704,133 @@ static void BmfEncapsulatedPacketReceived(
      *   the flooding.
      */
 
-    /* Forward from OLSR interface to non-OLSR interface: unpack encapsulated
-     * packet, [decrease TTL] and forward */
-    if (fwIntf->olsrIntf == NULL)
+    /* To a non-OLSR interface: unpack encapsulated packet and forward */
+    if (walker->olsrIntf == NULL)
     {
-#ifdef DO_TTL_STUFF
-      /* If the TTL is to become 0, do not forward this packet */
-      if (GetIpTtl(ethPkt) <= 1)
+      int nBytesWritten;
+
+      /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+       * update its destination address to match the subnet of the network
+       * interface on which the packet is being sent. */
+      CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &walker->broadAddr);
+
+      nBytesWritten = write(walker->capturingSkfd, ethernetFrame, ethernetFrameLen);
+      if (nBytesWritten != ethernetFrameLen)
       {
-        OLSR_PRINTF(
-          9,
-          "%s: --> not forwarding on \"%s\": TTL=0\n",
-          PLUGIN_NAME_SHORT,
-          fwIntf->ifName);
+        BmfPError("write() error forwarding unpacked encapsulated pkt on \"%s\"", walker->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);
+        /* Increase counter */
+        walker->nBmfPacketsTx++;
 
-#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);
-
-      } /* if (GetIpTtl(ethPkt) <= 1) */
-#endif
-    } /* if (fwIntf->olsrIntf == NULL) */
+        OLSR_PRINTF(
+          8,
+          "%s: --> unpacked and forwarded on \"%s\"\n",
+          PLUGIN_NAME_SHORT,
+          walker->ifName);
+      }
+    } /* if (walker->olsrIntf == NULL) */
 
-    /* Forward from OLSR interface to OLSR interface: forward the packet if this
-     * node is selected as MPR by the forwarding node */
+    /* To a 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);
+      int nBytesWritten;
 
-      /* Destination address is local broadcast */
-      encapDest.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr;
+      /* Compose destination of encapsulation packet */
+      if (ComposeEnapsulationDestination(
+        walker,
+        &mcSrc,
+        forwardedBy,
+        forwardedTo,
+        &forwardTo) == 0)
+      {
+        OLSR_PRINTF(
+          8,
+          "%s: --> not forwarding on \"%s\": there is no neighbor that needs my retransmission\n",
+          PLUGIN_NAME_SHORT,
+          walker->ifName);
+
+        continue; /* for */
+      }
 
       nBytesWritten = sendto(
-        fwIntf->encapsulatingSkfd,
-        buffer,
-        len,
+        walker->encapsulatingSkfd,
+        encapsulationUdpData,
+        encapsulationUdpDataLen,
         MSG_DONTROUTE,
-        (struct sockaddr*) &encapDest,
-        sizeof(encapDest));                   
+        (struct sockaddr*) &forwardTo,
+        sizeof(forwardTo));                   
 
-      if (nBytesWritten != len)
+      if (nBytesWritten != encapsulationUdpDataLen)
       {
-        olsr_printf(
-          1,
-          "%s: sendto() error forwarding encapsulated pkt via \"%s\": %s\n",
-          PLUGIN_NAME,
-          fwIntf->ifName,
-          strerror(errno));
+        BmfPError("sendto() error forwarding encapsulated pkt on \"%s\"", walker->ifName);
       }
       else
       {
+        /* Increase counter */
+        walker->nBmfPacketsTx++;
+
         OLSR_PRINTF(
-          9,
-          "%s: --> forwarded to \"%s\"\n",
+          8,
+          "%s: --> forwarded on \"%s\" to %s\n",
           PLUGIN_NAME_SHORT,
-          fwIntf->ifName);
+          walker->ifName,
+          inet_ntoa(forwardTo.sin_addr));
       }
     }  /* else if (iAmMpr) */
-    else /* fwIntf->olsrIntf != NULL && !iAmMpr */
+    else /* walker->olsrIntf != NULL && !iAmMpr */
     {
-      /* fwIntf is an OLSR interface and I am not selected as MPR */
+      /* 'walker' 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",
+        8,
+        "%s: --> not forwarding on \"%s\": I am not selected as MPR by %s\n",
         PLUGIN_NAME_SHORT,
-        fwIntf->ifName,
-        olsr_ip_to_string(fromIp));
+        walker->ifName,
+        olsr_ip_to_string(forwardedBy));
     }
-  } /* while (nextFwIntf != NULL) */
+  } /* for */
 }
 
 /* -------------------------------------------------------------------------
  * 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
+ * Description: Handle a Ethernet frame, captured outgoing on the tuntap interface
+ * Input      : encapsulationUdpData - space for the encapsulation header, followed by
+ *                the captured Ethernet frame
  * 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)
+static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
 {
   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;
+  union olsr_ip_addr dstIp;
+  union olsr_ip_addr broadAddr;
+  struct TBmfInterface* walker;
+  unsigned char* ethernetFrame;
+  u_int16_t ethernetFrameLen;
+  struct ip* ipHeader;
   u_int32_t crc32;
   struct TEncapHeader* encapHdr;
-  struct sockaddr broadAddr;
-  u_int16_t type;
+
+  ethernetFrame = GetEthernetFrame(encapsulationUdpData);
+  ethernetFrameLen = GetFrameLength(ethernetFrame);
 
   /* Only forward IPv4 packets */
-  memcpy(&type, ethPkt + ETH_TYPE_OFFSET, 2);
-  if (ntohs(type) != IPV4_TYPE)
+  if (GetEtherType(ethernetFrame) != IPV4_TYPE)
   {
     return;
   }
 
-  ipData = (struct ip*)(ethPkt + IP_HDR_OFFSET);
+  ipHeader = GetIpHeader(ethernetFrame);
 
-  /* 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)))
+  /* Only forward multicast packets. If configured, also forward local broadcast packets */
+  COPY_IP(&dstIp, &ipHeader->ip_dst);
+  broadAddr.v4 = htonl(EtherTunTapIpBroadcast);
+  if (IsMulticast(&dstIp) ||
+      (EnableLocalBroadcast != 0 && COMP_IP(&dstIp, &broadAddr)))
   {
     /* continue */
   }
@@ -802,102 +839,77 @@ static void BmfTunPacketCaptured(
     return;
   }
 
-  COPY_IP(&srcIp, &ipData->ip_src);
+  COPY_IP(&srcIp, &ipHeader->ip_src);
   OLSR_PRINTF(
-    9,
+    8,
     "%s: outgoing pkt of %ld bytes captured on tuntap interface \"%s\": %s->%s\n",
     PLUGIN_NAME_SHORT,
-    (long)ethPktLen,
+    (long)ethernetFrameLen,
     EtherTunTapIfName,
     olsr_ip_to_string(&srcIp),
-    olsr_ip_to_string(&destIp));
+    olsr_ip_to_string(&dstIp));
 
   /* Check if this packet was seen recently */
-  crc32 = PacketCrc32(ethPkt, ethPktLen);
+  crc32 = PacketCrc32(ethernetFrame, ethernetFrameLen);
   if (CheckAndMarkRecentPacket(Hash16(crc32)))
   {
     OLSR_PRINTF(
-      9,
+      8,
       "%s: --> discarding: packet is duplicate\n",
       PLUGIN_NAME_SHORT);
     return;
   }
 
   /* Compose encapsulation header */
-  encapHdr = (struct TEncapHeader*) buffer;
+  encapHdr = (struct TEncapHeader*) encapsulationUdpData;
   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)
+  /* Check with each network interface what needs to be done on it */
+  for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
   {
-    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)
+    if (walker->olsrIntf != NULL)
     {
-      /* Case 1: Forward to an OLSR interface.
-       * Encapsulate and forward packet. */
+      /* On an OLSR interface: encapsulate and forward packet. */
 
-      EncapsulateAndForwardPacket(fwIntf, buffer, len);
+      EncapsulateAndForwardPacket(walker, encapsulationUdpData);
     }
     else
     {
-      /* Case 2: Forward to a non-OLSR interface. */
+      /* On a non-OLSR interface: what to do?
+       * 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. */
 
       int nBytesWritten;
 
       /* Change source MAC address to that of sending interface */
-      memcpy(ethPkt + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
+      SetFrameSourceMac(ethernetFrame, walker->macAddr);
 
-      /* 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);
+      /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+       * update its destination address to match the subnet of the network
+       * interface on which the packet is being sent. */
+      CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &walker->broadAddr);
 
-      nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
-      if (nBytesWritten != ethPktLen)
+      nBytesWritten = write(walker->capturingSkfd, ethernetFrame, ethernetFrameLen);
+      if (nBytesWritten != ethernetFrameLen)
       {
-        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));
+        BmfPError("write() error forwarding pkt on \"%s\"", walker->ifName);
       }
       else
       {
+        /* Increase counter */
+        walker->nBmfPacketsTx++;
+
         OLSR_PRINTF(
-          9,
+          8,
           "%s: --> forwarded from non-OLSR to non-OLSR \"%s\"\n",
           PLUGIN_NAME_SHORT,
-          fwIntf->ifName);
-      }
-    } /* if (isToOlsrIntf) */
-  } /* while (nextFwIntf != NULL) */
+          walker->ifName);
+      } /* if */
+    } /* if */
+  } /* for */
 }
 
 /* -------------------------------------------------------------------------
@@ -911,13 +923,11 @@ static void BmfTunPacketCaptured(
  * ------------------------------------------------------------------------- */
 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 */
@@ -930,109 +940,184 @@ static void DoBmf(void)
   {
     if (errno != EINTR)
     {
-      olsr_printf(1, "%s: select() error: %s\n", PLUGIN_NAME, strerror(errno));
+      BmfPError("select() error");
     }
     return;
   }
 
   while (nFdBitsSet > 0)
   {
+    struct TBmfInterface* walker;
+
     /* Check if a packet was received on the capturing socket (if any)
      * of each network interface */
-    struct TBmfInterface* nextIf = BmfInterfaces;
-    while (nextIf != NULL)
+    for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
     {
-      int skfd;
-
-      currIf = nextIf;
-      nextIf = currIf->next;
-
-      skfd = currIf->capturingSkfd;
+      int skfd = walker->capturingSkfd;
       if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
       {
         struct sockaddr_ll pktAddr;
         socklen_t addrLen = sizeof(pktAddr);
         int nBytes;
-        unsigned char* ethPkt;
+        unsigned char* ethernetFrame;
 
         /* A packet was captured. */
 
         nFdBitsSet--;
 
-        /* Receive the packet, leaving space for the BMF encapsulation header */
-        ethPkt = rxBuffer + ENCAP_HDR_LEN;
+        /* Receive the captured Ethernet frame, leaving space for the BMF
+         * encapsulation header */
+        ethernetFrame = GetEthernetFrame(rxBuffer);
         nBytes = recvfrom(
           skfd,
-          ethPkt,
+          ethernetFrame,
           BMF_BUFFER_SIZE - ENCAP_HDR_LEN,
           0,
           (struct sockaddr*)&pktAddr,
           &addrLen);
         if (nBytes < 0)
         {
+          BmfPError("recvfrom() error on \"%s\"", walker->ifName);
+
+          continue; /* for */
+        } /* if (nBytes < 0) */
+
+        /* Check if the number of received bytes is large enough for an Ethernet
+         * frame which contains at least a minimum-size IP header.
+         * Note: There is an apparent bug in the packet socket implementation in
+         * combination with VLAN interfaces. On a VLAN interface, the value returned
+         * by 'recvfrom' may (but need not) be 4 (bytes) larger than the value
+         * returned on a non-VLAN interface, for the same ethernet frame. */
+        if (nBytes < IP_HDR_OFFSET + (int)sizeof(struct ip))
+        {
           olsr_printf(
             1,
-            "%s: recvfrom() error on \"%s\": %s\n",
+            "%s: captured frame too short (%d bytes) on \"%s\"\n",
             PLUGIN_NAME,
-            currIf->ifName,
-            strerror(errno));
+            nBytes,
+            walker->ifName);
+
+          continue; /* for */
+        }
+
+        if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
+            pktAddr.sll_pkttype == PACKET_MULTICAST ||
+            pktAddr.sll_pkttype == PACKET_BROADCAST)
+        {
+          /* A multicast or broadcast packet was captured */
+
+          BmfPacketCaptured(walker, pktAddr.sll_pkttype, rxBuffer);
+
+        } /* if (pktAddr.sll_pkttype == ...) */
+      } /* if (skfd >= 0 && (FD_ISSET...)) */
+    } /* for */
+    
+    /* Check if a BMF encapsulation packet was received on the listening
+     * socket (if any) of each network interface */
+    for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
+    {
+      int skfd = walker->listeningSkfd;
+      if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
+      {
+        struct sockaddr_ll pktAddr;
+        socklen_t addrLen = sizeof(pktAddr);
+        int nBytes;
+        int minimumLength;
+        struct ip* ipHeader;
+        struct udphdr* udpHeader;
+        u_int16_t destPort;
+        union olsr_ip_addr forwardedBy;
+        union olsr_ip_addr forwardedTo;
+
+        /* Heard a BMF packet */
+
+        nFdBitsSet--;
+
+        nBytes = recvfrom(
+          skfd,
+          rxBuffer,
+          BMF_BUFFER_SIZE,
+          0,
+          (struct sockaddr*)&pktAddr,
+          &addrLen);
+        if (nBytes < 0)
+        {
+          BmfPError("recvfrom() error on \"%s\"", walker->ifName);
+
+          continue; /* for */
+        } /* if (nBytes < 0) */
+
+        if (pktAddr.sll_pkttype != PACKET_OTHERHOST)
+        {
+          continue; /* for */
+        } /* if (pktAddr.sll_pkttype ...) */
+
+        /* Check if the received packet is UDP - BMF port */
+        ipHeader = (struct ip*)rxBuffer;
+        if (ipHeader->ip_p != SOL_UDP)
+        {
+          /* Not UDP */
+          continue; /* for */
         }
-        else if (nBytes < IP_HDR_OFFSET + (int)sizeof(struct iphdr))
+
+        udpHeader = (struct udphdr*)(rxBuffer + GetHeaderLength(rxBuffer));
+        destPort = ntohs(udpHeader->dest);
+        if (destPort != BMF_ENCAP_PORT)
+        {
+          /* Not BMF */
+          continue; /* for */
+        }
+
+        /* Check if the number of received bytes is large enough for a minimal BMF
+         * encapsulation packet, at least:
+         * - the IP header of the encapsulation IP packet
+         * - the UDP header of the encapsulation IP packet
+         * - the encapsulation header
+         * - the Ethernet header in the encapsulated Ethernet packet
+         * - a minimum IP header inside the encapsulated packet
+         * Note: on a VLAN interface, the value returned by 'recvfrom' may (but need
+         * not) be 4 (bytes) larger than the value returned on a non-VLAN interface, for
+         * the same ethernet frame. */
+        minimumLength =
+          GetHeaderLength(rxBuffer) +
+          sizeof(struct udphdr) +
+          ENCAP_HDR_LEN +
+          IP_HDR_OFFSET +
+          sizeof(struct ip);
+        if (nBytes < minimumLength)
         {
           olsr_printf(
             1,
-            "%s: captured packet too short (%d bytes) on \"%s\"\n",
+            "%s: captured a too short encapsulation packet (%d bytes) on \"%s\"\n",
             PLUGIN_NAME,
             nBytes,
-            currIf->ifName);
+            walker->ifName);
+
+          continue; /* for */
         }
-        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);
-
-          /* Don't let BMF crash by sending too short packets */
-          if (nBytes >= IP_HDR_OFFSET + GetIpHeaderLength(ethPkt))
-          {
-            if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
-                pktAddr.sll_pkttype == PACKET_MULTICAST ||
-                pktAddr.sll_pkttype == PACKET_BROADCAST)
-            {
-              /* A multicast or broadcast packet was captured */
-              BmfPacketCaptured(currIf, pktAddr.sll_pkttype, rxBuffer, nBytes + ENCAP_HDR_LEN);
-            }
-          }
-          else
-          {
-            olsr_printf(
-              1,
-              "%s: captured packet too short (%d bytes) on \"%s\"\n",
-              PLUGIN_NAME,
-              nBytes,
-              currIf->ifName);
-          }
-        } /* if (nBytes < 0) */
+
+        COPY_IP(&forwardedBy, &ipHeader->ip_src);
+        COPY_IP(&forwardedTo, &ipHeader->ip_dst);
+        BmfEncapsulationPacketReceived(
+          walker,
+          &forwardedBy,
+          &forwardedTo,
+          rxBuffer + GetHeaderLength(rxBuffer) + sizeof(struct udphdr));
+
       } /* if (skfd >= 0 && (FD_ISSET...)) */
-    } /* while (nextIf != NULL) */
-    
+    } /* for */
+
     /* Check if a packet was received on the encapsulating socket (if any)
      * of each network interface */
-    nextIf = BmfInterfaces;
-    while (nextIf != NULL)
+    for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
     {
-      int skfd;
-
-      currIf = nextIf;
-      nextIf = currIf->next;
-
-      skfd = currIf->encapsulatingSkfd;
+      int skfd = walker->encapsulatingSkfd;
       if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
       {
         struct sockaddr_in from;
         socklen_t fromLen = sizeof(from);
         int nBytes;
+        union olsr_ip_addr forwardedBy;
 
         /* An encapsulated packet was received */
 
@@ -1047,52 +1132,52 @@ static void DoBmf(void)
           &fromLen);
         if (nBytes < 0)
         {
+          BmfPError("recvfrom() error on \"%s\"", walker->ifName);
+
+          continue; /* for */
+        } /* if (nBytes < 0) */
+
+        COPY_IP(&forwardedBy, &from.sin_addr.s_addr);
+
+        /* Check if the number of received bytes is large enough for a minimal BMF
+         * encapsulation packet, at least:
+         * - the encapsulation header
+         * - the Ethernet header in the encapsulated Ethernet packet
+         * - a minimum IP header inside the encapsulated packet */
+        if (nBytes < ENCAP_HDR_LEN + IP_HDR_OFFSET + (int)sizeof(struct ip))
+        {
           olsr_printf(
             1,
-            "%s: recvfrom() error on \"%s\": %s\n",
+            "%s: received a too short encapsulation packet (%d bytes) from %s on \"%s\"\n",
             PLUGIN_NAME,
-            currIf->ifName,
-            strerror(errno));
+            nBytes,
+            olsr_ip_to_string(&forwardedBy),
+            walker->ifName);
+
+          continue; /* for */
         }
-        else
-        {
-          /* 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) */
+
+        BmfEncapsulationPacketReceived(walker, &forwardedBy, NULL, rxBuffer);
+
       } /* if (skfd >= 0 && (FD_ISSET...)) */
-    } /* while (nextIf != NULL) */
+    } /* for */
 
     if (nFdBitsSet > 0 && FD_ISSET(EtherTunTapFd, &rxFdSet))
     {
-      /* Check if an application has sent a packet to the tuntap
+      /* Check if an application has sent a packet out via the tuntap
        * network interface */
 
       int nBytes;
-      unsigned char* ethPkt;
+      unsigned char* ethernetFrame;
       unsigned char* bufferToRead;
       size_t nBytesToRead;
 
       nFdBitsSet--;
 
       /* Receive the packet, leaving space for the BMF encapsulation header */
-      ethPkt = rxBuffer + ENCAP_HDR_LEN;
+      ethernetFrame = GetEthernetFrame(rxBuffer);
     
-      bufferToRead = ethPkt;
+      bufferToRead = ethernetFrame;
       nBytesToRead = BMF_BUFFER_SIZE - ENCAP_HDR_LEN;
       if (TunOrTap == TT_TUN)
       {
@@ -1102,8 +1187,8 @@ static void DoBmf(void)
         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. */
+        /* Compose a valid Ethernet header, for other BMF-nodes which may be
+         * 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
@@ -1111,56 +1196,31 @@ static void DoBmf(void)
          * 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);
+        memset(ethernetFrame, 0xFF, IFHWADDRLEN);
 
         /* Source MAC address is not important. Set to all-zeros */
-        memset(ethPkt + IFHWADDRLEN, 0x00, IFHWADDRLEN);
+        memset(ethernetFrame + IFHWADDRLEN, 0x00, IFHWADDRLEN);
 
         /* Ethertype = 0800 = IP */
         type = htons(0x0800);
-        memcpy(ethPkt + ETH_TYPE_OFFSET, &type, 2);
+        memcpy(ethernetFrame + ETH_TYPE_OFFSET, &type, 2);
       }
 
-      nBytes = read(
-        EtherTunTapFd,
-        bufferToRead,
-        nBytesToRead);
+      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));
-        }
-      }
-      else if (nBytes < (int)sizeof(struct iphdr))
-      {
-        olsr_printf(
-          1,
-          "%s: captured packet too short (%d bytes) on \"%s\"\n",
-          PLUGIN_NAME,
-          nBytes,
-          EtherTunTapIfName);
+        BmfPError("recvfrom() error on \"%s\"", 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);
-
-        /* Don't let BMF crash by sending too short packets */
-        if (nBytes >= IP_HDR_OFFSET + GetIpHeaderLength(ethPkt))
+        /* Check if the number of received bytes is large enough for an Ethernet
+         * frame which contains at least a minimum-size IP header */
+        if (TunOrTap == TT_TUN)
         {
-          /* An outbound packet was captured */
-          BmfTunPacketCaptured(rxBuffer, nBytes + ENCAP_HDR_LEN);
+          nBytes += IP_HDR_OFFSET;
         }
-        else
+        if (nBytes < IP_HDR_OFFSET + (int)sizeof(struct ip))
         {
           olsr_printf(
             1,
@@ -1168,11 +1228,17 @@ static void DoBmf(void)
             PLUGIN_NAME,
             nBytes,
             EtherTunTapIfName);
-        } /* if (nBytes >= IP_HDR_OFFSET... */
+        }
+        else
+        {
+          /* An outbound packet was captured */
+
+          BmfTunPacketCaptured(rxBuffer);
+
+        } /* if (nBytes < IP_HDR_OFFSET... */
       } /* if (nBytes < 0) */
     } /* if (nFdBitsSet > 0 && ... */
   } /* while (nFdBitsSet > 0) */
-  /*free(rxBuffer);*/
 }
 
 /* -------------------------------------------------------------------------
@@ -1206,7 +1272,7 @@ static void* BmfRun(void* useless __attribute__((unused)))
   sigdelset(&blockedSigs, SIGALRM);
   if (pthread_sigmask(SIG_BLOCK, &blockedSigs, NULL) != 0)
   {
-    olsr_printf(1, "%s: pthread_sigmask() error: %s\n", PLUGIN_NAME, strerror(errno));
+    BmfPError("pthread_sigmask() error");
   }
 
   /* Set up the signal handler for the process: use SIGALRM to terminate
@@ -1217,7 +1283,7 @@ static void* BmfRun(void* useless __attribute__((unused)))
    * function (see DoBmf()). */
   if (signal(SIGALRM, BmfSignalHandler) == SIG_ERR)
   {
-    olsr_printf(1, "%s: signal() error: %s\n", PLUGIN_NAME, strerror(errno));
+    BmfPError("signal() error");
   }
 
   /* Call the thread function until flagged to exit */
@@ -1292,9 +1358,23 @@ int InitBmf(struct interface* skipThisIntf)
   BmfThreadRunning = 1;
   if (pthread_create(&BmfThread, NULL, BmfRun, NULL) != 0)
   {
-    olsr_printf(1, "%s: pthread_create error: %s\n", PLUGIN_NAME, strerror(errno));
+    BmfPError("pthread_create() error");
     return 0;
   }
+
+  if (EtherTunTapFd >= 0)
+  {
+    /* Deactivate IP spoof filter for EtherTunTap interface */
+    DeactivateSpoofFilter();
+
+    /* 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)
+    {
+      AddMulticastRoute();
+    }
+  }
+
   return 1;
 }
 
@@ -1308,22 +1388,31 @@ int InitBmf(struct interface* skipThisIntf)
  * ------------------------------------------------------------------------- */
 void CloseBmf(void)
 {
+  if (EtherTunTapFd >= 0)
+  {
+    /* If there is a multicast route, try to delete it first */
+    DeleteMulticastRoute();
+
+    /* Restore IP spoof filter for EtherTunTap interface */
+    RestoreSpoofFilter();
+  }
+
   /* Signal BmfThread to exit */
-  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(...). */
+  if (pthread_kill(BmfThread, SIGALRM) != 0)
   {
-    olsr_printf(1, "%s: pthread_kill() error: %s\n", PLUGIN_NAME, strerror(errno));
+    BmfPError("pthread_kill() error");
   }
 
   /* Wait for BmfThread to acknowledge */
   if (pthread_join(BmfThread, NULL) != 0)
   {
-    olsr_printf(1, "%s: pthread_join() error: %s\n", PLUGIN_NAME, strerror(errno));
+    BmfPError("pthread_join() error");
   }
 
-  /* Time to clean up */
+  /* Clean up after the BmfThread has been killed */
   CloseBmfNetworkInterfaces();
 }
 
@@ -1366,7 +1455,12 @@ int RegisterBmfParameter(char* key, char* value)
   {
     return SetCapturePacketsOnOlsrInterfaces(value);
   }
+  else if (strcmp(key, "BmfMechanism") == 0)
+  {
+    return SetBmfMechanism(value);
+  }
 
   /* Key not recognized */
   return 0;
 }
+
index 180e185..5648eec 100644 (file)
  * 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 */
 #define PLUGIN_NAME "OLSRD Basic Multicast Forwarding (BMF) plugin"
 #define PLUGIN_NAME_SHORT "OLSRD BMF"
-#define PLUGIN_VERSION "1.3 (" __DATE__ " " __TIME__ ")"
+#define PLUGIN_VERSION "1.4 (" __DATE__ " " __TIME__ ")"
 #define PLUGIN_COPYRIGHT "  (C) Thales Communications Huizen, Netherlands"
 #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 BMF_ENCAP_PORT 50698
 
+/* Forward declaration of OLSR interface type */
 struct interface;
 
+void BmfPError(char* format, ...) __attribute__((format(printf, 1, 2)));
+union olsr_ip_addr* MainAddressOf(union olsr_ip_addr* ip);
 int InterfaceChange(struct interface* interf, int action);
 int InitBmf(struct interface* skipThisIntf);
 void CloseBmf(void);
index e2f97ae..f661e5f 100644 (file)
@@ -36,7 +36,6 @@
  *              and local broadcast packets are dropped.
  * Created    : 29 Jun 2006
  *
- * $Id: DropList.c,v 1.2 2007/02/10 17:05:55 bernd67 Exp $ 
  * ------------------------------------------------------------------------- */
 
 
@@ -44,7 +43,8 @@
 
 /* System includes */
 #include <assert.h> /* assert() */
-#include <stdio.h> /* NULL */
+#include <stddef.h> /* NULL */
+#include <stdio.h> /* sscanf */
 #include <stdlib.h> /* malloc */
 #include <string.h> /* memcmp */
 
index dc79294..1df5113 100644 (file)
@@ -38,7 +38,6 @@
  * 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
index 1b6f8f1..26c80c4 100644 (file)
  * Description: Functions to open and close sockets
  * Created    : 29 Jun 2006
  *
- * $Id: NetworkInterfaces.c,v 1.4 2007/04/20 14:06:17 bernd67 Exp $ 
  * ------------------------------------------------------------------------- */
 
 #include "NetworkInterfaces.h"
 
 /* System includes */
+#include <stddef.h> /* NULL */
 #include <syslog.h> /* syslog() */
 #include <string.h> /* strerror(), strchr(), strcmp() */
 #include <errno.h> /* errno */
 #include "olsr.h" /* olsr_printf() */
 #include "defs.h" /* olsr_cnf */
 #include "local_hna_set.h" /* add_local_hna4_entry() */
+#include "link_set.h" /* get_link_set() */
+#include "lq_route.h" /* MIN_LINK_QUALITY */
+#include "tc_set.h" /* olsr_lookup_tc_entry(), olsr_tc_lookup_dst() */
 
 /* Plugin includes */
 #include "Packet.h" /* IFHWADDRLEN */
-#include "Bmf.h" /* PLUGIN_NAME */
+#include "Bmf.h" /* PLUGIN_NAME, MainAddressOf() */
 #include "Address.h" /* IsMulticast() */
 
 /* List of network interface objects used by BMF plugin */
 struct TBmfInterface* BmfInterfaces = NULL;
+struct TBmfInterface* LastBmfInterface = NULL;
 
 /* Highest-numbered open socket file descriptor. To be used as first
  * parameter in calls to select(...). */
@@ -89,10 +93,13 @@ char EtherTunTapIfName[IFNAMSIZ] = "bmf0";
  * used, and this variable will be set to TT_TUN. */
 enum TTunOrTap TunOrTap = TT_TUN;
 
-#define ETHERTUNTAPIPNOTSET 0
+/* The underlying mechanism to forward multicast packets. Either:
+ * - BM_BROADCAST: BMF uses the IP local broadcast as destination address
+ * - BM_UNICAST_PROMISCUOUS: BMF uses the IP address of the best neighbor as
+ *   destination address. The other neighbors listen promiscuously. */
+enum TBmfMechanism BmfMechanism = BM_BROADCAST;
 
-/* 10.255.255.253 in host byte order */
-#define ETHERTUNTAPDEFAULTIP 0x0AFFFFFD
+#define ETHERTUNTAPIPNOTSET 0
 
 /* The IP address of the BMF network interface in host byte order.
  * May be overruled by setting the plugin parameter "BmfInterfaceIp". */
@@ -104,7 +111,7 @@ 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;
+u_int32_t EtherTunTapIpBroadcast = ETHERTUNTAPIPNOTSET;
 
 /* Whether or not the configuration has overruled the default IP
  * configuration of the EtherTunTap interface */
@@ -122,7 +129,7 @@ int CapturePacketsOnOlsrInterfaces = 0;
  * Input      : ifname - network interface name (e.g. "mybmf0")
  * Output     : none
  * Return     : fail (0) or success (1)
- * Data Used  : none
+ * Data Used  : EtherTunTapIfName
  * ------------------------------------------------------------------------- */
 int SetBmfInterfaceName(const char* ifname)
 {
@@ -161,10 +168,11 @@ int SetBmfInterfaceType(const char* iftype)
  * 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
+ * Input      : ip - IP address string, followed by '/' and prefix length
  * Output     : none
  * Return     : fail (0) or success (1)
- * Data Used  : none
+ * Data Used  : EtherTunTapIp, EtherTunTapIpMask, EtherTunTapIpBroadcast,
+ *              TunTapIpOverruled
  * ------------------------------------------------------------------------- */
 int SetBmfInterfaceIp(const char* ip)
 {
@@ -251,6 +259,53 @@ int SetCapturePacketsOnOlsrInterfaces(const char* enable)
   return 0;
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : SetBmfMechanism
+ * Description: Overrule the default BMF mechanism to either BM_BROADCAST or
+ *              BM_UNICAST_PROMISCUOUS.
+ * Input      : mechanism - either "Broadcast" or "UnicastPromiscuous"
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int SetBmfMechanism(const char* mechanism)
+{
+  if (strcmp(mechanism, "Broadcast") == 0)
+  {
+    BmfMechanism = BM_BROADCAST;
+    return 1;
+  }
+  else if (strcmp(mechanism, "UnicastPromiscuous") == 0)
+  {
+    BmfMechanism = BM_UNICAST_PROMISCUOUS;
+    return 1;
+  }
+
+  /* Value not recognized */
+  return 0;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : AddDescriptorToInputSet
+ * Description: Add a socket descriptor to the global set of socket file descriptors
+ * Input      : skfd - socket file descriptor
+ * Output     : none
+ * Return     : none
+ * Data Used  : HighestSkfd, InputSet
+ * Notes      : Keeps track of the highest-numbered descriptor
+ * ------------------------------------------------------------------------- */
+static void AddDescriptorToInputSet(int skfd)
+{
+  /* Keep the highest-numbered descriptor */
+  if (skfd > HighestSkfd)
+  {
+    HighestSkfd = skfd;
+  }
+
+  /* Add descriptor to input set */
+  FD_SET(skfd, &InputSet);
+}
+
 /* To save the state of the IP spoof filter for the EtherTunTap interface */
 static char EthTapSpoofState = '1';
 
@@ -258,21 +313,19 @@ static char EthTapSpoofState = '1';
  * 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")
+ * Input      : none
  * Output     : none
  * Return     : fail (0) or success (1)
- * Data Used  : EthTapSpoofState
+ * Data Used  : EtherTunTapIfName, EthTapSpoofState
  * Notes      : Saves the current filter state for later restoring
  * ------------------------------------------------------------------------- */
-static int DeactivateSpoofFilter(const char* tunTapName)
+int DeactivateSpoofFilter(void)
 {
   FILE* procSpoof;
   char procFile[FILENAME_MAX];
 
-  assert(tunTapName != NULL);
-
   /* Generate the procfile name */
-  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", tunTapName);
+  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", EtherTunTapIfName);
 
   /* Open procfile for reading */
   procSpoof = fopen(procFile, "r");
@@ -319,20 +372,18 @@ static int DeactivateSpoofFilter(const char* tunTapName)
  * 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")
+ * Input      : none
  * Output     : none
  * Return     : none
- * Data Used  : EthTapSpoofState
+ * Data Used  : EtherTunTapIfName, EthTapSpoofState
  * ------------------------------------------------------------------------- */
-static void RestoreSpoofFilter(const char* tunTapName)
+void RestoreSpoofFilter(void)
 {
   FILE* procSpoof;
   char procFile[FILENAME_MAX];
 
-  assert(tunTapName != NULL);
-
   /* Generate the procfile name */
-  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", tunTapName);
+  sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", EtherTunTapIfName);
 
   /* Open procfile for writing */
   procSpoof = fopen(procFile, "w");
@@ -349,6 +400,560 @@ static void RestoreSpoofFilter(const char* tunTapName)
   }
 }
 
+#ifndef USING_THALES_LINK_COST_ROUTING
+/* -------------------------------------------------------------------------
+ * Function   : CalcEtx
+ * Description: Calculate the Expected Transmission Count (ETX) value, based on
+ *              link loss fraction and inverse link loss fraction
+ * Input      : loss - link loss fraction
+ *              neigh_loss - inverse link loss fraction 
+ * Output     : none
+ * Return     : the ETX value
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+static float CalcEtx(float loss, float neigh_loss) 
+{
+  if (loss < MIN_LINK_QUALITY || neigh_loss < MIN_LINK_QUALITY)
+  {
+    return INFINITE_ETX;
+  }
+  else
+  {
+    return 1.0 / (loss * neigh_loss);
+  }
+}
+#endif /* USING_THALES_LINK_COST_ROUTING */
+
+/* -------------------------------------------------------------------------
+ * Function   : GetBestNeighbor
+ * Description: Get the best neighbor on an interface to send a BMF packet to
+ * Input      : intf - the network interface
+ *              source - the source IP address of the BMF packet 
+ *              forwardedBy - the IP address of the node that forwarded the BMF
+ *                packet
+ *              forwardedTo - the IP address of the node to which the BMF packet
+ *                was directed 
+ * Output     : nPossibleNeighbors - number of found possible neighbors
+ * Return     : the best neighbor, or NULL if none found
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+struct link_entry* GetBestNeighbor(
+  struct TBmfInterface* intf,
+  union olsr_ip_addr* source,
+  union olsr_ip_addr* forwardedBy,
+  union olsr_ip_addr* forwardedTo,
+  int* nPossibleNeighbors)
+{
+  /* handle the non-LQ case */
+
+  if (olsr_cnf->lq_level == 0)
+  {
+    struct link_entry* walker;
+    struct link_entry* bestLink = NULL;
+    *nPossibleNeighbors = 0;
+
+    /* TODO: get_link_set() is not thread-safe! */
+    for (walker = get_link_set(); walker != NULL; walker = walker->next) 
+    {
+      union olsr_ip_addr* neighborMainIp;
+
+      /* Consider only links from the specified interface */
+      if (! COMP_IP(&intf->intAddr, &walker->local_iface_addr))
+      {
+        continue; /* for */
+      }
+
+      OLSR_PRINTF(
+        8,
+        "%s: ----> Considering forwarding pkt on \"%s\" to %s\n",
+        PLUGIN_NAME_SHORT,
+        intf->ifName,
+        olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+      neighborMainIp = MainAddressOf(&walker->neighbor_iface_addr);
+
+      /* Consider only neighbors with an IP address that differs from the
+       * passed IP addresses (if passed). Rely on short-circuit boolean evaluation. */
+      if (source != NULL && COMP_IP(neighborMainIp, MainAddressOf(source)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is source of pkt\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Rely on short-circuit boolean evaluation */
+      if (forwardedBy != NULL && COMP_IP(neighborMainIp, MainAddressOf(forwardedBy)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is the node that forwarded the pkt\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Rely on short-circuit boolean evaluation */
+      if (forwardedTo != NULL && COMP_IP(neighborMainIp, MainAddressOf(forwardedTo)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is the node to which the pkt was forwarded\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Found a candidate neighbor to direct our packet to */
+
+      *nPossibleNeighbors += 1;
+
+      /* Remember the first found link */
+      if (bestLink == NULL)
+      {
+        bestLink = walker;
+      }
+
+    } /* for */
+
+    if (bestLink == NULL)
+    {
+      OLSR_PRINTF(
+        9,
+        "%s: ----> No suitable neighbor found to forward to on \"%s\"\n",
+        PLUGIN_NAME_SHORT,
+        intf->ifName);
+    }
+    else
+    {
+      OLSR_PRINTF(
+        9,
+        "%s: ----> Best %sneighbor to forward to on \"%s\" is %s\n",
+        PLUGIN_NAME_SHORT,
+        *nPossibleNeighbors == 1 ? "(and only) " : "",
+        intf->ifName,
+        olsr_ip_to_string(&bestLink->neighbor_iface_addr));
+    }
+
+    return bestLink;
+  }
+  /* handle the LQ case */
+  else
+  {
+#ifdef USING_THALES_LINK_COST_ROUTING
+
+    struct link_entry* walker;
+    struct link_entry* bestLink = NULL;
+    float previousLinkCost = INFINITE_COST;
+    float bestLinkCost = INFINITE_COST;
+    *nPossibleNeighbors = 0;
+
+    if (forwardedBy != NULL)
+    {
+      /* Retrieve the cost of the link from 'forwardedBy' to myself */
+      struct link_entry* bestLinkFromForwarder = get_best_link_to_neighbor(forwardedBy);
+      if (bestLinkFromForwarder != NULL)
+      {
+        previousLinkCost = bestLinkFromForwarder->link_cost;
+      }
+    }
+
+    /* TODO: get_link_set() is not thread-safe! */
+    for (walker = get_link_set(); walker != NULL; walker = walker->next) 
+    {
+      union olsr_ip_addr* neighborMainIp;
+      struct link_entry* bestLinkToNeighbor;
+      struct tc_entry* tcLastHop;
+
+      /* Consider only links from the specified interface */
+      if (! COMP_IP(&intf->intAddr, &walker->local_iface_addr))
+      {
+        continue; /* for */
+      }
+
+      OLSR_PRINTF(
+        9,
+        "%s: ----> Considering forwarding pkt on \"%s\" to %s\n",
+        PLUGIN_NAME_SHORT,
+        intf->ifName,
+        olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+      neighborMainIp = MainAddressOf(&walker->neighbor_iface_addr);
+
+      /* Consider only neighbors with an IP address that differs from the
+       * passed IP addresses (if passed). Rely on short-circuit boolean evaluation. */
+      if (source != NULL && COMP_IP(neighborMainIp, MainAddressOf(source)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is source of pkt\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Rely on short-circuit boolean evaluation */
+      if (forwardedBy != NULL && COMP_IP(neighborMainIp, MainAddressOf(forwardedBy)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is the node that forwarded the pkt\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Rely on short-circuit boolean evaluation */
+      if (forwardedTo != NULL && COMP_IP(neighborMainIp, MainAddressOf(forwardedTo)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is the node to which the pkt was forwarded\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Found a candidate neighbor to direct our packet to */
+
+      /* Compare costs to check if the candidate neighbor is best reached via 'intf' */
+      OLSR_PRINTF(
+        9,
+        "%s: ----> Forwarding pkt to %s will cost %5.2f\n",
+        PLUGIN_NAME_SHORT,
+        olsr_ip_to_string(&walker->neighbor_iface_addr),
+        walker->link_cost);
+
+      /* If the candidate neighbor is best reached via another interface, then skip 
+       * the candidate neighbor; the candidate neighbor has been / will be selected via that
+       * other interface.
+       * TODO: get_best_link_to_neighbor() is not thread-safe. */
+      bestLinkToNeighbor = get_best_link_to_neighbor(&walker->neighbor_iface_addr);
+
+      if (walker != bestLinkToNeighbor)
+      {
+        if (bestLinkToNeighbor == NULL)
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: ----> Not forwarding to %s: no link found\n",
+            PLUGIN_NAME_SHORT,
+            olsr_ip_to_string(&walker->neighbor_iface_addr));
+        }
+        else
+        {
+          struct interface* bestIntf = if_ifwithaddr(&bestLinkToNeighbor->local_iface_addr);
+
+          OLSR_PRINTF(
+            9,
+            "%s: ----> Not forwarding to %s: \"%s\" gives a better link to this neighbor, costing %5.2f\n",
+            PLUGIN_NAME_SHORT,
+            olsr_ip_to_string(&walker->neighbor_iface_addr),
+            bestIntf->int_name,
+            bestLinkToNeighbor->link_cost);
+        }
+
+        continue; /* for */
+      }
+
+      if (forwardedBy != NULL)
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> 2-hop path from %s via me to %s will cost %5.2f\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(forwardedBy),
+          olsr_ip_to_string(&walker->neighbor_iface_addr),
+          previousLinkCost + walker->link_cost);
+      }
+
+      /* Check the topology table whether the 'forwardedBy' node is itself a direct
+       * neighbor of the candidate neighbor, at a lower cost than the 2-hop route
+       * via myself. If so, we do not need to forward the BMF packet to the candidate
+       * neighbor, because the 'forwardedBy' node will forward the packet. */
+      if (forwardedBy != NULL)
+      {
+        /* TODO: olsr_lookup_tc_entry() is not thread-safe. */
+        tcLastHop = olsr_lookup_tc_entry(MainAddressOf(forwardedBy));
+        if (tcLastHop != NULL)
+        {
+          struct topo_dst* tcDest;
+
+          /* TODO: olsr_tc_lookup_dst() is not thread-safe. */
+          tcDest = olsr_tc_lookup_dst(tcLastHop, MainAddressOf(&walker->neighbor_iface_addr));
+
+          /* Rely on short-circuit boolean evaluation */
+          if (tcDest != NULL && previousLinkCost + walker->link_cost > tcDest->link_cost)
+          {
+            OLSR_PRINTF(
+              9,
+              "%s: ----> Not forwarding to %s: I am not an MPR between %s and %s, direct link costs %5.2f\n",
+              PLUGIN_NAME_SHORT,
+              olsr_ip_to_string(&walker->neighbor_iface_addr),
+              olsr_ip_to_string(forwardedBy),
+              olsr_ip_to_string(&walker->neighbor_iface_addr),
+              tcDest->link_cost);
+
+            continue; /* for */
+          } /* if */
+        } /* if */
+      } /* if */
+
+      *nPossibleNeighbors += 1;
+
+      /* Remember the best link. If all are very bad, remember none. */
+      if (walker->link_cost < bestLinkCost)
+      {
+        bestLink = walker;
+        bestLinkCost = walker->link_cost;
+           }
+    } /* for */
+
+    if (bestLink == NULL)
+    {
+      OLSR_PRINTF(
+        9,
+        "%s: ----> No suitable neighbor found to forward to on \"%s\"\n",
+        PLUGIN_NAME_SHORT,
+        intf->ifName);
+    }
+    else
+    {
+      OLSR_PRINTF(
+        9,
+        "%s: ----> Best %sneighbor to forward to on \"%s\" is %s\n",
+        PLUGIN_NAME_SHORT,
+        *nPossibleNeighbors == 1 ? "(and only) " : "",
+        intf->ifName,
+        olsr_ip_to_string(&bestLink->neighbor_iface_addr));
+    }
+
+    return bestLink;
+
+#else /* USING_THALES_LINK_COST_ROUTING */
+        
+    struct link_entry* walker;
+    struct link_entry* bestLink = NULL;
+    float previousLinkEtx = INFINITE_ETX;
+    float bestEtx = INFINITE_ETX; 
+    *nPossibleNeighbors = 0;
+
+    if (forwardedBy != NULL)
+    {
+      /* Retrieve the cost of the link from 'forwardedBy' to myself */
+      struct link_entry* bestLinkFromForwarder = get_best_link_to_neighbor(forwardedBy);
+      if (bestLinkFromForwarder != NULL)
+      {
+        previousLinkEtx =
+          CalcEtx(
+            bestLinkFromForwarder->loss_link_quality,
+            bestLinkFromForwarder->neigh_link_quality);
+      }
+    }
+
+    /* TODO: get_link_set() is not thread-safe! */
+    for (walker = get_link_set(); walker != NULL; walker = walker->next) 
+    {
+      union olsr_ip_addr* neighborMainIp;
+      struct link_entry* bestLinkToNeighbor;
+      struct tc_entry* tcLastHop;
+      float currEtx;
+      /* Consider only links from the specified interface */
+      if (! COMP_IP(&intf->intAddr, &walker->local_iface_addr))
+      {
+        continue; /* for */
+      }
+
+      OLSR_PRINTF(
+        9,
+        "%s: ----> Considering forwarding pkt on \"%s\" to %s\n",
+        PLUGIN_NAME_SHORT,
+        intf->ifName,
+        olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+      neighborMainIp = MainAddressOf(&walker->neighbor_iface_addr);
+
+      /* Consider only neighbors with an IP address that differs from the
+       * passed IP addresses (if passed). Rely on short-circuit boolean evaluation. */
+      if (source != NULL && COMP_IP(neighborMainIp, MainAddressOf(source)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is source of pkt\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Rely on short-circuit boolean evaluation */
+      if (forwardedBy != NULL && COMP_IP(neighborMainIp, MainAddressOf(forwardedBy)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is the node that forwarded the pkt\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Rely on short-circuit boolean evaluation */
+      if (forwardedTo != NULL && COMP_IP(neighborMainIp, MainAddressOf(forwardedTo)))
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> Not forwarding to %s: is the node to which the pkt was forwarded\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(&walker->neighbor_iface_addr));
+
+        continue; /* for */
+      }
+
+      /* Found a candidate neighbor to direct our packet to */
+
+      /* Calculate the link quality (ETX) of the link to the found neighbor */
+      currEtx = CalcEtx(
+        walker->loss_link_quality,
+        walker->neigh_link_quality);
+      /* Compare costs to check if the candidate neighbor is best reached via 'intf' */
+      OLSR_PRINTF(
+        9,
+        "%s: ----> Forwarding pkt to %s will cost ETX %5.2f\n",
+        PLUGIN_NAME_SHORT,
+        olsr_ip_to_string(&walker->neighbor_iface_addr),
+        currEtx);
+
+      /* If the candidate neighbor is best reached via another interface, then skip 
+       * the candidate neighbor; the candidate neighbor has been / will be selected via that
+       * other interface.
+       * TODO: get_best_link_to_neighbor() is not thread-safe. */
+      bestLinkToNeighbor = get_best_link_to_neighbor(&walker->neighbor_iface_addr);
+
+      if (walker != bestLinkToNeighbor)
+      {
+        if (bestLinkToNeighbor == NULL)
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: ----> Not forwarding to %s: no link found\n",
+            PLUGIN_NAME_SHORT,
+            olsr_ip_to_string(&walker->neighbor_iface_addr));
+        }
+        else
+        {
+          struct interface* bestIntf = if_ifwithaddr(&bestLinkToNeighbor->local_iface_addr);
+
+          OLSR_PRINTF(
+            9,
+            "%s: ----> Not forwarding to %s: \"%s\" gives a better link to this neighbor, costing %5.2f\n",
+            PLUGIN_NAME_SHORT,
+            olsr_ip_to_string(&walker->neighbor_iface_addr),
+            bestIntf->int_name,
+            CalcEtx(
+              bestLinkToNeighbor->loss_link_quality,
+              bestLinkToNeighbor->neigh_link_quality));
+        }
+
+        continue; /* for */
+      }
+
+      if (forwardedBy != NULL)
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: ----> 2-hop path from %s via me to %s will cost ETX %5.2f\n",
+          PLUGIN_NAME_SHORT,
+          olsr_ip_to_string(forwardedBy),
+          olsr_ip_to_string(&walker->neighbor_iface_addr),
+          previousLinkEtx + currEtx);
+      }
+
+      /* Check the topology table whether the 'forwardedBy' node is itself a direct
+       * neighbor of the candidate neighbor, at a lower cost than the 2-hop route
+       * via myself. If so, we do not need to forward the BMF packet to the candidate
+       * neighbor, because the 'forwardedBy' node will forward the packet. */
+      if (forwardedBy != NULL)
+      {
+        /* TODO: olsr_lookup_tc_entry() is not thread-safe. */
+        tcLastHop = olsr_lookup_tc_entry(MainAddressOf(forwardedBy));
+        if (tcLastHop != NULL)
+        {
+          struct topo_dst* tcDest;
+
+          /* TODO: olsr_tc_lookup_dst() is not thread-safe. */
+          tcDest = olsr_tc_lookup_dst(tcLastHop, MainAddressOf(&walker->neighbor_iface_addr));
+
+          if (tcDest != NULL)
+          {
+            float tcEtx = CalcEtx(
+              tcDest->link_quality,
+              tcDest->inverse_link_quality);
+
+            if (previousLinkEtx + currEtx > tcEtx)
+            {
+              OLSR_PRINTF(
+                9,
+                "%s: ----> Not forwarding to %s: I am not an MPR between %s and %s, direct link costs %5.2f\n",
+                PLUGIN_NAME_SHORT,
+                olsr_ip_to_string(&walker->neighbor_iface_addr),
+                olsr_ip_to_string(forwardedBy),
+                olsr_ip_to_string(&walker->neighbor_iface_addr),
+                tcEtx);
+
+              continue; /* for */
+            } /* if */
+          } /* if */
+        } /* if */
+      } /* if */
+
+      *nPossibleNeighbors += 1;
+
+      /* Remember the best link. If all are very bad, remember none. */
+      if (currEtx < bestEtx)
+      {
+        bestLink = walker;
+        bestEtx = currEtx;
+      }
+
+    } /* for */
+
+    if (bestLink == NULL)
+    {
+      OLSR_PRINTF(
+        9,
+        "%s: ----> No suitable neighbor found to forward to on \"%s\"\n",
+        PLUGIN_NAME_SHORT,
+        intf->ifName);
+    }
+    else
+    {
+      OLSR_PRINTF(
+        9,
+        "%s: ----> Best %sneighbor to forward to on \"%s\" is %s\n",
+        PLUGIN_NAME_SHORT,
+        *nPossibleNeighbors == 1 ? "(and only) " : "",
+        intf->ifName,
+        olsr_ip_to_string(&bestLink->neighbor_iface_addr));
+    }
+
+    return bestLink;
+
+#endif /* USING_THALES_LINK_COST_ROUTING */
+
+  } /* if */
+} /* GetBestNeighbor */
+
 /* -------------------------------------------------------------------------
  * Function   : CreateCaptureSocket
  * Description: Create socket for promiscuously capturing multicast IP traffic
@@ -370,7 +975,7 @@ static int CreateCaptureSocket(const char* ifName)
   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));
+    BmfPError("socket(PF_PACKET) error");
     return -1;
   }
 
@@ -380,7 +985,7 @@ static int CreateCaptureSocket(const char* ifName)
   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));
+    BmfPError("setsockopt(PACKET_MR_PROMISC) error");
     close(skfd);
     return -1;
   }
@@ -391,22 +996,22 @@ static int CreateCaptureSocket(const char* ifName)
   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));
+    BmfPError("error retrieving MAC address");
     close(skfd);
     return -1;
   }
    
   /* Bind the socket to the specified interface */
   memset(&bindTo, 0, sizeof(bindTo));
+  bindTo.sll_family = AF_PACKET;
   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));
+    BmfPError("bind() error");
     close(skfd);
     return -1;
   }
@@ -414,19 +1019,88 @@ static int CreateCaptureSocket(const char* ifName)
   /* 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));
+    BmfPError("fcntl() error");
     close(skfd);
     return -1;
   }
 
-  /* Keep the highest-numbered descriptor */
-  if (skfd > HighestSkfd)
+  AddDescriptorToInputSet(skfd);
+
+  return skfd;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : CreateListeningSocket
+ * Description: Create socket for promiscuously listening to BMF packets.
+ *              Used when 'BmfMechanism' is BM_UNICAST_PROMISCUOUS
+ * 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) packet socket, bound to the specified
+ *              network interface
+ * ------------------------------------------------------------------------- */
+static int CreateListeningSocket(const char* ifName)
+{
+  int ifIndex = if_nametoindex(ifName);
+  struct packet_mreq mreq;
+  struct ifreq req;
+  struct sockaddr_ll bindTo;
+
+  /* Open UDP packet socket */
+  int skfd = socket(PF_PACKET, SOCK_DGRAM, 0);
+  if (skfd < 0)
   {
-    HighestSkfd = skfd;
+    BmfPError("socket(PF_PACKET) error");
+    return -1;
   }
 
-  /* Add descriptor to input set */
-  FD_SET(skfd, &InputSet);
+  /* 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)
+  {
+    BmfPError("setsockopt(PACKET_MR_PROMISC) error");
+    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)
+  {
+    BmfPError("error retrieving MAC address");
+    close(skfd);
+    return -1;
+  }
+   
+  /* Bind the socket to the specified interface */
+  memset(&bindTo, 0, sizeof(bindTo));
+  bindTo.sll_family = AF_PACKET;
+  bindTo.sll_protocol = htons(ETH_P_ALL);
+  bindTo.sll_ifindex = ifIndex;
+  memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
+  bindTo.sll_halen = IFHWADDRLEN;
+    
+  if (bind(skfd, (struct sockaddr*)&bindTo, sizeof(bindTo)) < 0)
+  {
+    BmfPError("bind() error");
+    close(skfd);
+    return -1;
+  }
+
+  /* Set socket to blocking operation */
+  if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
+  {
+    BmfPError("fcntl() error");
+    close(skfd);
+    return -1;
+  }
+
+  AddDescriptorToInputSet(skfd);
 
   return skfd;
 }
@@ -451,14 +1125,14 @@ static int CreateEncapsulateSocket(const char* ifName)
   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));
+    BmfPError("socket(PF_INET) error");
     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));
+    BmfPError("setsockopt(SO_BROADCAST) error");
     close(skfd);
     return -1;
   }
@@ -467,12 +1141,12 @@ static int CreateEncapsulateSocket(const char* 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));
+    BmfPError("setsockopt(SO_BINDTODEVICE) error");
     close(skfd);
     return -1;
   }
 
-  /* Bind to port */
+  /* Bind to BMF port */
   memset(&bindTo, 0, sizeof(bindTo));
   bindTo.sin_family = AF_INET;
   bindTo.sin_port = htons(BMF_ENCAP_PORT);
@@ -480,7 +1154,7 @@ static int CreateEncapsulateSocket(const char* ifName)
       
   if (bind(skfd, (struct sockaddr*)&bindTo, sizeof(bindTo)) < 0) 
   {
-    olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
+    BmfPError("bind() error");
     close(skfd);
     return -1;
   }
@@ -488,19 +1162,12 @@ static int CreateEncapsulateSocket(const char* ifName)
   /* 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));
+    BmfPError("fcntl() error");
     close(skfd);
     return -1;
   }
 
-  /* Keep the highest-numbered descriptor */
-  if (skfd > HighestSkfd)
-  {
-    HighestSkfd = skfd;
-  }
-
-  /* Add descriptor to input set */
-  FD_SET(skfd, &InputSet);
+  AddDescriptorToInputSet(skfd);
 
   return skfd;
 }
@@ -525,13 +1192,13 @@ static int CreateLocalEtherTunTap(void)
   static char* deviceName = "/dev/net/tun";
   struct ifreq ifreq;
   int etfd;
-  int ioctl_s;
+  int ioctlSkfd;
   int ioctlres;
 
   etfd = open(deviceName, O_RDWR | O_NONBLOCK);
   if (etfd < 0)
   {
-    olsr_printf(1, "%s: error opening %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
+    BmfPError("error opening %s", deviceName);
     return -1;
   }
 
@@ -553,7 +1220,7 @@ static int CreateLocalEtherTunTap(void)
 
   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0)
   {
-    olsr_printf(1, "%s: ioctl(TUNSETIFF) error on %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
+    BmfPError("ioctl(TUNSETIFF) error on %s", deviceName);
     close(etfd);
     return -1;
   }
@@ -563,10 +1230,10 @@ static int CreateLocalEtherTunTap(void)
   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
   ifreq.ifr_addr.sa_family = AF_INET;
 
-  ioctl_s = socket(PF_INET, SOCK_DGRAM, 0);
-  if (ioctl_s < 0)
+  ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
+  if (ioctlSkfd < 0)
   {
-    olsr_printf(1, "%s: socket(PF_INET) error on %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
+    BmfPError("socket(PF_INET) error on %s", deviceName);
     close(etfd);
     return -1;
   }
@@ -585,7 +1252,7 @@ static int CreateLocalEtherTunTap(void)
 
       if (bmfIf->olsrIntf != NULL)
       {
-        EtherTunTapIp = ntohl(((struct sockaddr_in*)&bmfIf->intAddr)->sin_addr.s_addr);
+        EtherTunTapIp = ntohl(bmfIf->intAddr.v4);
         EtherTunTapIpBroadcast = EtherTunTapIp;
       }
     }
@@ -599,25 +1266,25 @@ static int CreateLocalEtherTunTap(void)
   }
 
   ((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr.s_addr = htonl(EtherTunTapIp);
-  ioctlres = ioctl(ioctl_s, SIOCSIFADDR, &ifreq);
+  ioctlres = ioctl(ioctlSkfd, 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);
+    ioctlres = ioctl(ioctlSkfd, 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);
+      ioctlres = ioctl(ioctlSkfd, SIOCSIFBRDADDR, &ifreq);
       if (ioctlres >= 0)
       {
         /* Bring EtherTunTap interface up (if not already) */
-        ioctlres = ioctl(ioctl_s, SIOCGIFFLAGS, &ifreq);
+        ioctlres = ioctl(ioctlSkfd, SIOCGIFFLAGS, &ifreq);
         if (ioctlres >= 0)
         {
           ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING | IFF_BROADCAST);
-          ioctlres = ioctl(ioctl_s, SIOCSIFFLAGS, &ifreq);
+          ioctlres = ioctl(ioctlSkfd, SIOCSIFFLAGS, &ifreq);
         }
       }
     }
@@ -626,15 +1293,10 @@ static int CreateLocalEtherTunTap(void)
   if (ioctlres < 0)
   {
     /* Any of the above ioctl() calls failed */
-    olsr_printf(
-      1,
-      "%s: error bringing up EtherTunTap interface \"%s\": %s\n",
-      PLUGIN_NAME,
-      EtherTunTapIfName,
-      strerror(errno));
+    BmfPError("error bringing up EtherTunTap interface \"%s\"", EtherTunTapIfName);
 
     close(etfd);
-    close(ioctl_s);
+    close(ioctlSkfd);
     return -1;
   } /* if (ioctlres < 0) */
 
@@ -643,21 +1305,17 @@ static int CreateLocalEtherTunTap(void)
   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
 
-  ioctlres = ioctl(ioctl_s, SIOCGIFFLAGS, &ifreq);
+  ioctlres = ioctl(ioctlSkfd, SIOCGIFFLAGS, &ifreq);
   if (ioctlres >= 0)
   {
     ifreq.ifr_flags |= IFF_MULTICAST;
-    ioctlres = ioctl(ioctl_s, SIOCSIFFLAGS, &ifreq);
+    ioctlres = ioctl(ioctlSkfd, SIOCSIFFLAGS, &ifreq);
   }
   if (ioctlres < 0)
   {
     /* Any of the two above ioctl() calls failed */
-    olsr_printf(
-      1,
-      "%s: error setting multicast flag on EtherTunTap interface \"%s\": %s\n",
-      PLUGIN_NAME,
-      EtherTunTapIfName,
-      strerror(errno));
+    BmfPError("error setting multicast flag on EtherTunTap interface \"%s\"", EtherTunTapIfName);
+
     /* Continue anyway */
   }
 
@@ -666,32 +1324,18 @@ static int CreateLocalEtherTunTap(void)
    * 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));
+    BmfPError("error making EtherTunTap interface \"%s\" persistent", EtherTunTapIfName);
+
     /* 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;
-  }
+  OLSR_PRINTF(8, "%s: opened 1 socket on \"%s\"\n", PLUGIN_NAME_SHORT, EtherTunTapIfName);
 
-  /* Add descriptor to input set */
-  FD_SET(etfd, &InputSet);
+  AddDescriptorToInputSet(etfd);
 
   /* 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 */
+   * on the OLSR network via HNA */
   if (TunTapIpOverruled != 0)
   {
     union olsr_ip_addr temp_net;
@@ -702,67 +1346,11 @@ static int CreateLocalEtherTunTap(void)
     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);
+  close(ioctlSkfd);
 
   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;
-
-  assert(mac != NULL);
-
-  for (i = 0; i < IFHWADDRLEN; i++)
-  {
-    if (mac[i] != 0) return 0;
-  }
-  return 1;
-}
-#endif
-
 /* -------------------------------------------------------------------------
  * Function   : CreateInterface
  * Description: Create a new TBmfInterface object and adds it to the global
@@ -772,7 +1360,7 @@ static int IsNullMacAddress(char* mac)
  *                NULL if the network interface is not OLSR-enabled
  * Output     : none
  * Return     : the number of opened sockets
- * Data Used  : none
+ * Data Used  : BmfInterfaces, LastBmfInterface
  * ------------------------------------------------------------------------- */
 static int CreateInterface(
   const char* ifName,
@@ -780,6 +1368,7 @@ static int CreateInterface(
 {
   int capturingSkfd = -1;
   int encapsulatingSkfd = -1;
+  int listeningSkfd = -1;
   int ioctlSkfd;
   struct ifreq ifr;
   int nOpened = 0;
@@ -794,7 +1383,7 @@ static int CreateInterface(
 
   if (olsrIntf != NULL)
   {
-    /* On OLSR interfaces, create socket for encapsulating and forwarding 
+    /* On OLSR-enabled interfaces, create socket for encapsulating and forwarding 
      * multicast packets */
     encapsulatingSkfd = CreateEncapsulateSocket(ifName);
     if (encapsulatingSkfd < 0)
@@ -820,6 +1409,22 @@ static int CreateInterface(
     nOpened++;
   }
 
+  /* Create promiscuous mode listening interface if BMF uses IP unicast
+   * as underlying forwarding mechanism */
+  if (BmfMechanism == BM_UNICAST_PROMISCUOUS)
+  {
+    listeningSkfd = CreateListeningSocket(ifName);
+    if (listeningSkfd < 0)
+    {
+      close(listeningSkfd);
+      close(encapsulatingSkfd); /* no problem if 'encapsulatingSkfd' is -1 */
+      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;
@@ -830,43 +1435,27 @@ static int CreateInterface(
   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))
-  {
+    BmfPError("ioctl(SIOCGIFHWADDR) error for interface \"%s\"", ifName);
     close(capturingSkfd);
     close(encapsulatingSkfd);
     free(newIf);
     return 0;
   }
-  */
 
   /* Copy data into TBmfInterface object */
   newIf->capturingSkfd = capturingSkfd;
   newIf->encapsulatingSkfd = encapsulatingSkfd;
+  newIf->listeningSkfd = listeningSkfd;
   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;
+     * address from the OLSR interface object. Downcast to correct sockaddr
+     * subtype. */
+    COPY_IP(&newIf->intAddr, &((struct sockaddr_in *)&olsrIntf->int_addr)->sin_addr.s_addr);
+    COPY_IP(&newIf->broadAddr, &((struct sockaddr_in *)&olsrIntf->int_broadaddr)->sin_addr.s_addr);
   }
   else
   {
@@ -876,18 +1465,14 @@ static int CreateInterface(
     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");
+      BmfPError("ioctl(SIOCGIFADDR) error for interface \"%s\"", ifName);
+
+      newIf->intAddr.v4 = inet_addr("0.0.0.0");
          }
          else
          {
-      newIf->intAddr = ifr.ifr_addr;
+      /* Downcast to correct sockaddr subtype */
+      COPY_IP(&newIf->intAddr, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
     }
 
     /* For a non-OLSR interface, retrieve the IP broadcast address ourselves */
@@ -896,18 +1481,14 @@ static int CreateInterface(
     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");
+      BmfPError("ioctl(SIOCGIFBRDADDR) error for interface \"%s\"", ifName);
+
+      newIf->broadAddr.v4 = inet_addr("0.0.0.0");
          }
          else
          {
-      newIf->broadAddr = ifr.ifr_broadaddr;
+      /* Downcast to correct sockaddr subtype */
+      COPY_IP(&newIf->broadAddr, &((struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr.s_addr);
     }
   }
 
@@ -915,12 +1496,35 @@ static int CreateInterface(
   memset(&newIf->fragmentHistory, 0, sizeof(newIf->fragmentHistory));
   newIf->nextFragmentHistoryEntry = 0;
 
-  /* Add new TBmfInterface object to global list */
-  newIf->next = BmfInterfaces;
-  BmfInterfaces = newIf;
+  /* Reset counters */
+  newIf->nBmfPacketsRx = 0;
+  newIf->nBmfPacketsRxDup = 0;
+  newIf->nBmfPacketsTx = 0;
+
+  /* Add new TBmfInterface object to global list. OLSR interfaces are
+   * added at the front of the list, non-OLSR interfaces at the back. */
+  if (BmfInterfaces == NULL)
+  {
+    /* First TBmfInterface object in list */
+    BmfInterfaces = newIf;
+    LastBmfInterface = newIf;
+  }
+  else if (olsrIntf != NULL)
+  {
+    /* Add new TBmfInterface object at front of list */
+    newIf->next = BmfInterfaces;
+    BmfInterfaces = newIf;
+  }
+  else
+  {
+    /* Add new TBmfInterface object at back of list */
+    newIf->next = NULL;
+    LastBmfInterface->next= newIf;
+    LastBmfInterface = newIf;
+  }
 
   OLSR_PRINTF(
-    9,
+    8,
     "%s: opened %d socket%s on %s interface \"%s\"\n",
     PLUGIN_NAME_SHORT,
     nOpened,
@@ -955,11 +1559,7 @@ int CreateBmfNetworkInterfaces(struct interface* skipThisIntf)
   skfd = socket(PF_INET, SOCK_DGRAM, 0);
   if (skfd < 0)
   {
-    olsr_printf(
-      1,
-      "%s: no inet socket available to retrieve interface list: %s\n",
-      PLUGIN_NAME,
-      strerror(errno));
+    BmfPError("no inet socket available to retrieve interface list");
     return -1;
   }
 
@@ -972,7 +1572,7 @@ int CreateBmfNetworkInterfaces(struct interface* skipThisIntf)
 
     if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
     {
-      olsr_printf(1, "%s: ioctl(SIOCGIFCONF) error: %s\n", PLUGIN_NAME, strerror(errno));
+      BmfPError("ioctl(SIOCGIFCONF) error");
 
       close(skfd);
       free(ifc.ifc_buf);
@@ -995,9 +1595,15 @@ int CreateBmfNetworkInterfaces(struct interface* skipThisIntf)
   for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++)
   {
     struct interface* olsrIntf;
+    union olsr_ip_addr ipAddr;
+
+    /* Skip the BMF network interface itself */
+    if (strncmp(ifr->ifr_name, EtherTunTapIfName, IFNAMSIZ) == 0)
+    {
+      continue; /* for (n = ...) */
+    }
 
     /* ...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);
 
@@ -1073,14 +1679,19 @@ void AddInterface(struct interface* newIntf)
  *              Also restores the network state to the situation before BMF
  *              was started.
  * ------------------------------------------------------------------------- */
-
 void CloseBmfNetworkInterfaces(void)
 {
   int nClosed = 0;
-  
+  u_int32_t totalOlsrBmfPacketsRx = 0;
+  u_int32_t totalOlsrBmfPacketsRxDup = 0;
+  u_int32_t totalOlsrBmfPacketsTx = 0;
+  u_int32_t totalNonOlsrBmfPacketsRx = 0;
+  u_int32_t totalNonOlsrBmfPacketsRxDup = 0;
+  u_int32_t totalNonOlsrBmfPacketsTx = 0;
+
   /* Close all opened sockets */
   struct TBmfInterface* nextBmfIf = BmfInterfaces;
-  while (nextBmfIf != NULL)
+  while (nextBmfIf != NULL) 
   {
     struct TBmfInterface* bmfIf = nextBmfIf;
     nextBmfIf = bmfIf->next;
@@ -1097,61 +1708,65 @@ void CloseBmfNetworkInterfaces(void)
     }
 
     OLSR_PRINTF(
-      9,
+      7,
+      "%s: %s interface \"%s\": RX pkts %d (%d dups); TX pkts %d\n", 
+      PLUGIN_NAME_SHORT,
+      bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR",
+      bmfIf->ifName,
+      bmfIf->nBmfPacketsRx,
+      bmfIf->nBmfPacketsRxDup,
+      bmfIf->nBmfPacketsTx);
+
+    olsr_printf(
+      1,
       "%s: closed %s interface \"%s\"\n", 
       PLUGIN_NAME_SHORT,
       bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR",
       bmfIf->ifName);
 
+    /* Add totals */
+    if (bmfIf->olsrIntf != NULL)
+    {
+      totalOlsrBmfPacketsRx += bmfIf->nBmfPacketsRx;
+      totalOlsrBmfPacketsRxDup += bmfIf->nBmfPacketsRxDup;
+      totalOlsrBmfPacketsTx += bmfIf->nBmfPacketsTx;
+    }
+    else
+    {
+      totalNonOlsrBmfPacketsRx += bmfIf->nBmfPacketsRx;
+      totalNonOlsrBmfPacketsRxDup += bmfIf->nBmfPacketsRxDup;
+      totalNonOlsrBmfPacketsTx += bmfIf->nBmfPacketsTx;
+    }
+
     free(bmfIf);
-  }
+  } /* while */
   
   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);
+    OLSR_PRINTF(7, "%s: closed \"%s\"\n", PLUGIN_NAME_SHORT, EtherTunTapIfName);
   }
 
   BmfInterfaces = NULL;
 
-  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);
+  olsr_printf(1, "%s: closed %d sockets\n", PLUGIN_NAME_SHORT, nClosed);
 
-    kernel_route.rt_metric = 0;
-    kernel_route.rt_flags = RTF_UP;
-
-    kernel_route.rt_dev = EtherTunTapIfName;
-
-    if (ioctl(olsr_cnf->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 */
-    }
-  }
+  OLSR_PRINTF(
+    7,
+    "%s: Total all OLSR interfaces    : RX pkts %d (%d dups); TX pkts %d\n",
+    PLUGIN_NAME_SHORT,
+    totalOlsrBmfPacketsRx,
+    totalOlsrBmfPacketsRxDup,
+    totalOlsrBmfPacketsTx);
+  OLSR_PRINTF(
+    7,
+    "%s: Total all non-OLSR interfaces: RX pkts %d (%d dups); TX pkts %d\n",
+    PLUGIN_NAME_SHORT,
+    totalNonOlsrBmfPacketsRx,
+    totalNonOlsrBmfPacketsRxDup,
+    totalNonOlsrBmfPacketsTx);
 }
 
 #define MAX_NON_OLSR_IFS 32
@@ -1165,7 +1780,7 @@ static int nNonOlsrIfs = 0;
  * Input      : ifName - network interface (e.g. "eth0")
  * Output     : none
  * Return     : fail (0) or success (1)
- * Data Used  : none
+ * Data Used  : NonOlsrIfNames
  * ------------------------------------------------------------------------- */
 int AddNonOlsrBmfIf(const char* ifName)
 {
@@ -1193,7 +1808,7 @@ int AddNonOlsrBmfIf(const char* ifName)
  * Input      : ifName - network interface (e.g. "eth0")
  * Output     : none
  * Return     : true (1) or false (0)
- * Data Used  : none
+ * Data Used  : NonOlsrIfNames
  * ------------------------------------------------------------------------- */
 int IsNonOlsrBmfIf(const char* ifName)
 {
@@ -1212,36 +1827,32 @@ int IsNonOlsrBmfIf(const char* ifName)
  * 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
+ *              a local broadcast packet. In that case, set the destination
+ *              address of the IP packet to the passed broadcast address.
+ * Input      : ipPacket - the 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)
+void CheckAndUpdateLocalBroadcast(unsigned char* ipPacket, union olsr_ip_addr* broadAddr)
 {
   struct iphdr* iph;
   union olsr_ip_addr destIp;
 
-  assert(buffer != NULL && broadAddr != NULL);
+  assert(ipPacket != NULL && broadAddr != NULL);
 
-  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  iph = (struct iphdr*) ipPacket;
   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;
+    COPY_IP(&iph->daddr, broadAddr);
     newDaddr = ntohl(iph->daddr);
 
     /* Re-calculate IP header checksum for new destination */
@@ -1259,8 +1870,8 @@ void CheckAndUpdateLocalBroadcast(unsigned char* buffer, struct sockaddr* broadA
     {
       /* Re-calculate UDP/IP checksum for new destination */
 
-      int ipHeaderLen = GetIpHeaderLength(buffer);
-      struct udphdr* udph = (struct udphdr*) (buffer + IP_HDR_OFFSET + ipHeaderLen);
+      int ipHeaderLen = GetHeaderLength(ipPacket);
+      struct udphdr* udph = (struct udphdr*) (ipPacket + ipHeaderLen);
 
       /* RFC 1624, Eq. 3: HC' = ~(~HC - m + m') */
 
@@ -1277,3 +1888,91 @@ void CheckAndUpdateLocalBroadcast(unsigned char* buffer, struct sockaddr* broadA
   }
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : AddMulticastRoute
+ * Description: Insert a route to all multicast addresses in the kernel
+ *              routing table. The route will be via the BMF network interface.
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+void AddMulticastRoute(void)
+{
+  struct rtentry kernel_route;
+  int ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
+  if (ioctlSkfd < 0)
+  {
+    BmfPError("socket(PF_INET) error");
+    return;
+  }
+
+  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(ioctlSkfd, SIOCADDRT, &kernel_route) < 0)
+  {
+    BmfPError("error setting multicast route via EtherTunTap interface \"%s\"", EtherTunTapIfName);
+
+    /* Continue anyway */
+  }
+  close(ioctlSkfd);
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : DeleteMulticastRoute
+ * Description: Delete the route to all multicast addresses from the kernel
+ *              routing table
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+void DeleteMulticastRoute(void)
+{
+  if (EtherTunTapIp != ETHERTUNTAPDEFAULTIP)
+  {
+    struct rtentry kernel_route;
+    int ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
+    if (ioctlSkfd < 0)
+    {
+      BmfPError("socket(PF_INET) error");
+      return;
+    }
+
+    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(ioctlSkfd, SIOCDELRT, &kernel_route) < 0)
+    {
+      BmfPError("error deleting multicast route via EtherTunTap interface \"%s\"", EtherTunTapIfName);
+
+      /* Continue anyway */
+    }
+    close(ioctlSkfd);
+  }
+}
index 0e4f9c2..4cb9ef3 100644 (file)
  * 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 */
 
+/* OLSR includes */
+#include "olsr_types.h" /* olsr_ip_addr */
+
 /* Plugin includes */
 #include "Packet.h" /* IFHWADDRLEN */
 
@@ -59,6 +61,10 @@ struct TBmfInterface
    * Only used for OLSR-enabled interfaces; set to -1 if interface is not OLSR-enabled. */
   int encapsulatingSkfd;
 
+  /* File descriptor of UDP packet socket, used for listening to encapsulation packets.
+   * Used only when PlParam "BmfMechanism" is set to "UnicastPromiscuous". */
+  int listeningSkfd;
+
   unsigned char macAddr[IFHWADDRLEN];
 
   char ifName[IFNAMSIZ];
@@ -68,10 +74,10 @@ struct TBmfInterface
   struct interface* olsrIntf;
 
   /* IP address of this network interface */
-  struct sockaddr intAddr;
+  union olsr_ip_addr intAddr;
 
   /* Broadcast address of this network interface */
-  struct sockaddr broadAddr;
+  union olsr_ip_addr broadAddr;
 
   #define FRAGMENT_HISTORY_SIZE 10
   struct TFragmentHistory
@@ -84,6 +90,11 @@ struct TBmfInterface
 
   int nextFragmentHistoryEntry;
 
+  /* Number of received and transmitted BMF packets on this interface */
+  u_int32_t nBmfPacketsRx;
+  u_int32_t nBmfPacketsRxDup;
+  u_int32_t nBmfPacketsTx;
+
   /* Next element in list */
   struct TBmfInterface* next; 
 };
@@ -97,6 +108,9 @@ extern int EtherTunTapFd;
 
 extern char EtherTunTapIfName[];
 
+/* 10.255.255.253 in host byte order */
+#define ETHERTUNTAPDEFAULTIP 0x0AFFFFFD
+
 extern u_int32_t EtherTunTapIp;
 extern u_int32_t EtherTunTapIpMask;
 extern u_int32_t EtherTunTapIpBroadcast;
@@ -106,15 +120,29 @@ extern int CapturePacketsOnOlsrInterfaces;
 enum TTunOrTap { TT_TUN = 0, TT_TAP };
 extern enum TTunOrTap TunOrTap;
 
+enum TBmfMechanism { BM_BROADCAST = 0, BM_UNICAST_PROMISCUOUS };
+extern enum TBmfMechanism BmfMechanism;
+
 int SetBmfInterfaceName(const char* ifname);
 int SetBmfInterfaceType(const char* iftype);
 int SetBmfInterfaceIp(const char* ip);
 int SetCapturePacketsOnOlsrInterfaces(const char* enable);
+int SetBmfMechanism(const char* mechanism);
+int DeactivateSpoofFilter(void);
+void RestoreSpoofFilter(void);
+struct link_entry* GetBestNeighbor(
+  struct TBmfInterface* intf,
+  union olsr_ip_addr* source,
+  union olsr_ip_addr* forwardedBy,
+  union olsr_ip_addr* forwardedTo,
+  int* multipleNeighbors);
 int CreateBmfNetworkInterfaces(struct interface* skipThisIntf);
 void AddInterface(struct interface* newIntf);
 void CloseBmfNetworkInterfaces(void);
 int AddNonOlsrBmfIf(const char* ifName);
 int IsNonOlsrBmfIf(const char* ifName);
-void CheckAndUpdateLocalBroadcast(unsigned char* buffer, struct sockaddr* broadAddr);
+void CheckAndUpdateLocalBroadcast(unsigned char* ipPacket, union olsr_ip_addr* broadAddr);
+void AddMulticastRoute(void);
+void DeleteMulticastRoute(void);
 
 #endif /* _BMF_NETWORKINTERFACES_H */
index c353744..f4f007b 100644 (file)
 
 /* -------------------------------------------------------------------------
  * File       : Packet.c
- * Description: BMF and IP packet processing functions
+ * Description: IP packet and Ethernet frame processing functions
  * Created    : 29 Jun 2006
  *
- * $Id: Packet.c,v 1.3 2007/02/10 17:05:56 bernd67 Exp $ 
  * ------------------------------------------------------------------------- */
 
 #include "Packet.h"
 
 /* System includes */
+#include <stddef.h> /* NULL */
 #include <assert.h> /* assert() */
-#include <sys/types.h> /* u_int32_t */
+#include <string.h> /* memcpy() */
+#include <sys/types.h> /* u_int8_t, u_int16_t, u_int32_t */
 #include <netinet/in.h> /* ntohs(), htons() */
 #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
+ * Function   : IsIpFragment
+ * Description: Check if an IP packet is an IP fragment
+ * Input      : ipPacket - the IP packet
+ * Output     : none
+ * Return     : true (1) or false (0)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int IsIpFragment(unsigned char* ipPacket)
+{
+  struct ip* iph;
+
+  assert(ipPacket != NULL);
+
+  iph = (struct ip*) ipPacket;
+  if ((ntohs(iph->ip_off) & IP_OFFMASK) != 0)
+  {
+    return 1;
+  }
+  return 0;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : GetTotalLength
+ * Description: Retrieve the total length of the IP packet (in bytes) of
+ *              an IP packet
+ * Input      : ipPacket - the IP packet
  * Output     : none
  * Return     : IP packet length
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-int GetIpPacketLength(unsigned char* buffer)
+u_int16_t GetTotalLength(unsigned char* ipPacket)
 {
   struct iphdr* iph;
 
-  assert(buffer != NULL);
+  assert(ipPacket != NULL);
 
-  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  iph = (struct iphdr*) ipPacket;
   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
+ * Function   : GetHeaderLength
+ * Description: Retrieve the IP header length (in bytes) of an IP packet
+ * Input      : ipPacket - the IP packet
  * Output     : none
  * Return     : IP header length
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-int GetIpHeaderLength(unsigned char* buffer)
+unsigned int GetHeaderLength(unsigned char* ipPacket)
 {
   struct iphdr* iph;
 
-  assert(buffer != NULL);
+  assert(ipPacket != NULL);
 
-  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  iph = (struct iphdr*) ipPacket;
   return iph->ihl << 2;
 }
 
 /* -------------------------------------------------------------------------
- * Function   : GetIpTtl
+ * Function   : GetTtl
  * Description: Retrieve the TTL (Time To Live) value from the IP header of
- *              the passed ethernet-IP packet
- * Input      : buffer - the ethernet-IP packet
+ *              an IP packet
+ * Input      : ipPacket - the IP packet
  * Output     : none
  * Return     : TTL value
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-int GetIpTtl(unsigned char* buffer)
+u_int8_t GetTtl(unsigned char* ipPacket)
 {
   struct iphdr* iph;
 
-  assert(buffer != NULL);
+  assert(ipPacket != NULL);
 
-  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  iph = (struct iphdr*) ipPacket;
   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
+ *              the IP header of an IP packet
+ * Input      : ipPacket - the IP packet
  * Output     : sttl - the TTL and checksum values
  * Return     : none
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
+void SaveTtlAndChecksum(unsigned char* ipPacket, struct TSaveTtl* sttl)
 {
   struct iphdr* iph;
 
-  assert(buffer != NULL && sttl != NULL);
+  assert(ipPacket != NULL && sttl != NULL);
 
-  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  iph = (struct iphdr*) ipPacket;
   sttl->ttl = iph->ttl;
   sttl->check = ntohs(iph->check);
 }
@@ -127,20 +148,20 @@ void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
 /* -------------------------------------------------------------------------
  * 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
+ *              the IP header of an IP packet
+ * Input      : ipPacket - the IP packet
  *              sttl - the TTL and checksum values
  * Output     : none
  * Return     : none
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
+void RestoreTtlAndChecksum(unsigned char* ipPacket, struct TSaveTtl* sttl)
 {
   struct iphdr* iph;
 
-  assert(buffer != NULL && sttl != NULL);
+  assert(ipPacket != NULL && sttl != NULL);
 
-  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  iph = (struct iphdr*) ipPacket;
   iph->ttl = sttl->ttl;
   iph->check = htons(sttl->check);
 }
@@ -149,22 +170,118 @@ void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl)
  * Function   : DecreaseTtlAndUpdateHeaderChecksum
  * Description: For an IP packet, decrement the TTL value and update the IP header
  *              checksum accordingly.
- * Input      : buffer - the ethernet-IP packet
+ * Input      : ipPacket - the IP packet
  * Output     : none
  * Return     : none
  * Data Used  : none
  * Notes      : See also RFC1141
  * ------------------------------------------------------------------------- */
-void DecreaseTtlAndUpdateHeaderChecksum(unsigned char* buffer)
+void DecreaseTtlAndUpdateHeaderChecksum(unsigned char* ipPacket)
 {
   struct iphdr* iph;
   u_int32_t sum;
 
-  assert(buffer != NULL);
+  assert(ipPacket != NULL);
 
-  iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
+  iph = (struct iphdr*) ipPacket;
 
   iph->ttl--; /* decrement ttl */
   sum = ntohs(iph->check) + 0x100; /* increment checksum high byte */
   iph->check = htons(sum + (sum>>16)); /* add carry */
 }
+
+/* -------------------------------------------------------------------------
+ * Function   : GetEtherType
+ * Description: Retrieve the EtherType of an Ethernet frame
+ * Input      : ethernetFrame - the Ethernet frame
+ * Output     : none
+ * Return     : EtherType
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+u_int16_t GetEtherType(unsigned char* ethernetFrame)
+{
+  u_int16_t type;
+  memcpy(&type, ethernetFrame + ETH_TYPE_OFFSET, 2);
+  return ntohs(type);
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : GetIpHeader
+ * Description: Retrieve the IP header from an Ethernet frame
+ * Input      : ethernetFrame - the Ethernet frame
+ * Output     : none
+ * Return     : IP header
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+struct ip* GetIpHeader(unsigned char* ethernetFrame)
+{
+  return (struct ip*)(ethernetFrame + IP_HDR_OFFSET);
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : GetIpPacket
+ * Description: Retrieve the IP packet from an Ethernet frame
+ * Input      : ethernetFrame - the Ethernet frame
+ * Output     : none
+ * Return     : IP packet
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+unsigned char* GetIpPacket(unsigned char* ethernetFrame)
+{
+  return ethernetFrame + IP_HDR_OFFSET;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : GetFrameLength
+ * Description: Return the Ethernet frame length of an Ethernet frame containing
+ *              an IP packet
+ * Input      : ethernetFrame - the Ethernet frame
+ * Output     : none
+ * Return     : The frame length
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+u_int16_t GetFrameLength(unsigned char* ethernetFrame)
+{
+  return GetTotalLength(GetIpPacket(ethernetFrame)) + IP_HDR_OFFSET;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : SetFrameSourceMac
+ * Description: Set the source MAC address of an Ethernet frame
+ * Input      : ethernetFrame - the Ethernet frame
+              : srcMac - the source MAC address
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+void SetFrameSourceMac(unsigned char* ethernetFrame, unsigned char* srcMac)
+{
+  memcpy(ethernetFrame + IFHWADDRLEN, srcMac, IFHWADDRLEN);
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : GetEthernetFrame
+ * Description: Retrieve the Ethernet frame from BMF encapsulation UDP data
+ * Input      : encapsulationUdpData - the encapsulation UDP data
+ * Output     : none
+ * Return     : The Ethernet frame
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+unsigned char* GetEthernetFrame(unsigned char* encapsulationUdpData)
+{
+  return encapsulationUdpData + ENCAP_HDR_LEN;
+}
+
+/* -------------------------------------------------------------------------
+ * Function   : GetEncapsulationUdpDataLength
+ * Description: Return the length of BMF encapsulation UDP data
+ * Input      : encapsulationUdpData - the encapsulation UDP data
+ * Output     : none
+ * Return     : The packet length
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+u_int16_t GetEncapsulationUdpDataLength(unsigned char* encapsulationUdpData)
+{
+  return GetFrameLength(GetEthernetFrame(encapsulationUdpData)) + ENCAP_HDR_LEN;
+}
+
index 0b0e903..24f5c83 100644 (file)
@@ -38,7 +38,6 @@
  * 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 */
@@ -67,7 +66,7 @@ struct TEncapHeader
   u_int32_t futureExpansion3;
 } __attribute__((__packed__));
 
-#define        ENCAP_HDR_LEN (sizeof(struct TEncapHeader))
+#define        ENCAP_HDR_LEN ((int)sizeof(struct TEncapHeader))
 
 struct TSaveTtl
 {
@@ -75,11 +74,19 @@ struct TSaveTtl
   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);
-void DecreaseTtlAndUpdateHeaderChecksum(unsigned char* buffer);
+int IsIpFragment(unsigned char* ipPacket);
+u_int16_t GetTotalLength(unsigned char* ipPacket);
+unsigned int GetHeaderLength(unsigned char* ipPacket);
+u_int8_t GetTtl(unsigned char* ipPacket);
+void SaveTtlAndChecksum(unsigned char* ipPacket, struct TSaveTtl* sttl);
+void RestoreTtlAndChecksum(unsigned char* ipPacket, struct TSaveTtl* sttl);
+void DecreaseTtlAndUpdateHeaderChecksum(unsigned char* ipPacket);
+u_int16_t GetEtherType(unsigned char* ethernetFrame);
+struct ip* GetIpHeader(unsigned char* ethernetFrame);
+unsigned char* GetIpPacket(unsigned char* ethernetFrame);
+u_int16_t GetFrameLength(unsigned char* ethernetFrame);
+void SetFrameSourceMac(unsigned char* ethernetFrame, unsigned char* srcMac);
+unsigned char* GetEthernetFrame(unsigned char* encapsulationUdpData);
+u_int16_t GetEncapsulationUdpDataLength(unsigned char* encapsulationUdpData);
 
 #endif /* _BMF_PACKET_H */
index 21d6fbc..45e1ef4 100644 (file)
  *              multicast IP packets.
  * Created    : 29 Jun 2006
  *
- * $Id: PacketHistory.c,v 1.3 2007/04/20 14:06:18 bernd67 Exp $ 
  * ------------------------------------------------------------------------- */
 
 #include "PacketHistory.h"
 
 /* System includes */
+#include <stddef.h> /* NULL */
 #include <assert.h> /* assert() */
 #include <string.h> /* memset */
 #include <sys/types.h> /* u_int16_t, u_int32_t */
@@ -50,7 +50,7 @@
 /* OLSRD includes */
 #include "olsr.h" /* olsr_printf */
 
-/* Plugin includes */
+/* NULLPlugin includes */
 #include "Packet.h"
 
 static u_int32_t PacketHistory[HISTORY_TABLE_SIZE];
@@ -146,23 +146,23 @@ static u_int32_t CalcCrc32(unsigned char* buffer, ssize_t len)
 
 /* -------------------------------------------------------------------------
  * 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
+ * Description: Calculates the CRC-32 value for an Ethernet frame
+ * Input      : ethernetFrame - the Ethernet frame
+ *              len - the number of octets in the Ethernet frame
  * 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)
+u_int32_t PacketCrc32(unsigned char* ethernetFrame, ssize_t len)
 {
   ssize_t nCrcBytes;
   struct TSaveTtl sttl;
-  struct iphdr* iph;
+  struct ip* ipHeader;
   u_int32_t result;
 
-  assert(ethPkt != NULL);
+  assert(ethernetFrame != NULL);
 
   /* Start CRC calculation at ethertype; skip source and destination MAC 
    * addresses, and ethertype.
@@ -183,15 +183,15 @@ u_int32_t PacketCrc32(unsigned char* ethPkt, ssize_t len)
     nCrcBytes = CRC_UPTO_NBYTES;
   }
 
-  SaveTtlAndChecksum(ethPkt, &sttl);
+  SaveTtlAndChecksum(GetIpPacket(ethernetFrame), &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 */
+  ipHeader = GetIpHeader(ethernetFrame);
+  ipHeader->ip_ttl = 0xFF; /* fixed value of TTL for CRC-32 calculation */
+  ipHeader->ip_sum = 0x5A5A; /* fixed value of IP header checksum for CRC-32 calculation */
 
-  result = CalcCrc32(ethPkt + IP_HDR_OFFSET, nCrcBytes);
+  result = CalcCrc32(ethernetFrame + IP_HDR_OFFSET, nCrcBytes);
 
-  RestoreTtlAndChecksum(ethPkt, &sttl);
+  RestoreTtlAndChecksum(GetIpPacket(ethernetFrame), &sttl);
   return result;
 }
 
index 4f814ed..99ffb85 100644 (file)
@@ -39,7 +39,6 @@
  *              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 */
index 0707883..46cd894 100644 (file)
  * Description: Interface to the OLSRD plugin system
  * Created    : 29 Jun 2006
  *
- * $Id: olsrd_plugin.c,v 1.3 2007/04/20 14:06:18 bernd67 Exp $ 
  * ------------------------------------------------------------------------- */
 
 /* System includes */
 #include <assert.h> /* assert() */
-#include <stdio.h>
+#include <stddef.h> /* NULL */
 
 /* OLSRD includes */
 #include "olsrd_plugin.h"